linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/13] Add MediaTek ISP7.x camera system support
@ 2025-07-07  1:31 shangyao lin
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
                   ` (13 more replies)
  0 siblings, 14 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

Based on linux-next tag: next-20250630

This patch set adds the MediaTek ISP7.x camera system hardware driver.

The driver sets up ISP hardware, handles interrupts, and initializes
V4L2 device nodes and functions. It also implements a V4L2 standard video
driver utilizing the media framework APIs, connects sensors and the ISP
via the seninf interface, and communicates with the SCP co-processor to
compose ISP registers in firmware.

These patches include:

CSI data reception from sensors Sensor interface bridge RAW/YUV image
pre-processing ISP utility and control modules

Changelog (v2):

 - Fix documentation typos 
 - Address review comments from v1

Note: At this stage (v2), the related firmware interface and headers are
still under development and review. Once the code is more stable and ready
for upstream submission, we will provide the corresponding linux-firmware
submission and clearly document which MediaTek SCP firmware version is
required for this driver.  Thank you for reviewing these patches.

shangyao.lin (13):
  dt-bindings: media: mediatek: add camisp binding dt-bindings: media:
  mediatek: add seninf-core binding dt-bindings: media: mediatek: add
  cam-raw binding dt-bindings: media: mediatek: add cam-yuv binding media:
  platform: mediatek: add isp_7x seninf unit media: platform: mediatek:
  add isp_7x state ctrl MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW
  UNIT media: platform: mediatek: add isp_7x camsys unit media: platform:
  mediatek: add isp_7x utility media: platform: mediatek: add isp_7x
  video ops media: platform: mediatek: add isp_7x build config uapi:
  linux: add mediatek isp_7x camsys user api media: uapi: mediatek:
  document ISP7x camera system and user controls

 .../mediatek/mediatek,mt8188-cam-raw.yaml     |  156 +
 .../mediatek/mediatek,mt8188-cam-yuv.yaml     |  134 +
 .../mediatek/mediatek,mt8188-camisp.yaml      |   68 +
 .../mediatek/mediatek,mt8188-seninf-core.yaml |  121 +
 .../media/v4l/mtk-isp7x-camsys.rst            |   94 +
 .../media/v4l/mtk-isp7x-controls.rst          |  199 +
 drivers/media/platform/mediatek/Kconfig       |    1 +
 drivers/media/platform/mediatek/Makefile      |    2 +
 drivers/media/platform/mediatek/isp/Kconfig   |   21 +
 .../platform/mediatek/isp/isp_7x/Makefile     |    7 +
 .../mediatek/isp/isp_7x/camsys/Makefile       |   14 +
 .../isp_7x/camsys/kd_imgsensor_define_v4l2.h  |   86 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c | 1409 +++++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h |  131 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-defs.h |  161 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h  |   87 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h  |  213 +
 .../isp/isp_7x/camsys/mtk_cam-meta-mt8188.h   | 2296 ++++++++
 .../isp/isp_7x/camsys/mtk_cam-plat-util.c     |  141 +
 .../isp/isp_7x/camsys/mtk_cam-plat-util.h     |   15 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.c |  394 ++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.h |   28
 + .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.c  | 4883
 +++++++++++++++++ .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.h  |
 323 ++ .../isp/isp_7x/camsys/mtk_cam-regs-mt8188.h   |  374
 ++ .../isp/isp_7x/camsys/mtk_cam-seninf-def.h    |  237 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-drv.c    | 1441 +++++
 .../isp/isp_7x/camsys/mtk_cam-seninf-drv.h    |   16 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-hw.h     |  108 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-if.h     |   24 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-regs.h   |   44 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-route.c  |  279 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-route.h  |   20 +
 .../isp/isp_7x/camsys/mtk_cam-seninf.h        |  161 +
 .../isp/isp_7x/camsys/mtk_cam-timesync.c      |  125 +
 .../isp/isp_7x/camsys/mtk_cam-timesync.h      |   12 +
 .../isp/isp_7x/camsys/mtk_cam-video.c         | 1594
 ++++++ .../isp/isp_7x/camsys/mtk_cam-video.h         |
 223 + .../mediatek/isp/isp_7x/camsys/mtk_cam.c      | 3977
 ++++++++++++++ .../mediatek/isp/isp_7x/camsys/mtk_cam.h      |
 718 +++ .../isp_7x/camsys/mtk_camera-v4l2-controls.h  |   63
 + .../isp_7x/camsys/mtk_csi_phy_2_0/Makefile    |    5 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h   |  679 +++
 .../mtk_cam-seninf-csi0-cphy.h                |   51 +
 .../mtk_cam-seninf-csi0-dphy.h                |   98 +
 .../mtk_cam-seninf-hw_phy_2_0.c               | 1932 +++++++
 .../mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h  |  165 +
 .../mtk_cam-seninf-seninf1-csi2.h             |  264 +
 .../mtk_cam-seninf-seninf1-mux.h              |  120 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h  |   46 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h      |   43 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h |   76 +
 include/uapi/linux/mtkisp_camsys.h            |  132 +
 include/uapi/linux/videodev2.h                |   87 +
 54 files changed, 24098 insertions(+) create mode 100755
 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml
 create mode 100755
 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
 create mode 100755
 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
 create mode 100755
 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml
 create mode 100755
 Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst create mode
 100755 Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst mode
 change 100644 => 100755 drivers/media/platform/mediatek/Kconfig mode
 change 100644 => 100755 drivers/media/platform/mediatek/Makefile create
 mode 100755 drivers/media/platform/mediatek/isp/Kconfig create mode
 100755 drivers/media/platform/mediatek/isp/isp_7x/Makefile create mode
 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h create
 mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
 create mode 100755
 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h
 create mode 100755 include/uapi/linux/mtkisp_camsys.h mode change 100644
 => 100755 include/uapi/linux/videodev2.h

-- 2.18.0


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
                     ` (2 more replies)
  2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
                   ` (12 subsequent siblings)
  13 siblings, 3 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Add camera isp7x module device document.

---

Changes in v2:
  - Rename binding file to mediatek,mt8188-camisp.yaml
  - Split bindings into four separate patches (one per YAML file)
  - Various fixes per review comments
  - Update maintainers list

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/mediatek,mt8188-camisp.yaml      | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml

diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
new file mode 100755
index 000000000000..53dbf5152e78
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2024 MediaTek Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek/mediatek,camisp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: The camisp unit of MediaTek ISP system
+
+maintainers:
+  - Shangyao Lin <shangyao.lin@mediatek.com>
+  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
+  - Shun-yi Wang <shun-yi.wang@mediatek.com>
+  - Teddy Chen <teddy.chen@mediatek.com>
+
+description:
+  MediaTek camisp is the ISP auxiliary unit for camera system in MediaTek SoC.
+
+properties:
+  compatible:
+    const: mediatek,mt8188-camisp
+
+  reg:
+    minItems: 1
+    maxItems: 1
+    description:
+      Base address of the camisp hardware block.
+
+  reg-names:
+    items:
+      - const: base
+    minItems: 1
+    maxItems: 1
+    description:
+      Name for the register region. Must be "base".
+
+  power-domains:
+    minItems: 1
+    maxItems: 1
+    description: Power domain for the camisp block.
+
+  mediatek,scp:
+    description: MediaTek co-process unit for ISP system
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/power/mediatek,mt8188-power.h>
+
+    soc {
+      isp@16000000 {
+        compatible = "mediatek,mt8188-camisp";
+        reg = <0 0x16000000 0 0x1000>;
+        reg-names = "base";
+        mediatek,scp = <&scp_dual>;
+        power-domains = <&spm MT8188_POWER_DOMAIN_CAM_MAIN>;
+      };
+    };
+
+...
\ No newline at end of file
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
                     ` (2 more replies)
  2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
                   ` (11 subsequent siblings)
  13 siblings, 3 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

1. Add camera isp7x module device document

---

Changes in v2:
  - Rename binding file to mediatek,mt8188-seninf-core.yaml
  - Various fixes per review comments
  - Update maintainers list

Question for reviewer (CK):

Hi CK,

Thank you for your review and suggestions on this patch, especially for providing the reference patch (https://patchwork.kernel.org/project/linux-mediatek/list/?series=874617) and for mentioning in another patch ([V1,02/10] MEDIA: PLATFORM: MEDIATEK: ADD SENINF CONTROLLER) the suggestion to "Move the phy part to phy/mediatek/ folder. You could refer to phy/mediatek/phy-mtk-mipi-csi-0-5.c".

After reading your comments and the reference patches, my understanding is that only the seninf-core driver should manage all ports internally, and each port corresponds to a PHY. During probe, the driver will parse each port, obtain the corresponding PHY (e.g., devm_phy_get(dev, "csi0"), devm_phy_get(dev, "csi1"), etc.), and operate the PHY for each port individually during stream on/off or power on/off.

Could you please confirm if my understanding is correct?
If you have any additional reference patches or examples, I would greatly appreciate it.

Thank you for your guidance!

Best regards,
Shangyao

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/mediatek,mt8188-seninf-core.yaml | 121 ++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml

diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml
new file mode 100755
index 000000000000..763b96b561cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2023 MediaTek Inc.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/mediatek,seninf-core.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: The seninf-core top unit of MediaTek ISP system
+
+maintainers:
+  - Shangyao Lin <shangyao.lin@mediatek.com>
+  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
+  - Shun-yi Wang <shun-yi.wang@mediatek.com>
+  - Teddy Chen <teddy.chen@mediatek.com>
+
+description: |
+  MediaTek seninf-core is the ISP sensor interface unit in MediaTek SoC.
+  The sensor interface serves as the MIPI-CSI2 top RX controller.
+
+properties:
+  compatible:
+    const: mediatek,mt8188-seninf-core
+
+  reg:
+    minItems: 1
+    maxItems: 1
+    description: |
+      Base address register region.
+
+  reg-names:
+    items:
+      - const: base
+    minItems: 1
+    maxItems: 1
+
+  mtk_csi_phy_ver:
+    description: Describes MediaTek camera Rx controller version
+    $ref: /schemas/types.yaml#/definitions/string
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  power-domains:
+    minItems: 1
+    maxItems: 4
+
+  clocks:
+    minItems: 4
+    maxItems: 4
+    description: List of clock phandles required by the controller.
+
+  clock-names:
+    items:
+      - const: clk_cam_seninf
+      - const: clk_top_seninf
+      - const: clk_top_seninf1
+      - const: clk_top_camtm
+    minItems: 4
+    maxItems: 4
+
+  mediatek,larbs:
+    description: |
+      List of phandles to the local arbiters in the current SoCs.
+      Refer to bindings/memory-controllers/mediatek,smi-larb.yaml.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    minItems: 1
+    maxItems: 32
+
+  dma-ranges:
+    description: |
+      Describes the address information of IOMMU mapping to memory.
+      Defines six fields for the MediaTek IOMMU extended iova, pa, and size.
+    minItems: 1
+
+  phys:
+    description: List of phandle and args to the PHY provider.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+
+  phy-names:
+    description: Names of the PHYs.
+    $ref: /schemas/types.yaml#/definitions/string-array
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/power/mediatek,mt8188-power.h>
+    #include <dt-bindings/clock/mediatek,mt8188-clk.h>
+
+    seninf@16010000 {
+      compatible = "mediatek,mt8188-seninf-core";
+      reg = <0 0x16010000 0 0x8000>;
+      reg-names = "base";
+      mtk_csi_phy_ver = "mtk_csi_phy_2_0";
+      interrupts = <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH 0>;
+      power-domains = <&spm MT8188_POWER_DOMAIN_CSIRX_TOP>,
+                      <&spm MT8188_POWER_DOMAIN_CAM_VCORE>,
+                      <&spm MT8188_POWER_DOMAIN_CAM_MAIN>;
+      clocks = <&camsys CLK_CAM_MAIN_SENINF>,
+               <&topckgen CLK_TOP_SENINF>,
+               <&topckgen CLK_TOP_SENINF1>,
+               <&topckgen CLK_TOP_CAMTM>;
+      clock-names = "clk_cam_seninf",
+                    "clk_top_seninf",
+                    "clk_top_seninf1",
+                    "clk_top_camtm";
+    };
+
+...
\ No newline at end of file
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
  2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
                     ` (2 more replies)
  2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
                   ` (10 subsequent siblings)
  13 siblings, 3 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Add camera isp7x module device document.

---

Changes in v2:
  - Rename binding file to mediatek,mt8188-cam-raw.yaml
  - Various fixes per review comments
  - Update maintainers list

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/mediatek,mt8188-cam-raw.yaml     | 156 ++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml

diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml
new file mode 100755
index 000000000000..dfedb229e79c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml
@@ -0,0 +1,156 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2024 MediaTek Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: The cam-raw unit of MediaTek ISP system
+
+maintainers:
+  - Shangyao Lin <shangyao.lin@mediatek.com>
+  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
+  - Shun-yi Wang <shun-yi.wang@mediatek.com>
+  - Teddy Chen <teddy.chen@mediatek.com>
+
+description:
+  MediaTek cam-raw is the camera RAW processing unit in MediaTek SoC.
+
+properties:
+  compatible:
+    const: mediatek,mt8188-cam-raw
+
+  reg:
+    minItems: 1
+    maxItems: 2
+    description:
+      Base address and optional inner base address of the cam-raw hardware block.
+
+  reg-names:
+    items:
+      - const: base
+      - const: inner_base
+    minItems: 1
+    maxItems: 2
+    description:
+      Names for each register region. Must be "base" and optionally "inner_base".
+
+  mediatek,larbs:
+    description:
+      List of phandles to the local arbiters in the current SoCs.
+      Refer to bindings/memory-controllers/mediatek,smi-larb.yaml.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    minItems: 1
+    maxItems: 32
+
+  interrupts:
+    minItems: 1
+    description: Interrupts for the cam-raw block.
+
+  dma-ranges:
+    minItems: 1
+    description: Address information of IOMMU mapping to memory.
+
+  power-domains:
+    minItems: 1
+    description: Power domains for the cam-raw block.
+
+  clocks:
+    minItems: 4
+    maxItems: 16
+    description: List of phandles to the clocks required by the cam-raw block.
+
+  clock-names:
+    items:
+      - const: camsys_cam2mm0_cgpdn
+      - const: camsys_cam2mm1_cgpdn
+      - const: camsys_cam2sys_cgpdn
+      - const: camsys_cam_cgpdn
+      - const: camsys_camtg_cgpdn
+      - const: camsys_rawa_larbx_cgpdn
+      - const: camsys_rawa_cam_cgpdn
+      - const: camsys_rawa_camtg_cgpdn
+      - const: topckgen_top_cam
+      - const: topckgen_top_camtg
+      - const: topckgen_top_camtm
+    minItems: 4
+    maxItems: 16
+    description: Names of the clocks, must match the order of the clocks property.
+
+  iommus:
+    minItems: 1
+    maxItems: 32
+    description: Points to the respective IOMMU block with master port as argument.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+  - iommus
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/power/mediatek,mt8188-power.h>
+    #include <dt-bindings/clock/mediatek,mt8188-clk.h>
+    #include <dt-bindings/memory/mediatek,mt8188-memory-port.h>
+
+    soc {
+      raw@16030000 {
+        compatible = "mediatek,mt8188-cam-raw";
+        reg = <0 0x16030000 0 0x8000>,
+              <0 0x16038000 0 0x8000>;
+        reg-names = "base", "inner_base";
+        interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH 0>;
+        dma-ranges = <0x2 0x0 0x0 0x40000000 0x1 0x0>;
+        power-domains = <&spm MT8188_POWER_DOMAIN_CAM_SUBA>;
+        clocks = <&camsys CLK_CAM_MAIN_CAM2MM0_GALS>,
+                 <&camsys CLK_CAM_MAIN_CAM2MM1_GALS>,
+                 <&camsys CLK_CAM_MAIN_CAM2SYS_GALS>,
+                 <&camsys CLK_CAM_MAIN_CAM>,
+                 <&camsys CLK_CAM_MAIN_CAMTG>,
+                 <&camsys_rawa CLK_CAM_RAWA_LARBX>,
+                 <&camsys_rawa CLK_CAM_RAWA_CAM>,
+                 <&camsys_rawa CLK_CAM_RAWA_CAMTG>,
+                 <&topckgen CLK_TOP_CAM>,
+                 <&topckgen CLK_TOP_CAMTG>,
+                 <&topckgen CLK_TOP_CAMTM>;
+        clock-names = "camsys_cam2mm0_cgpdn",
+                      "camsys_cam2mm1_cgpdn",
+                      "camsys_cam2sys_cgpdn",
+                      "camsys_cam_cgpdn",
+                      "camsys_camtg_cgpdn",
+                      "camsys_rawa_larbx_cgpdn",
+                      "camsys_rawa_cam_cgpdn",
+                      "camsys_rawa_camtg_cgpdn",
+                      "topckgen_top_cam",
+                      "topckgen_top_camtg",
+                      "topckgen_top_camtm";
+        iommus = <&vpp_iommu M4U_PORT_L16A_IMGO_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_CQI_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_CQI_R2>,
+                 <&vpp_iommu M4U_PORT_L16A_BPCI_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_LSCI_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_RAWI_R2>,
+                 <&vpp_iommu M4U_PORT_L16A_RAWI_R3>,
+                 <&vpp_iommu M4U_PORT_L16A_UFDI_R2>,
+                 <&vpp_iommu M4U_PORT_L16A_UFDI_R3>,
+                 <&vpp_iommu M4U_PORT_L16A_RAWI_R4>,
+                 <&vpp_iommu M4U_PORT_L16A_RAWI_R5>,
+                 <&vpp_iommu M4U_PORT_L16A_AAI_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_UFDI_R5>,
+                 <&vpp_iommu M4U_PORT_L16A_FHO_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_AAO_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_TSFSO_R1>,
+                 <&vpp_iommu M4U_PORT_L16A_FLKO_R1>;
+      };
+    };
+
+...
\ No newline at end of file
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (2 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
                     ` (2 more replies)
  2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
                   ` (9 subsequent siblings)
  13 siblings, 3 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Add camera isp7x module device document.

---

Changes in v2:
  - Rename binding file to mediatek,mt8188-cam-yuv.yaml
  - Various fixes per review comments
  - Update maintainers list

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/mediatek,mt8188-cam-yuv.yaml     | 134 ++++++++++++++++++
 1 file changed, 134 insertions(+)
 create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml

diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
new file mode 100755
index 000000000000..0de120d3c6e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2024 MediaTek Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: The cam-yuv unit of MediaTek ISP system
+
+maintainers:
+  - Shangyao Lin <shangyao.lin@mediatek.com>
+  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
+  - Shun-yi Wang <shun-yi.wang@mediatek.com>
+  - Teddy Chen <teddy.chen@mediatek.com>
+
+description:
+  MediaTek cam-yuv is the camera YUV processing unit in MediaTek SoC.
+
+properties:
+  compatible:
+    const: mediatek,mt8188-cam-yuv
+
+  reg:
+    minItems: 1
+    maxItems: 2
+    description:
+      Base address and optional inner base address of the cam-yuv hardware block.
+
+  reg-names:
+    items:
+      - const: base
+      - const: inner_base
+    minItems: 1
+    maxItems: 2
+    description:
+      Names for each register region. Must be "base" and optionally "inner_base".
+
+  mediatek,larbs:
+    description:
+      List of phandles to the local arbiters in the current SoCs.
+      Refer to bindings/memory-controllers/mediatek,smi-larb.yaml.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    minItems: 1
+    maxItems: 32
+
+  interrupts:
+    minItems: 1
+    description: Interrupts for the cam-yuv block.
+
+  dma-ranges:
+    minItems: 1
+    description: Address information of IOMMU mapping to memory.
+
+  power-domains:
+    minItems: 1
+    description: Power domains for the cam-yuv block.
+
+  clocks:
+    minItems: 4
+    maxItems: 16
+    description: List of phandles to the clocks required by the cam-yuv block.
+
+  clock-names:
+    items:
+      - const: camsys_cam2mm0_cgpdn
+      - const: camsys_cam2mm1_cgpdn
+      - const: camsys_cam2sys_cgpdn
+      - const: camsys_yuva_larbx
+      - const: camsys_yuva_cam_cgpdn
+      - const: camsys_yuva_camtg_cgpdn
+      - const: camsys_yuvb_larbx_cgpdn
+      - const: camsys_yuvb_cam_cgpdn
+      - const: camsys_yuvb_camtg_cgpdn
+    minItems: 4
+    maxItems: 16
+    description: Names of the clocks, must match the order of the clocks property.
+
+  iommus:
+    minItems: 1
+    maxItems: 32
+    description: Points to the respective IOMMU block with master port as argument.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+  - iommus
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/power/mediatek,mt8188-power.h>
+    #include <dt-bindings/clock/mediatek,mt8188-clk.h>
+    #include <dt-bindings/memory/mediatek,mt8188-memory-port.h>
+
+    soc {
+      yuv@16050000 {
+        compatible = "mediatek,mt8188-cam-yuv";
+        reg = <0 0x16050000 0 0x8000>;
+        reg-names = "base";
+        mediatek,larbs = <&larb17a>;
+        interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH 0>;
+        dma-ranges = <0x2 0x0 0x0 0x40000000 0x1 0x0>;
+        power-domains = <&spm MT8188_POWER_DOMAIN_CAM_SUBA>;
+        clocks = <&camsys CLK_CAM_MAIN_CAM2MM0_GALS>,
+                 <&camsys CLK_CAM_MAIN_CAM2MM1_GALS>,
+                 <&camsys CLK_CAM_MAIN_CAM2SYS_GALS>,
+                 <&camsys_yuva CLK_CAM_YUVA_LARBX>,
+                 <&camsys_yuva CLK_CAM_YUVA_CAM>,
+                 <&camsys_yuva CLK_CAM_YUVA_CAMTG>;
+        clock-names = "camsys_cam2mm0_cgpdn",
+                      "camsys_cam2mm1_cgpdn",
+                      "camsys_cam2sys_cgpdn",
+                      "camsys_yuva_larbx_cgpdn",
+                      "camsys_yuva_cam_cgpdn",
+                      "camsys_yuva_camtg_cgpdn";
+        iommus = <&vpp_iommu M4U_PORT_L17A_YUVO_R1>,
+                 <&vpp_iommu M4U_PORT_L17A_YUVO_R3>,
+                 <&vpp_iommu M4U_PORT_L17A_YUVCO_R1>,
+                 <&vpp_iommu M4U_PORT_L17A_YUVO_R2>,
+                 <&vpp_iommu M4U_PORT_L17A_RZH1N2TO_R1>,
+                 <&vpp_iommu M4U_PORT_L17A_DRZS4NO_R1>,
+                 <&vpp_iommu M4U_PORT_L17A_TNCSO_R1>;
+      };
+    };
+
+...
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (3 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  5:50   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2025-07-07  1:31 ` [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl shangyao lin
                   ` (8 subsequent siblings)
  13 siblings, 3 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduce support for the MediaTek sensor interface (seninf) in the SoC camera
subsystem, focusing on CSI and stream control. The driver manages parameter
control, metering, status tracking, and interrupt handling for the camera sensor
interface hardware. It integrates with the MediaTek ISP CAMSYS, bridging camera
sensors and the ISP system, and provides V4L2 framework support for dynamic
stream configuration and virtual channel management.

---

Changes in v2:
 * Various fixes per review comments
 * Merged v1's 02/10 and 03/10 into a single patch

---

Question for AngeloGioacchino Del Regno:

Hi Angelo,

Thank you very much for your previous feedback. I have noticed some suggestions
to refactor the register read/write operations to use the regmap API. I would
like to ask: what are the main benefits of switching to regmap, and is it
recommended to convert all register accesses to use regmap for this driver?

If this is the preferred approach, I will update all register operations to use
regmap in v3.

Thank you for your guidance and advice!

Best regards,
Shangyao

---

Note:
The PHY operations have been refactored and separated from the seninf driver,
but there are still some issues to confirm with reviewers in this v2 patch
(dt-bindings: media: mediatek: add seninf-core binding). The PHY part will be
moved to drivers/phy/mediatek/ in v3.

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../isp_7x/camsys/kd_imgsensor_define_v4l2.h  |   86 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-def.h    |  237 ++
 .../isp/isp_7x/camsys/mtk_cam-seninf-drv.c    | 1441 ++++++++++++
 .../isp/isp_7x/camsys/mtk_cam-seninf-drv.h    |   16 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-hw.h     |  108 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-if.h     |   24 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-regs.h   |   44 +
 .../isp/isp_7x/camsys/mtk_cam-seninf-route.c  |  279 +++
 .../isp/isp_7x/camsys/mtk_cam-seninf-route.h  |   20 +
 .../isp/isp_7x/camsys/mtk_cam-seninf.h        |  161 ++
 .../isp_7x/camsys/mtk_csi_phy_2_0/Makefile    |    5 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h   |  679 ++++++
 .../mtk_cam-seninf-csi0-cphy.h                |   51 +
 .../mtk_cam-seninf-csi0-dphy.h                |   98 +
 .../mtk_cam-seninf-hw_phy_2_0.c               | 1932 +++++++++++++++++
 .../mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h  |  165 ++
 .../mtk_cam-seninf-seninf1-csi2.h             |  264 +++
 .../mtk_cam-seninf-seninf1-mux.h              |  120 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h  |   46 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h      |   43 +
 .../mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h |   76 +
 21 files changed, 5895 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h

diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
new file mode 100755
index 000000000000..54c23afe64bd
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef _KD_IMGSENSOR_DATA_V4L2_H
+#define _KD_IMGSENSOR_DATA_V4L2_H
+
+enum VC_FEATURE {
+	VC_NONE = 0,
+	VC_MIN_NUM,
+	VC_RAW_DATA = VC_MIN_NUM,
+	VC_RAW_DATA_MAX,
+
+	VC_PDAF_MIN_NUM = VC_RAW_DATA_MAX,
+	VC_PDAF_STATS = VC_PDAF_MIN_NUM,
+	VC_PDAF_STATS_NE,
+	VC_PDAF_STATS_ME,
+	VC_PDAF_STATS_SE,
+	VC_PDAF_STATS_PIX_1,
+	VC_PDAF_STATS_PIX_2,
+	VC_PDAF_STATS_NE_PIX_1 = VC_PDAF_STATS_PIX_1,
+	VC_PDAF_STATS_NE_PIX_2 = VC_PDAF_STATS_PIX_2,
+	VC_PDAF_STATS_ME_PIX_1,
+	VC_PDAF_STATS_ME_PIX_2,
+	VC_PDAF_STATS_SE_PIX_2,
+	VC_PDAF_MAX_NUM,
+
+	VC_HDR_MIN_NUM = VC_PDAF_MAX_NUM,
+	VC_HDR_MVHDR = VC_HDR_MIN_NUM,
+	VC_HDR_MAX_NUM,
+
+	VC_3HDR_MIN_NUM = VC_HDR_MAX_NUM,
+	VC_3HDR_EMBEDDED = VC_3HDR_MIN_NUM,
+	VC_3HDR_FLICKER,
+	VC_3HDR_Y,
+	VC_3HDR_AE,
+	VC_3HDR_MAX_NUM,
+
+	VC_STAGGER_MIN_NUM = VC_3HDR_MAX_NUM,
+	VC_STAGGER_EMBEDDED = VC_STAGGER_MIN_NUM,
+	VC_STAGGER_NE,
+	VC_STAGGER_ME,
+	VC_STAGGER_SE,
+	VC_STAGGER_MAX_NUM,
+
+	VC_YUV_MIN_NUM = VC_STAGGER_MAX_NUM,
+	VC_YUV_Y = VC_YUV_MIN_NUM,
+	VC_YUV_UV,
+	VC_YUV_MAX_NUM,
+
+	VC_RAW_EXT_MIN_NUM = VC_YUV_MAX_NUM,
+	VC_RAW_W_DATA = VC_RAW_EXT_MIN_NUM,
+	VC_RAW_PROCESSED_DATA,
+	VC_RAW_EXT_MAX_NUM,
+
+	VC_GENERAL_DATA_MIN_NUM = VC_RAW_EXT_MAX_NUM,
+	VC_GENERAL_EMBEDDED = VC_GENERAL_DATA_MIN_NUM,
+	VC_GENERAL_DATA_MAX_NUM,
+
+	VC_MAX_NUM = VC_GENERAL_DATA_MAX_NUM,
+};
+
+enum {
+	PAD_SINK = 0,
+	PAD_SRC_RAW0,
+	PAD_SRC_RAW1,
+	PAD_SRC_RAW2,
+	PAD_SRC_RAW_W0,
+	PAD_SRC_RAW_EXT0,
+	PAD_SRC_PDAF0,
+	PAD_SRC_PDAF1,
+	PAD_SRC_PDAF2,
+	PAD_SRC_PDAF3,
+	PAD_SRC_PDAF4,
+	PAD_SRC_PDAF5,
+	PAD_SRC_PDAF6,
+	PAD_SRC_HDR0,
+	PAD_SRC_HDR1,
+	PAD_SRC_HDR2,
+	PAD_SRC_GENERAL0,
+	PAD_MAXCNT,
+	PAD_ERR = 0xffff,
+};
+
+#endif              /* _KD_IMGSENSOR_DATA_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
new file mode 100755
index 000000000000..39f6005c8227
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2022 MediaTek Inc.
+
+#ifndef __MTK_CAM_SENINF_DEF_H__
+#define __MTK_CAM_SENINF_DEF_H__
+
+#include <linux/bitfield.h>
+
+#define SENINF_VC_MAXCNT 8
+#define SENINF_DEF_PIXEL_MODE 2
+
+#define SENINF_CLK_MARGIN_IN_PERCENT 0
+#define HW_BUF_EFFECT 10
+
+#define SENINF_HS_TRAIL_EN_CONDITION 1450000000
+#define SENINF_TIMESTAMP_CLK 1000
+#define ISP_CLK_LOW 273000000
+
+#define SENINF_CPHY_SETTLE_DELAY_DT 0x10
+#define SENINF_DPHY_SETTLE_DELAY_DT 0x10
+#define SENINF_SETTLE_DELAY_CK 0x11
+#define SENINF_HS_TRAIL_PARAMETER 0x34
+
+#define SENSOR_CLOCK_POLARITY_HIGH	0
+#define SENSOR_CLOCK_POLARITY_LOW	1
+#define NUM_PORTS			2
+#define DEFAULT_WIDTH			1600
+#define DEFAULT_HEIGHT			1200
+#define CSI_PORT_A_MASK GENMASK(3, 1)
+#define SENINF_MAX_STREAM 7
+
+// offset define
+#define ANA_CSI_RX_PORT0_OFFSET   0x0000
+#define ANA_CSI_RX_PORT0B_OFFSET  0x1000
+#define ANA_CSI_RX_PORT1_OFFSET   0x4000
+#define ANA_CSI_RX_PORT1B_OFFSET  0x5000
+#define ANA_CSI_RX_PORT2_OFFSET   0x8000
+#define ANA_CSI_RX_PORT2B_OFFSET  0x9000
+#define ANA_CSI_RX_PORT3_OFFSET   0xC000
+#define ANA_CSI_RX_PORT3B_OFFSET  0xD000
+
+#define ANA_DPHY_TOP_PORT0_OFFSET 0x2000
+#define ANA_DPHY_TOP_PORT1_OFFSET 0x6000
+#define ANA_DPHY_TOP_PORT2_OFFSET 0xA000
+#define ANA_DPHY_TOP_PORT3_OFFSET 0xE000
+
+#define ANA_CPHY_TOP_PORT0_OFFSET 0x3000
+#define ANA_CPHY_TOP_PORT1_OFFSET 0x7000
+#define ANA_CPHY_TOP_PORT2_OFFSET 0xB000
+#define ANA_CPHY_TOP_PORT3_OFFSET 0xF000
+
+#define IF_CTRL_BASE_OFFSET       0x0200
+#define IF_TG_BASE_OFFSET         0x0F00
+#define IF_CSI2_BASE_OFFSET       0x0A00
+#define IF_MUX_BASE_OFFSET        0x0D00
+#define IF_CAM_MUX_OFFSET         0x0400
+#define IF_PORT_STRIDE            0x1000
+
+enum CSI_PORT {
+	CSI_PORT_0 = 0,
+	CSI_PORT_1,
+	CSI_PORT_2,
+	CSI_PORT_3,
+	CSI_PORT_4,
+	CSI_PORT_5,
+	CSI_PORT_0A,
+	CSI_PORT_0B,
+	CSI_PORT_1A,
+	CSI_PORT_1B,
+	CSI_PORT_2A,
+	CSI_PORT_2B,
+	CSI_PORT_3A,
+	CSI_PORT_3B,
+	CSI_PORT_4A,
+	CSI_PORT_4B,
+	CSI_PORT_5A,
+	CSI_PORT_5B,
+	CSI_PORT_MAX_NUM,
+};
+
+#define SENINF_CSI_PORT_NAMES \
+	"0", \
+	"1", \
+	"2", \
+	"3", \
+	"4", \
+	"5", \
+	"0A", \
+	"0B", \
+	"1A", \
+	"1B", \
+	"2A", \
+	"2B", \
+	"3A", \
+	"3B", \
+	"4A", \
+	"4B", \
+	"5A", \
+	"5B", \
+
+enum SENINF_PHY_VER_ENUM {
+	SENINF_PHY_2_0,
+	SENINF_PHY_VER_NUM,
+};
+
+#define MTK_CSI_PHY_VERSIONS "mtk_csi_phy_2_0"
+
+enum SENINF_ENUM {
+	SENINF_1,
+	SENINF_2,
+	SENINF_3,
+	SENINF_4,
+	SENINF_5,
+	SENINF_6,
+	SENINF_7,
+	SENINF_8,
+	SENINF_9,
+	SENINF_10,
+	SENINF_11,
+	SENINF_12,
+	SENINF_NUM,
+};
+
+enum SENINF_MUX_ENUM {
+	SENINF_MUX1,
+	SENINF_MUX2,
+	SENINF_MUX3,
+	SENINF_MUX4,
+	SENINF_MUX5,
+	SENINF_MUX6,
+	SENINF_MUX7,
+	SENINF_MUX8,
+	SENINF_MUX9,
+	SENINF_MUX10,
+	SENINF_MUX11,
+	SENINF_MUX12,
+	SENINF_MUX13,
+	SENINF_MUX_NUM,
+	SENINF_MUX_ERROR = -1,
+};
+
+enum SENINF_CAM_MUX_ENUM {
+	SENINF_CAM_MUX0,
+	SENINF_CAM_MUX1,
+	SENINF_CAM_MUX2,
+	SENINF_CAM_MUX3,
+	SENINF_CAM_MUX4,
+	SENINF_CAM_MUX5,
+	SENINF_CAM_MUX6,
+	SENINF_CAM_MUX7,
+	SENINF_CAM_MUX8,
+	SENINF_CAM_MUX9,
+	SENINF_CAM_MUX10,
+	SENINF_CAM_MUX11,
+	SENINF_CAM_MUX12,
+	SENINF_CAM_MUX13,
+	SENINF_CAM_MUX14,
+	SENINF_CAM_MUX15,
+	SENINF_CAM_MUX_NUM,
+	SENINF_CAM_MUX_ERR = 0xff
+};
+
+/* 0:CSI2(2.5G), 3: parallel, 8:NCSI2(1.5G) */
+enum SENINF_SOURCE_ENUM {
+	CSI2 = 0x0,
+	TEST_MODEL = 0x1,
+	CCIR656	= 0x2,
+	PARALLEL_SENSOR = 0x3,
+	SERIAL_SENSOR = 0x4,
+	HD_TV = 0x5,
+	EXT_CSI2_OUT1 = 0x6,
+	EXT_CSI2_OUT2 = 0x7,
+	MIPI_SENSOR = 0x8,
+	VIRTUAL_CHANNEL_1 = 0x9,
+	VIRTUAL_CHANNEL_2 = 0xA,
+	VIRTUAL_CHANNEL_3 = 0xB,
+	VIRTUAL_CHANNEL_4 = 0xC,
+	VIRTUAL_CHANNEL_5 = 0xD,
+	VIRTUAL_CHANNEL_6 = 0xE,
+};
+
+enum SENINF_CSI2_ENUM {
+	CSI2_1_5G = 0x0,
+	CSI2_2_5G = 0x1,
+	CSI2_2_5G_CPHY = 0x2,
+};
+
+enum TG_FORMAT_ENUM {
+	FMT_RAW_8BIT = 0x0,
+	FMT_RAW_10BIT = 0x1,
+	FMT_RAW_12BIT = 0x2,
+	FMT_YUV422 = 0x3,
+	FMT_RAW_14BIT = 0x4,
+	FMT_RGB565_MIPI	= 0x5,
+	FMT_RGB888_MIPI	= 0x6,
+	FMT_JPEG = 0x7
+};
+
+enum {
+	CLK_CAM_SENINF = 0,
+	CLK_TOP_SENINF,
+	CLK_TOP_SENINF1,
+	CLK_TOP_SENINF2,
+	CLK_TOP_SENINF3,
+	CLK_TOP_SENINF4,
+	CLK_TOP_SENINF5,
+	CLK_TOP_SENINF_END,
+	CLK_TOP_CAMTM = CLK_TOP_SENINF_END,
+	CLK_MAXCNT,
+};
+
+#define SENINF_CLK_NAMES \
+	"clk_cam_seninf", \
+	"clk_top_seninf", \
+	"clk_top_seninf1", \
+	"clk_top_seninf2", \
+	"clk_top_seninf3", \
+	"clk_top_seninf4", \
+	"clk_top_seninf5", \
+	"clk_top_camtm", \
+
+static const int seninf_csi[CSI_PORT_MAX_NUM] = {
+    [CSI_PORT_0]  = SENINF_1,
+    [CSI_PORT_0A] = SENINF_1,
+    [CSI_PORT_0B] = SENINF_2,
+    [CSI_PORT_1]  = SENINF_3,
+    [CSI_PORT_1A] = SENINF_3,
+    [CSI_PORT_1B] = SENINF_4,
+    [CSI_PORT_2]  = SENINF_5,
+    [CSI_PORT_2A] = SENINF_5,
+    [CSI_PORT_2B] = SENINF_6,
+    [CSI_PORT_3]  = SENINF_7,
+    [CSI_PORT_3A] = SENINF_7,
+    [CSI_PORT_3B] = SENINF_8,
+};
+
+#endif /* __MTK_CAM_SENINF_DEF_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
new file mode 100755
index 000000000000..4e447ba0aec7
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
@@ -0,0 +1,1441 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/of_graph.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+#include <linux/nvmem-consumer.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-seninf-def.h"
+#include "mtk_cam-seninf.h"
+#include "mtk_cam-seninf-hw.h"
+#include "mtk_cam-seninf-route.h"
+#include "kd_imgsensor_define_v4l2.h"
+
+#define sd_to_ctx(__sd) container_of(__sd, struct seninf_ctx, subdev)
+#define notifier_to_ctx(__n) container_of(__n, struct seninf_ctx, notifier)
+#define ctrl_hdl_to_ctx(__h) container_of(__h, struct seninf_ctx, ctrl_handler)
+
+static const char * const csi_port_names[] = {
+	SENINF_CSI_PORT_NAMES
+};
+
+static const char * const clk_names[] = {
+	SENINF_CLK_NAMES
+};
+
+static const char * const set_reg_names[] = {
+	SET_REG_KEYS_NAMES
+};
+
+enum REG_OPS_CMD {
+	REG_OPS_CMD_ID,
+	REG_OPS_CMD_CSI,
+	REG_OPS_CMD_RG,
+	REG_OPS_CMD_VAL,
+	REG_OPS_CMD_MAX_NUM,
+};
+
+static int seninf_core_pm_runtime_enable(struct seninf_core *core)
+{
+	int i, ret;
+
+	core->pm_domain_cnt = of_count_phandle_with_args(core->dev->of_node,
+							 "power-domains",
+							 "#power-domain-cells");
+	if (core->pm_domain_cnt == 1) {
+		pm_runtime_enable(core->dev);
+	} else if (core->pm_domain_cnt > 1) {
+		core->pm_domain_devs =
+			devm_kcalloc(core->dev, core->pm_domain_cnt,
+				     sizeof(*core->pm_domain_devs), GFP_KERNEL);
+
+		if (!core->pm_domain_devs)
+			return -ENOMEM;
+
+		for (i = 0; i < core->pm_domain_cnt; i++) {
+			core->pm_domain_devs[i] =
+				dev_pm_domain_attach_by_id(core->dev, i);
+
+			if (IS_ERR(core->pm_domain_devs[i])) {
+				ret = PTR_ERR(core->pm_domain_devs[i]);
+
+				dev_info(core->dev,
+					 "%s: fail to probe pm id: %d (%d)\n",
+					 __func__, i, ret);
+
+				goto detach_pm;
+			}
+		}
+	}
+
+	return 0;
+
+detach_pm:
+	for (--i; i >= 0; i--)
+		dev_pm_domain_detach(core->pm_domain_devs[i], true);
+
+	return ret;
+}
+
+static int seninf_core_pm_runtime_disable(struct seninf_core *core)
+{
+	int i;
+
+	if (core->pm_domain_cnt == 1) {
+		pm_runtime_disable(core->dev);
+	} else {
+		if (!core->pm_domain_devs)
+			return -EINVAL;
+
+		for (i = 0; i < core->pm_domain_cnt; i++) {
+			if (core->pm_domain_devs[i])
+				dev_pm_domain_detach(core->pm_domain_devs[i], 1);
+		}
+	}
+
+	return 0;
+}
+
+static int seninf_core_pm_runtime_get_sync(struct seninf_core *core)
+{
+	int ret, i;
+
+	/* for one pm_domain */
+	if (core->pm_domain_cnt == 1) {
+		ret = pm_runtime_resume_and_get(core->dev);
+		if (ret < 0) {
+			dev_info(core->dev, "fail to resume seninf_core\n");
+			return ret;
+		}
+
+		return 0;
+	}
+
+	if (!core->pm_domain_devs)
+		return -EINVAL;
+
+	/* more than one pm_domain */
+	for (i = 0; i < core->pm_domain_cnt; i++) {
+		if (core->pm_domain_devs[i]) {
+			ret = pm_runtime_resume_and_get(core->pm_domain_devs[i]);
+			if (ret < 0) {
+				dev_info(core->dev,
+					 "fail to resume pm_domain_devs(%d)\n", i);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int seninf_core_pm_runtime_put(struct seninf_core *core)
+{
+	int i;
+
+	if (core->pm_domain_cnt == 1) {
+		pm_runtime_put_sync(core->dev);
+	} else {
+		if (!core->pm_domain_devs || core->pm_domain_cnt < 1)
+			return -EINVAL;
+
+		for (i = core->pm_domain_cnt - 1; i >= 0; i--) {
+			if (core->pm_domain_devs[i])
+				pm_runtime_put_sync(core->pm_domain_devs[i]);
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t mtk_irq_seninf(int irq, void *data)
+{
+	mtk_cam_seninf_irq_handler(irq, data);
+	return IRQ_HANDLED;
+}
+
+static int get_seninf_cfg(struct device *dev, struct seninf_core *core)
+{
+	int ret;
+	const char *ver;
+
+	ret = of_property_read_string(dev->of_node, "mtk_csi_phy_ver", &ver);
+	if (ret) {
+		dev_err(dev,
+			"Fail to get mtk_csi_phy_ver property (err=%d)\n", ret);
+
+		return ret;
+	}
+
+	if (!strcasecmp(ver, MTK_CSI_PHY_VERSIONS)) {
+		dev_info(dev, "%s: mtk_csi_phy_ver = %s\n", __func__, ver);
+
+		of_property_read_u32(dev->of_node, "seninf_num",
+				     &g_seninf_cfg->seninf_num);
+		of_property_read_u32(dev->of_node, "mux_num",
+				     &g_seninf_cfg->mux_num);
+		of_property_read_u32(dev->of_node, "cam_mux_num",
+				     &g_seninf_cfg->cam_mux_num);
+		of_property_read_u32(dev->of_node, "pref_mux_num",
+				     &g_seninf_cfg->pref_mux_num);
+
+		dev_info(dev,
+			 "%s: seninf_num = %d, mux_num = %d, cam_mux_num = %d, pref_mux_num =%d\n",
+			 __func__,
+			 g_seninf_cfg->seninf_num,
+			 g_seninf_cfg->mux_num,
+			 g_seninf_cfg->cam_mux_num,
+			 g_seninf_cfg->pref_mux_num);
+
+		return 0;
+	}
+
+	dev_err(dev, "DTS seninf config not correct.\n");
+
+	return -1;
+}
+
+static int seninf_core_probe(struct platform_device *pdev)
+{
+	int i, ret, irq;
+	struct resource *res;
+	struct seninf_core *core;
+	struct device *dev = &pdev->dev;
+
+	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, core);
+	core->dev = dev;
+	mutex_init(&core->mutex);
+	INIT_LIST_HEAD(&core->list);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
+	core->reg_if = devm_ioremap_resource(dev, res);
+	if (IS_ERR(core->reg_if))
+		return PTR_ERR(core->reg_if);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ana-rx");
+	core->reg_ana = devm_ioremap_resource(dev, res);
+	if (IS_ERR(core->reg_ana))
+		return PTR_ERR(core->reg_ana);
+
+	ret = get_seninf_cfg(dev, core);
+	if (ret) {
+		dev_err(dev, "failed to get seninf ops\n");
+		return ret;
+	}
+	mtk_cam_seninf_init_res(core);
+
+	spin_lock_init(&core->spinlock_irq);
+	irq = platform_get_irq(pdev, 0);
+	if (!irq) {
+		dev_err(dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_irq(dev, irq, mtk_irq_seninf, 0,
+			       dev_name(dev), core);
+	if (ret) {
+		dev_err(dev, "failed to request irq=%d\n", irq);
+		return ret;
+	}
+
+	/* default platform properties */
+	core->cphy_settle_delay_dt = SENINF_CPHY_SETTLE_DELAY_DT;
+	core->dphy_settle_delay_dt = SENINF_DPHY_SETTLE_DELAY_DT;
+	core->settle_delay_ck = SENINF_SETTLE_DELAY_CK;
+	core->hs_trail_parameter = SENINF_HS_TRAIL_PARAMETER;
+
+	/* read platform properties from device tree */
+	of_property_read_u32(dev->of_node, "cphy_settle_delay_dt",
+			     &core->cphy_settle_delay_dt);
+	of_property_read_u32(dev->of_node, "dphy_settle_delay_dt",
+			     &core->dphy_settle_delay_dt);
+	of_property_read_u32(dev->of_node, "settle_delay_ck",
+			     &core->settle_delay_ck);
+	of_property_read_u32(dev->of_node, "hs_trail_parameter",
+			     &core->hs_trail_parameter);
+
+	core->dfs.cnt = 0;
+	core->dfs.reg = NULL;
+
+	ret = seninf_core_pm_runtime_enable(core);
+	if (ret) {
+		dev_info(dev, "failed to enable seninf_core_pm_runtime\n");
+		return ret;
+	}
+
+	for (i = 0; i < CLK_MAXCNT; i++) {
+		core->clk[i] = devm_clk_get(dev, clk_names[i]);
+		if (IS_ERR(core->clk[i])) {
+			dev_info(dev, "failed to get %s\n", clk_names[i]);
+			core->clk[i] = NULL;
+			/* ignore not define seninf */
+		}
+	}
+
+	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+	if (ret) {
+		dev_info(dev, "%s: failed to create sub devices\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void seninf_core_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct seninf_core *core = dev_get_drvdata(dev);
+
+	of_platform_depopulate(dev);
+	seninf_core_pm_runtime_disable(core);
+}
+
+static const struct of_device_id seninf_core_of_match[] = {
+	{ .compatible = "mediatek,mt8188-seninf-core" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, seninf_core_of_match);
+
+struct platform_driver seninf_core_pdrv = {
+	.probe	= seninf_core_probe,
+	.remove	= seninf_core_remove,
+	.driver	= {
+		.name = "seninf-core",
+		.of_match_table = seninf_core_of_match,
+	},
+};
+
+static int get_csi_port(struct device *dev, int *port)
+{
+	int i, ret;
+	const char *name;
+
+	ret = of_property_read_string(dev->of_node, "csi-port", &name);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < CSI_PORT_MAX_NUM; i++) {
+		if (!strcasecmp(name, csi_port_names[i])) {
+			*port = i;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int seninf_subscribe_event(struct v4l2_subdev *sd,
+				  struct v4l2_fh *fh,
+				  struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void init_fmt(struct seninf_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->fmt); i++) {
+		ctx->fmt[i].format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+		ctx->fmt[i].format.width = DEFAULT_WIDTH;
+		ctx->fmt[i].format.height = DEFAULT_HEIGHT;
+		ctx->fmt[i].format.field = V4L2_FIELD_NONE;
+		ctx->fmt[i].format.colorspace = V4L2_COLORSPACE_SRGB;
+		ctx->fmt[i].format.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+		ctx->fmt[i].format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+		ctx->fmt[i].format.quantization = V4L2_QUANTIZATION_DEFAULT;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ctx->vcinfo.vc); i++)
+		ctx->vcinfo.vc[i].pixel_mode = SENINF_DEF_PIXEL_MODE;
+}
+
+static int dev_read_csi_efuse(struct seninf_ctx *ctx)
+{
+	struct nvmem_cell *cell;
+	size_t len = 0;
+	u32 *buf;
+
+	ctx->m_csi_efuse = 0x00000000;
+
+	cell = nvmem_cell_get(ctx->dev, "rg_csi");
+	dev_info(ctx->dev, "ctx->port = %d\n", ctx->port);
+	if (IS_ERR(cell)) {
+		if (PTR_ERR(cell) == -EPROBE_DEFER) {
+			dev_info(ctx->dev,
+				 "read csi efuse returned with error cell %d\n",
+				 -EPROBE_DEFER - EPROBE_DEFER);
+			return PTR_ERR(cell);
+		}
+		dev_info(ctx->dev,
+			 "read csi efuse returned with error cell %d\n", -1);
+		return -1;
+	}
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	nvmem_cell_put(cell);
+	if (IS_ERR(buf)) {
+		dev_info(ctx->dev, "read csi efuse returned with error buf\n");
+		return PTR_ERR(buf);
+	}
+	ctx->m_csi_efuse = *buf;
+	kfree(buf);
+	dev_info(ctx->dev, "Efuse Data: 0x%08x\n", ctx->m_csi_efuse);
+
+	return 0;
+}
+
+static const struct v4l2_mbus_framefmt fmt_default = {
+	.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+	.width = DEFAULT_WIDTH,
+	.height = DEFAULT_HEIGHT,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.xfer_func = V4L2_XFER_FUNC_DEFAULT,
+	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+	.quantization = V4L2_QUANTIZATION_DEFAULT,
+};
+
+static int mtk_cam_seninf_init_state(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *mf;
+	unsigned int i;
+
+	for (i = 0; i < sd->entity.num_pads; i++) {
+		mf = v4l2_subdev_state_get_format(sd_state, i);
+		*mf = fmt_default;
+	}
+
+	return 0;
+}
+
+static int mtk_cam_seninf_set_fmt(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+	struct v4l2_mbus_framefmt *format;
+	char sink_format_changed = 0;
+
+	if (fmt->pad < PAD_SINK || fmt->pad >= PAD_MAXCNT)
+		return -EINVAL;
+
+	format = &ctx->fmt[fmt->pad].format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
+
+		dev_dbg(ctx->dev,
+			"s_fmt pad %d code/res 0x%x/%dx%d which %d=> 0x%x/%dx%d\n",
+			fmt->pad,
+			fmt->format.code,
+			fmt->format.width,
+			fmt->format.height,
+			fmt->which,
+			format->code,
+			format->width,
+			format->height);
+	} else {
+		/* Update vcinfo once the SINK format changed */
+		if (fmt->pad == PAD_SINK)
+			sink_format_changed = 1;
+
+		format->code = fmt->format.code;
+		format->width = fmt->format.width;
+		format->height = fmt->format.height;
+
+		if (sink_format_changed && !ctx->is_test_model)
+			mtk_cam_seninf_get_vcinfo(ctx);
+
+		dev_info(ctx->dev,
+			 "s_fmt pad %d code/res 0x%x/%dx%d which %d=> 0x%x/%dx%d\n",
+			 fmt->pad,
+			 fmt->format.code,
+			 fmt->format.width,
+			 fmt->format.height,
+			 fmt->which,
+			 format->code,
+			 format->width,
+			 format->height);
+	}
+
+	return 0;
+}
+
+static int mtk_cam_seninf_get_fmt(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+	struct v4l2_mbus_framefmt *format;
+
+	if (fmt->pad < PAD_SINK || fmt->pad >= PAD_MAXCNT)
+		return -EINVAL;
+
+	format = &ctx->fmt[fmt->pad].format;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad);
+	} else {
+		fmt->format.code = format->code;
+		fmt->format.width = format->width;
+		fmt->format.height = format->height;
+		fmt->format.field = format->field;
+		fmt->format.colorspace = format->colorspace;
+		fmt->format.xfer_func = format->xfer_func;
+		fmt->format.ycbcr_enc = format->ycbcr_enc;
+		fmt->format.quantization = format->quantization;
+	}
+
+	return 0;
+}
+
+static int config_hw(struct seninf_ctx *ctx)
+{
+	int i, intf, skip_mux_ctrl;
+	int hs_pol, vs_pol, vc_sel, dt_sel, dt_en;
+	struct seninf_vcinfo *vcinfo;
+	struct seninf_vc *vc;
+	struct seninf_mux *mux;
+
+	intf = ctx->seninf_idx;
+	vcinfo = &ctx->vcinfo;
+
+	mtk_cam_seninf_reset(ctx, intf);
+
+	mtk_cam_seninf_set_vc(ctx, intf, vcinfo);
+
+	mtk_cam_seninf_set_csi_mipi(ctx);
+
+	/* should set false */
+	hs_pol = 0;
+	vs_pol = 0;
+
+	for (i = 0; i < vcinfo->cnt; i++) {
+		vc = &vcinfo->vc[i];
+
+		mux =mtk_cam_seninf_mux_get_pref(ctx,
+							g_seninf_cfg->pref_mux_num);
+		skip_mux_ctrl = 0;
+
+		if (!mux) {
+			mtk_cam_seninf_release_mux(ctx);
+			return -EBUSY;
+		}
+
+		vc->mux = mux->idx;
+		vc->cam = ctx->pad2cam[vc->out_pad];
+
+		if (!skip_mux_ctrl) {
+			mtk_cam_seninf_mux(ctx, vc->mux);
+			mtk_cam_seninf_set_mux_ctrl(ctx, vc->mux,
+						    hs_pol, vs_pol,
+				MIPI_SENSOR,
+				vc->pixel_mode);
+
+			mtk_cam_seninf_set_top_mux_ctrl(ctx, vc->mux, intf);
+
+			/* disable mtk_cam_seninf_set_mux_crop length limit */
+		}
+		dev_info(ctx->dev, "ctx->pad2cam[%d] %d vc->out_pad %d vc->cam %d, i %d",
+			 vc->out_pad, ctx->pad2cam[vc->out_pad], vc->out_pad, vc->cam, i);
+
+		if (vc->cam != 0xff) {
+			vc_sel = 0;
+			dt_sel = vc->dt;
+			dt_en = !!dt_sel;
+
+			/* CMD_SENINF_FINALIZE_CAM_MUX */
+			mtk_cam_seninf_set_cammux_vc(ctx, vc->cam,
+						     vc_sel, dt_sel,
+						     dt_en, dt_en);
+			mtk_cam_seninf_set_cammux_src(ctx, vc->mux, vc->cam);
+			mtk_cam_seninf_set_cammux_chk_pixel_mode(ctx,
+								 vc->cam,
+								 vc->pixel_mode);
+			mtk_cam_seninf_cammux(ctx, vc->cam);
+
+			dev_info(ctx->dev, "vc[%d] pad %d intf %d mux %d cam %d\n",
+				 i, vc->out_pad, intf, vc->mux, vc->cam);
+		} else {
+			dev_info(ctx->dev,
+				 "not set camtg yet, vc[%d] pad %d intf %d mux %d cam %d\n",
+				 i, vc->out_pad, intf, vc->mux, vc->cam);
+		}
+	}
+	return 0;
+}
+
+static int calc_buffered_pixel_rate(struct device *dev,
+				    s64 width, s64 height,
+				    s64 hblank, s64 vblank,
+				    int fps_n, int fps_d, s64 *result)
+{
+	s64 orig_pixel_rate = *result;
+	u64 buffered_pixel_rate, pclk, k;
+
+	if (fps_d == 0 || width == 0 || hblank == 0 || ISP_CLK_LOW == 0) {
+		dev_info(dev,
+			 "Prevent divided by 0, fps_d= %d, w= %llu, h= %llu, ISP_CLK= %d\n",
+			 fps_d, width, hblank, ISP_CLK_LOW);
+		return 0;
+	}
+
+	/* calculate pclk */
+	pclk = (width + hblank) * (height + vblank) * fps_n;
+	do_div(pclk, fps_d);
+
+	/* calculate buffered pixel_rate */
+	buffered_pixel_rate = orig_pixel_rate * width;
+	k = HW_BUF_EFFECT * orig_pixel_rate;
+	do_div(k, ISP_CLK_LOW);
+	do_div(buffered_pixel_rate, (width + hblank - k));
+	*result = buffered_pixel_rate;
+
+	dev_info(dev,
+		 "%s: w %lld h %lld hb %lld vb %lld fps %d/%d pclk %lld->%lld orig %lld k %lld hbe %d\n",
+		 __func__, width, height, hblank, vblank,
+		 fps_n, fps_d, pclk, buffered_pixel_rate, orig_pixel_rate, k, HW_BUF_EFFECT);
+
+	return 0;
+}
+
+static int get_buffered_pixel_rate(struct seninf_ctx *ctx,
+				   struct v4l2_subdev *sd, int sd_pad_idx,
+				   s64 *result)
+{
+	int ret;
+	struct v4l2_ctrl *ctrl;
+	struct v4l2_subdev_format fmt;
+	struct v4l2_subdev_frame_interval fi;
+	s64 width, height, hblank, vblank;
+
+	fmt.pad = sd_pad_idx;
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+	if (ret) {
+		dev_info(ctx->dev, "no get_fmt in %s\n", sd->name);
+		return ret;
+	}
+
+	width = fmt.format.width;
+	height = fmt.format.height;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.pad = sd_pad_idx;
+	ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &fi);
+	if (ret) {
+		dev_info(ctx->dev, "no get_frame_interval in %s\n", sd->name);
+		return ret;
+	}
+
+	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_HBLANK);
+	if (!ctrl) {
+		dev_info(ctx->dev, "no hblank in %s\n", sd->name);
+		return -EINVAL;
+	}
+
+	hblank = v4l2_ctrl_g_ctrl(ctrl);
+
+	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_VBLANK);
+	if (!ctrl) {
+		dev_info(ctx->dev, "no vblank in %s\n", sd->name);
+		return -EINVAL;
+	}
+
+	vblank = v4l2_ctrl_g_ctrl(ctrl);
+
+	/* update fps */
+	ctx->fps_n = fi.interval.denominator;
+	ctx->fps_d = fi.interval.numerator;
+
+	return calc_buffered_pixel_rate(ctx->dev, width, height, hblank, vblank,
+					ctx->fps_n, ctx->fps_d, result);
+}
+
+int update_isp_clk(struct seninf_ctx *ctx)
+{
+	int i, pixelmode;
+	struct seninf_dfs *dfs = &ctx->core->dfs;
+	s64 pixel_rate = -1;
+	u64 dfs_freq;
+	struct seninf_vc *vc;
+	int ret = 0;
+
+	if (!dfs->cnt) {
+		dev_info(ctx->dev, "dfs not ready.\n");
+		return ret;
+	}
+
+	vc = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0);
+	if (!vc) {
+		dev_info(ctx->dev, "failed to get vc\n");
+		return -1;
+	}
+	dev_info(ctx->dev,
+		 "%s dfs->cnt %d pixel mode %d customized_pixel_rate %lld, buffered_pixel_rate %lld mipi_pixel_rate %lld\n",
+		 __func__, dfs->cnt, vc->pixel_mode, ctx->customized_pixel_rate,
+		 ctx->buffered_pixel_rate, ctx->mipi_pixel_rate);
+
+	/* Use SensorPixelrate */
+	if (ctx->customized_pixel_rate) {
+		pixel_rate = ctx->customized_pixel_rate;
+	} else if (ctx->buffered_pixel_rate) {
+		pixel_rate = ctx->buffered_pixel_rate;
+	} else if (ctx->mipi_pixel_rate) {
+		pixel_rate = ctx->mipi_pixel_rate;
+	} else {
+		dev_info(ctx->dev, "failed to get pixel_rate\n");
+		return -EINVAL;
+	}
+
+	pixelmode = vc->pixel_mode;
+	for (i = 0; i < dfs->cnt; i++) {
+		dfs_freq = dfs->freqs[i];
+		dfs_freq = dfs_freq * (100 - SENINF_CLK_MARGIN_IN_PERCENT);
+		do_div(dfs_freq, 100);
+		if ((dfs_freq << pixelmode) >= pixel_rate)
+			break;
+	}
+
+	if (i == dfs->cnt) {
+		dev_info(ctx->dev, "mux is overrun. please adjust pixelmode\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int debug_err_detect_initialize(struct seninf_ctx *ctx)
+{
+	struct seninf_core *core;
+	struct seninf_ctx *ctx_;
+
+	core = dev_get_drvdata(ctx->dev->parent);
+
+	core->csi_irq_en_flag = 0;
+
+	list_for_each_entry(ctx_, &core->list, list) {
+		ctx_->data_not_enough_flag = 0;
+		ctx_->err_lane_resync_flag = 0;
+		ctx_->crc_err_flag = 0;
+		ctx_->ecc_err_double_flag = 0;
+		ctx_->ecc_err_corrected_flag = 0;
+		ctx_->fifo_overrun_flag = 0;
+		ctx_->size_err_flag = 0;
+		ctx_->data_not_enough_cnt = 0;
+		ctx_->err_lane_resync_cnt = 0;
+		ctx_->crc_err_cnt = 0;
+		ctx_->ecc_err_double_cnt = 0;
+		ctx_->ecc_err_corrected_cnt = 0;
+		ctx_->fifo_overrun_cnt = 0;
+		ctx_->size_err_cnt = 0;
+	}
+
+	return 0;
+}
+
+static int seninf_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	int ret;
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+
+	if (ctx->streaming == enable)
+		return 0;
+
+	if (!ctx->sensor_sd) {
+		dev_info(ctx->dev, "no sensor\n");
+		return -EFAULT;
+	}
+
+	if (enable) {
+		debug_err_detect_initialize(ctx);
+
+		ctx->buffered_pixel_rate = ctx->mipi_pixel_rate;
+		get_buffered_pixel_rate(ctx, ctx->sensor_sd,
+					ctx->sensor_pad_idx,
+					&ctx->buffered_pixel_rate);
+
+		ret = pm_runtime_resume_and_get(ctx->dev);
+		if (ret < 0) {
+			dev_info(ctx->dev,
+				 "%s pm_runtime_resume_and_get ret %d\n",
+				 __func__, ret);
+			return ret;
+		}
+
+		update_isp_clk(ctx);
+
+		ret = config_hw(ctx);
+		if (ret) {
+			dev_info(ctx->dev, "config_seninf_hw ret %d\n", ret);
+			return ret;
+		}
+
+		/* middleware control sensor fsync after set cam-mux */
+
+		ret = v4l2_subdev_call(ctx->sensor_sd, video, s_stream, 1);
+		if (ret) {
+			dev_info(ctx->dev, "sensor stream-on ret %d\n", ret);
+			return ret;
+		}
+
+	} else {
+		ret = v4l2_subdev_call(ctx->sensor_sd, video, s_stream, 0);
+		if (ret) {
+			dev_info(ctx->dev, "sensor stream-off ret %d\n", ret);
+			return ret;
+		}
+
+		mtk_cam_seninf_set_idle(ctx);
+		mtk_cam_seninf_release_mux(ctx);
+
+		mtk_cam_seninf_poweroff(ctx);
+		pm_runtime_put_sync(ctx->dev);
+	}
+
+	ctx->streaming = enable;
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops seninf_subdev_pad_ops = {
+	.link_validate = mtk_cam_link_validate,
+	.set_fmt = mtk_cam_seninf_set_fmt,
+	.get_fmt = mtk_cam_seninf_get_fmt,
+};
+
+static const struct v4l2_subdev_video_ops seninf_subdev_video_ops = {
+	.s_stream = seninf_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops seninf_subdev_core_ops = {
+	.subscribe_event	= seninf_subscribe_event,
+	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_internal_ops seninf_subdev_internal_ops = {
+	.init_state = mtk_cam_seninf_init_state,
+};
+
+static const struct v4l2_subdev_ops seninf_subdev_ops = {
+	.core	= &seninf_subdev_core_ops,
+	.video	= &seninf_subdev_video_ops,
+	.pad	= &seninf_subdev_pad_ops,
+};
+
+static int seninf_link_setup(struct media_entity *entity,
+			     const struct media_pad *local,
+			     const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd;
+	struct seninf_ctx *ctx;
+
+	sd = media_entity_to_v4l2_subdev(entity);
+	if (!sd)
+		return -EINVAL;
+	ctx = v4l2_get_subdevdata(sd);
+	if (!ctx)
+		return -EINVAL;
+
+	if (local->flags & MEDIA_PAD_FL_SOURCE) {
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			if (!mtk_cam_seninf_get_vc_by_pad(ctx, local->index)) {
+				dev_info(ctx->dev,
+					 "%s enable link w/o vc_info pad idex %d\n",
+					 __func__, local->index);
+			}
+		}
+	} else {
+		/* Update vcinfo once the link becomes enabled */
+		if (flags & MEDIA_LNK_FL_ENABLED) {
+			ctx->sensor_sd =
+				media_entity_to_v4l2_subdev(remote->entity);
+			ctx->sensor_pad_idx = remote->index;
+			mtk_cam_seninf_get_vcinfo(ctx);
+		}
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations seninf_media_ops = {
+	.link_setup = seninf_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+struct sensor_async_subdev {
+	struct v4l2_async_connection asc;
+	u32 port;
+	u32 bus_type;
+	u32 lanes;
+};
+
+static int seninf_notifier_bound(struct v4l2_async_notifier *notifier,
+				 struct v4l2_subdev *sd,
+				 struct v4l2_async_connection *asc)
+{
+	struct seninf_ctx *ctx = notifier_to_ctx(notifier);
+	struct sensor_async_subdev *s_asd =
+		container_of(asc, struct sensor_async_subdev, asc);
+	int ret;
+
+	dev_info(ctx->dev, "[%s] %s bounded, bus_type:%d, lanes:%d\n",
+		 __func__, sd->entity.name, s_asd->bus_type, s_asd->lanes);
+
+	ctx->is_cphy = (s_asd->bus_type == V4L2_MBUS_CSI2_CPHY);
+	ctx->num_data_lanes = s_asd->lanes;
+
+	ret = media_create_pad_link(&sd->entity, 0, &ctx->subdev.entity, 0, 0);
+	if (ret) {
+		dev_info(ctx->dev, "failed to create link for %s\n",
+			 sd->entity.name);
+		return ret;
+	}
+
+	ret = v4l2_device_register_subdev_nodes(ctx->subdev.v4l2_dev);
+	if (ret) {
+		dev_info(ctx->dev, "failed to create subdev nodes\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void seninf_notifier_unbind(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *sd,
+				   struct v4l2_async_connection *asc)
+{
+	struct seninf_ctx *ctx = notifier_to_ctx(notifier);
+
+	dev_info(ctx->dev, "%s is unbounded\n", sd->entity.name);
+}
+
+static const struct v4l2_async_notifier_operations seninf_async_ops = {
+	.bound = seninf_notifier_bound,
+	.unbind = seninf_notifier_unbind,
+};
+
+static int mtk_cam_seninf_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct seninf_ctx *ctx = ctrl_hdl_to_ctx(ctrl->handler);
+	int ret = -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_TEST_PATTERN:
+		break;
+	default:
+		ret = 0;
+		dev_info(ctx->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+			 __func__, ctrl->id, ctrl->val);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops seninf_ctrl_ops = {
+	.s_ctrl = mtk_cam_seninf_set_ctrl,
+};
+
+static int seninf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+
+	mutex_lock(&ctx->mutex);
+	ctx->open_refcnt++;
+
+	if (ctx->open_refcnt == 1)
+		dev_info(ctx->dev, "%s open_refcnt %d\n",
+			 __func__, ctx->open_refcnt);
+
+	mutex_unlock(&ctx->mutex);
+
+	return 0;
+}
+
+static int seninf_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+
+	mutex_lock(&ctx->mutex);
+	ctx->open_refcnt--;
+
+	if (!ctx->open_refcnt) {
+		dev_info(ctx->dev, "%s open_refcnt %d\n",
+			 __func__, ctx->open_refcnt);
+		if (ctx->streaming)
+			seninf_s_stream(&ctx->subdev, 0);
+	}
+
+	mutex_unlock(&ctx->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops seninf_internal_ops = {
+	.open = seninf_open,
+	.close = seninf_close,
+};
+
+static const char *const seninf_test_pattern_menu[] = {
+	"Disabled",
+	"generate_test_pattern",
+	"generate_test_pattern_stagger",
+	"generate_test_pattern_pd",
+};
+
+static int seninf_initialize_controls(struct seninf_ctx *ctx)
+{
+	struct v4l2_ctrl_handler *handler;
+	int ret;
+
+	handler = &ctx->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(handler, 2);
+	if (ret)
+		return ret;
+	v4l2_ctrl_new_std_menu_items(handler, &seninf_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(seninf_test_pattern_menu) - 1,
+				     0, 0, seninf_test_pattern_menu);
+
+	if (handler->error) {
+		ret = handler->error;
+		dev_info(ctx->dev, "Failed to init controls(%d)\n", ret);
+		goto err_free_handler;
+	}
+
+	ctx->subdev.ctrl_handler = handler;
+	return 0;
+
+err_free_handler:
+	v4l2_ctrl_handler_free(handler);
+
+	return ret;
+}
+
+static int seninf_parse_endpoint(struct device *dev,
+				 struct v4l2_fwnode_endpoint *vep,
+				 struct sensor_async_subdev *s_asd)
+{
+	struct fwnode_handle *remote_hnd;
+
+	s_asd->port = vep->base.port;
+	s_asd->bus_type = vep->bus_type;
+	s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
+
+	dev_dbg(dev, "Got local node port:%d type:%d lanes:%d\n",
+		vep->base.port, vep->bus_type,
+		vep->bus.mipi_csi2.num_data_lanes);
+
+	/* check if sensor endpoint assign mipi lane nums */
+	remote_hnd = fwnode_graph_get_remote_endpoint(vep->base.local_fwnode);
+	if (remote_hnd) {
+		u32 remote_bus = 0, remote_lanes = 0;
+
+		fwnode_property_read_u32(remote_hnd, "bus-type", &remote_bus);
+		if (remote_bus == V4L2_FWNODE_BUS_TYPE_CSI2_DPHY)
+			s_asd->bus_type = V4L2_MBUS_CSI2_DPHY;
+		else if (remote_bus == V4L2_FWNODE_BUS_TYPE_CSI2_CPHY)
+			s_asd->bus_type = V4L2_MBUS_CSI2_CPHY;
+
+		remote_lanes =
+			fwnode_property_count_u32(remote_hnd, "data-lanes");
+		if (remote_lanes > 0 &&
+		    remote_lanes <= vep->bus.mipi_csi2.num_data_lanes)
+			s_asd->lanes = remote_lanes;
+
+		fwnode_handle_put(remote_hnd);
+		dev_dbg(dev, "Got remote node lanes:%d\n", remote_lanes);
+	}
+
+	return 0;
+}
+
+static int seninf_parse_fwnode(struct device *dev,
+			       struct v4l2_async_notifier *notifier)
+{
+	struct fwnode_handle *fwnode = NULL;
+	struct v4l2_fwnode_endpoint vep = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY, /* CDPHY only */
+	};
+	int ret = 0;
+
+	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
+		struct sensor_async_subdev *s_asd;
+
+		ret = v4l2_fwnode_endpoint_parse(fwnode, &vep);
+		if (ret) {
+			dev_err(dev, "failed to parse v4l2 fwnode endpoint\n");
+			break;
+		}
+
+		if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
+		    vep.bus_type != V4L2_MBUS_CSI2_CPHY) {
+			dev_err(dev, "Got unsupported endpoint:%d, bus:%d\n",
+				vep.base.port, vep.bus_type);
+			continue;
+		}
+
+		s_asd = v4l2_async_nf_add_fwnode_remote(notifier, fwnode,
+							struct sensor_async_subdev);
+		if (IS_ERR(s_asd)) {
+			ret = PTR_ERR(s_asd);
+			break;
+		}
+
+		ret = seninf_parse_endpoint(dev, &vep, s_asd);
+		if (ret < 0)
+			break;
+	}
+
+	if (fwnode)
+		fwnode_handle_put(fwnode);
+
+	return ret;
+}
+
+static int register_subdev(struct seninf_ctx *ctx)
+{
+	int i, ret;
+	struct v4l2_subdev *sd = &ctx->subdev;
+	struct device *dev = ctx->dev;
+	struct media_pad *pads = ctx->pads;
+	struct v4l2_async_notifier *notifier = &ctx->notifier;
+
+	v4l2_subdev_init(sd, &seninf_subdev_ops);
+	sd->internal_ops = &seninf_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	sd->dev = dev;
+
+	if (strlen(dev->of_node->name) > 16)
+		snprintf(sd->name, sizeof(sd->name), "%s-%s",
+			 dev_driver_string(dev), &dev->of_node->name[16]);
+	else
+		snprintf(sd->name, sizeof(sd->name), "%s-%s",
+			 dev_driver_string(dev), csi_port_names[ctx->port]);
+
+	v4l2_set_subdevdata(sd, ctx);
+
+	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	sd->entity.ops = &seninf_media_ops;
+	sd->internal_ops = &seninf_internal_ops;
+
+	pads[PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	for (i = PAD_SRC_RAW0; i < PAD_MAXCNT; i++)
+		pads[i].flags = MEDIA_PAD_FL_SOURCE;
+
+	for (i = 0; i < PAD_MAXCNT; i++)
+		ctx->pad2cam[i] = 0xff;
+
+	ret = media_entity_pads_init(&sd->entity, PAD_MAXCNT, pads);
+	if (ret < 0) {
+		dev_info(dev, "failed to init pads\n");
+		return ret;
+	}
+
+	/* register seninf as mtk_cam async child */
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0) {
+		dev_info(dev, "failed to register subdev\n");
+		return ret;
+	}
+
+	/* register seninf as sensor async parent */
+	v4l2_async_subdev_nf_init(notifier, sd);
+	ret = seninf_parse_fwnode(dev, notifier);
+	if (ret < 0)
+		dev_info(dev, "no endpoint\n");
+
+	notifier->ops = &seninf_async_ops;
+	ret = v4l2_async_nf_register(notifier);
+	if (ret < 0) {
+		dev_info(dev, "failed to register notifier\n");
+		goto err_unregister_subdev;
+	}
+
+	return 0;
+
+err_unregister_subdev:
+	v4l2_device_unregister_subdev(sd);
+	v4l2_async_nf_cleanup(notifier);
+
+	return ret;
+}
+
+static void unregister_subdev(struct seninf_ctx *ctx)
+{
+	struct v4l2_subdev *sd = &ctx->subdev;
+
+	v4l2_async_nf_unregister(&ctx->notifier);
+	v4l2_async_nf_cleanup(&ctx->notifier);
+	v4l2_async_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+}
+
+static int seninf_probe(struct platform_device *pdev)
+{
+	int ret, port;
+	struct seninf_ctx *ctx;
+	struct device *dev = &pdev->dev;
+	struct seninf_core *core;
+
+	if (!dev->parent)
+		return -EPROBE_DEFER;
+
+	/* get mtk seninf_core */
+	core = dev_get_drvdata(dev->parent);
+	if (!core)
+		return -EPROBE_DEFER;
+
+	/* init seninf_csi ctx */
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, ctx);
+	ctx->dev = dev;
+	ctx->core = core;
+	list_add(&ctx->list, &core->list);
+	INIT_LIST_HEAD(&ctx->list_mux);
+	INIT_LIST_HEAD(&ctx->list_cam_mux);
+
+	ctx->open_refcnt = 0;
+	mutex_init(&ctx->mutex);
+
+	ret = get_csi_port(dev, &port);
+	if (ret) {
+		dev_info(dev, "get_csi_port ret %d\n", ret);
+		return ret;
+	}
+
+	mtk_cam_seninf_init_iomem(ctx, core->reg_if, core->reg_ana);
+	mtk_cam_seninf_init_port(ctx, port);
+	init_fmt(ctx);
+
+	/* platform properties */
+	ctx->cphy_settle_delay_dt = ctx->core->cphy_settle_delay_dt;
+	ctx->dphy_settle_delay_dt = ctx->core->dphy_settle_delay_dt;
+	ctx->settle_delay_ck = ctx->core->settle_delay_ck;
+	ctx->hs_trail_parameter = ctx->core->hs_trail_parameter;
+
+	of_property_read_u32(dev->of_node, "cphy_settle_delay_dt",
+			     &ctx->cphy_settle_delay_dt);
+	of_property_read_u32(dev->of_node, "dphy_settle_delay_dt",
+			     &ctx->dphy_settle_delay_dt);
+	of_property_read_u32(dev->of_node, "settle_delay_ck",
+			     &ctx->settle_delay_ck);
+	of_property_read_u32(dev->of_node, "hs_trail_parameter",
+			     &ctx->hs_trail_parameter);
+
+	dev_info(dev,
+		 "seninf d_settlte/d_settle_ck/d_trail/c_settle= 0x%x/0x%x/0x%x/0x%x\n",
+		 ctx->dphy_settle_delay_dt,
+		 ctx->settle_delay_ck,
+		 ctx->hs_trail_parameter,
+		 ctx->cphy_settle_delay_dt);
+
+	ret = dev_read_csi_efuse(ctx);
+	if (ret < 0)
+		dev_info(dev, "Failed to read efuse data\n");
+
+	ret = seninf_initialize_controls(ctx);
+	if (ret) {
+		dev_info(dev, "Failed to initialize controls\n");
+		return ret;
+	}
+
+	/* bind seninf_csi to mtkcam */
+	ret = register_subdev(ctx);
+	if (ret < 0) {
+		dev_err(dev, "register_subdev failed\n");
+		goto err_free_handler;
+	}
+
+	pm_runtime_enable(dev);
+
+	dev_info(dev, "%s: port=%d\n", __func__, ctx->port);
+
+	dev_info(dev, "camsys | [%s] success\n", __func__);
+
+	return 0;
+
+err_free_handler:
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+
+	return ret;
+}
+
+static int runtime_suspend(struct device *dev)
+{
+	int i;
+	struct seninf_ctx *ctx = dev_get_drvdata(dev);
+	struct seninf_core *core = ctx->core;
+
+	mutex_lock(&core->mutex);
+
+	core->refcnt--;
+	if (core->refcnt == 0) {
+		i = CLK_TOP_SENINF_END;
+		do {
+			i--;
+			if (ctx->core->clk[i])
+				clk_disable_unprepare(ctx->core->clk[i]);
+		} while (i);
+		seninf_core_pm_runtime_put(core);
+	}
+
+	mutex_unlock(&core->mutex);
+
+	return 0;
+}
+
+static int runtime_resume(struct device *dev)
+{
+	u32 i;
+	int ret;
+
+	struct seninf_ctx *ctx = dev_get_drvdata(dev);
+	struct seninf_core *core = ctx->core;
+
+	mutex_lock(&core->mutex);
+
+	core->refcnt++;
+
+	if (core->refcnt == 1) {
+		ret = seninf_core_pm_runtime_get_sync(core);
+		if (ret < 0) {
+			dev_info(dev, "seninf_core_pm_runtime_get_sync failed\n");
+			return ret;
+		}
+
+		for (i = 0; i < CLK_TOP_SENINF_END; i++) {
+			if (core->clk[i])
+				ret = clk_prepare_enable(core->clk[i]);
+			if (ret)
+				dev_dbg(dev, "%s: clk seninf%d is empty\n",
+					__func__, i);
+		}
+		mtk_cam_seninf_disable_all_mux(ctx);
+		mtk_cam_seninf_disable_all_cammux(ctx);
+	}
+
+	mutex_unlock(&core->mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops pm_ops = {
+	SET_RUNTIME_PM_OPS(runtime_suspend, runtime_resume, NULL)
+};
+
+static void seninf_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct seninf_ctx *ctx = dev_get_drvdata(dev);
+
+	if (ctx->streaming) {
+		mtk_cam_seninf_set_idle(ctx);
+		mtk_cam_seninf_release_mux(ctx);
+	}
+
+	pm_runtime_disable(ctx->dev);
+
+	unregister_subdev(ctx);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+
+	mutex_destroy(&ctx->mutex);
+}
+
+static const struct of_device_id seninf_of_match[] = {
+	{ .compatible = "mediatek,mt8188-seninf" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, seninf_of_match);
+
+static int seninf_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	return 0;
+}
+
+static int seninf_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+struct platform_driver seninf_pdrv = {
+	.probe	= seninf_probe,
+	.remove	= seninf_remove,
+	.suspend = seninf_suspend,
+	.resume = seninf_resume,
+	.driver	= {
+		.name = "seninf",
+		.of_match_table = seninf_of_match,
+		.pm  = &pm_ops,
+	},
+};
+
+int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height,
+				  s64 hblank, s64 vblank,
+				  int fps_n, int fps_d,
+				  s64 sensor_pixel_rate)
+{
+	int ret;
+	s64 p_pixel_rate = sensor_pixel_rate;
+
+	ret = calc_buffered_pixel_rate(dev, width, height, hblank, vblank,
+				       fps_n, fps_d, &p_pixel_rate);
+	if (ret)
+		return sensor_pixel_rate;
+
+	return p_pixel_rate;
+}
+
+int mtk_cam_seninf_dump(struct v4l2_subdev *sd)
+{
+	int ret = 0;
+	//TODO debug patch
+	return ret;
+}
+
+void mtk_cam_seninf_set_secure(struct v4l2_subdev *sd,
+			       int enable, unsigned int sec_info_addr)
+{
+	struct seninf_ctx *ctx = sd_to_ctx(sd);
+
+	ctx->sec_info_addr = sec_info_addr;
+	dev_info(ctx->dev, "[%s]: %x, enable: %d\n",
+		 __func__, sec_info_addr, enable);
+	ctx->is_secure = enable ? 1 : 0;
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
new file mode 100755
index 000000000000..117ae208cf4b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_SENINF_DRV_H
+#define __MTK_CAM_SENINF_DRV_H
+
+#include "mtk_cam-seninf.h"
+
+extern struct platform_driver seninf_core_pdrv;
+extern struct platform_driver seninf_pdrv;
+
+int update_isp_clk(struct seninf_ctx *ctx);
+
+#endif /*__MTK_CAM_SENINF_DRV_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
new file mode 100755
index 000000000000..5d4fc0d6e995
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_SENINF_HW_H__
+#define __MTK_CAM_SENINF_HW_H__
+
+enum SET_REG_KEYS {
+	REG_KEY_MIN = 0,
+	REG_KEY_SETTLE_CK = REG_KEY_MIN,
+	REG_KEY_SETTLE_DT,
+	REG_KEY_HS_TRAIL_EN,
+	REG_KEY_HS_TRAIL_PARAM,
+	REG_KEY_CSI_IRQ_STAT,
+	REG_KEY_CSI_RESYNC_CYCLE,
+	REG_KEY_MUX_IRQ_STAT,
+	REG_KEY_CAMMUX_IRQ_STAT,
+	REG_KEY_CAMMUX_VSYNC_IRQ_EN,
+	REG_KEY_CSI_IRQ_EN,
+	REG_KEY_MAX_NUM
+};
+
+#define SET_REG_KEYS_NAMES \
+	"RG_SETTLE_CK", \
+	"RG_SETTLE_DT", \
+	"RG_HS_TRAIL_EN", \
+	"RG_HS_TRAIL_PARAM", \
+	"RG_CSI_IRQ_STAT", \
+	"RG_CSI_RESYNC_CYCLE", \
+	"RG_MUX_IRQ_STAT", \
+	"RG_CAMMUX_IRQ_STAT", \
+	"REG_VSYNC_IRQ_EN", \
+	"RG_CSI_IRQ_EN", \
+
+struct mtk_cam_seninf_mux_meter {
+	u32 width;
+	u32 height;
+	u32 h_valid;
+	u32 h_blank;
+	u32 v_valid;
+	u32 v_blank;
+	s64 mipi_pixel_rate;
+	s64 vb_in_us;
+	s64 hb_in_us;
+	s64 line_time_in_us;
+};
+
+struct mtk_cam_seninf_cfg {
+	unsigned int seninf_num;
+	unsigned int mux_num;
+	unsigned int cam_mux_num;
+	unsigned int pref_mux_num;
+};
+
+extern struct mtk_cam_seninf_cfg *g_seninf_cfg;
+
+int mtk_cam_seninf_init_iomem(struct seninf_ctx *ctx, void __iomem *if_base,
+			      void __iomem *ana_base);
+int mtk_cam_seninf_init_port(struct seninf_ctx *ctx, int port);
+int mtk_cam_seninf_is_cammux_used(struct seninf_ctx *ctx, int cam_mux);
+int mtk_cam_seninf_cammux(struct seninf_ctx *ctx, int cam_mux);
+int mtk_cam_seninf_disable_cammux(struct seninf_ctx *ctx, int cam_mux);
+int mtk_cam_seninf_disable_all_cammux(struct seninf_ctx *ctx);
+int mtk_cam_seninf_set_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx,
+				    int seninf_src);
+int mtk_cam_seninf_get_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx);
+int mtk_cam_seninf_get_cammux_ctrl(struct seninf_ctx *ctx, int cam_mux);
+u32 mtk_cam_seninf_get_cammux_res(struct seninf_ctx *ctx, int cam_mux);
+int mtk_cam_seninf_set_cammux_vc(struct seninf_ctx *ctx, int cam_mux,
+				 int vc_sel, int dt_sel, int vc_en,
+				 int dt_en);
+int mtk_cam_seninf_set_cammux_src(struct seninf_ctx *ctx, int src,
+				  int target);
+int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx,
+			  struct seninf_vcinfo *vcinfo);
+int mtk_cam_seninf_set_mux_ctrl(struct seninf_ctx *ctx, u32 mux, int hs_pol,
+				int vs_pol, int src_sel, int pixel_mode);
+int mtk_cam_seninf_set_mux_crop(struct seninf_ctx *ctx, u32 mux, int start_x,
+				int end_x, int enable);
+int mtk_cam_seninf_is_mux_used(struct seninf_ctx *ctx, u32 mux);
+int mtk_cam_seninf_mux(struct seninf_ctx *ctx, u32 mux);
+int mtk_cam_seninf_disable_mux(struct seninf_ctx *ctx, u32 mux);
+int mtk_cam_seninf_disable_all_mux(struct seninf_ctx *ctx);
+int mtk_cam_seninf_set_cammux_chk_pixel_mode(struct seninf_ctx *ctx,
+					     int cam_mux, int pixel_mode);
+int mtk_cam_seninf_set_csi_mipi(struct seninf_ctx *ctx);
+int mtk_cam_seninf_poweroff(struct seninf_ctx *ctx);
+int mtk_cam_seninf_reset(struct seninf_ctx *ctx, u32 seninf_idx);
+int mtk_cam_seninf_set_idle(struct seninf_ctx *ctx);
+int mtk_cam_seninf_switch_to_cammux_inner_page(struct seninf_ctx *ctx,
+					       bool inner);
+int mtk_cam_seninf_set_cammux_next_ctrl(struct seninf_ctx *ctx, int src,
+					int target);
+int mtk_cam_seninf_update_mux_pixel_mode(struct seninf_ctx *ctx, u32 mux,
+					 int pixel_mode);
+int mtk_cam_seninf_irq_handler(int irq, void *data);
+int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable,
+				   int index);
+int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index);
+int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable,
+					  int index);
+int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable,
+					    int cam_mux);
+int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx);
+int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val);
+
+#endif /* __MTK_CAM_SENINF_HW_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
new file mode 100755
index 000000000000..12300b193c14
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2022 MediaTek Inc.
+
+#ifndef __MTK_CAM_SENINF_IF_H__
+#define __MTK_CAM_SENINF_IF_H__
+
+int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd, int pad_id,
+				 int *pixelmode);
+
+int mtk_cam_seninf_set_pixelmode(struct v4l2_subdev *sd, int pad_id,
+				 int pixelmode);
+
+int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg);
+
+int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height,
+				  s64 hblank, s64 vblank, int fps_n, int fps_d,
+				  s64 sensor_pixel_rate);
+
+int mtk_cam_seninf_dump(struct v4l2_subdev *sd);
+
+unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd,
+					   unsigned int pad);
+
+#endif /* __MTK_CAM_SENINF_IF_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
new file mode 100755
index 000000000000..a955dbaa29ea
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/bitfield.h>
+
+#ifndef __MTK_CAM_SENINF_REGS_H__
+#define __MTK_CAM_SENINF_REGS_H__
+
+#define SENINF_BITS(base, reg, field, val) do { \
+    void __iomem *__p = (void __iomem *)((u8 __iomem *)(base) + (reg)); \
+    u32 __v = readl(__p); \
+    __v &= ~(field); \
+    __v |= FIELD_PREP(field, val); \
+    writel(__v, __p); \
+} while (0)
+
+#define SENINF_READ_BITS(base, reg, field) \
+({ \
+    void __iomem *__p = (void __iomem *)((u8 __iomem *)(base) + (reg)); \
+    u32 __v = readl(__p); \
+    FIELD_GET(field, __v); \
+})
+
+#define SENINF_READ_REG(base, reg) \
+({ \
+	u32 __iomem *__p = (base) + (reg); \
+	u32 __v = readl(__p); \
+	__v; \
+})
+
+#define SENINF_WRITE_REG(base, reg, val) { \
+	u32 __iomem *__p = (base) + (reg); \
+	writel(val, __p); \
+}
+
+#define SENINF_BITS_VAR(base, reg, mask, val) do { \
+    void __iomem *__p = (void __iomem *)((u8 __iomem *)(base) + (reg)); \
+    u32 __v = readl(__p); \
+    __v &= ~(mask); \
+    __v |= ((val) << __builtin_ctz(mask)) & (mask); \
+    writel(__v, __p); \
+} while (0)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
new file mode 100755
index 000000000000..aa54a865ad84
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_graph.h>
+#include <linux/of_device.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+
+#include "mtk_cam-seninf.h"
+#include "mtk_cam-seninf-route.h"
+#include "mtk_cam-seninf-if.h"
+#include "mtk_cam-seninf-hw.h"
+#include "mtk_cam-seninf-drv.h"
+#include "kd_imgsensor_define_v4l2.h"
+
+#define to_std_fmt_code(code) \
+	((code) & 0xFFFF)
+
+void mtk_cam_seninf_init_res(struct seninf_core *core)
+{
+	int i;
+
+	INIT_LIST_HEAD(&core->list_mux);
+	for (i = 0; i < g_seninf_cfg->mux_num; i++) {
+		core->mux[i].idx = i;
+		list_add_tail(&core->mux[i].list, &core->list_mux);
+	}
+}
+
+struct seninf_mux *mtk_cam_seninf_mux_get(struct seninf_ctx *ctx)
+{
+	struct seninf_core *core = ctx->core;
+	struct seninf_mux *ent = NULL;
+
+	mutex_lock(&core->mutex);
+
+	if (!list_empty(&core->list_mux)) {
+		ent = list_first_entry(&core->list_mux,
+				       struct seninf_mux, list);
+		list_move_tail(&ent->list, &ctx->list_mux);
+	}
+
+	mutex_unlock(&core->mutex);
+
+	return ent;
+}
+
+struct seninf_mux *mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx,
+					        int pref_cnt)
+{
+	int i;
+	struct seninf_core *core = ctx->core;
+	struct seninf_mux *ent = NULL;
+
+	mutex_lock(&core->mutex);
+
+	list_for_each_entry(ent, &core->list_mux, list) {
+		for (i = 0; i < pref_cnt; i++) {
+			if (ent->idx == i) {
+				list_move_tail(&ent->list,
+					       &ctx->list_mux);
+				mutex_unlock(&core->mutex);
+				return ent;
+			}
+		}
+	}
+
+	mutex_unlock(&core->mutex);
+
+	return mtk_cam_seninf_mux_get(ctx);
+}
+
+void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux)
+{
+	struct seninf_core *core = ctx->core;
+
+	mutex_lock(&core->mutex);
+	list_move_tail(&mux->list, &core->list_mux);
+	mutex_unlock(&core->mutex);
+}
+
+struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx)
+{
+	int i;
+	struct seninf_vcinfo *vcinfo = &ctx->vcinfo;
+
+	for (i = 0; i < vcinfo->cnt; i++) {
+		if (vcinfo->vc[i].out_pad == idx)
+			return &vcinfo->vc[i];
+	}
+
+	return NULL;
+}
+
+unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd,
+					   unsigned int pad)
+{
+	struct seninf_vc *pvc = NULL;
+	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
+
+	pvc = mtk_cam_seninf_get_vc_by_pad(ctx, pad);
+	if (pvc)
+		return pvc->feature;
+
+	return VC_NONE;
+}
+
+int mtk_cam_seninf_get_vcinfo(struct seninf_ctx *ctx)
+{
+	struct seninf_vcinfo *vcinfo = &ctx->vcinfo;
+	struct seninf_vc *vc;
+
+	if (!ctx->sensor_sd)
+		return -EINVAL;
+
+	vcinfo->cnt = 0;
+
+	switch (to_std_fmt_code(ctx->fmt[PAD_SINK].format.code)) {
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		vc = &vcinfo->vc[vcinfo->cnt++];
+		vc->dt = 0x2a;
+		vc->feature = VC_RAW_DATA;
+		vc->out_pad = PAD_SRC_RAW0;
+		break;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		vc = &vcinfo->vc[vcinfo->cnt++];
+		vc->dt = 0x2b;
+		vc->feature = VC_RAW_DATA;
+		vc->out_pad = PAD_SRC_RAW0;
+		break;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		vc = &vcinfo->vc[vcinfo->cnt++];
+		vc->dt = 0x2c;
+		vc->feature = VC_RAW_DATA;
+		vc->out_pad = PAD_SRC_RAW0;
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx)
+{
+	struct seninf_mux *ent, *tmp;
+
+	list_for_each_entry_safe(ent, tmp, &ctx->list_mux, list) {
+		mtk_cam_seninf_mux_put(ctx, ent);
+	}
+}
+
+int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd,
+				 int pad_id, int *pixel_mode)
+{
+	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
+	struct seninf_vc *vc;
+
+	vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id);
+	if (!vc) {
+		pr_info("%s: invalid pad=%d\n", __func__, pad_id);
+		return -1;
+	}
+
+	*pixel_mode = vc->pixel_mode;
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_pixelmode(struct v4l2_subdev *sd,
+				 int pad_id, int pixel_mode)
+{
+	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
+	struct seninf_vc *vc;
+
+	vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id);
+	if (!vc) {
+		pr_info("%s: invalid pad=%d\n", __func__, pad_id);
+		return -1;
+	}
+
+	vc->pixel_mode = pixel_mode;
+	if (ctx->streaming) {
+		update_isp_clk(ctx);
+		mtk_cam_seninf_update_mux_pixel_mode(ctx, vc->mux, pixel_mode);
+	}
+
+	return 0;
+}
+
+static int _mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd,
+				     int pad_id, int camtg, bool disable_last)
+{
+	int old_camtg;
+	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
+	struct seninf_vc *vc;
+
+	if (pad_id < PAD_SRC_RAW0 || pad_id >= PAD_MAXCNT)
+		return -EINVAL;
+
+	vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id);
+	if (!vc)
+		return -EINVAL;
+
+	ctx->pad2cam[pad_id] = camtg;
+
+	/* change cam-mux while streaming */
+	if (ctx->streaming && vc->cam != camtg) {
+		if (camtg == 0xff) {
+			old_camtg = vc->cam;
+			vc->cam = 0xff;
+			mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true);
+			mtk_cam_seninf_set_cammux_next_ctrl(ctx, 0x1f, old_camtg);
+			mtk_cam_seninf_disable_cammux(ctx, old_camtg);
+		} else {
+			/* disable old */
+			old_camtg = vc->cam;
+			/* enable new */
+			vc->cam = camtg;
+			mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true);
+			mtk_cam_seninf_set_cammux_next_ctrl(ctx, 0x1f, vc->cam);
+
+			mtk_cam_seninf_switch_to_cammux_inner_page(ctx, false);
+
+			mtk_cam_seninf_set_cammux_vc(ctx, vc->cam,
+						     0, vc->dt,
+						     !!vc->dt, !!vc->dt);
+			mtk_cam_seninf_set_cammux_src(ctx, vc->mux, vc->cam,);
+			mtk_cam_seninf_set_cammux_chk_pixel_mode(ctx,
+								 vc->cam,
+								 vc->pixel_mode);
+			if (old_camtg != 0xff && disable_last) {
+				/* disable old in next sof */
+				mtk_cam_seninf_disable_cammux(ctx, old_camtg);
+			}
+			mtk_cam_seninf_cammux(ctx, vc->cam); /* enable in next sof */
+			mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true);
+			mtk_cam_seninf_set_cammux_next_ctrl(ctx, vc->mux, vc->cam);
+			if (old_camtg != 0xff && disable_last)
+				mtk_cam_seninf_set_cammux_next_ctrl(ctx,
+								    vc->mux,
+								    old_camtg);
+
+			/* user control sensor fsync after change cam-mux */
+		}
+
+		dev_info(ctx->dev, "%s: pad %d mux %d cam %d -> %d\n",
+			 __func__, vc->out_pad, vc->mux, old_camtg, vc->cam);
+	} else {
+		dev_info(ctx->dev, "%s: pad_id %d, camtg %d, ctx->streaming %d, vc->cam %d\n",
+			 __func__, pad_id, camtg, ctx->streaming, vc->cam);
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg)
+{
+	return _mtk_cam_seninf_set_camtg(sd, pad_id, camtg, true);
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
new file mode 100755
index 000000000000..f0698b9f9df4
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_SENINF_ROUTE_H__
+#define __MTK_CAM_SENINF_ROUTE_H__
+
+#define MAX_MUX_CHANNEL 4
+
+void mtk_cam_seninf_init_res(struct seninf_core *core);
+
+struct seninf_mux *mtk_cam_seninf_mux_get(struct seninf_ctx *ctx);
+struct seninf_mux *mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx, int pref_cnt);
+void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux);
+void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx);
+struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx);
+int mtk_cam_seninf_get_vcinfo(struct seninf_ctx *ctx);
+
+#endif /* __MTK_CAM_SENINF_ROUTE_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
new file mode 100755
index 000000000000..efd6c30ce4b4
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_SENINF_H__
+#define __MTK_CAM_SENINF_H__
+
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+
+#include "mtk_cam-seninf-def.h"
+#include "kd_imgsensor_define_v4l2.h"
+#include "mtk_cam-seninf-regs.h"
+
+struct seninf_mux {
+	struct list_head list;
+	int idx;
+};
+
+struct seninf_vc {
+	u8 dt;
+	u8 feature;
+	u8 out_pad;
+	u8 pixel_mode;
+	u8 mux; /* allocated per group */
+	u8 cam; /* assigned by cam driver */
+	u8 enable;
+};
+
+struct seninf_vcinfo {
+	struct seninf_vc vc[SENINF_VC_MAXCNT];
+	int cnt;
+};
+
+struct seninf_dfs {
+	struct device *dev;
+	struct regulator *reg;
+	unsigned long *freqs;
+	unsigned long *volts;
+	int cnt;
+};
+
+struct seninf_core {
+	struct device *dev;
+	int pm_domain_cnt;
+	struct device **pm_domain_devs;
+	struct clk *clk[CLK_MAXCNT];
+	struct seninf_dfs dfs;
+	struct list_head list;
+	struct list_head list_mux; /* available mux */
+	struct seninf_mux mux[SENINF_MUX_NUM];
+	struct mutex mutex;  /* protect seninf core operations */
+	void __iomem *reg_if;
+	void __iomem *reg_ana;
+	int refcnt;
+
+	/* platform properties */
+	int cphy_settle_delay_dt;
+	int dphy_settle_delay_dt;
+	int settle_delay_ck;
+	int hs_trail_parameter;
+
+	/* protect variables in irq handler */
+	spinlock_t spinlock_irq;
+
+	/* mipi error detection count */
+	unsigned int detection_cnt;
+	/* enable csi irq flag */
+	unsigned int csi_irq_en_flag;
+};
+
+struct seninf_ctx {
+	struct v4l2_subdev subdev;
+	struct v4l2_async_notifier notifier;
+	struct device *dev;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct media_pad pads[PAD_MAXCNT];
+	struct v4l2_subdev_format fmt[PAD_MAXCNT];
+	struct seninf_core *core;
+	struct list_head list;
+
+	u32 port;
+	u32 port_a;
+	u32 port_b;
+	u32 port_num;
+	u32 num_data_lanes;
+	s64 mipi_pixel_rate;
+	s64 buffered_pixel_rate;
+	s64 customized_pixel_rate;
+	unsigned int m_csi_efuse;
+
+	unsigned int is_4d1c:1;
+	unsigned int is_cphy:1;
+	unsigned int is_test_model:4;
+	unsigned int is_secure:1;
+	unsigned int sec_info_addr;
+	u32 seninf_idx;
+	int pad2cam[PAD_MAXCNT];
+
+	/* remote sensor */
+	struct v4l2_subdev *sensor_sd;
+	u32 sensor_pad_idx;
+
+	/* provided by sensor */
+	struct seninf_vcinfo vcinfo;
+	int fps_n;
+	int fps_d;
+
+	/* dfs */
+	int isp_freq;
+
+	void __iomem *reg_ana_csi_rx[CSI_PORT_MAX_NUM];
+	void __iomem *reg_ana_dphy_top[CSI_PORT_MAX_NUM];
+	void __iomem *reg_ana_cphy_top[CSI_PORT_MAX_NUM];
+	void __iomem *reg_if_top;
+	void __iomem *reg_if_ctrl[SENINF_NUM];
+	void __iomem *reg_if_cam_mux;
+	void __iomem *reg_if_cam_mux_gcsr;
+	void __iomem *reg_if_cam_mux_pcsr[SENINF_CAM_MUX_NUM];
+	void __iomem *reg_if_tg[SENINF_NUM];
+	void __iomem *reg_if_csi2[SENINF_NUM];
+	void __iomem *reg_if_mux[SENINF_MUX_NUM];
+
+	/* resources */
+	struct list_head list_mux; /* work mux */
+	struct list_head list_cam_mux;
+
+	/* flags */
+	unsigned int streaming:1;
+
+	int cphy_settle_delay_dt;
+	int dphy_settle_delay_dt;
+	int settle_delay_ck;
+	int hs_trail_parameter;
+
+	int open_refcnt;
+	struct mutex mutex;  /* protect seninf context */
+
+	/* csi irq */
+	unsigned int data_not_enough_cnt;
+	unsigned int err_lane_resync_cnt;
+	unsigned int crc_err_cnt;
+	unsigned int ecc_err_double_cnt;
+	unsigned int ecc_err_corrected_cnt;
+	/* seninf_mux fifo overrun irq */
+	unsigned int fifo_overrun_cnt;
+	/* cam_mux h/v size irq */
+	unsigned int size_err_cnt;
+	/* error flag */
+	unsigned int data_not_enough_flag;
+	unsigned int err_lane_resync_flag;
+	unsigned int crc_err_flag;
+	unsigned int ecc_err_double_flag;
+	unsigned int ecc_err_corrected_flag;
+	unsigned int fifo_overrun_flag;
+	unsigned int size_err_flag;
+};
+
+#endif /* __MTK_CAM_SENINF_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
new file mode 100755
index 000000000000..e00b8d3904a9
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022 MediaTek Inc.
+
+mtk-cam-isp-objs += \
+	mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.o
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
new file mode 100755
index 000000000000..631578ecc060
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
@@ -0,0 +1,679 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#include <linux/bitfield.h>
+
+#ifndef __SENINF_CAM_MUX_H__
+#define __SENINF_CAM_MUX_H__
+
+// Register offset
+#define SENINF_CAM_MUX_CTRL_0  0x0000
+#define SENINF_CAM_MUX_CTRL_1  0x0004
+#define SENINF_CAM_MUX_CTRL_2  0x0008
+#define SENINF_CAM_MUX_CTRL_3  0x000c
+#define SENINF_CAM_MUX_EN      0x0010
+#define SENINF_CAM_MUX_CHK_EN  0x0018
+#define SENINF_CAM_MUX0_OPT    0x0020
+#define SENINF_CAM_MUX1_OPT    0x0024
+#define SENINF_CAM_MUX2_OPT    0x0028
+#define SENINF_CAM_MUX3_OPT    0x002c
+#define SENINF_CAM_MUX4_OPT    0x0030
+#define SENINF_CAM_MUX5_OPT    0x0034
+#define SENINF_CAM_MUX6_OPT    0x0038
+
+#define SENINF_CAM_MUX_CTRL(target)   (0x0100 + 0x10 * ((target) / 4))
+#define SENINF_CAM_MUX_CHK_CTL_1(target)   (0x0104 + 0x10 * (target))
+#define RG_SENINF_CAM_MUX_EXP_HSIZE        GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX_EXP_VSIZE        GENMASK(31, 16)
+
+// SENINF_CAM_MUX_CTRL_0
+#define RG_SENINF_CAM_MUX0_SRC_SEL   GENMASK(3, 0)
+#define RG_SENINF_CAM_MUX1_SRC_SEL   GENMASK(11, 8)
+#define RG_SENINF_CAM_MUX2_SRC_SEL   GENMASK(19, 16)
+#define RG_SENINF_CAM_MUX3_SRC_SEL   GENMASK(27, 24)
+
+// SENINF_CAM_MUX_CTRL_1
+#define RG_SENINF_CAM_MUX4_SRC_SEL   GENMASK(3, 0)
+#define RG_SENINF_CAM_MUX5_SRC_SEL   GENMASK(11, 8)
+#define RG_SENINF_CAM_MUX6_SRC_SEL   GENMASK(19, 16)
+#define RG_SENINF_CAM_MUX7_SRC_SEL   GENMASK(27, 24)
+
+// SENINF_CAM_MUX_CTRL_2
+#define RG_SENINF_CAM_MUX8_SRC_SEL   GENMASK(3, 0)
+#define RG_SENINF_CAM_MUX9_SRC_SEL   GENMASK(11, 8)
+#define RG_SENINF_CAM_MUX10_SRC_SEL  GENMASK(19, 16)
+#define RG_SENINF_CAM_MUX11_SRC_SEL  GENMASK(27, 24)
+
+// SENINF_CAM_MUX_CTRL_3
+#define RG_SENINF_CAM_MUX12_SRC_SEL  GENMASK(3, 0)
+#define RG_SENINF_CAM_MUX13_SRC_SEL  GENMASK(11, 8)
+#define RG_SENINF_CAM_MUX14_SRC_SEL  GENMASK(19, 16)
+#define RG_SENINF_CAM_MUX15_SRC_SEL  GENMASK(27, 24)
+
+// SENINF_CAM_MUX_EN
+#define SENINF_CAM_MUX0_EN   GENMASK(0, 0)
+#define SENINF_CAM_MUX1_EN   GENMASK(1, 1)
+#define SENINF_CAM_MUX2_EN   GENMASK(2, 2)
+#define SENINF_CAM_MUX3_EN   GENMASK(3, 3)
+#define SENINF_CAM_MUX4_EN   GENMASK(4, 4)
+#define SENINF_CAM_MUX5_EN   GENMASK(5, 5)
+#define SENINF_CAM_MUX6_EN   GENMASK(6, 6)
+#define SENINF_CAM_MUX7_EN   GENMASK(7, 7)
+#define SENINF_CAM_MUX8_EN   GENMASK(8, 8)
+#define SENINF_CAM_MUX9_EN   GENMASK(9, 9)
+#define SENINF_CAM_MUX10_EN  GENMASK(10, 10)
+#define SENINF_CAM_MUX11_EN  GENMASK(11, 11)
+#define SENINF_CAM_MUX12_EN  GENMASK(12, 12)
+#define SENINF_CAM_MUX13_EN  GENMASK(13, 13)
+#define SENINF_CAM_MUX14_EN  GENMASK(14, 14)
+#define SENINF_CAM_MUX15_EN  GENMASK(15, 15)
+
+// SENINF_CAM_MUX_CHK_EN
+#define SENINF_CAM_MUX0_CHK_EN   GENMASK(0, 0)
+#define SENINF_CAM_MUX1_CHK_EN   GENMASK(1, 1)
+#define SENINF_CAM_MUX2_CHK_EN   GENMASK(2, 2)
+#define SENINF_CAM_MUX3_CHK_EN   GENMASK(3, 3)
+#define SENINF_CAM_MUX4_CHK_EN   GENMASK(4, 4)
+#define SENINF_CAM_MUX5_CHK_EN   GENMASK(5, 5)
+#define SENINF_CAM_MUX6_CHK_EN   GENMASK(6, 6)
+#define SENINF_CAM_MUX7_CHK_EN   GENMASK(7, 7)
+#define SENINF_CAM_MUX8_CHK_EN   GENMASK(8, 8)
+#define SENINF_CAM_MUX9_CHK_EN   GENMASK(9, 9)
+#define SENINF_CAM_MUX10_CHK_EN  GENMASK(10, 10)
+#define SENINF_CAM_MUX11_CHK_EN  GENMASK(11, 11)
+#define SENINF_CAM_MUX12_CHK_EN  GENMASK(12, 12)
+#define SENINF_CAM_MUX13_CHK_EN  GENMASK(13, 13)
+#define SENINF_CAM_MUX14_CHK_EN  GENMASK(14, 14)
+#define SENINF_CAM_MUX15_CHK_EN  GENMASK(15, 15)
+
+// SENINF_CAM_MUXx_OPT
+#define RG_SENINF_CAM_MUXx_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUXx_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUXx_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUXx_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUXx_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX0_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX0_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX0_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX0_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX0_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX1_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX1_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX1_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX1_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX1_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX2_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX2_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX2_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX2_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX2_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX3_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX3_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX3_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX3_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX3_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX4_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX4_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX4_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX4_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX4_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX5_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX5_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX5_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX5_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX5_VSYNC_BYPASS  GENMASK(24, 24)
+
+#define RG_SENINF_CAM_MUX6_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX6_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX6_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX6_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX6_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX7_OPT
+#define SENINF_CAM_MUX7_OPT 0x003c
+#define RG_SENINF_CAM_MUX7_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX7_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX7_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX7_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX7_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX8_OPT
+#define SENINF_CAM_MUX8_OPT 0x0040
+#define RG_SENINF_CAM_MUX8_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX8_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX8_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX8_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX8_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX9_OPT
+#define SENINF_CAM_MUX9_OPT 0x0044
+#define RG_SENINF_CAM_MUX9_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX9_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX9_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX9_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX9_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX10_OPT
+#define SENINF_CAM_MUX10_OPT 0x0048
+#define RG_SENINF_CAM_MUX10_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX10_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX10_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX10_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX10_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX11_OPT
+#define SENINF_CAM_MUX11_OPT 0x004c
+#define RG_SENINF_CAM_MUX11_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX11_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX11_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX11_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX11_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX12_OPT
+#define SENINF_CAM_MUX12_OPT 0x0050
+#define RG_SENINF_CAM_MUX12_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX12_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX12_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX12_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX12_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX13_OPT
+#define SENINF_CAM_MUX13_OPT 0x0054
+#define RG_SENINF_CAM_MUX13_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX13_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX13_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX13_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX13_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX14_OPT
+#define SENINF_CAM_MUX14_OPT 0x0058
+#define RG_SENINF_CAM_MUX14_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX14_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX14_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX14_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX14_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX15_OPT
+#define SENINF_CAM_MUX15_OPT 0x005c
+#define RG_SENINF_CAM_MUX15_VC_EN         GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX15_DT_EN         GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX15_VC_SEL        GENMASK(12, 8)
+#define RG_SENINF_CAM_MUX15_DT_SEL        GENMASK(21, 16)
+#define RG_SENINF_CAM_MUX15_VSYNC_BYPASS  GENMASK(24, 24)
+
+// SENINF_CAM_MUX_CTRL
+//#define SENINF_CAM_MUX_CTRL 0x0080
+#define SENINF_CAM_MUX_SW_RST                GENMASK(0, 0)
+#define SENINF_CAM_MUX_IRQ_SW_RST            GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX_SLICE_FULL_OPT     GENMASK(7, 7)
+#define RG_SENINF_CAM_MUX_IRQ_CLR_MODE       GENMASK(8, 8)
+#define RG_SENINF_CAM_MUX_IRQ_VERIF_EN       GENMASK(9, 9)
+
+// SENINF_CAM_MUX_DYN_CTRL
+#define SENINF_CAM_MUX_DYN_CTRL 0x0088
+#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0    GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1    GENMASK(4, 4)
+#define CAM_MUX_DYN_PAGE_SEL                 GENMASK(28, 28)
+
+// SENINF_CAM_MUX_DYN_EN
+#define SENINF_CAM_MUX_DYN_EN 0x008c
+#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN0     GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN1     GENMASK(31, 16)
+
+// SENINF_CAM_MUX_NEXT_CTRL_0
+#define SENINF_CAM_MUX_NEXT_CTRL_0 0x0090
+#define CAM_MUX0_NEXT_SRC_SEL    GENMASK(3, 0)
+#define CAM_MUX1_NEXT_SRC_SEL    GENMASK(11, 8)
+#define CAM_MUX2_NEXT_SRC_SEL    GENMASK(19, 16)
+#define CAM_MUX3_NEXT_SRC_SEL    GENMASK(27, 24)
+
+// SENINF_CAM_MUX_NEXT_CTRL_1
+#define SENINF_CAM_MUX_NEXT_CTRL_1 0x0094
+#define CAM_MUX4_NEXT_SRC_SEL    GENMASK(3, 0)
+#define CAM_MUX5_NEXT_SRC_SEL    GENMASK(11, 8)
+#define CAM_MUX6_NEXT_SRC_SEL    GENMASK(19, 16)
+#define CAM_MUX7_NEXT_SRC_SEL    GENMASK(27, 24)
+
+// SENINF_CAM_MUX_NEXT_CTRL_2
+#define SENINF_CAM_MUX_NEXT_CTRL_2 0x0098
+#define CAM_MUX8_NEXT_SRC_SEL    GENMASK(3, 0)
+#define CAM_MUX9_NEXT_SRC_SEL    GENMASK(11, 8)
+#define CAM_MUX10_NEXT_SRC_SEL   GENMASK(19, 16)
+#define CAM_MUX11_NEXT_SRC_SEL   GENMASK(27, 24)
+
+// SENINF_CAM_MUX_NEXT_CTRL_3
+#define SENINF_CAM_MUX_NEXT_CTRL_3 0x009c
+#define CAM_MUX12_NEXT_SRC_SEL   GENMASK(3, 0)
+#define CAM_MUX13_NEXT_SRC_SEL   GENMASK(11, 8)
+#define CAM_MUX14_NEXT_SRC_SEL   GENMASK(19, 16)
+#define CAM_MUX15_NEXT_SRC_SEL   GENMASK(27, 24)
+
+// SENINF_CAM_MUX_IRQ_EN
+#define SENINF_CAM_MUX_IRQ_EN 0x00a0
+#define RG_SENINF_CAM_MUX0_HSIZE_ERR_IRQ_EN   GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX0_VSIZE_ERR_IRQ_EN   GENMASK(1, 1)
+#define RG_SENINF_CAM_MUX1_HSIZE_ERR_IRQ_EN   GENMASK(2, 2)
+#define RG_SENINF_CAM_MUX1_VSIZE_ERR_IRQ_EN   GENMASK(3, 3)
+#define RG_SENINF_CAM_MUX2_HSIZE_ERR_IRQ_EN   GENMASK(4, 4)
+#define RG_SENINF_CAM_MUX2_VSIZE_ERR_IRQ_EN   GENMASK(5, 5)
+#define RG_SENINF_CAM_MUX3_HSIZE_ERR_IRQ_EN   GENMASK(6, 6)
+#define RG_SENINF_CAM_MUX3_VSIZE_ERR_IRQ_EN   GENMASK(7, 7)
+#define RG_SENINF_CAM_MUX4_HSIZE_ERR_IRQ_EN   GENMASK(8, 8)
+#define RG_SENINF_CAM_MUX4_VSIZE_ERR_IRQ_EN   GENMASK(9, 9)
+#define RG_SENINF_CAM_MUX5_HSIZE_ERR_IRQ_EN   GENMASK(10, 10)
+#define RG_SENINF_CAM_MUX5_VSIZE_ERR_IRQ_EN   GENMASK(11, 11)
+#define RG_SENINF_CAM_MUX6_HSIZE_ERR_IRQ_EN   GENMASK(12, 12)
+#define RG_SENINF_CAM_MUX6_VSIZE_ERR_IRQ_EN   GENMASK(13, 13)
+#define RG_SENINF_CAM_MUX7_HSIZE_ERR_IRQ_EN   GENMASK(14, 14)
+#define RG_SENINF_CAM_MUX7_VSIZE_ERR_IRQ_EN   GENMASK(15, 15)
+#define RG_SENINF_CAM_MUX8_HSIZE_ERR_IRQ_EN   GENMASK(16, 16)
+#define RG_SENINF_CAM_MUX8_VSIZE_ERR_IRQ_EN   GENMASK(17, 17)
+#define RG_SENINF_CAM_MUX9_HSIZE_ERR_IRQ_EN   GENMASK(18, 18)
+#define RG_SENINF_CAM_MUX9_VSIZE_ERR_IRQ_EN   GENMASK(19, 19)
+#define RG_SENINF_CAM_MUX10_HSIZE_ERR_IRQ_EN  GENMASK(20, 20)
+#define RG_SENINF_CAM_MUX10_VSIZE_ERR_IRQ_EN  GENMASK(21, 21)
+#define RG_SENINF_CAM_MUX11_HSIZE_ERR_IRQ_EN  GENMASK(22, 22)
+#define RG_SENINF_CAM_MUX11_VSIZE_ERR_IRQ_EN  GENMASK(23, 23)
+#define RG_SENINF_CAM_MUX12_HSIZE_ERR_IRQ_EN  GENMASK(24, 24)
+#define RG_SENINF_CAM_MUX12_VSIZE_ERR_IRQ_EN  GENMASK(25, 25)
+#define RG_SENINF_CAM_MUX13_HSIZE_ERR_IRQ_EN  GENMASK(26, 26)
+#define RG_SENINF_CAM_MUX13_VSIZE_ERR_IRQ_EN  GENMASK(27, 27)
+#define RG_SENINF_CAM_MUX14_HSIZE_ERR_IRQ_EN  GENMASK(28, 28)
+#define RG_SENINF_CAM_MUX14_VSIZE_ERR_IRQ_EN  GENMASK(29, 29)
+#define RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN  GENMASK(30, 30)
+#define RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN  GENMASK(31, 31)
+
+// SENINF_CAM_MUX_IRQ_STATUS
+#define SENINF_CAM_MUX_IRQ_STATUS 0x00a8
+#define RO_SENINF_CAM_MUX0_HSIZE_ERR_IRQ    GENMASK(0, 0)
+#define RO_SENINF_CAM_MUX0_VSIZE_ERR_IRQ    GENMASK(1, 1)
+#define RO_SENINF_CAM_MUX1_HSIZE_ERR_IRQ    GENMASK(2, 2)
+#define RO_SENINF_CAM_MUX1_VSIZE_ERR_IRQ    GENMASK(3, 3)
+#define RO_SENINF_CAM_MUX2_HSIZE_ERR_IRQ    GENMASK(4, 4)
+#define RO_SENINF_CAM_MUX2_VSIZE_ERR_IRQ    GENMASK(5, 5)
+#define RO_SENINF_CAM_MUX3_HSIZE_ERR_IRQ    GENMASK(6, 6)
+#define RO_SENINF_CAM_MUX3_VSIZE_ERR_IRQ    GENMASK(7, 7)
+#define RO_SENINF_CAM_MUX4_HSIZE_ERR_IRQ    GENMASK(8, 8)
+#define RO_SENINF_CAM_MUX4_VSIZE_ERR_IRQ    GENMASK(9, 9)
+#define RO_SENINF_CAM_MUX5_HSIZE_ERR_IRQ    GENMASK(10, 10)
+#define RO_SENINF_CAM_MUX5_VSIZE_ERR_IRQ    GENMASK(11, 11)
+#define RO_SENINF_CAM_MUX6_HSIZE_ERR_IRQ    GENMASK(12, 12)
+#define RO_SENINF_CAM_MUX6_VSIZE_ERR_IRQ    GENMASK(13, 13)
+#define RO_SENINF_CAM_MUX7_HSIZE_ERR_IRQ    GENMASK(14, 14)
+#define RO_SENINF_CAM_MUX7_VSIZE_ERR_IRQ    GENMASK(15, 15)
+#define RO_SENINF_CAM_MUX8_HSIZE_ERR_IRQ    GENMASK(16, 16)
+#define RO_SENINF_CAM_MUX8_VSIZE_ERR_IRQ    GENMASK(17, 17)
+#define RO_SENINF_CAM_MUX9_HSIZE_ERR_IRQ    GENMASK(18, 18)
+#define RO_SENINF_CAM_MUX9_VSIZE_ERR_IRQ    GENMASK(19, 19)
+#define RO_SENINF_CAM_MUX10_HSIZE_ERR_IRQ   GENMASK(20, 20)
+#define RO_SENINF_CAM_MUX10_VSIZE_ERR_IRQ   GENMASK(21, 21)
+#define RO_SENINF_CAM_MUX11_HSIZE_ERR_IRQ   GENMASK(22, 22)
+#define RO_SENINF_CAM_MUX11_VSIZE_ERR_IRQ   GENMASK(23, 23)
+#define RO_SENINF_CAM_MUX12_HSIZE_ERR_IRQ   GENMASK(24, 24)
+#define RO_SENINF_CAM_MUX12_VSIZE_ERR_IRQ   GENMASK(25, 25)
+#define RO_SENINF_CAM_MUX13_HSIZE_ERR_IRQ   GENMASK(26, 26)
+#define RO_SENINF_CAM_MUX13_VSIZE_ERR_IRQ   GENMASK(27, 27)
+#define RO_SENINF_CAM_MUX14_HSIZE_ERR_IRQ   GENMASK(28, 28)
+#define RO_SENINF_CAM_MUX14_VSIZE_ERR_IRQ   GENMASK(29, 29)
+#define RO_SENINF_CAM_MUX15_HSIZE_ERR_IRQ   GENMASK(30, 30)
+#define RO_SENINF_CAM_MUX15_VSIZE_ERR_IRQ   GENMASK(31, 31)
+
+// SENINF_CAM_MUX_VSYNC_IRQ_EN
+#define SENINF_CAM_MUX_VSYNC_IRQ_EN 0x00b0
+#define RG_SENINF_CAM_MUX_VSYNC_IRQ_EN         GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX_VSYNC_ALL_IRQ_EN     GENMASK(25, 24)
+#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ_EN GENMASK(29, 28)
+
+// SENINF_CAM_MUX_VSYNC_IRQ_STS
+#define SENINF_CAM_MUX_VSYNC_IRQ_STS 0x00b4
+#define RO_SENINF_CAM_MUX_VSYNC_IRQ         GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX_VSYNC_ALL_IRQ     GENMASK(25, 24)
+#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ GENMASK(29, 28)
+
+// SENINF_CAM_MUX_DBG_CTRL
+#define SENINF_CAM_MUX_DBG_CTRL 0x00c0
+#define RG_SENINF_CAM_MUX_DBG_EN   GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX_DBG_SEL  GENMASK(15, 8)
+
+// SENINF_CAM_MUX_DBG_OUT
+#define SENINF_CAM_MUX_DBG_OUT 0x00c4
+#define RO_SENINF_CAM_MUX_DBG_OUT  GENMASK(31, 0)
+
+// SENINF_CAM_MUX_VSYNC_T0_WINDOW_L
+#define SENINF_CAM_MUX_VSYNC_T0_WINDOW_L 0x00d0
+#define RG_SENINF_CAM_MUX_VSYNC_TIMER0_WINDOW_L GENMASK(31, 0)
+
+// SENINF_CAM_MUX_VSYNC_T1_WINDOW_L
+#define SENINF_CAM_MUX_VSYNC_T1_WINDOW_L 0x00d8
+#define RG_SENINF_CAM_MUX_VSYNC_TIMER1_WINDOW_L GENMASK(31, 0)
+
+// SENINF_CAM_MUX_SAT_IRQ_EN
+#define SENINF_CAM_MUX_SAT_IRQ_EN 0x00e0
+#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ_EN GENMASK(0, 0)
+#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ_EN GENMASK(1, 1)
+
+// SENINF_CAM_MUX_SAT_IRQ_STATUS
+#define SENINF_CAM_MUX_SAT_IRQ_STATUS 0x00e8
+#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ GENMASK(0, 0)
+#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ GENMASK(1, 1)
+
+// SENINF_CAM_SPARE
+#define SENINF_CAM_SPARE 0x00f8
+#define RG_SENINF_TOP_SPARE_0 GENMASK(7, 0)
+#define RG_SENINF_TOP_SPARE_1 GENMASK(23, 16)
+
+// SENINF_CAM_MUX0_CHK_CTL_0
+#define SENINF_CAM_MUX0_CHK_CTL_0 0x0100
+#define RG_SENINF_CAM_MUX0_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX0_CHK_CTL_1
+#define SENINF_CAM_MUX0_CHK_CTL_1 0x0104
+#define RG_SENINF_CAM_MUX0_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX0_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX0_CHK_RES
+#define SENINF_CAM_MUX0_CHK_RES 0x0108
+#define RO_SENINF_CAM_MUX0_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX0_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX0_CHK_ERR_RES
+#define SENINF_CAM_MUX0_CHK_ERR_RES 0x010c
+#define RO_SENINF_CAM_MUX0_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX0_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX1_CHK_CTL_0
+#define SENINF_CAM_MUX1_CHK_CTL_0 0x0110
+#define RG_SENINF_CAM_MUX1_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX1_CHK_CTL_1
+#define SENINF_CAM_MUX1_CHK_CTL_1 0x0114
+#define RG_SENINF_CAM_MUX1_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX1_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX1_CHK_RES
+#define SENINF_CAM_MUX1_CHK_RES 0x0118
+#define RO_SENINF_CAM_MUX1_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX1_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX1_CHK_ERR_RES
+#define SENINF_CAM_MUX1_CHK_ERR_RES 0x011c
+#define RO_SENINF_CAM_MUX1_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX1_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX2_CHK_CTL_0
+#define SENINF_CAM_MUX2_CHK_CTL_0 0x0120
+#define RG_SENINF_CAM_MUX2_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX2_CHK_CTL_1
+#define SENINF_CAM_MUX2_CHK_CTL_1 0x0124
+#define RG_SENINF_CAM_MUX2_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX2_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX2_CHK_RES
+#define SENINF_CAM_MUX2_CHK_RES 0x0128
+#define RO_SENINF_CAM_MUX2_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX2_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX2_CHK_ERR_RES
+#define SENINF_CAM_MUX2_CHK_ERR_RES 0x012c
+#define RO_SENINF_CAM_MUX2_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX2_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX3_CHK_CTL_0
+#define SENINF_CAM_MUX3_CHK_CTL_0 0x0130
+#define RG_SENINF_CAM_MUX3_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX3_CHK_CTL_1
+#define SENINF_CAM_MUX3_CHK_CTL_1 0x0134
+#define RG_SENINF_CAM_MUX3_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX3_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX3_CHK_RES
+#define SENINF_CAM_MUX3_CHK_RES 0x0138
+#define RO_SENINF_CAM_MUX3_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX3_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX3_CHK_ERR_RES
+#define SENINF_CAM_MUX3_CHK_ERR_RES 0x013c
+#define RO_SENINF_CAM_MUX3_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX3_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX4_CHK_CTL_0
+#define SENINF_CAM_MUX4_CHK_CTL_0 0x0140
+#define RG_SENINF_CAM_MUX4_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX4_CHK_CTL_1
+#define SENINF_CAM_MUX4_CHK_CTL_1 0x0144
+#define RG_SENINF_CAM_MUX4_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX4_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX4_CHK_RES
+#define SENINF_CAM_MUX4_CHK_RES 0x0148
+#define RO_SENINF_CAM_MUX4_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX4_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX4_CHK_ERR_RES
+#define SENINF_CAM_MUX4_CHK_ERR_RES 0x014c
+#define RO_SENINF_CAM_MUX4_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX4_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX5_CHK_CTL_0
+#define SENINF_CAM_MUX5_CHK_CTL_0 0x0150
+#define RG_SENINF_CAM_MUX5_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX5_CHK_CTL_1
+#define SENINF_CAM_MUX5_CHK_CTL_1 0x0154
+#define RG_SENINF_CAM_MUX5_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX5_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX5_CHK_RES
+#define SENINF_CAM_MUX5_CHK_RES 0x0158
+#define RO_SENINF_CAM_MUX5_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX5_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX5_CHK_ERR_RES
+#define SENINF_CAM_MUX5_CHK_ERR_RES 0x015c
+#define RO_SENINF_CAM_MUX5_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX5_RCV_ERR_VSIZE GENMASK(31, 16)
+
+#include <linux/bitfield.h>
+
+// SENINF_CAM_MUX6_CHK_CTL_0
+#define SENINF_CAM_MUX6_CHK_CTL_0 0x0160
+#define RG_SENINF_CAM_MUX6_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX6_CHK_CTL_1
+#define SENINF_CAM_MUX6_CHK_CTL_1 0x0164
+#define RG_SENINF_CAM_MUX6_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX6_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX6_CHK_RES
+#define SENINF_CAM_MUX6_CHK_RES 0x0168
+#define RO_SENINF_CAM_MUX6_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX6_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX6_CHK_ERR_RES
+#define SENINF_CAM_MUX6_CHK_ERR_RES 0x016c
+#define RO_SENINF_CAM_MUX6_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX6_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX7_CHK_CTL_0
+#define SENINF_CAM_MUX7_CHK_CTL_0 0x0170
+#define RG_SENINF_CAM_MUX7_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX7_CHK_CTL_1
+#define SENINF_CAM_MUX7_CHK_CTL_1 0x0174
+#define RG_SENINF_CAM_MUX7_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX7_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX7_CHK_RES
+#define SENINF_CAM_MUX7_CHK_RES 0x0178
+#define RO_SENINF_CAM_MUX7_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX7_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX7_CHK_ERR_RES
+#define SENINF_CAM_MUX7_CHK_ERR_RES 0x017c
+#define RO_SENINF_CAM_MUX7_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX7_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX8_CHK_CTL_0
+#define SENINF_CAM_MUX8_CHK_CTL_0 0x0180
+#define RG_SENINF_CAM_MUX8_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX8_CHK_CTL_1
+#define SENINF_CAM_MUX8_CHK_CTL_1 0x0184
+#define RG_SENINF_CAM_MUX8_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX8_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX8_CHK_RES
+#define SENINF_CAM_MUX8_CHK_RES 0x0188
+#define RO_SENINF_CAM_MUX8_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX8_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX8_CHK_ERR_RES
+#define SENINF_CAM_MUX8_CHK_ERR_RES 0x018c
+#define RO_SENINF_CAM_MUX8_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX8_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX9_CHK_CTL_0
+#define SENINF_CAM_MUX9_CHK_CTL_0 0x0190
+#define RG_SENINF_CAM_MUX9_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX9_CHK_CTL_1
+#define SENINF_CAM_MUX9_CHK_CTL_1 0x0194
+#define RG_SENINF_CAM_MUX9_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX9_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX9_CHK_RES
+#define SENINF_CAM_MUX9_CHK_RES 0x0198
+#define RO_SENINF_CAM_MUX9_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX9_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX9_CHK_ERR_RES
+#define SENINF_CAM_MUX9_CHK_ERR_RES 0x019c
+#define RO_SENINF_CAM_MUX9_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX9_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX10_CHK_CTL_0
+#define SENINF_CAM_MUX10_CHK_CTL_0 0x01a0
+#define RG_SENINF_CAM_MUX10_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX10_CHK_CTL_1
+#define SENINF_CAM_MUX10_CHK_CTL_1 0x01a4
+#define RG_SENINF_CAM_MUX10_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX10_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX10_CHK_RES
+#define SENINF_CAM_MUX10_CHK_RES 0x01a8
+#define RO_SENINF_CAM_MUX10_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX10_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX10_CHK_ERR_RES
+#define SENINF_CAM_MUX10_CHK_ERR_RES 0x01ac
+#define RO_SENINF_CAM_MUX10_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX10_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX11_CHK_CTL_0
+#define SENINF_CAM_MUX11_CHK_CTL_0 0x01b0
+#define RG_SENINF_CAM_MUX11_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX11_CHK_CTL_1
+#define SENINF_CAM_MUX11_CHK_CTL_1 0x01b4
+#define RG_SENINF_CAM_MUX11_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX11_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX11_CHK_RES
+#define SENINF_CAM_MUX11_CHK_RES 0x01b8
+#define RO_SENINF_CAM_MUX11_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX11_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX11_CHK_ERR_RES
+#define SENINF_CAM_MUX11_CHK_ERR_RES 0x01bc
+#define RO_SENINF_CAM_MUX11_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX11_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX12_CHK_CTL_0
+#define SENINF_CAM_MUX12_CHK_CTL_0 0x01c0
+#define RG_SENINF_CAM_MUX12_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX12_CHK_CTL_1
+#define SENINF_CAM_MUX12_CHK_CTL_1 0x01c4
+#define RG_SENINF_CAM_MUX12_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX12_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX12_CHK_RES
+#define SENINF_CAM_MUX12_CHK_RES 0x01c8
+#define RO_SENINF_CAM_MUX12_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX12_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX12_CHK_ERR_RES
+#define SENINF_CAM_MUX12_CHK_ERR_RES 0x01cc
+#define RO_SENINF_CAM_MUX12_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX12_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX13_CHK_CTL_0
+#define SENINF_CAM_MUX13_CHK_CTL_0 0x01d0
+#define RG_SENINF_CAM_MUX13_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX13_CHK_CTL_1
+#define SENINF_CAM_MUX13_CHK_CTL_1 0x01d4
+#define RG_SENINF_CAM_MUX13_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX13_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX13_CHK_RES
+#define SENINF_CAM_MUX13_CHK_RES 0x01d8
+#define RO_SENINF_CAM_MUX13_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX13_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX13_CHK_ERR_RES
+#define SENINF_CAM_MUX13_CHK_ERR_RES 0x01dc
+#define RO_SENINF_CAM_MUX13_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX13_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX14_CHK_CTL_0
+#define SENINF_CAM_MUX14_CHK_CTL_0 0x01e0
+#define RG_SENINF_CAM_MUX14_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX14_CHK_CTL_1
+#define SENINF_CAM_MUX14_CHK_CTL_1 0x01e4
+#define RG_SENINF_CAM_MUX14_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX14_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX14_CHK_RES
+#define SENINF_CAM_MUX14_CHK_RES 0x01e8
+#define RO_SENINF_CAM_MUX14_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX14_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX14_CHK_ERR_RES
+#define SENINF_CAM_MUX14_CHK_ERR_RES 0x01ec
+#define RO_SENINF_CAM_MUX14_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX14_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX15_CHK_CTL_0
+#define SENINF_CAM_MUX15_CHK_CTL_0 0x01f0
+#define RG_SENINF_CAM_MUX15_PIX_MODE_SEL GENMASK(1, 0)
+
+// SENINF_CAM_MUX15_CHK_CTL_1
+#define SENINF_CAM_MUX15_CHK_CTL_1 0x01f4
+#define RG_SENINF_CAM_MUX15_EXP_HSIZE GENMASK(15, 0)
+#define RG_SENINF_CAM_MUX15_EXP_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX15_CHK_RES
+#define SENINF_CAM_MUX15_CHK_RES 0x01f8
+#define RO_SENINF_CAM_MUX15_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX15_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_CAM_MUX15_CHK_ERR_RES
+#define SENINF_CAM_MUX15_CHK_ERR_RES 0x01fc
+#define RO_SENINF_CAM_MUX15_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_CAM_MUX15_RCV_ERR_VSIZE GENMASK(31, 16)
+
+#endif
\ No newline at end of file
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
new file mode 100755
index 000000000000..7e72f34a297b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __CSI0_CPHY_TOP_H__
+#define __CSI0_CPHY_TOP_H__
+
+#include <linux/bitfield.h>
+
+// CPHY_RX_CTRL
+#define CPHY_RX_CTRL 0x0000
+#define CPHY_RX_TR0_LPRX_EN      GENMASK(0, 0)
+#define CPHY_RX_TR1_LPRX_EN      GENMASK(1, 1)
+#define CPHY_RX_TR2_LPRX_EN      GENMASK(2, 2)
+#define CPHY_RX_TR3_LPRX_EN      GENMASK(3, 3)
+#define CPHY_RX_TR0_HSRX_EN      GENMASK(4, 4)
+#define CPHY_RX_TR1_HSRX_EN      GENMASK(5, 5)
+#define CPHY_RX_TR2_HSRX_EN      GENMASK(6, 6)
+#define CPHY_RX_TR3_HSRX_EN      GENMASK(7, 7)
+#define CPHY_RX_TR0_BIST_EN      GENMASK(16, 16)
+#define CPHY_RX_TR1_BIST_EN      GENMASK(17, 17)
+#define CPHY_RX_TR2_BIST_EN      GENMASK(18, 18)
+#define CPHY_RX_TR3_BIST_EN      GENMASK(19, 19)
+
+// CPHY_RX_DETECT_CTRL_SYNC
+#define CPHY_RX_DETECT_CTRL_SYNC 0x0010
+#define RG_CPHY_RX_DETECT_7S_DIS_SYNC     GENMASK(0, 0)
+#define RG_CPHY_RX_DETECT_7S_MASK_SYNC    GENMASK(7, 1)
+#define RG_CPHY_RX_DETECT_7S_WORD_SYNC    GENMASK(28, 8)
+
+// CPHY_RX_DETECT_CTRL_ESCAPE
+#define CPHY_RX_DETECT_CTRL_ESCAPE 0x0014
+#define RG_CPHY_RX_DETECT_7S_DIS_ESCAPE   GENMASK(0, 0)
+#define RG_CPHY_RX_DETECT_7S_MASK_ESCAPE  GENMASK(7, 1)
+#define RG_CPHY_RX_DETECT_7S_WORD_ESCAPE  GENMASK(28, 8)
+
+// CPHY_RX_DETECT_CTRL_POST
+#define CPHY_RX_DETECT_CTRL_POST 0x0018
+#define RG_CPHY_RX_DETECT_7S_DIS_POST     GENMASK(0, 0)
+#define RG_CPHY_RX_DATA_VALID_POST_EN     GENMASK(4, 4)
+#define RG_CPHY_RX_DETECT_7S_WORD_POST    GENMASK(28, 8)
+
+// CPHY_RX_FSM_STATUS
+#define CPHY_RX_FSM_STATUS 0x00e4
+#define RO_CPHY_RX_TR0_FSM GENMASK(7, 0)
+#define RO_CPHY_RX_TR1_FSM GENMASK(15, 8)
+#define RO_CPHY_RX_TR2_FSM GENMASK(23, 16)
+#define RO_CPHY_RX_TR3_FSM GENMASK(31, 24)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
new file mode 100755
index 000000000000..fc8a190f040b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __CSI0_DPHY_TOP_H__
+#define __CSI0_DPHY_TOP_H__
+
+#include <linux/bitfield.h>
+
+// DPHY_RX_LANE_EN
+#define DPHY_RX_LANE_EN 0x0000
+#define DPHY_RX_LC0_EN    GENMASK(0, 0)
+#define DPHY_RX_LC1_EN    GENMASK(1, 1)
+#define DPHY_RX_LD0_EN    GENMASK(8, 8)
+#define DPHY_RX_LD1_EN    GENMASK(9, 9)
+#define DPHY_RX_LD2_EN    GENMASK(10, 10)
+#define DPHY_RX_LD3_EN    GENMASK(11, 11)
+#define DPHY_RX_SW_RST    GENMASK(31, 31)
+
+// DPHY_RX_LANE_SELECT
+#define DPHY_RX_LANE_SELECT 0x0004
+#define RG_DPHY_RX_LC0_SEL      GENMASK(2, 0)
+#define RG_DPHY_RX_LC1_SEL      GENMASK(6, 4)
+#define RG_DPHY_RX_LD0_SEL      GENMASK(10, 8)
+#define RG_DPHY_RX_LD1_SEL      GENMASK(14, 12)
+#define RG_DPHY_RX_LD2_SEL      GENMASK(18, 16)
+#define RG_DPHY_RX_LD3_SEL      GENMASK(22, 20)
+#define DPHY_RX_CK_DATA_MUX_EN  GENMASK(31, 31)
+
+// DPHY_RX_HS_RX_EN_SW
+#define DPHY_RX_HS_RX_EN_SW 0x0008
+#define RG_DPHY_RX_LC0_HSRX_EN_SW         GENMASK(0, 0)
+#define RG_DPHY_RX_LC1_HSRX_EN_SW         GENMASK(1, 1)
+#define RG_CDPHY_RX_LD0_TRIO0_HSRX_EN_SW  GENMASK(8, 8)
+#define RG_CDPHY_RX_LD1_TRIO1_HSRX_EN_SW  GENMASK(9, 9)
+#define RG_CDPHY_RX_LD2_TRIO2_HSRX_EN_SW  GENMASK(10, 10)
+#define RG_CDPHY_RX_LD2_TRIO3_HSRX_EN_SW  GENMASK(11, 11)
+
+// DPHY_RX_CLOCK_LANE0_HS_PARAMETER
+#define DPHY_RX_CLOCK_LANE0_HS_PARAMETER 0x0010
+#define RG_DPHY_RX_LC0_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_DPHY_RX_LC0_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LC0_HS_OPTION            GENMASK(30, 30)
+
+// DPHY_RX_CLOCK_LANE1_HS_PARAMETER
+#define DPHY_RX_CLOCK_LANE1_HS_PARAMETER 0x0014
+#define RG_DPHY_RX_LC1_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_DPHY_RX_LC1_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LC1_HS_OPTION            GENMASK(30, 30)
+
+// DPHY_RX_DATA_LANE0_HS_PARAMETER
+#define DPHY_RX_DATA_LANE0_HS_PARAMETER 0x0020
+#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER          GENMASK(15, 8)
+#define RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LD0_HS_TRAIL_EN                 GENMASK(29, 29)
+
+// DPHY_RX_DATA_LANE1_HS_PARAMETER
+#define DPHY_RX_DATA_LANE1_HS_PARAMETER 0x0024
+#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER          GENMASK(15, 8)
+#define RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LD1_HS_TRAIL_EN                 GENMASK(29, 29)
+
+// DPHY_RX_DATA_LANE2_HS_PARAMETER
+#define DPHY_RX_DATA_LANE2_HS_PARAMETER 0x0028
+#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER          GENMASK(15, 8)
+#define RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LD2_HS_TRAIL_EN                 GENMASK(29, 29)
+
+// DPHY_RX_DATA_LANE3_HS_PARAMETER
+#define DPHY_RX_DATA_LANE3_HS_PARAMETER 0x002c
+#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_PARAMETER GENMASK(7, 0)
+#define RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER          GENMASK(15, 8)
+#define RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER  GENMASK(23, 16)
+#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_EN        GENMASK(28, 28)
+#define RG_DPHY_RX_LD3_HS_TRAIL_EN                 GENMASK(29, 29)
+
+// DPHY_RX_CLOCK_LANE_FSM
+#define DPHY_RX_CLOCK_LANE_FSM 0x0030
+#define RO_DPHY_RX_CL0_FSM GENMASK(5, 0)
+#define RO_DPHY_RX_CL1_FSM GENMASK(13, 8)
+
+// DPHY_RX_DATA_LANE_FSM
+#define DPHY_RX_DATA_LANE_FSM 0x0034
+#define RO_DPHY_RX_DL0_FSM GENMASK(7, 0)
+#define RO_DPHY_RX_DL1_FSM GENMASK(15, 8)
+#define RO_DPHY_RX_DL2_FSM GENMASK(23, 16)
+#define RO_DPHY_RX_DL3_FSM GENMASK(31, 24)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
new file mode 100755
index 000000000000..a3c926cc3cee
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
@@ -0,0 +1,1932 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+
+#include "../mtk_cam-seninf.h"
+#include "../mtk_cam-seninf-hw.h"
+#include "../mtk_cam-seninf-regs.h"
+#include "mtk_cam-seninf-top-ctrl.h"
+#include "mtk_cam-seninf-seninf1-mux.h"
+#include "mtk_cam-seninf-seninf1.h"
+#include "mtk_cam-seninf-seninf1-csi2.h"
+#include "mtk_cam-seninf-tg1.h"
+#include "mtk_cam-seninf-cammux.h"
+#include "mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h"
+#include "mtk_cam-seninf-csi0-cphy.h"
+#include "mtk_cam-seninf-csi0-dphy.h"
+#include "../kd_imgsensor_define_v4l2.h"
+
+static struct mtk_cam_seninf_cfg _seninf_cfg = {
+	.mux_num = 8,
+	.seninf_num = 4,
+	.cam_mux_num = 11,
+	.pref_mux_num = 11,
+};
+
+struct mtk_cam_seninf_cfg *g_seninf_cfg = &_seninf_cfg;
+
+static inline u32 get_port_num(int port)
+{
+    if (port >= CSI_PORT_0A)
+        return FIELD_GET(CSI_PORT_A_MASK, port - CSI_PORT_0A);
+    else
+        return port;
+}
+
+static inline void mtk_cam_seninf_set_di_ch_ctrl(void __iomem *pseninf,
+						 unsigned int stream_id,
+						 struct seninf_vc *vc)
+{
+	if (stream_id > SENINF_MAX_STREAM)
+		return;
+
+	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
+		    RG_CSI2_DT_SEL, vc->dt);
+	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
+		    RG_CSI2_VC_SEL, 0);
+	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
+		    RG_CSI2_DT_INTERLEAVE_MODE, 1);
+	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
+		    RG_CSI2_VC_INTERLEAVE_EN, 1);
+
+	switch (stream_id) {
+	case 0:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S0_GRP_EN, 1);
+		break;
+	case 1:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S1_GRP_EN, 1);
+		break;
+	case 2:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S2_GRP_EN, 1);
+		break;
+	case 3:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S3_GRP_EN, 1);
+		break;
+	case 4:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S4_GRP_EN, 1);
+		break;
+	case 5:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S5_GRP_EN, 1);
+		break;
+	case 6:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S6_GRP_EN, 1);
+		break;
+	case 7:
+		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
+			    RG_CSI2_S7_GRP_EN, 1);
+		break;
+	default:
+		return;
+	}
+}
+
+int mtk_cam_seninf_init_iomem(struct seninf_ctx *ctx, void __iomem *if_base,
+			      void __iomem *ana_base)
+{
+	u32 i;
+
+	// reg_ana_csi_rx
+	ctx->reg_ana_csi_rx[CSI_PORT_0]  = ana_base + ANA_CSI_RX_PORT0_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_0A] = ana_base + ANA_CSI_RX_PORT0_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_0B] = ana_base + ANA_CSI_RX_PORT0B_OFFSET;
+
+	ctx->reg_ana_csi_rx[CSI_PORT_1]  = ana_base + ANA_CSI_RX_PORT1_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_1A] = ana_base + ANA_CSI_RX_PORT1_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_1B] = ana_base + ANA_CSI_RX_PORT1B_OFFSET;
+
+	ctx->reg_ana_csi_rx[CSI_PORT_2]  = ana_base + ANA_CSI_RX_PORT2_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_2A] = ana_base + ANA_CSI_RX_PORT2_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_2B] = ana_base + ANA_CSI_RX_PORT2B_OFFSET;
+
+	ctx->reg_ana_csi_rx[CSI_PORT_3]  = ana_base + ANA_CSI_RX_PORT3_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_3A] = ana_base + ANA_CSI_RX_PORT3_OFFSET;
+	ctx->reg_ana_csi_rx[CSI_PORT_3B] = ana_base + ANA_CSI_RX_PORT3B_OFFSET;
+
+	// reg_ana_dphy_top
+	ctx->reg_ana_dphy_top[CSI_PORT_0]  = ana_base + ANA_DPHY_TOP_PORT0_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_0A] = ana_base + ANA_DPHY_TOP_PORT0_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_0B] = ana_base + ANA_DPHY_TOP_PORT0_OFFSET;
+
+	ctx->reg_ana_dphy_top[CSI_PORT_1]  = ana_base + ANA_DPHY_TOP_PORT1_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_1A] = ana_base + ANA_DPHY_TOP_PORT1_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_1B] = ana_base + ANA_DPHY_TOP_PORT1_OFFSET;
+
+	ctx->reg_ana_dphy_top[CSI_PORT_2]  = ana_base + ANA_DPHY_TOP_PORT2_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_2A] = ana_base + ANA_DPHY_TOP_PORT2_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_2B] = ana_base + ANA_DPHY_TOP_PORT2_OFFSET;
+
+	ctx->reg_ana_dphy_top[CSI_PORT_3]  = ana_base + ANA_DPHY_TOP_PORT3_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_3A] = ana_base + ANA_DPHY_TOP_PORT3_OFFSET;
+	ctx->reg_ana_dphy_top[CSI_PORT_3B] = ana_base + ANA_DPHY_TOP_PORT3_OFFSET;
+
+	// reg_ana_cphy_top
+	ctx->reg_ana_cphy_top[CSI_PORT_0]  = ana_base + ANA_CPHY_TOP_PORT0_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_0A] = ana_base + ANA_CPHY_TOP_PORT0_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_0B] = ana_base + ANA_CPHY_TOP_PORT0_OFFSET;
+
+	ctx->reg_ana_cphy_top[CSI_PORT_1]  = ana_base + ANA_CPHY_TOP_PORT1_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_1A] = ana_base + ANA_CPHY_TOP_PORT1_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_1B] = ana_base + ANA_CPHY_TOP_PORT1_OFFSET;
+
+	ctx->reg_ana_cphy_top[CSI_PORT_2]  = ana_base + ANA_CPHY_TOP_PORT2_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_2A] = ana_base + ANA_CPHY_TOP_PORT2_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_2B] = ana_base + ANA_CPHY_TOP_PORT2_OFFSET;
+
+	ctx->reg_ana_cphy_top[CSI_PORT_3]  = ana_base + ANA_CPHY_TOP_PORT3_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_3A] = ana_base + ANA_CPHY_TOP_PORT3_OFFSET;
+	ctx->reg_ana_cphy_top[CSI_PORT_3B] = ana_base + ANA_CPHY_TOP_PORT3_OFFSET;
+
+	ctx->reg_if_top = if_base;
+
+	for (i = SENINF_1; i < _seninf_cfg.seninf_num; i++) {
+		ctx->reg_if_ctrl[i]  = if_base + IF_CTRL_BASE_OFFSET  + (IF_PORT_STRIDE * i);
+		ctx->reg_if_tg[i]    = if_base + IF_TG_BASE_OFFSET    + (IF_PORT_STRIDE * i);
+		ctx->reg_if_csi2[i]  = if_base + IF_CSI2_BASE_OFFSET  + (IF_PORT_STRIDE * i);
+	}
+
+	for (i = SENINF_MUX1; i < _seninf_cfg.mux_num; i++)
+		ctx->reg_if_mux[i] = if_base + IF_MUX_BASE_OFFSET + (IF_PORT_STRIDE * i);
+
+	ctx->reg_if_cam_mux = if_base + IF_CAM_MUX_OFFSET;
+
+	return 0;
+}
+int mtk_cam_seninf_init_port(struct seninf_ctx *ctx, int port)
+{
+	u32 port_num;
+
+	port_num = get_port_num(port);
+
+	ctx->port = port;
+	ctx->port_num = port_num;
+	ctx->port_a = CSI_PORT_0A + (port_num << 1);
+	ctx->port_b = ctx->port_a + 1;
+	ctx->is_4d1c = (port == port_num);
+
+	ctx->seninf_idx = seninf_csi[port];
+
+	return 0;
+}
+
+int mtk_cam_seninf_is_cammux_used(struct seninf_ctx *ctx, int cam_mux)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+	u32 temp = readl(seninf_cam_mux + SENINF_CAM_MUX_EN);
+
+	return !!(temp & (1 << cam_mux));
+}
+
+int mtk_cam_seninf_cammux(struct seninf_ctx *ctx, int cam_mux)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+	u32 temp;
+
+	temp = readl(seninf_cam_mux + SENINF_CAM_MUX_EN);
+	SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_EN,
+			 temp | BIT(cam_mux));
+
+	SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_IRQ_STATUS,
+			 3 << (cam_mux * 2)); /* clr irq */
+
+	dev_dbg(ctx->dev, "cam_mux %d EN 0x%x IRQ_EN 0x%x IRQ_STATUS 0x%x\n",
+		cam_mux, readl(seninf_cam_mux + SENINF_CAM_MUX_EN),
+		readl(seninf_cam_mux + SENINF_CAM_MUX_IRQ_EN),
+		readl(seninf_cam_mux + SENINF_CAM_MUX_IRQ_STATUS));
+
+	return 0;
+}
+
+int mtk_cam_seninf_disable_cammux(struct seninf_ctx *ctx, int cam_mux)
+{
+	void __iomem *base = ctx->reg_if_cam_mux;
+	u32 temp;
+
+	temp = readl(base + SENINF_CAM_MUX_EN);
+
+	if ((1 << cam_mux) & temp) {
+		SENINF_WRITE_REG(base, SENINF_CAM_MUX_EN,
+				 temp & (~(1 << cam_mux)));
+
+		dev_dbg(ctx->dev, "cammux %d EN %x IRQ_EN %x IRQ_STATUS %x",
+			cam_mux, readl(base + SENINF_CAM_MUX_EN),
+			readl(base + SENINF_CAM_MUX_IRQ_EN),
+			readl(base + SENINF_CAM_MUX_IRQ_STATUS));
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_disable_all_cammux(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+
+	SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_EN, 0);
+
+	dev_dbg(ctx->dev, "%s all cam_mux EN 0x%x\n", __func__,
+		readl(seninf_cam_mux + SENINF_CAM_MUX_EN));
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx,
+				    int seninf_src)
+{
+	void __iomem *seninf = ctx->reg_if_top;
+
+	switch (mux_idx) {
+	case SENINF_MUX1:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+			    RG_SENINF_MUX1_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX2:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+			    RG_SENINF_MUX2_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX3:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+			    RG_SENINF_MUX3_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX4:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+			    RG_SENINF_MUX4_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX5:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+			    RG_SENINF_MUX5_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX6:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+			    RG_SENINF_MUX6_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX7:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+			    RG_SENINF_MUX7_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX8:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+			    RG_SENINF_MUX8_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX9:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+			    RG_SENINF_MUX9_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX10:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+			    RG_SENINF_MUX10_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX11:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+			    RG_SENINF_MUX11_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX12:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+			    RG_SENINF_MUX12_SRC_SEL, seninf_src);
+		break;
+	case SENINF_MUX13:
+		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_3,
+			    RG_SENINF_MUX13_SRC_SEL, seninf_src);
+		break;
+	default:
+		dev_dbg(ctx->dev, "invalid mux_idx %d\n", mux_idx);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_get_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx)
+{
+	void __iomem *seninf = ctx->reg_if_top;
+	u32 seninf_src = 0;
+
+	switch (mux_idx) {
+	case SENINF_MUX1:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+					      RG_SENINF_MUX1_SRC_SEL);
+		break;
+	case SENINF_MUX2:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+					      RG_SENINF_MUX2_SRC_SEL);
+		break;
+	case SENINF_MUX3:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+					      RG_SENINF_MUX3_SRC_SEL);
+		break;
+	case SENINF_MUX4:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
+					      RG_SENINF_MUX4_SRC_SEL);
+		break;
+	case SENINF_MUX5:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+					      RG_SENINF_MUX5_SRC_SEL);
+		break;
+	case SENINF_MUX6:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+					      RG_SENINF_MUX6_SRC_SEL);
+		break;
+	case SENINF_MUX7:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+					      RG_SENINF_MUX7_SRC_SEL);
+		break;
+	case SENINF_MUX8:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
+					      RG_SENINF_MUX8_SRC_SEL);
+		break;
+	case SENINF_MUX9:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+					      RG_SENINF_MUX9_SRC_SEL);
+		break;
+	case SENINF_MUX10:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+					      RG_SENINF_MUX10_SRC_SEL);
+		break;
+	case SENINF_MUX11:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+					      RG_SENINF_MUX11_SRC_SEL);
+		break;
+	case SENINF_MUX12:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
+					      RG_SENINF_MUX12_SRC_SEL);
+		break;
+	case SENINF_MUX13:
+		seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_3,
+					      RG_SENINF_MUX13_SRC_SEL);
+		break;
+	default:
+		dev_dbg(ctx->dev, "invalid mux_idx %d", mux_idx);
+		return -EINVAL;
+	}
+
+	return seninf_src;
+}
+
+int mtk_cam_seninf_get_cammux_ctrl(struct seninf_ctx *ctx, int cam_mux)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+	u32 seninf_mux_src = 0;
+
+	switch (cam_mux) {
+	case SENINF_CAM_MUX0:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_0,
+						  RG_SENINF_CAM_MUX0_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX1:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_0,
+						  RG_SENINF_CAM_MUX1_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX2:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_0,
+						  RG_SENINF_CAM_MUX2_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX3:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_0,
+						  RG_SENINF_CAM_MUX3_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX4:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_1,
+						  RG_SENINF_CAM_MUX4_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX5:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_1,
+						  RG_SENINF_CAM_MUX5_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX6:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_1,
+						  RG_SENINF_CAM_MUX6_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX7:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_1,
+						  RG_SENINF_CAM_MUX7_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX8:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_2,
+						  RG_SENINF_CAM_MUX8_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX9:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_2,
+						  RG_SENINF_CAM_MUX9_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX10:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_2,
+						  RG_SENINF_CAM_MUX10_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX11:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_2,
+						  RG_SENINF_CAM_MUX11_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX12:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_3,
+						  RG_SENINF_CAM_MUX12_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX13:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_3,
+						  RG_SENINF_CAM_MUX13_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX14:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_3,
+						  RG_SENINF_CAM_MUX14_SRC_SEL);
+		break;
+	case SENINF_CAM_MUX15:
+		seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux,
+						  SENINF_CAM_MUX_CTRL_3,
+						  RG_SENINF_CAM_MUX15_SRC_SEL);
+		break;
+	default:
+		dev_dbg(ctx->dev, "invalid cam_mux %d", cam_mux);
+		return -EINVAL;
+	}
+
+	return seninf_mux_src;
+}
+
+u32 mtk_cam_seninf_get_cammux_res(struct seninf_ctx *ctx, int cam_mux)
+{
+	return readl(ctx->reg_if_cam_mux +
+			       SENINF_CAM_MUX0_CHK_RES + (0x10 * cam_mux));
+}
+
+int mtk_cam_seninf_set_cammux_vc(struct seninf_ctx *ctx, int cam_mux,
+				 int vc_sel, int dt_sel, int vc_en,
+				 int dt_en)
+{
+	void __iomem *seninf_cam_mux_vc_addr = ctx->reg_if_cam_mux + (cam_mux << 0x2);
+
+	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
+		    RG_SENINF_CAM_MUX0_VC_SEL, vc_sel);
+	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
+		    RG_SENINF_CAM_MUX0_DT_SEL, dt_sel);
+	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
+		    RG_SENINF_CAM_MUX0_VC_EN, vc_en);
+	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
+		    RG_SENINF_CAM_MUX0_DT_EN, dt_en);
+
+	return 0;
+}
+
+int mtk_cam_seninf_switch_to_cammux_inner_page(struct seninf_ctx *ctx,
+					       bool inner)
+{
+	void __iomem *seninf_cam_mux_addr = ctx->reg_if_cam_mux;
+
+	SENINF_BITS(seninf_cam_mux_addr, SENINF_CAM_MUX_DYN_CTRL,
+		    CAM_MUX_DYN_PAGE_SEL, inner ? 0 : 1);
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_cammux_next_ctrl(struct seninf_ctx *ctx, int src,
+					int target)
+{
+	void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux;
+
+	if (target >= _seninf_cfg.cam_mux_num) {
+		dev_dbg(ctx->dev,
+			"%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n",
+			__func__, target, _seninf_cfg.cam_mux_num);
+
+		return 0;
+	}
+
+	switch (target) {
+	case SENINF_CAM_MUX0:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0,
+			    CAM_MUX0_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX1:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0,
+			    CAM_MUX1_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX2:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0,
+			    CAM_MUX2_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX3:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0,
+			    CAM_MUX3_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX4:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1,
+			    CAM_MUX4_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX5:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1,
+			    CAM_MUX5_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX6:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1,
+			    CAM_MUX6_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX7:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1,
+			    CAM_MUX7_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX8:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2,
+			    CAM_MUX8_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX9:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2,
+			    CAM_MUX9_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX10:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2,
+			    CAM_MUX10_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX11:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2,
+			    CAM_MUX11_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX12:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3,
+			    CAM_MUX12_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX13:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3,
+			    CAM_MUX13_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX14:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3,
+			    CAM_MUX14_NEXT_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX15:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3,
+			    CAM_MUX15_NEXT_SRC_SEL, src);
+		break;
+	default:
+		dev_dbg(ctx->dev, "invalid src %d target %d", src, target);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_cammux_src(struct seninf_ctx *ctx, int src,
+                                  int target)
+{
+    void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux;
+
+    if (target < 0 || target >= _seninf_cfg.cam_mux_num) {
+        dev_dbg(ctx->dev,
+            "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n",
+            __func__, target, _seninf_cfg.cam_mux_num);
+        return 0;
+    }
+
+	switch (target) {
+	case SENINF_CAM_MUX0:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(0), RG_SENINF_CAM_MUX0_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX1:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(0), RG_SENINF_CAM_MUX1_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX2:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(0), RG_SENINF_CAM_MUX2_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX3:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(0), RG_SENINF_CAM_MUX3_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX4:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(1), RG_SENINF_CAM_MUX4_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX5:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(1), RG_SENINF_CAM_MUX5_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX6:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(1), RG_SENINF_CAM_MUX6_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX7:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(1), RG_SENINF_CAM_MUX7_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX8:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(2), RG_SENINF_CAM_MUX8_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX9:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(2), RG_SENINF_CAM_MUX9_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX10:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(2), RG_SENINF_CAM_MUX10_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX11:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(2), RG_SENINF_CAM_MUX11_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX12:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(3), RG_SENINF_CAM_MUX12_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX13:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(3), RG_SENINF_CAM_MUX13_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX14:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(3), RG_SENINF_CAM_MUX14_SRC_SEL, src);
+		break;
+	case SENINF_CAM_MUX15:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL(3), RG_SENINF_CAM_MUX15_SRC_SEL, src);
+		break;
+	default:
+		dev_dbg(ctx->dev, "%s: invalid target %d\n", __func__, target);
+		return -EINVAL;
+	}
+
+    SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CHK_CTL_1(target),
+                RG_SENINF_CAM_MUX_EXP_HSIZE, 0);
+    SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CHK_CTL_1(target),
+                RG_SENINF_CAM_MUX_EXP_VSIZE, 0);
+
+    return 0;
+}
+
+int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx,
+			  struct seninf_vcinfo *vcinfo)
+{
+	void __iomem *seninf_csi2 = ctx->reg_if_csi2[seninf_idx];
+	int i;
+	struct seninf_vc *vc;
+
+	if (WARN_ON(!vcinfo || !vcinfo->cnt))
+		return -EINVAL;
+
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S0_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S1_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S2_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S3_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S4_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S5_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S6_DI_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S7_DI_CTRL, 0);
+
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH0_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH1_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH2_CTRL, 0);
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH3_CTRL, 0);
+
+	for (i = 0; i < vcinfo->cnt; i++) {
+		vc = &vcinfo->vc[i];
+
+		/* General Long Packet Data Types: 0x10-0x17 */
+		if (vc->dt >= 0x10 && vc->dt <= 0x17) {
+			SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT,
+				    RG_CSI2_GENERIC_LONG_PACKET_EN, 1);
+		}
+
+		mtk_cam_seninf_set_di_ch_ctrl(seninf_csi2, i, vc);
+	}
+
+	dev_dbg(ctx->dev, "DI_CTRL 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+		readl(seninf_csi2 + SENINF_CSI2_S0_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S1_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S2_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S3_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S4_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S5_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S6_DI_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_S7_DI_CTRL));
+
+	dev_dbg(ctx->dev, "CH_CTRL 0x%x 0x%x 0x%x 0x%x\n",
+		readl(seninf_csi2 + SENINF_CSI2_CH0_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_CH1_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_CH2_CTRL),
+		readl(seninf_csi2 + SENINF_CSI2_CH3_CTRL));
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_mux_ctrl(struct seninf_ctx *ctx, u32 mux, int hs_pol,
+				int vs_pol, int src_sel, int pixel_mode)
+{
+	u32 temp = 0;
+	void __iomem *seninf_mux;
+
+	seninf_mux = ctx->reg_if_mux[mux];
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1,
+		    RG_SENINF_MUX_SRC_SEL, src_sel);
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1,
+		    RG_SENINF_MUX_PIX_MODE_SEL, pixel_mode);
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_OPT,
+		    RG_SENINF_MUX_HSYNC_POL, hs_pol);
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_OPT,
+		    RG_SENINF_MUX_VSYNC_POL, vs_pol);
+
+	temp = readl(seninf_mux + SENINF_MUX_CTRL_0);
+	SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp |
+			 SENINF_MUX_IRQ_SW_RST | SENINF_MUX_SW_RST);
+	SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp & 0xFFFFFFF9);
+
+	return 0;
+}
+
+int mtk_cam_seninf_update_mux_pixel_mode(struct seninf_ctx *ctx, u32 mux,
+					 int pixel_mode)
+{
+	u32 temp = 0;
+	void __iomem *seninf_mux;
+
+	seninf_mux = ctx->reg_if_mux[mux];
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1,
+		    RG_SENINF_MUX_PIX_MODE_SEL, pixel_mode);
+
+	temp = readl(seninf_mux + SENINF_MUX_CTRL_0);
+	SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp |
+			 SENINF_MUX_IRQ_SW_RST | SENINF_MUX_SW_RST);
+	SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp & 0xFFFFFFF9);
+
+	dev_dbg(ctx->dev,
+		"%s mux %d SENINF_MUX_CTRL_1(0x%x), SENINF_MUX_OPT(0x%x)",
+		__func__, mux, readl(seninf_mux + SENINF_MUX_CTRL_1),
+		readl(seninf_mux + SENINF_MUX_OPT));
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_mux_crop(struct seninf_ctx *ctx, u32 mux, int start_x,
+				int end_x, int enable)
+{
+	void __iomem *seninf_mux = ctx->reg_if_mux[mux];
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CROP_PIX_CTRL,
+		    RG_SENINF_MUX_CROP_START_8PIX_CNT, start_x / 8);
+	SENINF_BITS(seninf_mux, SENINF_MUX_CROP_PIX_CTRL,
+		    RG_SENINF_MUX_CROP_END_8PIX_CNT,
+		    start_x / 8 + (end_x - start_x + 1) / 8 - 1 +
+			    (((end_x - start_x + 1) % 8) > 0 ? 1 : 0));
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1,
+		    RG_SENINF_MUX_CROP_EN, enable);
+
+	dev_dbg(ctx->dev, "MUX_CROP_PIX_CTRL 0x%x MUX_CTRL_1 0x%x\n",
+		readl(seninf_mux + SENINF_MUX_CROP_PIX_CTRL),
+		readl(seninf_mux + SENINF_MUX_CTRL_1));
+
+	dev_dbg(ctx->dev, "mux %d, start %d, end %d, enable %d\n",
+		mux, start_x, end_x, enable);
+
+	return 0;
+}
+
+int mtk_cam_seninf_is_mux_used(struct seninf_ctx *ctx, u32 mux)
+{
+	void __iomem *seninf_mux = ctx->reg_if_mux[mux];
+
+	return SENINF_READ_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN);
+}
+
+int mtk_cam_seninf_mux(struct seninf_ctx *ctx, u32 mux)
+{
+	void __iomem *seninf_mux = ctx->reg_if_mux[mux];
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 1);
+	return 0;
+}
+
+int mtk_cam_seninf_disable_mux(struct seninf_ctx *ctx, u32 mux)
+{
+	int i;
+	void __iomem *seninf_mux = ctx->reg_if_mux[mux];
+
+	SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 0);
+
+	/* also disable CAM_MUX with input from mux */
+	for (i = SENINF_CAM_MUX0; i < _seninf_cfg.cam_mux_num; i++) {
+		if (mux == mtk_cam_seninf_get_cammux_ctrl(ctx, i))
+			mtk_cam_seninf_disable_cammux(ctx, i);
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_disable_all_mux(struct seninf_ctx *ctx)
+{
+	int i;
+	void __iomem *seninf_mux;
+
+	for (i = 0; i < _seninf_cfg.mux_num; i++) {
+		seninf_mux = ctx->reg_if_mux[i];
+		SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 0);
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_cammux_chk_pixel_mode(struct seninf_ctx *ctx,
+					     int cam_mux, int pixel_mode)
+{
+	void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux;
+
+	switch (cam_mux) {
+	case SENINF_CAM_MUX0:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX0_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX0_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX1:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX1_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX1_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX2:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX2_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX2_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX3:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX3_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX3_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX4:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX4_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX4_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX5:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX5_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX5_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX6:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX6_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX6_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX7:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX7_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX7_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX8:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX8_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX8_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX9:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX9_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX9_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX10:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX10_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX10_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX11:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX11_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX11_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX12:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX12_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX12_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX13:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX13_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX13_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX14:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX14_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX14_PIX_MODE_SEL, pixel_mode);
+		break;
+	case SENINF_CAM_MUX15:
+		SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX15_CHK_CTL_0,
+			    RG_SENINF_CAM_MUX15_PIX_MODE_SEL, pixel_mode);
+		break;
+	default:
+		dev_dbg(ctx->dev, "invalid cam_mux %d pixel_mode %d\n",
+			cam_mux, pixel_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void csirx_phy_a_power_off(struct seninf_ctx *ctx, u32 port_idx)
+{
+	void __iomem *base = ctx->reg_ana_csi_rx[port_idx];
+
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L0_T0AB_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L1_T1AB_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L2_T1BC_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0BC_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0CA_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T1CA_EQ_OS_CAL_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_LPF_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_CORE_EN, 0);
+
+	usleep_range(200, 300);
+}
+
+static int csirx_phy_a_power_on(struct seninf_ctx *ctx, u32 port_idx)
+{
+	void __iomem *base = ctx->reg_ana_csi_rx[port_idx];
+
+	/* Power off first to ensure a clean state */
+	csirx_phy_a_power_off(ctx, port_idx);
+
+	/* Power on sequence */
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_CORE_EN, 1);
+	usleep_range(10, 20);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_LPF_EN, 1);
+	usleep_range(10, 20);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L0_T0AB_EQ_OS_CAL_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L1_T1AB_EQ_OS_CAL_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L2_T1BC_EQ_OS_CAL_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0BC_EQ_OS_CAL_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0CA_EQ_OS_CAL_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T1CA_EQ_OS_CAL_EN, 1);
+
+	usleep_range(200, 300);
+
+	return 0;
+}
+
+static int apply_efuse_data(struct seninf_ctx *ctx)
+{
+	void __iomem *base;
+	u32 m_csi_efuse = ctx->m_csi_efuse;
+	u32 port;
+	int ret = 0;
+
+	if (m_csi_efuse == 0) {
+		dev_dbg(ctx->dev, "No efuse data. Returned.\n");
+		return -1;
+	}
+
+	port = ctx->port;
+	base = ctx->reg_ana_csi_rx[port];
+
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0P_T0A_HSRT_CODE,
+		    (m_csi_efuse >> 27) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0N_T0B_HSRT_CODE,
+		    (m_csi_efuse >> 27) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1P_T0C_HSRT_CODE,
+		    (m_csi_efuse >> 22) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1N_T1A_HSRT_CODE,
+		    (m_csi_efuse >> 22) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2P_T1B_HSRT_CODE,
+		    (m_csi_efuse >> 17) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2N_T1C_HSRT_CODE,
+		    (m_csi_efuse >> 17) & 0x1f);
+
+	dev_dbg(ctx->dev,
+		"CSI%dA CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x) CDPHY_RX_ANA_4(0x%x)",
+		ctx->port,
+		readl(base + CDPHY_RX_ANA_2),
+		readl(base + CDPHY_RX_ANA_3),
+		readl(base + CDPHY_RX_ANA_4));
+
+	if (ctx->is_4d1c == 0)
+		return ret;
+
+	port = ctx->port_b;
+	base = ctx->reg_ana_csi_rx[port];
+
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0P_T0A_HSRT_CODE,
+		    (m_csi_efuse >> 12) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0N_T0B_HSRT_CODE,
+		    (m_csi_efuse >> 12) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1P_T0C_HSRT_CODE,
+		    (m_csi_efuse >> 7) & 0x1f);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1N_T1A_HSRT_CODE,
+		    (m_csi_efuse >> 7) & 0x1f);
+
+	if (port < CSI_PORT_2A) {
+		SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2P_T1B_HSRT_CODE,
+			    (m_csi_efuse >> 2) & 0x1f);
+		SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2N_T1C_HSRT_CODE,
+			    (m_csi_efuse >> 2) & 0x1f);
+		
+		dev_dbg(ctx->dev,
+			"CSI%dB CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x) CDPHY_RX_ANA_4(0x%x)",
+			ctx->port,
+			readl(base + CDPHY_RX_ANA_2),
+			readl(base + CDPHY_RX_ANA_3),
+			readl(base + CDPHY_RX_ANA_4));
+	} else {
+		dev_dbg(ctx->dev,
+			"CSI%dB CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x)",
+			ctx->port,
+			readl(base + CDPHY_RX_ANA_2),
+			readl(base + CDPHY_RX_ANA_3));
+	}
+
+	return 0;
+}
+
+static void csirx_phy_a_setup_port(struct seninf_ctx *ctx, u32 port)
+{
+	void __iomem *base = ctx->reg_ana_csi_rx[port];
+
+	SENINF_BITS(base, CDPHY_RX_ANA_1, RG_CSI0_BG_LPRX_VTL_SEL, 0x4);
+	SENINF_BITS(base, CDPHY_RX_ANA_1, RG_CSI0_BG_LPRX_VTH_SEL, 0x4);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_BG_ALP_RX_VTL_SEL, 0x4);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_BG_ALP_RX_VTH_SEL, 0x4);
+	SENINF_BITS(base, CDPHY_RX_ANA_1, RG_CSI0_BG_VREF_SEL, 0x8);
+	SENINF_BITS(base, CDPHY_RX_ANA_1, RG_CSI0_CDPHY_EQ_DES_VREF_SEL, 0x2);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_9, RG_CSI0_RESERVE, 0x3003);
+	SENINF_BITS(base, CDPHY_RX_ANA_SETTING_0, CSR_CSI_RST_MODE, 0x2);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0P_T0A_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0N_T0B_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1P_T0C_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1N_T1A_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2P_T1B_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2N_T1C_HSRT_CODE, 0x10);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_CPHY_T0_CDR_FIRST_EDGE_EN, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_CPHY_T1_CDR_FIRST_EDGE_EN, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_CPHY_T0_CDR_SELF_CAL_EN, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_CPHY_T1_CDR_SELF_CAL_EN, 0x0);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_6, RG_CSI0_CPHY_T0_CDR_CK_DELAY, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_7, RG_CSI0_CPHY_T1_CDR_CK_DELAY, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_6, RG_CSI0_CPHY_T0_CDR_AB_WIDTH, 0x9);
+	SENINF_BITS(base, CDPHY_RX_ANA_6, RG_CSI0_CPHY_T0_CDR_BC_WIDTH, 0x9);
+	SENINF_BITS(base, CDPHY_RX_ANA_6, RG_CSI0_CPHY_T0_CDR_CA_WIDTH, 0x9);
+	SENINF_BITS(base, CDPHY_RX_ANA_7, RG_CSI0_CPHY_T1_CDR_AB_WIDTH, 0x9);
+	SENINF_BITS(base, CDPHY_RX_ANA_7, RG_CSI0_CPHY_T1_CDR_BC_WIDTH, 0x9);
+	SENINF_BITS(base, CDPHY_RX_ANA_7, RG_CSI0_CPHY_T1_CDR_CA_WIDTH, 0x9);
+
+	dev_dbg(ctx->dev, "port:%d CDPHY_RX_ANA_0(0x%x)\n",
+		port, SENINF_READ_REG(base, CDPHY_RX_ANA_0));
+}
+
+static int csirx_phyA_init(struct seninf_ctx *ctx)
+{
+	csirx_phy_a_setup_port(ctx, ctx->port);
+
+	if (ctx->is_4d1c)
+		csirx_phy_a_setup_port(ctx, ctx->port_b);
+
+	apply_efuse_data(ctx);
+
+	return 0;
+}
+
+static int csirx_dphy_init(struct seninf_ctx *ctx)
+{
+	void __iomem *base = ctx->reg_ana_dphy_top[ctx->port];
+	u8 bits_per_pixel;
+	int settle_delay_dt, settle_delay_ck, hs_trail, hs_trail_en;
+	u64 data_rate;
+
+	/* Settle delay parameters */
+	settle_delay_dt = ctx->is_cphy ? ctx->core->cphy_settle_delay_dt :
+					 ctx->core->dphy_settle_delay_dt;
+	settle_delay_ck = ctx->core->settle_delay_ck;
+
+	/* HS trail parameter */
+	hs_trail = ctx->hs_trail_parameter;
+
+	/* Settle delay for data lanes */
+	SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+		    RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER,
+		    settle_delay_dt);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+		    RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER,
+		    settle_delay_dt);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+		    RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER,
+		    settle_delay_dt);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+		    RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER,
+		    settle_delay_dt);
+
+	/* Settle delay for clock lanes */
+	SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER,
+		    RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER,
+		    settle_delay_ck);
+	SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER,
+		    RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER,
+		    settle_delay_ck);
+
+	/* HS prepare parameter for data lanes */
+	SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+		    RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_PARAMETER, 2);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+		    RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_PARAMETER, 2);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+		    RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_PARAMETER, 2);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+		    RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_PARAMETER, 2);
+
+	/* HS trail parameter for data lanes */
+	SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+		    RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, hs_trail);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+		    RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, hs_trail);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+		    RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, hs_trail);
+	SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+		    RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, hs_trail);
+
+	if (!ctx->is_cphy) {
+		bits_per_pixel = 10;
+
+		data_rate = ctx->customized_pixel_rate ?
+			    ctx->customized_pixel_rate : ctx->mipi_pixel_rate;
+		data_rate *= bits_per_pixel;
+		do_div(data_rate, ctx->num_data_lanes);
+
+		hs_trail_en = data_rate < 1400000000;
+
+		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+			    RG_DPHY_RX_LD0_HS_TRAIL_EN, hs_trail_en);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+			    RG_DPHY_RX_LD1_HS_TRAIL_EN, hs_trail_en);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+			    RG_DPHY_RX_LD2_HS_TRAIL_EN, hs_trail_en);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+			    RG_DPHY_RX_LD3_HS_TRAIL_EN, hs_trail_en);
+	}
+
+	return 0;
+}
+
+static int csirx_cphy_init(struct seninf_ctx *ctx)
+{
+	void __iomem *base = ctx->reg_ana_cphy_top[ctx->port];
+
+	SENINF_BITS(base, CPHY_RX_DETECT_CTRL_POST,
+		    RG_CPHY_RX_DATA_VALID_POST_EN, 1);
+
+	return 0;
+}
+
+static int csirx_phy_init(struct seninf_ctx *ctx)
+{
+	/* phyA init */
+	csirx_phyA_init(ctx);
+
+	/* phyD init */
+	csirx_dphy_init(ctx);
+	csirx_cphy_init(ctx);
+
+	return 0;
+}
+
+static int csirx_seninf_csi2_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf_csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
+	int csi_en;
+
+	SENINF_BITS(seninf_csi2, SENINF_CSI2_DBG_CTRL,
+		    RG_CSI2_DBG_PACKET_CNT_EN, 1);
+
+	/* lane/trio count */
+	SENINF_BITS(seninf_csi2, SENINF_CSI2_RESYNC_MERGE_CTRL,
+		    RG_CSI2_RESYNC_CYCLE_CNT_OPT, 1);
+
+	csi_en = BIT(ctx->num_data_lanes) - 1;
+
+	if (ctx->is_cphy) { /* cphy */
+		u8 map_hdr_len[] = { 0, 1, 2, 4, 5 };
+
+		SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, csi_en);
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT,
+				RG_CSI2_CPHY_SEL, 1);
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0,
+				RG_CSI2_HEADER_MODE, 2);
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0,
+				RG_CSI2_HEADER_LEN,
+				map_hdr_len[ctx->num_data_lanes]);
+	} else { /* dphy */
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT, RG_CSI2_CPHY_SEL, 0);
+		SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, csi_en);
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0,
+				RG_CSI2_HEADER_MODE, 0);
+		SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0,
+				RG_CSI2_HEADER_LEN, 0);
+	}
+
+	return 0;
+}
+
+static int csirx_seninf_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf = ctx->reg_if_ctrl[ctx->seninf_idx];
+
+	/* enable/disable seninf csi */
+	SENINF_BITS(seninf, SENINF_CSI_CTRL, RG_SENINF_CSI2_EN, 1);
+
+	/* enable/disable seninf, enable after csi2, testmdl is done */
+	SENINF_BITS(seninf, SENINF_CTRL, SENINF_EN, 1);
+
+	return 0;
+}
+
+static int csirx_seninf_top_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf_top = ctx->reg_if_top;
+
+	switch (ctx->port) {
+	case CSI_PORT_0:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+			    RG_PHY_SENINF_MUX0_CPHY_MODE, 0); //4T
+		break;
+	case CSI_PORT_0A:
+	case CSI_PORT_0B:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+			    RG_PHY_SENINF_MUX0_CPHY_MODE, 2); //2+2T
+		break;
+	case CSI_PORT_1:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+			    RG_PHY_SENINF_MUX1_CPHY_MODE, 0); //4T
+		break;
+	case CSI_PORT_1A:
+	case CSI_PORT_1B:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+			    RG_PHY_SENINF_MUX1_CPHY_MODE, 2); //2+2T
+		break;
+	case CSI_PORT_2:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+			    RG_PHY_SENINF_MUX2_CPHY_MODE, 0); //4T
+		break;
+	case CSI_PORT_2A:
+	case CSI_PORT_2B:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+			    RG_PHY_SENINF_MUX2_CPHY_MODE, 2); //2+2T
+		break;
+	case CSI_PORT_3:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+			    RG_PHY_SENINF_MUX3_CPHY_MODE, 0); //4T
+		break;
+	case CSI_PORT_3A:
+	case CSI_PORT_3B:
+		SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+			    RG_PHY_SENINF_MUX3_CPHY_MODE, 2); //2+2T
+		break;
+	default:
+		break;
+	}
+
+	/* port operation mode */
+	switch (ctx->port) {
+	case CSI_PORT_0:
+	case CSI_PORT_0A:
+	case CSI_PORT_0B:
+		if (ctx->is_cphy) {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+					PHY_SENINF_MUX0_DPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+					PHY_SENINF_MUX0_CPHY_EN, 1);
+		} else {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+					PHY_SENINF_MUX0_CPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0,
+					PHY_SENINF_MUX0_DPHY_EN, 1);
+		}
+		break;
+	case CSI_PORT_1:
+	case CSI_PORT_1A:
+	case CSI_PORT_1B:
+		if (ctx->is_cphy) {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+					PHY_SENINF_MUX1_DPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+					PHY_SENINF_MUX1_CPHY_EN, 1);
+		} else {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+					PHY_SENINF_MUX1_CPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1,
+					PHY_SENINF_MUX1_DPHY_EN, 1);
+		}
+		break;
+	case CSI_PORT_2:
+	case CSI_PORT_2A:
+	case CSI_PORT_2B:
+		if (ctx->is_cphy) {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+					PHY_SENINF_MUX2_DPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+					PHY_SENINF_MUX2_CPHY_EN, 1);
+		} else {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+					PHY_SENINF_MUX2_CPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2,
+					PHY_SENINF_MUX2_DPHY_EN, 1);
+		}
+		break;
+	case CSI_PORT_3:
+	case CSI_PORT_3A:
+	case CSI_PORT_3B:
+		if (ctx->is_cphy) {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+					PHY_SENINF_MUX3_DPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+					PHY_SENINF_MUX3_CPHY_EN, 1);
+		} else {
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+					PHY_SENINF_MUX3_CPHY_EN, 0);
+			SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3,
+					PHY_SENINF_MUX3_DPHY_EN, 1);
+		}
+		break;
+	default:
+		dev_err(ctx->dev, "Invalid CSI port: %d\n", ctx->port);
+    	return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void csirx_phyA_dphy_4d1c_setting(struct seninf_ctx *ctx, void __iomem *baseA, void __iomem *baseB)
+{
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 0);
+	/* clear clk sel first */
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 0);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 0);
+
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKSEL, 1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKSEL, 1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKSEL, 1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKSEL, 1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKSEL, 1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKSEL, 1);
+
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 0);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 0);
+
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+}
+
+static void csirx_phyA_dphy_setting(struct seninf_ctx *ctx, void __iomem *base)
+{
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 0);
+	/* clear clk sel first */
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 0);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKSEL, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKSEL, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKSEL, 0);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L0_CKMODE_EN, 0);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L1_CKMODE_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_DPHY_L2_CKMODE_EN, 0);
+
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+}
+
+static void csirx_phyA_cphy_4d1c_setting(struct seninf_ctx *ctx, void __iomem *baseA, void __iomem *baseB)
+{
+	SENINF_BITS(baseA, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 1);
+
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x0);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x3);
+	SENINF_BITS(baseA, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x0);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x3);
+	SENINF_BITS(baseB, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+}
+
+static void csirx_phyA_cphy_setting(struct seninf_ctx *ctx, void __iomem *base)
+{
+	SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_CPHY_EN, 1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_BW, 0x3);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_IS, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG0_EN, 0x1);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_DG1_EN, 0x0);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR0, 0x3);
+	SENINF_BITS(base, CDPHY_RX_ANA_5, RG_CSI0_CDPHY_EQ_SR1, 0x0);
+}
+
+static void csirx_phyA_power_on_wrapper(struct seninf_ctx *ctx)
+{
+	if (ctx->is_4d1c) {
+		csirx_phy_a_power_on(ctx, ctx->port_a);
+		csirx_phy_a_power_on(ctx, ctx->port_b);
+	} else {
+		csirx_phy_a_power_on(ctx, ctx->port);
+	}
+}
+
+static int csirx_phyA_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *base, *baseA, *baseB;
+
+	base = ctx->reg_ana_csi_rx[ctx->port];
+	baseA = ctx->reg_ana_csi_rx[ctx->port_a];
+	baseB = ctx->reg_ana_csi_rx[ctx->port_b];
+
+	if (!ctx->is_cphy) { /* dphy */
+		if (ctx->is_4d1c)
+			csirx_phyA_dphy_4d1c_setting(ctx, baseA, baseB);
+		else
+			csirx_phyA_dphy_setting(ctx, base);
+	} else { /* cphy */
+		if (ctx->is_4d1c)
+			csirx_phyA_cphy_4d1c_setting(ctx, baseA, baseB);
+		else
+			csirx_phyA_cphy_setting(ctx, base);
+	}
+
+	csirx_phyA_power_on_wrapper(ctx);
+
+	return 0;
+}
+
+static int csirx_dphy_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *base = ctx->reg_ana_dphy_top[ctx->port];
+
+	if (ctx->is_4d1c) {
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD3_SEL, 4);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD2_SEL, 0);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD1_SEL, 3);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD0_SEL, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC0_SEL, 2);
+
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD0_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD1_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD2_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD3_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC0_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC1_EN, 0);
+	} else {
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD3_SEL, 5);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD2_SEL, 3);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD1_SEL, 2);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD0_SEL, 0);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC1_SEL, 4);
+		SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC0_SEL, 1);
+
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD0_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD1_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD2_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD3_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC0_EN, 1);
+		SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC1_EN, 1);
+	}
+
+	SENINF_BITS(base, DPHY_RX_LANE_SELECT, DPHY_RX_CK_DATA_MUX_EN, 1);
+
+	return 0;
+}
+
+static int csirx_cphy_setting(struct seninf_ctx *ctx)
+{
+	void __iomem *base = ctx->reg_ana_cphy_top[ctx->port];
+
+	switch (ctx->port) {
+	case CSI_PORT_0:
+	case CSI_PORT_1:
+	case CSI_PORT_2:
+	case CSI_PORT_3:
+	case CSI_PORT_0A:
+	case CSI_PORT_1A:
+	case CSI_PORT_2A:
+	case CSI_PORT_3A:
+		if (ctx->num_data_lanes == 3) {
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1);
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR1_LPRX_EN, 1);
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1);
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR3_LPRX_EN, 0);
+		} else if (ctx->num_data_lanes == 2) {
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1);
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR1_LPRX_EN, 1);
+		} else {
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1);
+		}
+		break;
+	case CSI_PORT_0B:
+	case CSI_PORT_1B:
+	case CSI_PORT_2B:
+	case CSI_PORT_3B:
+		if (ctx->num_data_lanes == 2) {
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1);
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR3_LPRX_EN, 1);
+		} else {
+			SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int csirx_phy_setting(struct seninf_ctx *ctx)
+{
+	/* phyA */
+	csirx_phyA_setting(ctx);
+
+	if (ctx->is_cphy)
+		csirx_cphy_setting(ctx);
+	else
+		csirx_dphy_setting(ctx);
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_csi_mipi(struct seninf_ctx *ctx)
+{
+	csirx_phy_init(ctx);
+
+	/* seninf csi2 */
+	csirx_seninf_csi2_setting(ctx);
+
+	/* seninf */
+	csirx_seninf_setting(ctx);
+
+	/* seninf top */
+	csirx_seninf_top_setting(ctx);
+
+	/* phy */
+	csirx_phy_setting(ctx);
+
+	return 0;
+}
+
+int mtk_cam_seninf_poweroff(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf_csi2;
+
+	seninf_csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
+
+	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, 0x0);
+
+	if (ctx->is_4d1c) {
+		csirx_phy_a_power_off(ctx, ctx->port_a);
+		csirx_phy_a_power_off(ctx, ctx->port_b);
+	} else {
+		csirx_phy_a_power_off(ctx, ctx->port);
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_reset(struct seninf_ctx *ctx, u32 seninf_idx)
+{
+	int i;
+	void __iomem *seninf_mux;
+	void __iomem *seninf = ctx->reg_if_ctrl[seninf_idx];
+
+	SENINF_BITS(seninf, SENINF_CSI_CTRL, SENINF_CSI2_SW_RST, 1);
+	udelay(1);
+	SENINF_BITS(seninf, SENINF_CSI_CTRL, SENINF_CSI2_SW_RST, 0);
+
+	dev_dbg(ctx->dev, "reset seninf %d\n", seninf_idx);
+
+	for (i = SENINF_MUX1; i < _seninf_cfg.mux_num; i++)
+		if (mtk_cam_seninf_get_top_mux_ctrl(ctx, i) == seninf_idx &&
+		    mtk_cam_seninf_is_mux_used(ctx, i)) {
+			seninf_mux = ctx->reg_if_mux[i];
+			SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0,
+				    SENINF_MUX_SW_RST, 1);
+			udelay(1);
+			SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0,
+				    SENINF_MUX_SW_RST, 0);
+			dev_dbg(ctx->dev, "reset mux %d\n", i);
+		}
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_idle(struct seninf_ctx *ctx)
+{
+	int i;
+	struct seninf_vcinfo *vcinfo = &ctx->vcinfo;
+	struct seninf_vc *vc;
+
+	for (i = 0; i < vcinfo->cnt; i++) {
+		vc = &vcinfo->vc[i];
+		if (vc->enable) {
+			mtk_cam_seninf_disable_mux(ctx, vc->mux);
+			mtk_cam_seninf_disable_cammux(ctx, vc->cam);
+			ctx->pad2cam[vc->out_pad] = 0xff;
+		}
+	}
+
+	return 0;
+}
+
+int mtk_cam_seninf_irq_handler(int irq, void *data)
+{
+	struct seninf_core *core = (struct seninf_core *)data;
+	unsigned long flags; /* for mipi err detection */
+	struct seninf_ctx *ctx;
+	struct seninf_vc *vc;
+	void __iomem *csi2, *pmux, *seninf_cam_mux;
+	int i;
+	unsigned int csi_irq_ro;
+	unsigned int mux_irq_ro;
+	unsigned int cam_irq_exp_ro;
+	unsigned int cam_irq_res_ro;
+
+	spin_lock_irqsave(&core->spinlock_irq, flags);
+
+	/* debug for set_reg case: REG_KEY_CSI_IRQ_EN */
+	if (core->csi_irq_en_flag) {
+		list_for_each_entry(ctx, &core->list, list) {
+			csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
+			csi_irq_ro =
+				readl(csi2 + SENINF_CSI2_IRQ_STATUS);
+
+			if (csi_irq_ro) {
+				SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
+						 0xFFFFFFFF);
+			}
+
+			if (csi_irq_ro & RO_CSI2_ECC_ERR_CORRECTED_IRQ)
+				ctx->ecc_err_corrected_cnt++;
+			if (csi_irq_ro & RO_CSI2_ECC_ERR_DOUBLE_IRQ)
+				ctx->ecc_err_double_cnt++;
+			if (csi_irq_ro & RO_CSI2_CRC_ERR_IRQ)
+				ctx->crc_err_cnt++;
+			if (csi_irq_ro & RO_CSI2_ERR_LANE_RESYNC_IRQ)
+				ctx->err_lane_resync_cnt++;
+			if (csi_irq_ro & RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ)
+				ctx->data_not_enough_cnt++;
+
+			for (i = 0; i < ctx->vcinfo.cnt; i++) {
+				vc = &ctx->vcinfo.vc[i];
+				pmux = ctx->reg_if_mux[vc->mux];
+				seninf_cam_mux = ctx->reg_if_cam_mux;
+
+				mux_irq_ro = readl(pmux +
+							     SENINF_MUX_IRQ_STATUS);
+
+				cam_irq_exp_ro = readl(seninf_cam_mux +
+								 SENINF_CAM_MUX0_CHK_CTL_1 +
+								 (0x10 * (vc->cam)));
+
+				cam_irq_res_ro = readl(seninf_cam_mux +
+								 SENINF_CAM_MUX0_CHK_RES +
+								 (0x10 * (vc->cam)));
+
+				if (mux_irq_ro)
+					SENINF_WRITE_REG(pmux,
+							 SENINF_MUX_IRQ_STATUS,
+							 0xFFFFFFFF);
+
+				if (cam_irq_res_ro != cam_irq_exp_ro)
+					SENINF_WRITE_REG(seninf_cam_mux,
+							 SENINF_CAM_MUX0_CHK_RES +
+							 (0x10 * (vc->cam)),
+							 0xFFFFFFFF);
+
+				if (mux_irq_ro & (0x1 << 0))
+					ctx->fifo_overrun_cnt++;
+
+				if (cam_irq_res_ro != cam_irq_exp_ro)
+					ctx->size_err_cnt++;
+			}
+
+			/* dump status counter: debug for electrical signal */
+			if (ctx->data_not_enough_cnt >= core->detection_cnt ||
+			    ctx->err_lane_resync_cnt >= core->detection_cnt ||
+			    ctx->crc_err_cnt >= core->detection_cnt ||
+			    ctx->ecc_err_double_cnt >= core->detection_cnt ||
+			    ctx->ecc_err_corrected_cnt >= core->detection_cnt ||
+			    ctx->fifo_overrun_cnt >= core->detection_cnt ||
+			    ctx->size_err_cnt >= core->detection_cnt) {
+				/* disable all interrupts */
+				SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_EN, 0x80000000);
+
+				if (ctx->data_not_enough_cnt >= core->detection_cnt)
+					ctx->data_not_enough_flag = 1;
+				if (ctx->err_lane_resync_cnt >= core->detection_cnt)
+					ctx->err_lane_resync_flag = 1;
+				if (ctx->crc_err_cnt >= core->detection_cnt)
+					ctx->crc_err_flag = 1;
+				if (ctx->ecc_err_double_cnt >= core->detection_cnt)
+					ctx->ecc_err_double_flag = 1;
+				if (ctx->ecc_err_corrected_cnt >= core->detection_cnt)
+					ctx->ecc_err_corrected_flag = 1;
+				if (ctx->fifo_overrun_cnt >= core->detection_cnt)
+					ctx->fifo_overrun_flag = 1;
+				if (ctx->size_err_cnt >= core->detection_cnt)
+					ctx->size_err_flag = 1;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&core->spinlock_irq, flags);
+
+	return 0;
+}
+
+int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable, int index)
+{
+    void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+    unsigned int mask;
+
+    mask = index ? RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1 : RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0;
+
+    SENINF_BITS_VAR(seninf_cam_mux, SENINF_CAM_MUX_DYN_CTRL, mask, enable);
+
+    return 0;
+}
+
+int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+
+	if (index == 0)
+		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
+			    RG_SENINF_CAM_MUX_DYN_SWITCH_EN0, 0);
+	else
+		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
+			    RG_SENINF_CAM_MUX_DYN_SWITCH_EN1, 0);
+	return 0;
+}
+
+int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable,
+					  int index)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+
+	if (index == 0)
+		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
+			    RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN, enable);
+	else
+		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
+			    RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN, enable);
+	return 0;
+}
+
+int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable,
+					    int cam_mux)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+	int tmp = 0;
+
+	tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
+			       RG_SENINF_CAM_MUX_VSYNC_IRQ_EN);
+	if (enable)
+		tmp |= (enable << cam_mux);
+	else
+		tmp &= ~(enable << cam_mux);
+	SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
+		    RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, tmp);
+	return 0;
+}
+
+int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx)
+{
+	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
+
+	SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
+		    RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, 0);
+	return 0;
+}
+
+int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val)
+{
+	int i;
+	void __iomem *base = ctx->reg_ana_dphy_top[ctx->port];
+	void __iomem *csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
+	void __iomem *pmux, *pcammux;
+	struct seninf_vc *vc;
+	struct seninf_core *core;
+	struct seninf_ctx *ctx_;
+	void __iomem *csi2_;
+
+	core = dev_get_drvdata(ctx->dev->parent);
+
+	if (!ctx->streaming)
+		return 0;
+
+	dev_dbg(ctx->dev, "%s key = 0x%x, val = 0x%x\n", __func__, key, val);
+
+	switch (key) {
+	case REG_KEY_SETTLE_CK:
+		SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER,
+			    RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER,
+			    RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER, val);
+		break;
+	case REG_KEY_SETTLE_DT:
+		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+			    RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+			    RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+			    RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+			    RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER, val);
+		break;
+	case REG_KEY_HS_TRAIL_EN:
+		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+			    RG_DPHY_RX_LD0_HS_TRAIL_EN, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+			    RG_DPHY_RX_LD1_HS_TRAIL_EN, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+			    RG_DPHY_RX_LD2_HS_TRAIL_EN, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+			    RG_DPHY_RX_LD3_HS_TRAIL_EN, val);
+		break;
+	case REG_KEY_HS_TRAIL_PARAM:
+		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
+			    RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
+			    RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
+			    RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, val);
+		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
+			    RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, val);
+		break;
+	case REG_KEY_CSI_IRQ_STAT:
+		SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
+				 val & 0xFFFFFFFF);
+		break;
+	case REG_KEY_MUX_IRQ_STAT:
+		for (i = 0; i < ctx->vcinfo.cnt; i++) {
+			vc = &ctx->vcinfo.vc[i];
+			pmux = ctx->reg_if_mux[vc->mux];
+			SENINF_WRITE_REG(pmux, SENINF_MUX_IRQ_STATUS,
+					 val & 0xFFFFFFFF);
+		}
+		break;
+	case REG_KEY_CAMMUX_IRQ_STAT:
+		for (i = 0; i < ctx->vcinfo.cnt; i++) {
+			vc = &ctx->vcinfo.vc[i];
+			pcammux = ctx->reg_if_cam_mux;
+			SENINF_WRITE_REG(pcammux, SENINF_CAM_MUX_IRQ_STATUS,
+					 val & 0xFFFFFFFF);
+		}
+		break;
+	case REG_KEY_CSI_IRQ_EN:
+		{
+			if (!val) {
+				core->csi_irq_en_flag = 0;
+				return 0;
+			}
+
+			core->csi_irq_en_flag = 1;
+			core->detection_cnt = val;
+			list_for_each_entry(ctx_, &core->list, list) {
+				csi2_ = ctx_->reg_if_csi2[ctx_->seninf_idx];
+				SENINF_WRITE_REG(csi2_, SENINF_CSI2_IRQ_EN,
+						 0xA0002058);
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
new file mode 100755
index 000000000000..e4e28c0ef85b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MIPI_RX_ANA_CDPHY_CSI0A_H__
+#define __MIPI_RX_ANA_CDPHY_CSI0A_H__
+
+#include <linux/bitfield.h>
+
+// CDPHY_RX_ANA_0
+#define CDPHY_RX_ANA_0 0x0000
+#define RG_CSI0_BG_CORE_EN                GENMASK(0, 0)
+#define RG_CSI0_BG_LPF_EN                 GENMASK(1, 1)
+#define RG_CSI0_EQ_PROTECT_EN             GENMASK(4, 4)
+#define RG_CSI0_BYTE_CK_RSTB_SEL          GENMASK(5, 5)
+#define RG_CSI0_DPHY_L0_CKSEL             GENMASK(8, 8)
+#define RG_CSI0_DPHY_L1_CKSEL             GENMASK(9, 9)
+#define RG_CSI0_DPHY_L2_CKSEL             GENMASK(10, 10)
+#define RG_CSI0_DPHY_L0_CKMODE_EN         GENMASK(12, 12)
+#define RG_CSI0_DPHY_L1_CKMODE_EN         GENMASK(13, 13)
+#define RG_CSI0_DPHY_L2_CKMODE_EN         GENMASK(14, 14)
+#define RG_CSI0_CDPHY_L0_T0_BYTECK_INVERT GENMASK(16, 16)
+#define RG_CSI0_DPHY_L1_BYTECK_INVERT     GENMASK(17, 17)
+#define RG_CSI0_CDPHY_L2_T1_BYTECK_INVERT GENMASK(18, 18)
+#define RG_CSI0_CPHY_EN                   GENMASK(20, 20)
+#define RG_CSI0_CPHY_T0_CDR_FIRST_EDGE_EN GENMASK(21, 21)
+#define RG_CSI0_CPHY_T1_CDR_FIRST_EDGE_EN GENMASK(22, 22)
+#define RG_CSI0_CDPHY_L0_T0_FORCE_INIT    GENMASK(24, 24)
+#define RG_CSI0_DPHY_L1_FORCE_INIT        GENMASK(25, 25)
+#define RG_CSI0_CDPHY_L2_T1_FORCE_INIT    GENMASK(26, 26)
+#define RG_CSI0_CDPHY_L0_T0_SYNC_INIT_CTRL GENMASK(28, 28)
+#define RG_CSI0_DPHY_L1_SYNC_INIT_CTRL    GENMASK(29, 29)
+#define RG_CSI0_CDPHY_L2_T1_SYNC_INIT_CTRL GENMASK(30, 30)
+#define RG_CSI0_FORCE_HSRT_EN             GENMASK(31, 31)
+
+// CDPHY_RX_ANA_1
+#define CDPHY_RX_ANA_1 0x0004
+#define RG_CSI0_BG_LPRX_VTL_SEL           GENMASK(2, 0)
+#define RG_CSI0_BG_LPRX_VTH_SEL           GENMASK(6, 4)
+#define RG_CSI0_BG_VREF_SEL               GENMASK(11, 8)
+#define RG_CSI0_CDPHY_DELAYCAL_CK_SEL     GENMASK(14, 12)
+#define RG_CSI0_CDPHY_EQ_DES_VREF_SEL     GENMASK(18, 16)
+#define RG_CSI0_CDPHY_DELAY_VREF_SEL      GENMASK(22, 20)
+#define RG_CSI0_DPHY_L0_DELAYCAL_EN       GENMASK(24, 24)
+#define RG_CSI0_DPHY_L1_DELAYCAL_EN       GENMASK(25, 25)
+#define RG_CSI0_DPHY_L2_DELAYCAL_EN       GENMASK(26, 26)
+#define RG_CSI0_DPHY_L0_DELAYCAL_RSTB     GENMASK(28, 28)
+#define RG_CSI0_DPHY_L1_DELAYCAL_RSTB     GENMASK(29, 29)
+#define RG_CSI0_DPHY_L2_DELAYCAL_RSTB     GENMASK(30, 30)
+
+// CDPHY_RX_ANA_2
+#define CDPHY_RX_ANA_2 0x0008
+#define RG_CSI0_L0P_T0A_HSRT_CODE         GENMASK(4, 0)
+#define RG_CSI0_L0N_T0B_HSRT_CODE         GENMASK(12, 8)
+#define RG_CSI0_CPHY_T0_CDR_SELF_CAL_EN   GENMASK(16, 16)
+#define RG_CSI0_CPHY_T1_CDR_SELF_CAL_EN   GENMASK(17, 17)
+#define RG_CSI0_BG_ALP_RX_VTH_SEL         GENMASK(26, 24)
+#define RG_CSI0_BG_ALP_RX_VTL_SEL         GENMASK(30, 28)
+
+// CDPHY_RX_ANA_3
+#define CDPHY_RX_ANA_3 0x000c
+#define RG_CSI0_L1P_T0C_HSRT_CODE         GENMASK(4, 0)
+#define RG_CSI0_L1N_T1A_HSRT_CODE         GENMASK(12, 8)
+#define RG_CSI0_OS_CAL_CNT_SEL            GENMASK(17, 16)
+#define RG_CSI0_EQ_DES_VREF_SEL           GENMASK(25, 20)
+
+// CDPHY_RX_ANA_4
+#define CDPHY_RX_ANA_4 0x0010
+#define RG_CSI0_L2P_T1B_HSRT_CODE         GENMASK(4, 0)
+#define RG_CSI0_L2N_T1C_HSRT_CODE         GENMASK(12, 8)
+
+// CDPHY_RX_ANA_5
+#define CDPHY_RX_ANA_5 0x0014
+#define RG_CSI0_CDPHY_EQ_BW               GENMASK(1, 0)
+#define RG_CSI0_CDPHY_EQ_IS               GENMASK(3, 2)
+#define RG_CSI0_CDPHY_EQ_DG0_EN           GENMASK(4, 4)
+#define RG_CSI0_CDPHY_EQ_DG1_EN           GENMASK(5, 5)
+#define RG_CSI0_CDPHY_EQ_LATCH_EN         GENMASK(6, 6)
+#define RG_CSI0_CDPHY_EQ_SR0              GENMASK(11, 8)
+#define RG_CSI0_CDPHY_EQ_SR1              GENMASK(15, 12)
+#define RG_CSI0_L0_T0AB_EQ_MON_EN         GENMASK(16, 16)
+#define RG_CSI0_L1_T1AB_EQ_MON_EN         GENMASK(17, 17)
+#define RG_CSI0_L2_T1BC_EQ_MON_EN         GENMASK(18, 18)
+#define RG_CSI0_XX_T0BC_EQ_MON_EN         GENMASK(24, 24)
+#define RG_CSI0_XX_T0CA_EQ_MON_EN         GENMASK(25, 25)
+#define RG_CSI0_XX_T1CA_EQ_MON_EN         GENMASK(26, 26)
+
+// CDPHY_RX_ANA_6
+#define CDPHY_RX_ANA_6 0x0018
+#define RG_CSI0_CPHY_T0_CDR_AB_WIDTH      GENMASK(5, 0)
+#define RG_CSI0_CPHY_T0_CDR_BC_WIDTH      GENMASK(13, 8)
+#define RG_CSI0_CPHY_T0_CDR_CA_WIDTH      GENMASK(21, 16)
+#define RG_CSI0_CPHY_T0_CDR_CK_DELAY      GENMASK(29, 24)
+
+// CDPHY_RX_ANA_7
+#define CDPHY_RX_ANA_7 0x001c
+#define RG_CSI0_CPHY_T1_CDR_AB_WIDTH      GENMASK(5, 0)
+#define RG_CSI0_CPHY_T1_CDR_BC_WIDTH      GENMASK(13, 8)
+#define RG_CSI0_CPHY_T1_CDR_CA_WIDTH      GENMASK(21, 16)
+#define RG_CSI0_CPHY_T1_CDR_CK_DELAY      GENMASK(29, 24)
+
+// CDPHY_RX_ANA_8
+#define CDPHY_RX_ANA_8 0x0020
+#define RGS_CSI0_CDPHY_L0_T0AB_OS_CAL_CPLT GENMASK(0, 0)
+#define RGS_CSI0_CDPHY_L1_T1AB_OS_CAL_CPLT GENMASK(1, 1)
+#define RGS_CSI0_CDPHY_L2_T1BC_OS_CAL_CPLT GENMASK(2, 2)
+#define RGS_CSI0_CPHY_T0BC_OS_CAL_CPLT     GENMASK(3, 3)
+#define RGS_CSI0_CPHY_T0CA_OS_CAL_CPLT     GENMASK(4, 4)
+#define RGS_CSI0_CPHY_T1CA_OS_CAL_CPLT     GENMASK(5, 5)
+#define RGS_CSI0_OS_CAL_CODE               GENMASK(15, 8)
+#define RG_CSI0_L0_T0AB_EQ_OS_CAL_EN       GENMASK(16, 16)
+#define RG_CSI0_L1_T1AB_EQ_OS_CAL_EN       GENMASK(17, 17)
+#define RG_CSI0_L2_T1BC_EQ_OS_CAL_EN       GENMASK(18, 18)
+#define RG_CSI0_XX_T0BC_EQ_OS_CAL_EN       GENMASK(19, 19)
+#define RG_CSI0_XX_T0CA_EQ_OS_CAL_EN       GENMASK(20, 20)
+#define RG_CSI0_XX_T1CA_EQ_OS_CAL_EN       GENMASK(21, 21)
+#define RG_CSI0_OS_CAL_SEL                 GENMASK(26, 24)
+#define RG_CSI0_OS_CAL_DIV                 GENMASK(30, 28)
+
+// CDPHY_RX_ANA_9
+#define CDPHY_RX_ANA_9 0x0024
+#define RGS_CSI0_CPHY_T0_DLL_CODE          GENMASK(3, 0)
+#define RGS_CSI0_CPHY_T0_MASK_CAL_CPLT     GENMASK(4, 4)
+#define RGS_CSI0_CPHY_T0_MASK_CAL_OF       GENMASK(5, 5)
+#define RGS_CSI0_CPHY_T1_DLL_CODE          GENMASK(11, 8)
+#define RGS_CSI0_CPHY_T1_MASK_CAL_CPLT     GENMASK(12, 12)
+#define RGS_CSI0_CPHY_T1_MASK_CAL_OF       GENMASK(13, 13)
+#define RG_CSI0_RESERVE                    GENMASK(31, 16)
+
+// CDPHY_RX_ANA_AD_0
+#define CDPHY_RX_ANA_AD_0 0x0048
+#define RO_AD_CSI0_CDPHY_L0P_T0A_LPRX_OUT GENMASK(0, 0)
+#define RO_AD_CSI0_CDPHY_L0N_T0B_LPRX_OUT GENMASK(1, 1)
+#define RO_AD_CSI0_CDPHY_L1P_T0C_LPRX_OUT GENMASK(4, 4)
+#define RO_AD_CSI0_CDPHY_L1N_T1A_LPRX_OUT GENMASK(5, 5)
+#define RO_AD_CSI0_CDPHY_L2P_T1B_LPRX_OUT GENMASK(8, 8)
+#define RO_AD_CSI0_CDPHY_L2N_T1C_LPRX_OUT GENMASK(9, 9)
+
+// CDPHY_RX_ANA_AD_HS_0
+#define CDPHY_RX_ANA_AD_HS_0 0x00a0
+#define RO_AD_CSI0_CPHY_T0CA         GENMASK(7, 0)
+#define RO_AD_CSI0_CPHY_T0BC         GENMASK(15, 8)
+#define RO_AD_CSI0_CDPHY_L0_T0AB     GENMASK(23, 16)
+
+// CDPHY_RX_ANA_AD_HS_1
+#define CDPHY_RX_ANA_AD_HS_1 0x00a4
+#define RO_AD_CSI0_DPHY_L1           GENMASK(23, 16)
+
+// CDPHY_RX_ANA_AD_HS_2
+#define CDPHY_RX_ANA_AD_HS_2 0x00a8
+#define RO_AD_CSI0_CPHY_T1CA         GENMASK(15, 8)
+#define RO_AD_CSI0_CDPHY_L2_T1BC     GENMASK(23, 16)
+#define RO_AD_CSI0_CPHY_T1AB         GENMASK(31, 24)
+
+// CDPHY_RX_ANA_SETTING_0
+#define CDPHY_RX_ANA_SETTING_0 0x00f0
+#define CSR_CSI_CLK_MON              GENMASK(0, 0)
+#define CSR_CSI_CLK_EN               GENMASK(1, 1)
+#define CSR_ASYNC_FIFO_GATING_SEL    GENMASK(7, 4)
+#define CSR_CSI_MON_MUX              GENMASK(15, 8)
+#define CSR_CSI_RST_MODE             GENMASK(17, 16)
+#define CSR_SW_RST                   GENMASK(27, 24)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
new file mode 100755
index 000000000000..08586e426469
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#include <linux/bitfield.h>
+
+#ifndef __SENINF1_CSI2_H__
+#define __SENINF1_CSI2_H__
+
+// SENINF_CSI2_EN
+#define SENINF_CSI2_EN 0x0000
+#define CSI2_LANE0_EN GENMASK(0, 0)
+#define CSI2_LANE1_EN GENMASK(1, 1)
+#define CSI2_LANE2_EN GENMASK(2, 2)
+#define CSI2_LANE3_EN GENMASK(3, 3)
+
+// SENINF_CSI2_OPT
+#define SENINF_CSI2_OPT 0x0004
+#define RG_CSI2_CPHY_SEL GENMASK(0, 0)
+#define RG_CSI2_ECC_EN GENMASK(1, 1)
+#define RG_CSI2_B2P_EN GENMASK(2, 2)
+#define RG_CSI2_GENERIC_LONG_PACKET_EN GENMASK(3, 3)
+#define RG_CSI2_IMG_PACKET_EN GENMASK(4, 4)
+#define RG_CSI2_SPEC_V2P0_SEL GENMASK(5, 5)
+#define RG_CSI2_DESCRAMBLE_EN GENMASK(6, 6)
+#define RG_CSI2_VS_OUTPUT_MODE GENMASK(8, 8)
+#define RG_CSI2_VS_OUTPUT_LEN_SEL GENMASK(9, 9)
+#define RG_CSI2_HSYNC_POL GENMASK(12, 12)
+#define RG_CSI2_VSYNC_POL GENMASK(13, 13)
+#define RG_CSI2_FIFO_PUSH_EN GENMASK(21, 16)
+
+// SENINF_CSI2_HDR_MODE_0
+#define SENINF_CSI2_HDR_MODE_0 0x0008
+#define RG_CSI2_HEADER_MODE GENMASK(7, 0)
+#define RG_CSI2_HEADER_LEN GENMASK(10, 8)
+
+// SENINF_CSI2_RESYNC_MERGE_CTRL
+#define SENINF_CSI2_RESYNC_MERGE_CTRL 0x0010
+#define RG_CSI2_RESYNC_CYCLE_CNT GENMASK(4, 0)
+#define RG_CSI2_RESYNC_CYCLE_CNT_OPT GENMASK(8, 8)
+#define RG_CSI2_RESYNC_DATAOUT_OPT GENMASK(9, 9)
+#define RG_CSI2_RESYNC_BYPASS GENMASK(10, 10)
+
+// common VC/DT
+#define RG_CSI2_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S0_DI_CTRL
+#define SENINF_CSI2_S0_DI_CTRL 0x0020
+#define RG_CSI2_S0_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S0_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S0_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S0_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S1_DI_CTRL
+#define SENINF_CSI2_S1_DI_CTRL 0x0024
+#define RG_CSI2_S1_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S1_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S1_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S1_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S2_DI_CTRL
+#define SENINF_CSI2_S2_DI_CTRL 0x0028
+#define RG_CSI2_S2_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S2_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S2_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S2_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S3_DI_CTRL
+#define SENINF_CSI2_S3_DI_CTRL 0x002c
+#define RG_CSI2_S3_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S3_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S3_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S3_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S4_DI_CTRL
+#define SENINF_CSI2_S4_DI_CTRL 0x0030
+#define RG_CSI2_S4_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S4_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S4_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S4_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S5_DI_CTRL
+#define SENINF_CSI2_S5_DI_CTRL 0x0034
+#define RG_CSI2_S5_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S5_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S5_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S5_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S6_DI_CTRL
+#define SENINF_CSI2_S6_DI_CTRL 0x0038
+#define RG_CSI2_S6_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S6_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S6_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S6_DT_SEL GENMASK(21, 16)
+
+// SENINF_CSI2_S7_DI_CTRL
+#define SENINF_CSI2_S7_DI_CTRL 0x003c
+#define RG_CSI2_S7_VC_INTERLEAVE_EN GENMASK(0, 0)
+#define RG_CSI2_S7_DT_INTERLEAVE_MODE GENMASK(5, 4)
+#define RG_CSI2_S7_VC_SEL GENMASK(12, 8)
+#define RG_CSI2_S7_DT_SEL GENMASK(21, 16)
+
+// CSI2 group mode/VSYNC bypass/GRP EN
+#define RG_CSI2_GRP_MODE GENMASK(0, 0)
+#define RG_CSI2_VSYNC_BYPASS GENMASK(1, 1)
+#define RG_CSI2_S0_GRP_EN GENMASK(8, 8)
+#define RG_CSI2_S1_GRP_EN GENMASK(9, 9)
+#define RG_CSI2_S2_GRP_EN GENMASK(10, 10)
+#define RG_CSI2_S3_GRP_EN GENMASK(11, 11)
+#define RG_CSI2_S4_GRP_EN GENMASK(12, 12)
+#define RG_CSI2_S5_GRP_EN GENMASK(13, 13)
+#define RG_CSI2_S6_GRP_EN GENMASK(14, 14)
+#define RG_CSI2_S7_GRP_EN GENMASK(15, 15)
+
+// SENINF_CSI2_CH0_CTRL
+#define SENINF_CSI2_CH0_CTRL 0x0060
+#define RG_CSI2_CH0_GRP_MODE GENMASK(0, 0)
+#define RG_CSI2_CH0_VSYNC_BYPASS GENMASK(1, 1)
+#define RG_CSI2_CH0_S0_GRP_EN GENMASK(8, 8)
+#define RG_CSI2_CH0_S1_GRP_EN GENMASK(9, 9)
+#define RG_CSI2_CH0_S2_GRP_EN GENMASK(10, 10)
+#define RG_CSI2_CH0_S3_GRP_EN GENMASK(11, 11)
+#define RG_CSI2_CH0_S4_GRP_EN GENMASK(12, 12)
+#define RG_CSI2_CH0_S5_GRP_EN GENMASK(13, 13)
+#define RG_CSI2_CH0_S6_GRP_EN GENMASK(14, 14)
+#define RG_CSI2_CH0_S7_GRP_EN GENMASK(15, 15)
+
+
+// SENINF_CSI2_CH1_CTRL
+#define SENINF_CSI2_CH1_CTRL 0x0064
+#define RG_CSI2_CH1_GRP_MODE      GENMASK(0, 0)
+#define RG_CSI2_CH1_VSYNC_BYPASS  GENMASK(1, 1)
+#define RG_CSI2_CH1_S0_GRP_EN     GENMASK(8, 8)
+#define RG_CSI2_CH1_S1_GRP_EN     GENMASK(9, 9)
+#define RG_CSI2_CH1_S2_GRP_EN     GENMASK(10, 10)
+#define RG_CSI2_CH1_S3_GRP_EN     GENMASK(11, 11)
+#define RG_CSI2_CH1_S4_GRP_EN     GENMASK(12, 12)
+#define RG_CSI2_CH1_S5_GRP_EN     GENMASK(13, 13)
+#define RG_CSI2_CH1_S6_GRP_EN     GENMASK(14, 14)
+#define RG_CSI2_CH1_S7_GRP_EN     GENMASK(15, 15)
+
+// SENINF_CSI2_CH2_CTRL
+#define SENINF_CSI2_CH2_CTRL 0x0068
+#define RG_CSI2_CH2_GRP_MODE      GENMASK(0, 0)
+#define RG_CSI2_CH2_VSYNC_BYPASS  GENMASK(1, 1)
+#define RG_CSI2_CH2_S0_GRP_EN     GENMASK(8, 8)
+#define RG_CSI2_CH2_S1_GRP_EN     GENMASK(9, 9)
+#define RG_CSI2_CH2_S2_GRP_EN     GENMASK(10, 10)
+#define RG_CSI2_CH2_S3_GRP_EN     GENMASK(11, 11)
+#define RG_CSI2_CH2_S4_GRP_EN     GENMASK(12, 12)
+#define RG_CSI2_CH2_S5_GRP_EN     GENMASK(13, 13)
+#define RG_CSI2_CH2_S6_GRP_EN     GENMASK(14, 14)
+#define RG_CSI2_CH2_S7_GRP_EN     GENMASK(15, 15)
+
+// SENINF_CSI2_CH3_CTRL
+#define SENINF_CSI2_CH3_CTRL 0x006c
+#define RG_CSI2_CH3_GRP_MODE      GENMASK(0, 0)
+#define RG_CSI2_CH3_VSYNC_BYPASS  GENMASK(1, 1)
+#define RG_CSI2_CH3_S0_GRP_EN     GENMASK(8, 8)
+#define RG_CSI2_CH3_S1_GRP_EN     GENMASK(9, 9)
+#define RG_CSI2_CH3_S2_GRP_EN     GENMASK(10, 10)
+#define RG_CSI2_CH3_S3_GRP_EN     GENMASK(11, 11)
+#define RG_CSI2_CH3_S4_GRP_EN     GENMASK(12, 12)
+#define RG_CSI2_CH3_S5_GRP_EN     GENMASK(13, 13)
+#define RG_CSI2_CH3_S6_GRP_EN     GENMASK(14, 14)
+#define RG_CSI2_CH3_S7_GRP_EN     GENMASK(15, 15)
+
+// SENINF_CSI2_IRQ_EN
+#define SENINF_CSI2_IRQ_EN 0x00c0
+#define RG_CSI2_ERR_FRAME_SYNC_IRQ_EN         GENMASK(0, 0)
+#define RG_CSI2_ERR_ID_IRQ_EN                 GENMASK(1, 1)
+#define RG_CSI2_ECC_ERR_UNDETECTED_IRQ_EN     GENMASK(2, 2)
+#define RG_CSI2_ECC_ERR_CORRECTED_IRQ_EN      GENMASK(3, 3)
+#define RG_CSI2_ECC_ERR_DOUBLE_IRQ_EN         GENMASK(4, 4)
+#define RG_CSI2_CRC_CORRECT_IRQ_EN            GENMASK(5, 5)
+#define RG_CSI2_CRC_ERR_IRQ_EN                GENMASK(6, 6)
+#define RG_CSI2_ERR_MULTI_LANE_SYNC_IRQ_EN    GENMASK(7, 7)
+#define RG_CSI2_FS_RECEIVE_IRQ_EN             GENMASK(8, 8)
+#define RG_CSI2_FE_RECEIVE_IRQ_EN             GENMASK(9, 9)
+#define RG_CSI2_LS_RECEIVE_IRQ_EN             GENMASK(10, 10)
+#define RG_CSI2_LE_RECEIVE_IRQ_EN             GENMASK(11, 11)
+#define RG_CSI2_GS_RECEIVE_IRQ_EN             GENMASK(12, 12)
+#define RG_CSI2_ERR_LANE_RESYNC_IRQ_EN        GENMASK(13, 13)
+#define RG_CSI2_LANE_MERGE_FIFO_AF_IRQ_EN     GENMASK(14, 14)
+#define RG_CSI2_ERR_FRAME_SYNC_S0_IRQ_EN      GENMASK(16, 16)
+#define RG_CSI2_ERR_FRAME_SYNC_S1_IRQ_EN      GENMASK(17, 17)
+#define RG_CSI2_ERR_FRAME_SYNC_S2_IRQ_EN      GENMASK(18, 18)
+#define RG_CSI2_ERR_FRAME_SYNC_S3_IRQ_EN      GENMASK(19, 19)
+#define RG_CSI2_ERR_FRAME_SYNC_S4_IRQ_EN      GENMASK(20, 20)
+#define RG_CSI2_ERR_FRAME_SYNC_S5_IRQ_EN      GENMASK(21, 21)
+#define RG_CSI2_ERR_FRAME_SYNC_S6_IRQ_EN      GENMASK(22, 22)
+#define RG_CSI2_ERR_FRAME_SYNC_S7_IRQ_EN      GENMASK(23, 23)
+#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ_EN GENMASK(24, 24)
+#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ_EN GENMASK(25, 25)
+#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ_EN GENMASK(26, 26)
+#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ_EN GENMASK(27, 27)
+#define RG_CSI2_ASYNC_FIFO_OVERRUN_IRQ_EN      GENMASK(28, 28)
+#define RG_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_EN GENMASK(29, 29)
+#define RG_CSI2_IRQ_CLR_MODE                   GENMASK(31, 31)
+
+// SENINF_CSI2_IRQ_STATUS
+#define SENINF_CSI2_IRQ_STATUS 0x00c8
+#define RO_CSI2_ERR_FRAME_SYNC_IRQ         GENMASK(0, 0)
+#define RO_CSI2_ERR_ID_IRQ                 GENMASK(1, 1)
+#define RO_CSI2_ECC_ERR_UNDETECTED_IRQ     GENMASK(2, 2)
+#define RO_CSI2_ECC_ERR_CORRECTED_IRQ      GENMASK(3, 3)
+#define RO_CSI2_ECC_ERR_DOUBLE_IRQ         GENMASK(4, 4)
+#define RO_CSI2_CRC_CORRECT_IRQ            GENMASK(5, 5)
+#define RO_CSI2_CRC_ERR_IRQ                GENMASK(6, 6)
+#define RO_CSI2_ERR_MULTI_LANE_SYNC_IRQ    GENMASK(7, 7)
+#define RO_CSI2_FS_RECEIVE_IRQ             GENMASK(8, 8)
+#define RO_CSI2_FE_RECEIVE_IRQ             GENMASK(9, 9)
+#define RO_CSI2_LS_RECEIVE_IRQ             GENMASK(10, 10)
+#define RO_CSI2_LE_RECEIVE_IRQ             GENMASK(11, 11)
+#define RO_CSI2_GS_RECEIVE_IRQ             GENMASK(12, 12)
+#define RO_CSI2_ERR_LANE_RESYNC_IRQ        GENMASK(13, 13)
+#define RO_CSI2_LANE_MERGE_FIFO_AF_IRQ     GENMASK(14, 14)
+#define RO_CSI2_ERR_FRAME_SYNC_S0_IRQ      GENMASK(16, 16)
+#define RO_CSI2_ERR_FRAME_SYNC_S1_IRQ      GENMASK(17, 17)
+#define RO_CSI2_ERR_FRAME_SYNC_S2_IRQ      GENMASK(18, 18)
+#define RO_CSI2_ERR_FRAME_SYNC_S3_IRQ      GENMASK(19, 19)
+#define RO_CSI2_ERR_FRAME_SYNC_S4_IRQ      GENMASK(20, 20)
+#define RO_CSI2_ERR_FRAME_SYNC_S5_IRQ      GENMASK(21, 21)
+#define RO_CSI2_ERR_FRAME_SYNC_S6_IRQ      GENMASK(22, 22)
+#define RO_CSI2_ERR_FRAME_SYNC_S7_IRQ      GENMASK(23, 23)
+#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ GENMASK(24, 24)
+#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ GENMASK(25, 25)
+#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ GENMASK(26, 26)
+#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ GENMASK(27, 27)
+#define RO_CSI2_ASYNC_FIFO_OVERRUN_IRQ      GENMASK(28, 28)
+#define RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ GENMASK(29, 29)
+
+// SENINF_CSI2_LINE_FRAME_NUM
+#define SENINF_CSI2_LINE_FRAME_NUM 0x00d0
+#define RO_CSI2_LINE_NUM   GENMASK(15, 0)
+#define RO_CSI2_FRAME_NUM  GENMASK(31, 16)
+
+// SENINF_CSI2_PACKET_STATUS
+#define SENINF_CSI2_PACKET_STATUS 0x00d4
+#define RO_CSI2_PACKET_DT GENMASK(5, 0)
+#define RO_CSI2_PACKET_VC GENMASK(12, 8)
+#define RO_CSI2_PACKET_WC GENMASK(31, 16)
+
+// SENINF_CSI2_GEN_SHORT_PACKET_STATUS
+#define SENINF_CSI2_GEN_SHORT_PACKET_STATUS 0x00d8
+#define RO_CSI2_GENERIC_SHORT_PACKET_DT GENMASK(5, 0)
+#define RO_CSI2_GENERIC_SHORT_PACKET_WC GENMASK(31, 16)
+
+// SENINF_CSI2_PACKET_CNT_STATUS
+#define SENINF_CSI2_PACKET_CNT_STATUS 0x00dc
+#define RO_CSI2_PACKET_CNT     GENMASK(15, 0)
+#define RO_CSI2_PACKET_CNT_BUF GENMASK(31, 16)
+
+// SENINF_CSI2_DBG_CTRL
+#define SENINF_CSI2_DBG_CTRL 0x00e0
+#define RG_CSI2_DBG_SEL           GENMASK(7, 0)
+#define RG_CSI2_DBG_EN            GENMASK(16, 16)
+#define RG_CSI2_DBG_PACKET_CNT_EN GENMASK(17, 17)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
new file mode 100755
index 000000000000..8c4619a516e8
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __SENINF1_MUX_H__
+#define __SENINF1_MUX_H__
+
+#include <linux/bitfield.h>
+
+// SENINF_MUX_CTRL_0
+#define SENINF_MUX_CTRL_0 0x0000
+#define SENINF_MUX_EN           GENMASK(0, 0)
+#define SENINF_MUX_IRQ_SW_RST   GENMASK(1, 1)
+#define SENINF_MUX_SW_RST       GENMASK(2, 2)
+
+// SENINF_MUX_CTRL_1
+#define SENINF_MUX_CTRL_1 0x0004
+#define RG_SENINF_MUX_SRC_SEL           GENMASK(3, 0)
+#define RG_SENINF_MUX_PIX_MODE_SEL      GENMASK(9, 8)
+#define RG_SENINF_MUX_FIFO_PUSH_EN      GENMASK(21, 16)
+#define RG_SENINF_MUX_RDY_FORCE_MODE_EN GENMASK(24, 24)
+#define RG_SENINF_MUX_RDY_FORCE_MODE_VAL GENMASK(25, 25)
+#define RG_SENINF_MUX_CROP_EN           GENMASK(28, 28)
+
+// SENINF_MUX_OPT
+#define SENINF_MUX_OPT 0x0008
+#define RG_SENINF_MUX_CNT_INIT_OPT         GENMASK(1, 0)
+#define RG_SENINF_MUX_FIFO_FULL_OUTPUT_OPT GENMASK(9, 8)
+#define RG_SENINF_MUX_FIFO_FULL_WR_MODE    GENMASK(11, 10)
+#define RG_SENINF_MUX_FIFO_OVERRUN_RST_EN  GENMASK(12, 12)
+#define RG_SENINF_MUX_HSYNC_POL            GENMASK(16, 16)
+#define RG_SENINF_MUX_VSYNC_POL            GENMASK(17, 17)
+
+// SENINF_MUX_IRQ_EN
+#define SENINF_MUX_IRQ_EN 0x0010
+#define RG_SENINF_MUX_FIFO_OVERRUN_IRQ_EN  GENMASK(0, 0)
+#define RG_SENINF_MUX_FSM_ERR_IRQ_EN       GENMASK(1, 1)
+#define RG_SENINF_MUX_HSIZE_ERR_IRQ_EN     GENMASK(2, 2)
+#define RG_SENINF_MUX_VSIZE_ERR_IRQ_EN     GENMASK(3, 3)
+#define RG_SENINF_MUX_IRQ_CLR_MODE         GENMASK(31, 31)
+
+// SENINF_MUX_IRQ_STATUS
+#define SENINF_MUX_IRQ_STATUS 0x0018
+#define RO_SENINF_MUX_FIFO_OVERRUN_IRQ GENMASK(0, 0)
+#define RO_SENINF_MUX_FSM_ERR_IRQ      GENMASK(1, 1)
+#define RO_SENINF_MUX_HSIZE_ERR_IRQ    GENMASK(2, 2)
+#define RO_SENINF_MUX_VSIZE_ERR_IRQ    GENMASK(3, 3)
+
+// SENINF_MUX_IMG_SIZE
+#define SENINF_MUX_IMG_SIZE 0x0020
+#define RG_SENINF_MUX_EXPECT_HSIZE GENMASK(15, 0)
+#define RG_SENINF_MUX_EXPECT_VSIZE GENMASK(31, 16)
+
+// SENINF_MUX_CROP_PIX_CTRL
+#define SENINF_MUX_CROP_PIX_CTRL 0x0028
+#define RG_SENINF_MUX_CROP_START_8PIX_CNT GENMASK(11, 0)
+#define RG_SENINF_MUX_CROP_END_8PIX_CNT   GENMASK(27, 16)
+
+// SENINF_MUX_SIZE
+#define SENINF_MUX_SIZE 0x0030
+#define RO_SENINF_MUX_RCV_HSIZE GENMASK(15, 0)
+#define RO_SENINF_MUX_RCV_VSIZE GENMASK(31, 16)
+
+// SENINF_MUX_ERR_SIZE
+#define SENINF_MUX_ERR_SIZE 0x0034
+#define RO_SENINF_MUX_RCV_ERR_HSIZE GENMASK(15, 0)
+#define RO_SENINF_MUX_RCV_ERR_VSIZE GENMASK(31, 16)
+
+// SENINF_MUX_FIFO_STATUS
+#define SENINF_MUX_FIFO_STATUS 0x0040
+#define RO_SENINF_MUX_FIFO_WA  GENMASK(8, 0)
+#define RO_SENINF_MUX_FIFO_WCS GENMASK(12, 12)
+#define RO_SENINF_MUX_FIFO_RA  GENMASK(24, 16)
+#define RO_SENINF_MUX_FIFO_RCS GENMASK(28, 28)
+
+// SENINF_MUX_DBG_CTRL
+#define SENINF_MUX_DBG_CTRL 0x0080
+#define RG_SENINF_MUX_DBG_EN  GENMASK(0, 0)
+#define RG_SENINF_MUX_DBG_SEL GENMASK(15, 8)
+
+// SENINF_MUX_DBG_OUT
+#define SENINF_MUX_DBG_OUT 0x0088
+#define RO_SENINF_MUX_DBG_OUT GENMASK(31, 0)
+
+// SENINF_MUX_CAM_MON
+#define SENINF_MUX_CAM_MON 0x00a0
+#define RO_SENINF_MUX_CAM_MON_0 GENMASK(15, 0)
+#define RO_SENINF_MUX_CAM_MON_1 GENMASK(31, 16)
+
+// SENINF_MUX_PIX_CNT
+#define SENINF_MUX_PIX_CNT 0x00a4
+#define RO_SENINF_MUX_PIX_CNT GENMASK(31, 0)
+
+// SENINF_MUX_FRAME_SIZE_MON_CTRL
+#define SENINF_MUX_FRAME_SIZE_MON_CTRL 0x00a8
+#define RG_SENINF_MUX_FRAME_SIZE_MON_EN GENMASK(0, 0)
+
+// SENINF_MUX_FRAME_SIZE_MON_H_VALID
+#define SENINF_MUX_FRAME_SIZE_MON_H_VALID 0x00b0
+#define RO_SENINF_MUX_FRAME_H_VALID GENMASK(31, 0)
+
+// SENINF_MUX_FRAME_SIZE_MON_H_BLANK
+#define SENINF_MUX_FRAME_SIZE_MON_H_BLANK 0x00b4
+#define RO_SENINF_MUX_FRAME_H_BLANK GENMASK(31, 0)
+
+// SENINF_MUX_FRAME_SIZE_MON_V_VALID
+#define SENINF_MUX_FRAME_SIZE_MON_V_VALID 0x00b8
+#define RO_SENINF_MUX_FRAME_V_VALID GENMASK(31, 0)
+
+// SENINF_MUX_FRAME_SIZE_MON_V_BLANK
+#define SENINF_MUX_FRAME_SIZE_MON_V_BLANK 0x00bc
+#define RO_SENINF_MUX_FRAME_V_BLANK GENMASK(31, 0)
+
+// SENINF_MUX_SPARE
+#define SENINF_MUX_SPARE 0x00f0
+#define RG_SENINF_MUX_SPARE_0 GENMASK(7, 0)
+#define RG_SENINF_MUX_SPARE_1 GENMASK(23, 16)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
new file mode 100755
index 000000000000..f1e195f4184c
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __SENINF1_H__
+#define __SENINF1_H__
+
+#include <linux/bitfield.h>
+
+// SENINF_CTRL
+#define SENINF_CTRL 0x0000
+#define SENINF_EN GENMASK(0, 0)
+
+// SENINF_DBG
+#define SENINF_DBG 0x0004
+#define RG_SENINF_DBG_SEL GENMASK(3, 0)
+
+// SENINF_CSI_CTRL
+#define SENINF_CSI_CTRL 0x0010
+#define RG_SENINF_CSI2_EN GENMASK(0, 0)
+#define SENINF_CSI2_SW_RST GENMASK(4, 4)
+
+// SENINF_TESTMDL_CTRL
+#define SENINF_TESTMDL_CTRL 0x0020
+#define RG_SENINF_TESTMDL_EN GENMASK(0, 0)
+#define SENINF_TESTMDL_SW_RST GENMASK(4, 4)
+
+// SENINF_TG_CTRL
+#define SENINF_TG_CTRL 0x0030
+#define SENINF_TG_SW_RST GENMASK(4, 4)
+
+// SENINF_SCAM_CTRL
+#define SENINF_SCAM_CTRL 0x0040
+#define RG_SENINF_SCAM_EN GENMASK(0, 0)
+#define SENINF_SCAM_SW_RST GENMASK(4, 4)
+
+// SENINF_PCAM_CTRL
+#define SENINF_PCAM_CTRL 0x0050
+#define RG_SENINF_PCAM_DATA_SEL GENMASK(2, 0)
+
+// SENINF_CCIR_CTRL
+#define SENINF_CCIR_CTRL 0x0060
+#define SENINF_CCIR_SW_RST GENMASK(4, 4)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
new file mode 100755
index 000000000000..62949e6da530
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __SENINF_TG1_H__
+#define __SENINF_TG1_H__
+
+#include <linux/bitfield.h>
+
+// TM_CTL
+#define TM_CTL 0x0008
+#define TM_EN                  GENMASK(0, 0)
+#define TM_RST                 GENMASK(1, 1)
+#define TM_FMT                 GENMASK(2, 2)
+#define TM_BIN_IMG_SWITCH_EN   GENMASK(3, 3)
+#define TM_PAT                 GENMASK(8, 4)
+
+// TM_SIZE
+#define TM_SIZE 0x000c
+#define TM_PXL  GENMASK(15, 0)
+#define TM_LINE GENMASK(31, 16)
+
+// TM_CLK
+#define TM_CLK 0x0010
+#define TM_CLK_CNT      GENMASK(7, 0)
+#define TM_CLRBAR_OFT   GENMASK(20, 8)
+#define TM_CLRBAR_IDX   GENMASK(30, 28)
+
+// TM_DUM
+#define TM_DUM 0x0018
+#define TM_DUMMYPXL GENMASK(15, 0)
+#define TM_VSYNC    GENMASK(31, 16)
+
+// TM_RAND_SEED
+#define TM_RAND_SEED 0x001c
+#define TM_SEED GENMASK(31, 0)
+
+// TM_RAND_CTL
+#define TM_RAND_CTL 0x0020
+#define TM_DIFF_FRM GENMASK(0, 0)
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h
new file mode 100755
index 000000000000..8e760ef13db9
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __SENINF_TOP_H__
+#define __SENINF_TOP_H__
+
+#include <linux/bitfield.h>
+
+// SENINF_TOP_CTRL
+#define SENINF_TOP_CTRL 0x0000
+#define SENINF_TOP_SW_RST             GENMASK(0, 0)
+#define SENINF_TOP_N3D_SW_RST         GENMASK(4, 4)
+#define RG_SENINF1_PCAM_PCLK_SEL      GENMASK(8, 8)
+#define RG_SENINF2_PCAM_PCLK_SEL      GENMASK(9, 9)
+#define RG_SENINF1_PCAM_PCLK_EN       GENMASK(12, 12)
+#define RG_SENINF2_PCAM_PCLK_EN       GENMASK(13, 13)
+#define RG_SLICE_FIFO_FULL_OPT        GENMASK(16, 16)
+
+// SENINF_TOP_MUX_CTRL_0
+#define SENINF_TOP_MUX_CTRL_0 0x0010
+#define RG_SENINF_MUX1_SRC_SEL        GENMASK(3, 0)
+#define RG_SENINF_MUX2_SRC_SEL        GENMASK(11, 8)
+#define RG_SENINF_MUX3_SRC_SEL        GENMASK(19, 16)
+#define RG_SENINF_MUX4_SRC_SEL        GENMASK(27, 24)
+
+// SENINF_TOP_MUX_CTRL_1
+#define SENINF_TOP_MUX_CTRL_1 0x0014
+#define RG_SENINF_MUX5_SRC_SEL        GENMASK(3, 0)
+#define RG_SENINF_MUX6_SRC_SEL        GENMASK(11, 8)
+#define RG_SENINF_MUX7_SRC_SEL        GENMASK(19, 16)
+#define RG_SENINF_MUX8_SRC_SEL        GENMASK(27, 24)
+
+// SENINF_TOP_MUX_CTRL_2
+#define SENINF_TOP_MUX_CTRL_2 0x0018
+#define RG_SENINF_MUX9_SRC_SEL        GENMASK(3, 0)
+#define RG_SENINF_MUX10_SRC_SEL       GENMASK(11, 8)
+#define RG_SENINF_MUX11_SRC_SEL       GENMASK(19, 16)
+#define RG_SENINF_MUX12_SRC_SEL       GENMASK(27, 24)
+
+// SENINF_TOP_MUX_CTRL_3
+#define SENINF_TOP_MUX_CTRL_3 0x001c
+#define RG_SENINF_MUX13_SRC_SEL       GENMASK(3, 0)
+
+// SENINF_TOP_PHY_CTRL_CSI0
+#define SENINF_TOP_PHY_CTRL_CSI0 0x0060
+#define PHY_SENINF_MUX0_DPHY_EN       GENMASK(0, 0)
+#define PHY_SENINF_MUX0_CPHY_EN       GENMASK(1, 1)
+#define RG_PHY_SENINF_MUX0_CPHY_MODE  GENMASK(9, 8)
+
+// SENINF_TOP_PHY_CTRL_CSI1
+#define SENINF_TOP_PHY_CTRL_CSI1 0x0064
+#define PHY_SENINF_MUX1_DPHY_EN       GENMASK(0, 0)
+#define PHY_SENINF_MUX1_CPHY_EN       GENMASK(1, 1)
+#define RG_PHY_SENINF_MUX1_CPHY_MODE  GENMASK(9, 8)
+
+// SENINF_TOP_PHY_CTRL_CSI2
+#define SENINF_TOP_PHY_CTRL_CSI2 0x0068
+#define PHY_SENINF_MUX2_DPHY_EN       GENMASK(0, 0)
+#define PHY_SENINF_MUX2_CPHY_EN       GENMASK(1, 1)
+#define RG_PHY_SENINF_MUX2_CPHY_MODE  GENMASK(9, 8)
+
+// SENINF_TOP_PHY_CTRL_CSI3
+#define SENINF_TOP_PHY_CTRL_CSI3 0x006c
+#define PHY_SENINF_MUX3_DPHY_EN       GENMASK(0, 0)
+#define PHY_SENINF_MUX3_CPHY_EN       GENMASK(1, 1)
+#define RG_PHY_SENINF_MUX3_CPHY_MODE  GENMASK(9, 8)
+
+// SENINF_TOP_PHY_CTRL_CSI4
+#define SENINF_TOP_PHY_CTRL_CSI4 0x0070
+#define PHY_SENINF_MUX4_DPHY_EN       GENMASK(0, 0)
+#define PHY_SENINF_MUX4_CPHY_EN       GENMASK(1, 1)
+#define RG_PHY_SENINF_MUX4_CPHY_MODE  GENMASK(9, 8)
+
+#endif
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (4 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-11  8:56   ` CK Hu (胡俊光)
  2025-07-21  1:40   ` CK Hu (胡俊光)
  2025-07-07  1:31 ` [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT shangyao lin
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduce state management and debugging mechanisms for the MediaTek ISP7.x
camsys platform. State management establishes control over ISP operations and
events, defining distinct states for request handling, sensor control, and
frame synchronization, ensuring proper event processing. The debugging
mechanism ensures stable operation and timely data collection during anomalies.

---

Changes in v2:
- Removed mtk_cam-debug.c and mtk_cam-debug.h, along with related code
- Various fixes per review comments

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c | 1409 +++++++++++++++++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h |  131 ++
 2 files changed, 1540 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h

diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
new file mode 100755
index 000000000000..15af1eac5444
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
@@ -0,0 +1,1409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#include <linux/list.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/videodev2.h>
+#include <linux/hrtimer.h>
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-ctrl.h"
+#include "mtk_cam-pool.h"
+#include "mtk_cam-raw.h"
+
+#include "mtk_cam-regs-mt8188.h"
+
+#include "mtk_camera-v4l2-controls.h"
+
+#define SENSOR_SET_DEADLINE_MS  18
+#define SENSOR_SET_RESERVED_MS  7
+#define SENSOR_SET_DEADLINE_MS_60FPS  6
+#define SENSOR_SET_RESERVED_MS_60FPS  6
+#define STATE_NUM_AT_SOF 3
+#define INITIAL_DROP_FRAME_CNT 1
+
+enum MTK_CAMSYS_STATE_RESULT {
+	STATE_RESULT_TRIGGER_CQ = 0,
+	STATE_RESULT_PASS_CQ_INIT,
+	STATE_RESULT_PASS_CQ_SW_DELAY,
+	STATE_RESULT_PASS_CQ_SCQ_DELAY,
+	STATE_RESULT_PASS_CQ_HW_DELAY,
+};
+
+void state_transition(struct mtk_camsys_ctrl_state *state_entry,
+		      enum MTK_CAMSYS_STATE_IDX from,
+		      enum MTK_CAMSYS_STATE_IDX to)
+{
+	if (state_entry->estate == from)
+		state_entry->estate = to;
+}
+
+static void mtk_cam_event_eos(struct mtk_raw_pipeline *pipeline)
+{
+	struct v4l2_event event = {
+		.type = V4L2_EVENT_EOS,
+	};
+	v4l2_event_queue(pipeline->subdev.devnode, &event);
+}
+
+static void mtk_cam_event_frame_sync(struct mtk_raw_pipeline *pipeline,
+				     unsigned int frame_seq_no)
+{
+	struct v4l2_event event = {
+		.type = V4L2_EVENT_FRAME_SYNC,
+		.u.frame_sync.frame_sequence = frame_seq_no,
+	};
+	v4l2_event_queue(pipeline->subdev.devnode, &event);
+}
+
+static void mtk_cam_event_request_drained(struct mtk_raw_pipeline *pipeline)
+{
+	struct v4l2_event event = {
+		.type = V4L2_EVENT_REQUEST_DRAINED,
+	};
+	v4l2_event_queue(pipeline->subdev.devnode, &event);
+}
+
+static bool mtk_cam_request_drained(struct mtk_camsys_sensor_ctrl *sensor_ctrl)
+{
+	struct mtk_cam_ctx *ctx = sensor_ctrl->ctx;
+	int sensor_seq_no_next =
+		atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1;
+	int res = 0;
+
+	if (sensor_seq_no_next <= atomic_read(&ctx->enqueued_frame_seq_no))
+		res = 1;
+	/* Send V4L2_EVENT_REQUEST_DRAINED event */
+	if (res == 0) {
+		mtk_cam_event_request_drained(ctx->pipe);
+		dev_dbg(ctx->cam->dev, "request_drained:(%d)\n",
+			sensor_seq_no_next);
+	}
+	return (res == 0);
+}
+
+static bool mtk_cam_req_frame_sync_start(struct mtk_cam_request *req)
+{
+	/* All ctx with sensor is in ready state */
+	struct mtk_cam_device *cam =
+		container_of(req->req.mdev, struct mtk_cam_device, media_dev);
+	struct mtk_cam_ctx *sync_ctx[MTKCAM_SUBDEV_MAX];
+	int i;
+	u32 ctx_cnt = 0;
+	bool ret = false;
+
+	/* pick out the used ctxs */
+	for (i = 0; i < cam->max_stream_num; i++) {
+		if (!(1 << i & req->ctx_used))
+			continue;
+
+		sync_ctx[ctx_cnt] = &cam->ctxs[i];
+		ctx_cnt++;
+	}
+
+	dev_dbg(cam->dev, "%s:%s:target/on/off(%d/%d/%d)\n", __func__,
+		req->req.debug_str, req->fs.target, req->fs.on_cnt,
+		req->fs.off_cnt);
+	return ret;
+}
+
+static bool mtk_cam_req_frame_sync_end(struct mtk_cam_request *req)
+{
+	/* All ctx with sensor is not in ready state */
+	struct mtk_cam_device *cam =
+		container_of(req->req.mdev, struct mtk_cam_device, media_dev);
+	bool ret = false;
+
+	mutex_lock(&req->fs.op_lock);
+	if (req->fs.target && req->fs.on_cnt) {
+		/* check fs on */
+		req->fs.off_cnt++;
+		if (req->fs.on_cnt != req->fs.target ||
+		    req->fs.off_cnt != req->fs.target) {
+			/* not the last */
+			goto EXIT;
+		}
+		dev_dbg(cam->dev,
+			"%s:%s:fs_sync_frame(0): ctxs: 0x%x\n",
+			__func__, req->req.debug_str, req->ctx_used);
+		ret = true;
+		goto EXIT;
+	}
+EXIT:
+	dev_dbg(cam->dev, "%s:%s:target/on/off(%d/%d/%d)\n", __func__,
+		req->req.debug_str, req->fs.target, req->fs.on_cnt,
+		req->fs.off_cnt);
+	mutex_unlock(&req->fs.op_lock);
+	return ret;
+}
+
+static void mtk_cam_stream_on(struct mtk_raw_device *raw_dev,
+			      struct mtk_cam_ctx *ctx)
+{
+	spin_lock(&ctx->streaming_lock);
+	if (ctx->streaming)
+		mtk_cam_raw_stream_on(raw_dev, 1);
+
+	spin_unlock(&ctx->streaming_lock);
+}
+
+void mtk_cam_set_sensor_full(struct mtk_cam_request_stream_data *s_data,
+			     struct mtk_camsys_sensor_ctrl *sensor_ctrl)
+{
+	struct mtk_cam_device *cam;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request *req;
+	struct mtk_raw_device *raw_dev;
+	unsigned int time_after_sof = 0;
+
+	/* EnQ this request's state element to state_list (STATE:READY) */
+	spin_lock(&sensor_ctrl->camsys_state_lock);
+	list_add_tail(&s_data->state.state_element,
+		      &sensor_ctrl->camsys_state_list);
+	atomic_set(&sensor_ctrl->sensor_request_seq_no, s_data->frame_seq_no);
+	spin_unlock(&sensor_ctrl->camsys_state_lock);
+
+	/* sensor_worker task */
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	req = mtk_cam_s_data_get_req(s_data);
+
+	dev_dbg(cam->dev, "%s:%s:ctx(%d) req(%d):sensor try set start\n",
+		__func__, req->req.debug_str, ctx->stream_id, s_data->frame_seq_no);
+
+	if (ctx->used_raw_num && mtk_cam_req_frame_sync_start(req))
+		dev_dbg(cam->dev,
+			"%s:%s:ctx(%d): sensor ctrl with frame sync - start\n",
+			__func__, req->req.debug_str, ctx->stream_id);
+
+	/*
+	 * request setup
+	 * 1st frame sensor setting is treated like normal frame
+	 * and is set with other settings like max fps.
+	 * 2nd is special, only exposure is set.
+	 */
+	if (s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN) {
+		v4l2_ctrl_request_setup(&req->req,
+					s_data->sensor->ctrl_handler);
+		time_after_sof =
+			div_u64(ktime_get_boottime_ns(), 1000000) -
+				ctx->sensor_ctrl.sof_time;
+		dev_dbg(cam->dev,
+			"[SOF+%dms] Sensor request:%d[ctx:%d] setup\n",
+			time_after_sof, s_data->frame_seq_no,
+			ctx->stream_id);
+	}
+
+	state_transition(&s_data->state, E_STATE_READY, E_STATE_SENSOR);
+
+	if (ctx->used_raw_num && mtk_cam_req_frame_sync_end(req))
+		dev_dbg(cam->dev,
+			"%s:ctx(%d): sensor ctrl with frame sync - stop\n",
+			__func__, ctx->stream_id);
+
+	if (ctx->used_raw_num) {
+		raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe);
+		if (raw_dev && atomic_read(&raw_dev->vf_en) == 0 &&
+		    ctx->sensor_ctrl.initial_cq_done == 1 &&
+		    s_data->frame_seq_no == 1)
+			mtk_cam_stream_on(raw_dev, ctx);
+	}
+
+	dev_dbg(cam->dev, "%s:%s:ctx(%d)req(%d):sensor done at SOF+%dms\n",
+		__func__, req->req.debug_str, ctx->stream_id,
+		s_data->frame_seq_no, time_after_sof);
+
+	mtk_cam_complete_sensor_hdl(s_data);
+}
+
+static void mtk_cam_try_set_sensor(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_camsys_ctrl_state *state_entry;
+	struct mtk_cam_request *req;
+	int sensor_seq_no_next =
+		atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1;
+	int time_after_sof = div_u64(ktime_get_boottime_ns(), 1000000) -
+			   ctx->sensor_ctrl.sof_time;
+	/*for 1st unsync, sensor setting will be set at enque thread*/
+	if (ctx->used_raw_num) {
+		if (ctx->pipe->feature_active == 0 && sensor_seq_no_next <= 2)
+			return;
+	} else {
+		if (sensor_seq_no_next <= 2)
+			return;
+	}
+	spin_lock(&sensor_ctrl->camsys_state_lock);
+	/* Check if previous state was without cq done */
+	list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list,
+			    state_element) {
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_entry);
+		if (req_stream_data->frame_seq_no ==
+			atomic_read(&sensor_ctrl->sensor_request_seq_no)) {
+			if (state_entry->estate == E_STATE_CQ &&
+			    req_stream_data->frame_seq_no > INITIAL_DROP_FRAME_CNT) {
+				state_entry->estate = E_STATE_CQ_SCQ_DELAY;
+				spin_unlock(&sensor_ctrl->camsys_state_lock);
+				dev_dbg(ctx->cam->dev,
+					"[%s] SCQ DELAY STATE at SOF+%dms\n",
+					__func__, time_after_sof);
+				return;
+			} else if (state_entry->estate == E_STATE_CAMMUX_OUTER_CFG) {
+				state_entry->estate =
+					E_STATE_CAMMUX_OUTER_CFG_DELAY;
+				spin_unlock(&sensor_ctrl->camsys_state_lock);
+
+				dev_dbg(ctx->cam->dev,
+					"[%s] CAMMUX OUTTER CFG DELAY STATE\n",
+					__func__);
+				return;
+
+			} else if (state_entry->estate <= E_STATE_SENSOR) {
+				spin_unlock(&sensor_ctrl->camsys_state_lock);
+				dev_dbg(ctx->cam->dev,
+					"[%s] wrong state:%d (sensor workqueue delay)\n",
+					__func__, state_entry->estate);
+				return;
+			}
+		} else if (req_stream_data->frame_seq_no ==
+			atomic_read(&sensor_ctrl->sensor_request_seq_no) - 1) {
+			if (state_entry->estate < E_STATE_INNER) {
+				spin_unlock(&sensor_ctrl->camsys_state_lock);
+				dev_dbg(ctx->cam->dev,
+					"[%s] req:%d isn't arrive inner at SOF+%dms\n",
+					__func__, req_stream_data->frame_seq_no,
+					time_after_sof);
+				return;
+			}
+		}
+	}
+	spin_unlock(&sensor_ctrl->camsys_state_lock);
+
+	/** Frame sync:
+	 * make sure the all ctxs of previous request are triggered
+	 */
+	req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id,
+						 sensor_seq_no_next - 1);
+	if (req_stream_data) {
+		req = mtk_cam_s_data_get_req(req_stream_data);
+		/* fs complete: fs.target <= off and on == off */
+		if (!(req->fs.target <= req->fs.off_cnt &&
+		      req->fs.off_cnt == req->fs.on_cnt)) {
+			dev_info(ctx->cam->dev,
+				 "[TimerIRQ] ctx:%d the fs of req(%s/%d) is not completed, target/on/off(%d/%d/%d)\n",
+				 ctx->stream_id, req->req.debug_str,
+				 sensor_seq_no_next - 1, req->fs.target,
+				 req->fs.on_cnt, req->fs.off_cnt);
+			return;
+		}
+	}
+
+	req_stream_data =
+		mtk_cam_get_req_s_data(ctx, ctx->stream_id, sensor_seq_no_next);
+	if (req_stream_data) {
+		req = mtk_cam_s_data_get_req(req_stream_data);
+		mtk_cam_set_sensor_full(req_stream_data, &ctx->sensor_ctrl);
+
+		dev_dbg(cam->dev,
+			"%s:[TimerIRQ [SOF+%dms]:] ctx:%d, sensor_req_seq_no:%d\n",
+			__func__, time_after_sof, ctx->stream_id,
+			sensor_seq_no_next);
+	} else {
+		dev_dbg(cam->dev,
+			"%s:[TimerIRQ [SOF+%dms]] ctx:%d, empty req_queue, sensor_req_seq_no:%d\n",
+			__func__, time_after_sof, ctx->stream_id,
+			atomic_read(&sensor_ctrl->sensor_request_seq_no));
+	}
+}
+
+static void mtk_cam_sensor_worker_in_sensorctrl(struct kthread_work *work)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl =
+			container_of(work, struct mtk_camsys_sensor_ctrl, work);
+	struct mtk_cam_ctx *ctx;
+
+	ctx = sensor_ctrl->ctx;
+	mtk_cam_try_set_sensor(ctx);
+}
+
+bool mtk_cam_submit_kwork_in_sensorctrl(struct kthread_worker *worker,
+					struct mtk_camsys_sensor_ctrl *sensor_ctrl)
+{
+	if (!worker) {
+		pr_info("%s: not queue work since kthread_worker is null\n",
+			__func__);
+
+		return false;
+	}
+
+	return kthread_queue_work(worker, &sensor_ctrl->work);
+}
+
+static enum hrtimer_restart sensor_set_handler(struct hrtimer *t)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl =
+		container_of(t, struct mtk_camsys_sensor_ctrl,
+			     sensor_deadline_timer);
+
+	mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq,
+					   sensor_ctrl);
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart sensor_deadline_timer_handler(struct hrtimer *t)
+{
+	unsigned int enq_no, sen_no;
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl =
+		container_of(t, struct mtk_camsys_sensor_ctrl,
+			     sensor_deadline_timer);
+	struct mtk_cam_ctx *ctx = sensor_ctrl->ctx;
+	struct mtk_cam_device *cam = ctx->cam;
+	ktime_t m_kt;
+	int time_after_sof = div_u64(ktime_get_boottime_ns(), 1000000) -
+			   sensor_ctrl->sof_time;
+	bool drained_res = false;
+
+	sensor_ctrl->sensor_deadline_timer.function = sensor_set_handler;
+
+	m_kt = ktime_set(0, sensor_ctrl->timer_req_sensor * 1000000);
+
+	if (ctx->used_raw_num) {
+		/* handle V4L2_EVENT_REQUEST_DRAINED event */
+		drained_res = mtk_cam_request_drained(sensor_ctrl);
+	}
+	dev_dbg(cam->dev,
+		"[TimerIRQ [SOF+%dms]] ctx:%d, sensor_req_seq_no:%d\n",
+		time_after_sof, ctx->stream_id,
+		atomic_read(&sensor_ctrl->sensor_request_seq_no));
+	if (drained_res == 0) {
+		sen_no = atomic_read(&sensor_ctrl->sensor_enq_seq_no);
+		enq_no = atomic_read(&ctx->enqueued_frame_seq_no);
+		if (enq_no == sen_no) {
+			mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq,
+							   sensor_ctrl);
+			return HRTIMER_NORESTART;
+		}
+		dev_dbg(cam->dev,
+			"[TimerIRQ [SOF+%dms]] ctx:%d, enq:%d/sensor_enq:%d\n",
+			time_after_sof, ctx->stream_id, enq_no, sen_no);
+	}
+	/*using enque timing for sensor setting*/
+	if (ctx->used_raw_num) {
+		if (ctx->pipe->feature_active == 0) {
+			int drained_seq_no =
+				atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1;
+			atomic_set(&sensor_ctrl->last_drained_seq_no, drained_seq_no);
+			return HRTIMER_NORESTART;
+		}
+	}
+	hrtimer_forward_now(&sensor_ctrl->sensor_deadline_timer, m_kt);
+
+	return HRTIMER_RESTART;
+}
+
+static void mtk_cam_sof_timer_setup(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	ktime_t m_kt;
+	int after_sof_ms = div_u64(ktime_get_boottime_ns(), 1000000) -
+			sensor_ctrl->sof_time;
+
+	sensor_ctrl->sensor_deadline_timer.function =
+		sensor_deadline_timer_handler;
+	sensor_ctrl->ctx = ctx;
+	if (after_sof_ms < 0)
+		after_sof_ms = 0;
+	else if (after_sof_ms > sensor_ctrl->timer_req_event)
+		after_sof_ms = sensor_ctrl->timer_req_event - 1;
+	m_kt = ktime_set(0, sensor_ctrl->timer_req_event * 1000000 -
+			 after_sof_ms * 1000000);
+	hrtimer_start(&sensor_ctrl->sensor_deadline_timer, m_kt, HRTIMER_MODE_REL);
+}
+
+static void
+mtk_cam_set_timestamp(struct mtk_cam_request_stream_data *stream_data,
+		      u64 time_boot,
+		      u64 time_mono)
+{
+	stream_data->timestamp = time_boot;
+	stream_data->timestamp_mono = time_mono;
+}
+
+static int
+mtk_camsys_raw_state_handle(struct mtk_raw_device *raw_dev,
+			    struct mtk_camsys_sensor_ctrl *sensor_ctrl,
+			    struct mtk_camsys_ctrl_state **current_state,
+			    struct mtk_camsys_irq_info *irq_info)
+{
+	struct mtk_cam_ctx *ctx = sensor_ctrl->ctx;
+	struct mtk_camsys_ctrl_state *state_temp, *state_outer = NULL;
+	struct mtk_camsys_ctrl_state *state_inner = NULL;
+	struct mtk_camsys_ctrl_state *state_rec[STATE_NUM_AT_SOF];
+	struct mtk_cam_request_stream_data *req_stream_data;
+	int frame_idx_inner = irq_info->frame_idx_inner;
+	int stateidx;
+	int que_cnt = 0;
+	int write_cnt;
+	u64 time_boot = ktime_get_boottime_ns();
+	u64 time_mono = ktime_get_ns();
+	int working_req_found = 0;
+
+	/* List state-queue status*/
+	spin_lock(&sensor_ctrl->camsys_state_lock);
+	list_for_each_entry(state_temp, &sensor_ctrl->camsys_state_list,
+			    state_element) {
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp);
+		stateidx = atomic_read(&sensor_ctrl->sensor_request_seq_no) -
+			   req_stream_data->frame_seq_no;
+		if (stateidx < STATE_NUM_AT_SOF && stateidx > -1) {
+			state_rec[stateidx] = state_temp;
+			if (stateidx == 0)
+				working_req_found = 1;
+
+			/* Find outer state element */
+			if (state_temp->estate == E_STATE_OUTER ||
+			    state_temp->estate == E_STATE_CAMMUX_OUTER ||
+			    state_temp->estate == E_STATE_OUTER_HW_DELAY) {
+				state_outer = state_temp;
+				mtk_cam_set_timestamp(req_stream_data,
+						      time_boot, time_mono);
+			}
+
+			/* Find inner state element request */
+			if (state_temp->estate == E_STATE_INNER ||
+			    state_temp->estate == E_STATE_INNER_HW_DELAY)
+				state_inner = state_temp;
+
+			dev_dbg(raw_dev->dev,
+				"[SOF] STATE_CHECK [N-%d] Req:%d / State:%d\n",
+				stateidx, req_stream_data->frame_seq_no,
+				state_rec[stateidx]->estate);
+		}
+		/* counter for state queue*/
+		que_cnt++;
+	}
+	spin_unlock(&sensor_ctrl->camsys_state_lock);
+
+	/* HW imcomplete case */
+	if (state_inner) {
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_inner);
+		write_cnt = (atomic_read(&sensor_ctrl->isp_request_seq_no) / 256)
+					* 256 + irq_info->write_cnt;
+
+		if (frame_idx_inner > atomic_read(&sensor_ctrl->isp_request_seq_no) ||
+		    atomic_read(&req_stream_data->frame_done_work.is_queued) == 1) {
+			dev_dbg_ratelimited(raw_dev->dev,
+					    "[SOF] frame done work too late frames. req(%d),ts(%llu)\n",
+					    req_stream_data->frame_seq_no,
+					    irq_info->ts_ns);
+		} else if (write_cnt >= req_stream_data->frame_seq_no) {
+			dev_info_ratelimited(raw_dev->dev,
+					     "[SOF] frame done reading lost %d frames. req(%d),ts(%llu)\n",
+					     write_cnt - req_stream_data->frame_seq_no + 1,
+					     req_stream_data->frame_seq_no,
+					     irq_info->ts_ns);
+			mtk_cam_set_timestamp(req_stream_data,
+					      time_boot - 1000, time_mono - 1000);
+			mtk_camsys_frame_done(ctx, write_cnt, ctx->stream_id);
+		} else if ((write_cnt >= req_stream_data->frame_seq_no - 1) &&
+			   irq_info->fbc_cnt == 0) {
+			dev_info_ratelimited(raw_dev->dev,
+					     "[SOF] frame done reading lost frames. req(%d),ts(%llu)\n",
+					     req_stream_data->frame_seq_no, irq_info->ts_ns);
+			mtk_cam_set_timestamp(req_stream_data,
+					      time_boot - 1000, time_mono - 1000);
+			mtk_camsys_frame_done(ctx, write_cnt + 1, ctx->stream_id);
+		} else {
+			state_transition(state_inner,
+					 E_STATE_INNER, E_STATE_INNER_HW_DELAY);
+			if (state_outer) {
+				state_transition(state_outer,
+						 E_STATE_OUTER,
+						 E_STATE_OUTER_HW_DELAY);
+				state_transition(state_outer,
+						 E_STATE_CAMMUX_OUTER,
+						 E_STATE_OUTER_HW_DELAY);
+			}
+			dev_info_ratelimited(raw_dev->dev,
+					     "[SOF] HW_IMCOMPLETE state cnt(%d,%d),req(%d),ts(%llu)\n",
+					     write_cnt, irq_info->write_cnt,
+					     req_stream_data->frame_seq_no,
+					     irq_info->ts_ns);
+			return STATE_RESULT_PASS_CQ_HW_DELAY;
+		}
+	}
+
+	/* Transit outer state to inner state */
+	if (state_outer && sensor_ctrl->sensorsetting_wq) {
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_outer);
+		if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 &&
+		    req_stream_data->frame_seq_no > frame_idx_inner) {
+			dev_info(raw_dev->dev,
+				 "[SOF-noDBLOAD] HW delay outer_no:%d, inner_idx:%d <= processing_idx:%d,ts:%llu\n",
+				 req_stream_data->frame_seq_no, frame_idx_inner,
+				 atomic_read(&sensor_ctrl->isp_request_seq_no),
+				 irq_info->ts_ns);
+			return STATE_RESULT_PASS_CQ_HW_DELAY;
+		}
+
+		if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 &&
+		    req_stream_data->frame_seq_no == frame_idx_inner) {
+			if (frame_idx_inner >
+			    atomic_read(&sensor_ctrl->isp_request_seq_no)) {
+				state_transition(state_outer,
+						 E_STATE_OUTER_HW_DELAY,
+						 E_STATE_INNER_HW_DELAY);
+				state_transition(state_outer,
+						 E_STATE_OUTER,
+						 E_STATE_INNER);
+				state_transition(state_outer,
+						 E_STATE_CAMMUX_OUTER,
+						 E_STATE_INNER);
+				atomic_set(&sensor_ctrl->isp_request_seq_no, frame_idx_inner);
+				dev_dbg(raw_dev->dev,
+					"[SOF-DBLOAD] frame_seq_no:%d, OUTER->INNER state:%d,ts:%llu\n",
+					req_stream_data->frame_seq_no,
+					state_outer->estate, irq_info->ts_ns);
+			}
+		}
+	}
+
+	/* Trigger high resolution timer to try sensor setting */
+	sensor_ctrl->sof_time = div_u64(irq_info->ts_ns, 1000000);
+	mtk_cam_sof_timer_setup(ctx);
+
+	if (que_cnt > 1 && state_rec[1]) {
+		state_temp = state_rec[1];
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp);
+		if (req_stream_data->frame_seq_no == 1)
+			state_transition(state_temp,
+					 E_STATE_SENSOR, E_STATE_INNER);
+	}
+
+	if (que_cnt > 0) {
+		if (working_req_found && state_rec[0]) {
+			if (state_rec[0]->estate == E_STATE_READY) {
+				dev_info(raw_dev->dev, "[SOF] sensor delay ts:%llu\n",
+					 irq_info->ts_ns);
+				req_stream_data =
+					mtk_cam_ctrl_state_to_req_s_data(state_rec[0]);
+				req_stream_data->flags |=
+					MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED;
+			}
+
+			if (state_rec[0]->estate == E_STATE_SENINF)
+				dev_info(raw_dev->dev, "[SOF] sensor switch delay\n");
+
+			/* CQ triggering judgment*/
+			if (state_rec[0]->estate == E_STATE_SENSOR) {
+				*current_state = state_rec[0];
+				return STATE_RESULT_TRIGGER_CQ;
+			}
+			/* last SCQ triggering delay judgment*/
+			if (state_rec[0]->estate == E_STATE_CQ_SCQ_DELAY) {
+				state_transition(state_rec[0],
+						 E_STATE_CQ_SCQ_DELAY,
+						 E_STATE_OUTER);
+				dev_info(raw_dev->dev, "[SOF] SCQ_DELAY state:%d ts:%llu\n",
+					 state_rec[0]->estate, irq_info->ts_ns);
+				return STATE_RESULT_PASS_CQ_SCQ_DELAY;
+			}
+		} else {
+			dev_dbg(raw_dev->dev, "[SOF] working request not found\n");
+		}
+	}
+	return STATE_RESULT_PASS_CQ_SW_DELAY;
+}
+
+static void mtk_camsys_raw_frame_start(struct mtk_raw_device *raw_dev,
+				       struct mtk_cam_ctx *ctx,
+				       struct mtk_camsys_irq_info *irq_info)
+{
+	unsigned int dequeued_frame_seq_no = irq_info->frame_idx_inner;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_cam_working_buf_entry *buf_entry;
+	struct mtk_camsys_ctrl_state *current_state;
+	struct mtk_cam_buffer *buf;
+
+	dma_addr_t base_addr;
+	enum MTK_CAMSYS_STATE_RESULT state_handle_ret;
+
+	/* touch watchdog*/
+	if (watchdog_scenario(ctx))
+		mtk_ctx_watchdog_kick(ctx);
+	/* inner register dequeue number */
+	ctx->dequeued_frame_seq_no = dequeued_frame_seq_no;
+	/* Send V4L2_EVENT_FRAME_SYNC event */
+	mtk_cam_event_frame_sync(ctx->pipe, dequeued_frame_seq_no);
+
+	/* Handle directly enque buffers */
+	spin_lock(&ctx->cam->dma_processing_lock);
+	list_for_each_entry(buf, &ctx->cam->dma_processing, list) {
+		if (buf->state.estate == E_BUF_STATE_COMPOSED) {
+			spin_unlock(&ctx->cam->dma_processing_lock);
+			goto apply_cq;
+		}
+	}
+	spin_unlock(&ctx->cam->dma_processing_lock);
+	buf = NULL;
+	current_state = NULL;
+
+	/* Find request of this dequeued frame */
+	req_stream_data =
+		mtk_cam_get_req_s_data(ctx, ctx->stream_id, dequeued_frame_seq_no);
+
+	if (ctx->sensor) {
+		state_handle_ret =
+			mtk_camsys_raw_state_handle(raw_dev, sensor_ctrl,
+						    &current_state, irq_info);
+
+		if (state_handle_ret != STATE_RESULT_TRIGGER_CQ) {
+			dev_dbg(raw_dev->dev, "[SOF] CQ drop s:%d deq:%d\n",
+				state_handle_ret, dequeued_frame_seq_no);
+			return;
+		}
+	}
+
+apply_cq:
+	/* Update CQ base address if needed */
+	if (ctx->composed_frame_seq_no <= dequeued_frame_seq_no) {
+		dev_info_ratelimited(raw_dev->dev,
+				     "SOF[ctx:%d-#%d], CQ isn't updated [composed_frame_deq (%d) ts:%llu]\n",
+				     ctx->stream_id, dequeued_frame_seq_no,
+				     ctx->composed_frame_seq_no, irq_info->ts_ns);
+		return;
+	}
+	/* apply next composed buffer */
+	spin_lock(&ctx->composed_buffer_list.lock);
+	if (list_empty(&ctx->composed_buffer_list.list)) {
+		dev_info_ratelimited(raw_dev->dev,
+				     "SOF_INT_ST, no buffer update, cq_num:%d, frame_seq:%d, ts:%llu\n",
+				     ctx->composed_frame_seq_no, dequeued_frame_seq_no,
+				     irq_info->ts_ns);
+		spin_unlock(&ctx->composed_buffer_list.lock);
+	} else {
+		buf_entry = list_first_entry(&ctx->composed_buffer_list.list,
+					     struct mtk_cam_working_buf_entry,
+					     list_entry);
+		list_del(&buf_entry->list_entry);
+		ctx->composed_buffer_list.cnt--;
+		spin_unlock(&ctx->composed_buffer_list.lock);
+		spin_lock(&ctx->processing_buffer_list.lock);
+		list_add_tail(&buf_entry->list_entry,
+			      &ctx->processing_buffer_list.list);
+		ctx->processing_buffer_list.cnt++;
+		spin_unlock(&ctx->processing_buffer_list.lock);
+		base_addr = buf_entry->buffer.iova;
+		mtk_cam_raw_apply_cq(raw_dev, base_addr,
+				     buf_entry->cq_desc_size,
+				     buf_entry->cq_desc_offset,
+				     buf_entry->sub_cq_desc_size,
+				     buf_entry->sub_cq_desc_offset);
+
+		if (buf) {
+			buf->state.estate = E_BUF_STATE_CQ;
+			return;
+		}
+
+		/* Transit state from Sensor -> CQ */
+		if (ctx->sensor) {
+			/* req_stream_data of req_cq*/
+			req_stream_data = mtk_cam_ctrl_state_to_req_s_data(current_state);
+			state_transition(current_state,
+					 E_STATE_SENSOR, E_STATE_CQ);
+
+			dev_dbg(raw_dev->dev,
+				"SOF[ctx:%d-#%d], CQ-%d is update, composed:%d, cq_addr:0x%pad, time:%lld, monotime:%lld\n",
+				ctx->stream_id, dequeued_frame_seq_no,
+				req_stream_data->frame_seq_no,
+				ctx->composed_frame_seq_no, &base_addr,
+				req_stream_data->timestamp,
+				req_stream_data->timestamp_mono);
+		}
+	}
+}
+
+static void mtk_camsys_raw_cq_done(struct mtk_raw_device *raw_dev,
+				   struct mtk_cam_ctx *ctx,
+				   unsigned int frame_seq_no_outer)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_camsys_ctrl_state *state_entry;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_cam_buffer *buf;
+
+	/* initial CQ done */
+	if (raw_dev->sof_count == 0) {
+		sensor_ctrl->initial_cq_done = 1;
+		spin_lock(&ctx->cam->dma_processing_lock);
+		if (!list_empty(&ctx->cam->dma_processing)) {
+			buf = list_first_entry(&ctx->cam->dma_processing,
+					       struct mtk_cam_buffer,
+					       list);
+			if (buf->state.estate == E_BUF_STATE_CQ)
+				buf->state.estate = E_BUF_STATE_OUTER;
+			spin_unlock(&ctx->cam->dma_processing_lock);
+			mtk_cam_stream_on(raw_dev, ctx);
+			return;
+		}
+		spin_unlock(&ctx->cam->dma_processing_lock);
+		req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, 1);
+		if (!req_stream_data) {
+			dev_err(raw_dev->dev, "Cannot find req stream data with stream_id:%d\n",
+				ctx->stream_id);
+			return;
+		}
+		if (req_stream_data->state.estate >= E_STATE_SENSOR || !ctx->sensor) {
+			mtk_cam_stream_on(raw_dev, ctx);
+		} else {
+			dev_dbg(raw_dev->dev,
+				"[CQD] 1st sensor not set yet, req:%d, state:%d\n",
+				req_stream_data->frame_seq_no, req_stream_data->state.estate);
+		}
+	}
+	/* Legacy CQ done will be always happened at frame done */
+	spin_lock(&sensor_ctrl->camsys_state_lock);
+	list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list,
+			    state_element) {
+		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_entry);
+		if (req_stream_data->frame_seq_no == frame_seq_no_outer) {
+			if (frame_seq_no_outer > atomic_read(&sensor_ctrl->isp_request_seq_no)) {
+				/*
+				 * outer number is 1 more from last SOF's
+				 * inner number
+				 */
+				if (frame_seq_no_outer == 1)
+					state_entry->estate = E_STATE_OUTER;
+				state_transition(state_entry, E_STATE_CQ,
+						 E_STATE_OUTER);
+				state_transition(state_entry, E_STATE_CQ_SCQ_DELAY,
+						 E_STATE_OUTER);
+				state_transition(state_entry, E_STATE_SENINF,
+						 E_STATE_OUTER);
+
+				dev_dbg(raw_dev->dev,
+					"[CQD] req:%d, CQ->OUTER state:%d\n",
+					req_stream_data->frame_seq_no,
+					state_entry->estate);
+			}
+		}
+	}
+	spin_unlock(&sensor_ctrl->camsys_state_lock);
+}
+
+static bool
+mtk_camsys_raw_prepare_frame_done(struct mtk_raw_device *raw_dev,
+				  struct mtk_cam_ctx *ctx,
+				  unsigned int dequeued_frame_seq_no)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_camsys_ctrl_state *state_entry;
+	struct mtk_cam_request *state_req;
+	struct mtk_cam_request_stream_data *s_data;
+
+	if (!ctx->sensor) {
+		dev_info(cam->dev, "%s: no sensor found in ctx:%d, req:%d",
+			 __func__, ctx->stream_id, dequeued_frame_seq_no);
+
+		return true;
+	}
+
+	spin_lock(&camsys_sensor_ctrl->camsys_state_lock);
+	/**
+	 * Find inner register number's request and transit to
+	 * STATE_DONE_xxx
+	 */
+	list_for_each_entry(state_entry, &camsys_sensor_ctrl->camsys_state_list,
+			    state_element) {
+		state_req = mtk_cam_ctrl_state_get_req(state_entry);
+		s_data = mtk_cam_ctrl_state_to_req_s_data(state_entry);
+		if (s_data->frame_seq_no == dequeued_frame_seq_no) {
+			state_transition(state_entry,
+					 E_STATE_INNER_HW_DELAY, E_STATE_DONE_MISMATCH);
+			state_transition(state_entry,
+					 E_STATE_INNER, E_STATE_DONE_NORMAL);
+			if (atomic_read(&camsys_sensor_ctrl->isp_request_seq_no) == 0)
+				state_transition(state_entry,
+						 E_STATE_CQ, E_STATE_OUTER);
+
+			dev_dbg(cam->dev,
+				"[SWD] req:%d/state:%d/time:%lld/sync_id:%lld\n",
+				s_data->frame_seq_no, state_entry->estate,
+				s_data->timestamp, state_req->sync_id);
+		}
+	}
+	spin_unlock(&camsys_sensor_ctrl->camsys_state_lock);
+
+	return true;
+}
+
+static void mtk_cam_handle_frame_done(struct mtk_cam_ctx *ctx,
+				      unsigned int frame_seq_no,
+				      unsigned int pipe_id)
+{
+	struct mtk_raw_device *raw_dev;
+	bool need_dequeue;
+
+	/**
+	 * If ctx is already off, just return; mtk_cam_dev_req_cleanup()
+	 * triggered by mtk_cam_vb2_stop_streaming() puts the all media
+	 * requests back.
+	 */
+	spin_lock(&ctx->streaming_lock);
+	if (!ctx->streaming) {
+		dev_info(ctx->cam->dev,
+			 "%s: skip frame done for stream off ctx:%d\n",
+			 __func__, ctx->stream_id);
+		spin_unlock(&ctx->streaming_lock);
+		return;
+	}
+	spin_unlock(&ctx->streaming_lock);
+	raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe);
+	if (!raw_dev) {
+		dev_err(ctx->cam->dev, "%s: not found raw device\n", __func__);
+		return;
+	}
+
+	need_dequeue =
+		mtk_camsys_raw_prepare_frame_done(raw_dev, ctx, frame_seq_no);
+
+	if (!need_dequeue)
+		return;
+
+	dev_dbg(ctx->cam->dev, "[%s] job done ctx-%d:pipe-%d:req(%d)\n",
+		__func__, ctx->stream_id, pipe_id, frame_seq_no);
+	if (mtk_cam_dequeue_req_frame(ctx, frame_seq_no, pipe_id)) {
+		mutex_lock(&ctx->cam->queue_lock);
+		mtk_cam_dev_req_try_queue(ctx->cam);
+		mutex_unlock(&ctx->cam->queue_lock);
+	}
+}
+
+void mtk_cam_meta1_done_work(struct work_struct *work)
+{
+	struct mtk_cam_req_work *meta1_done_work =
+		(struct mtk_cam_req_work *)work;
+	struct mtk_cam_request_stream_data *s_data, *s_data_ctx;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request *req;
+	struct mtk_cam_buffer *buf;
+	struct vb2_buffer *vb;
+	void *vaddr;
+	bool unreliable = false;
+
+	s_data = mtk_cam_req_work_get_s_data(meta1_done_work);
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	req = mtk_cam_s_data_get_req(s_data);
+	s_data_ctx = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
+
+	dev_dbg(ctx->cam->dev, "%s: ctx:%d\n", __func__, ctx->stream_id);
+
+	spin_lock(&ctx->streaming_lock);
+	if (!ctx->streaming) {
+		spin_unlock(&ctx->streaming_lock);
+		dev_info(ctx->cam->dev, "%s: skip for stream off ctx:%d\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+	spin_unlock(&ctx->streaming_lock);
+
+	if (!s_data) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get s_data\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	/* Copy the meta1 output content to user buffer */
+	buf = mtk_cam_s_data_get_vbuf(s_data, MTK_RAW_META_OUT_1);
+	if (!buf) {
+		dev_info(ctx->cam->dev,
+			 "ctx(%d): can't get MTK_RAW_META_OUT_1 buf from req(%d)\n",
+			 ctx->stream_id, s_data->frame_seq_no);
+		return;
+	}
+
+	vb = &buf->vbb.vb2_buf;
+	if (!vb) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get vb2 buf\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	vaddr = vb2_plane_vaddr(&buf->vbb.vb2_buf, 0);
+	if (!vaddr) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get plane_vadd\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	/* Update the timestamp for the buffer*/
+	mtk_cam_s_data_update_timestamp(buf, s_data_ctx);
+
+	/* clean the stream data for req reinit case */
+	mtk_cam_s_data_reset_vbuf(s_data, MTK_RAW_META_OUT_1);
+
+	/* Let user get the buffer */
+	if (unreliable)
+		vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR);
+	else
+		vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_DONE);
+
+	dev_dbg(ctx->cam->dev, "%s:%s: req(%d) done\n",
+		__func__, req->req.debug_str, s_data->frame_seq_no);
+}
+
+static void mtk_cam_meta1_done(struct mtk_cam_ctx *ctx,
+			       unsigned int frame_seq_no,
+			       unsigned int pipe_id)
+{
+	struct mtk_cam_request *req;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_cam_req_work *meta1_done_work;
+
+	req = mtk_cam_get_req(ctx, frame_seq_no);
+	if (!req) {
+		dev_info(ctx->cam->dev, "%s:ctx-%d:pipe-%d:req(%d) not found!\n",
+			 __func__, ctx->stream_id, pipe_id, frame_seq_no);
+		return;
+	}
+
+	req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0);
+	if (!req_stream_data) {
+		dev_info(ctx->cam->dev, "%s:ctx-%d:pipe-%d:s_data not found!\n",
+			 __func__, ctx->stream_id, pipe_id);
+		return;
+	}
+
+	if (!(req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT))
+		return;
+
+	meta1_done_work = &req_stream_data->meta1_done_work;
+	atomic_set(&meta1_done_work->is_queued, 1);
+	queue_work(ctx->frame_done_wq, &meta1_done_work->work);
+}
+
+void mtk_cam_frame_done_work(struct work_struct *work)
+{
+	struct mtk_cam_req_work *frame_done_work =
+		(struct mtk_cam_req_work *)work;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_cam_ctx *ctx;
+
+	req_stream_data = mtk_cam_req_work_get_s_data(frame_done_work);
+	ctx = mtk_cam_s_data_get_ctx(req_stream_data);
+
+	mtk_cam_handle_frame_done(ctx,
+					req_stream_data->frame_seq_no,
+					req_stream_data->pipe_id);
+}
+
+void mtk_camsys_frame_done(struct mtk_cam_ctx *ctx,
+			   unsigned int frame_seq_no,
+			   unsigned int pipe_id)
+{
+	struct mtk_cam_req_work *frame_done_work;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_cam_buffer *buf;
+	struct mtk_cam_working_buf_entry *buf_entry = NULL;
+	bool is_pending_buffer = false;
+
+	spin_lock(&ctx->cam->dma_processing_lock);
+	if (!list_empty(&ctx->cam->dma_processing)) {
+		buf = list_first_entry(&ctx->cam->dma_processing,
+				       struct mtk_cam_buffer, list);
+		list_del(&buf->list);
+		ctx->cam->dma_processing_count--;
+		vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_DONE);
+		is_pending_buffer = true;
+	}
+	spin_unlock(&ctx->cam->dma_processing_lock);
+	if (is_pending_buffer) {
+		spin_lock(&ctx->processing_buffer_list.lock);
+		if (!list_empty(&ctx->processing_buffer_list.list)) {
+			buf_entry =
+				list_first_entry(&ctx->processing_buffer_list.list,
+						 struct mtk_cam_working_buf_entry,
+						 list_entry);
+			list_del(&buf_entry->list_entry);
+			ctx->processing_buffer_list.cnt--;
+		}
+		spin_unlock(&ctx->processing_buffer_list.lock);
+		if (buf_entry)
+			mtk_cam_working_buf_put(buf_entry);
+
+		mtk_cam_buf_try_queue(ctx);
+		return;
+	}
+
+	req_stream_data = mtk_cam_get_req_s_data(ctx, pipe_id, frame_seq_no);
+	if (!req_stream_data) {
+		dev_err(ctx->cam->dev,
+			 "%s:ctx-%d:pipe-%d:req(%d) not found!\n",
+			 __func__, ctx->stream_id, pipe_id, frame_seq_no);
+		return;
+	}
+
+	if (atomic_read(&req_stream_data->frame_done_work.is_queued)) {
+		dev_info(ctx->cam->dev,
+			 "already queue done work req:%d seq:%d pipe_id:%d\n",
+			 req_stream_data->frame_seq_no, frame_seq_no, pipe_id);
+		return;
+	}
+
+	atomic_set(&req_stream_data->frame_done_work.is_queued, 1);
+	frame_done_work = &req_stream_data->frame_done_work;
+	queue_work(ctx->frame_done_wq, &frame_done_work->work);
+}
+
+void mtk_camsys_state_delete(struct mtk_cam_ctx *ctx,
+			     struct mtk_camsys_sensor_ctrl *sensor_ctrl,
+			     struct mtk_cam_request *req)
+{
+	struct mtk_camsys_ctrl_state *state_entry, *state_entry_prev;
+	struct mtk_cam_request_stream_data *s_data;
+	struct mtk_camsys_ctrl_state *req_state;
+	int state_found = 0;
+
+	if (ctx->sensor) {
+		spin_lock(&sensor_ctrl->camsys_state_lock);
+		list_for_each_entry_safe(state_entry, state_entry_prev,
+					 &sensor_ctrl->camsys_state_list,
+					 state_element) {
+			s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
+			req_state = &s_data->state;
+
+			if (state_entry == req_state) {
+				list_del(&state_entry->state_element);
+				state_found = 1;
+			}
+		}
+		spin_unlock(&sensor_ctrl->camsys_state_lock);
+		if (state_found == 0)
+			dev_dbg(ctx->cam->dev, "state not found\n");
+	}
+}
+
+static bool mtk_camsys_is_all_cq_done(struct mtk_cam_ctx *ctx,
+				      unsigned int pipe_id)
+{
+	unsigned int all_subdevs = 0;
+	bool ret = false;
+
+	spin_lock(&ctx->first_cq_lock);
+	if (ctx->is_first_cq_done) {
+		ret = true;
+		spin_unlock(&ctx->first_cq_lock);
+		goto EXIT;
+	}
+
+	// update cq done status
+	ctx->cq_done_status |= (1 << pipe_id);
+
+	// check cq done status
+	if (ctx->used_raw_num)
+		all_subdevs |= (1 << ctx->pipe->id);
+	if ((ctx->cq_done_status & all_subdevs) == all_subdevs) {
+		ctx->is_first_cq_done = 1;
+		ret = true;
+	}
+	spin_unlock(&ctx->first_cq_lock);
+	dev_info(ctx->cam->dev,
+		 "[1st-CQD] all done:%d, pipe_id:%d (using raw:%d)\n",
+		 ctx->is_first_cq_done, pipe_id, ctx->used_raw_num);
+EXIT:
+	return ret;
+}
+
+static int mtk_camsys_event_handle_raw(struct mtk_cam_device *cam,
+				       unsigned int engine_id,
+				       struct mtk_camsys_irq_info *irq_info)
+{
+	struct mtk_raw_device *raw_dev;
+	struct mtk_cam_ctx *ctx;
+
+	raw_dev = dev_get_drvdata(cam->raw.devs[engine_id]);
+	ctx = mtk_cam_find_ctx(cam, &raw_dev->pipeline->subdev.entity);
+	if (!ctx) {
+		dev_err(raw_dev->dev, "cannot find ctx\n");
+		return -EINVAL;
+	}
+
+	/* raw's CQ done */
+	if (irq_info->irq_type & 1 << CAMSYS_IRQ_SETTING_DONE) {
+		if (mtk_camsys_is_all_cq_done(ctx, ctx->pipe->id))
+				mtk_camsys_raw_cq_done(raw_dev, ctx,
+						       irq_info->frame_idx);
+	}
+
+	/* raw's DMA done, we only allow AFO done here */
+	if (irq_info->irq_type & 1 << CAMSYS_IRQ_AFO_DONE)
+		mtk_cam_meta1_done(ctx, ctx->dequeued_frame_seq_no, ctx->stream_id);
+
+	/* raw's SW done */
+	if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_DONE) {
+		mtk_camsys_frame_done(ctx, ctx->dequeued_frame_seq_no,
+						ctx->stream_id);
+	}
+	/* raw's SOF */
+	if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_START) {
+		if (atomic_read(&raw_dev->vf_en) == 0) {
+			dev_info(raw_dev->dev, "skip sof event when vf off\n");
+			return 0;
+		}
+		mtk_camsys_raw_frame_start(raw_dev, ctx, irq_info);
+	}
+
+	return 0;
+}
+
+int mtk_camsys_isr_event(struct mtk_cam_device *cam,
+			 unsigned int engine_id,
+			 struct mtk_camsys_irq_info *irq_info)
+{
+	int ret = 0;
+
+	ret = mtk_camsys_event_handle_raw(cam, engine_id, irq_info);
+
+	return ret;
+}
+
+void mtk_cam_initial_sensor_setup(struct mtk_cam_request *initial_req,
+				  struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_cam_request_stream_data *req_stream_data;
+
+	sensor_ctrl->ctx = ctx;
+	req_stream_data = mtk_cam_req_get_s_data(initial_req, ctx->stream_id, 0);
+	req_stream_data->ctx = ctx;
+	mtk_cam_set_sensor_full(req_stream_data, &ctx->sensor_ctrl);
+	dev_info(ctx->cam->dev, "Directly setup sensor req:%d\n",
+		 req_stream_data->frame_seq_no);
+}
+
+static void mtk_cam_complete_hdl(struct mtk_cam_request_stream_data *s_data,
+				 struct media_request_object *hdl_obj,
+				 char *name)
+{
+	char *debug_str;
+	u64 start, cost;
+
+	debug_str = mtk_cam_s_data_get_dbg_str(s_data);
+
+	start = ktime_get_boottime_ns();
+	if (hdl_obj->ops)
+		hdl_obj->ops->unbind(hdl_obj);	/* mutex used */
+	else
+		pr_info("%s:%s:pipe(%d):seq(%d): cannot unbind %s hd\n",
+			__func__, debug_str, s_data->pipe_id,
+			s_data->frame_seq_no, name);
+
+	cost = ktime_get_boottime_ns() - start;
+	if (cost > 1000000)
+		pr_info("%s:%s:pipe(%d):seq(%d): complete hdl:%s, cost:%llu ns\n",
+			__func__, debug_str, s_data->pipe_id,
+			s_data->frame_seq_no, name, cost);
+	else
+		pr_debug("%s:%s:pipe(%d):seq(%d): complete hdl:%s, cost:%llu ns\n",
+			 __func__, debug_str, s_data->pipe_id,
+			 s_data->frame_seq_no, name, cost);
+
+	media_request_object_complete(hdl_obj);
+}
+
+void mtk_cam_complete_sensor_hdl(struct mtk_cam_request_stream_data *s_data)
+{
+	if (s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN &&
+	    !(s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE) &&
+	    s_data->sensor_hdl_obj) {
+		mtk_cam_complete_hdl(s_data, s_data->sensor_hdl_obj, "sensor");
+		s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE;
+	}
+}
+
+void mtk_cam_complete_raw_hdl(struct mtk_cam_request_stream_data *s_data)
+{
+	if ((s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN) &&
+	    !(s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE) &&
+	    s_data->raw_hdl_obj) {
+		mtk_cam_complete_hdl(s_data, s_data->raw_hdl_obj, "raw");
+		s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE;
+	}
+}
+
+void mtk_cam_req_ctrl_setup(struct mtk_raw_pipeline *raw_pipe,
+			    struct mtk_cam_request *req)
+{
+	struct mtk_cam_request_stream_data *req_stream_data;
+
+	req_stream_data = mtk_cam_req_get_s_data(req, raw_pipe->id, 0);
+
+	/* request setup*/
+	if (req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN &&
+	    !(req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE) &&
+	    req_stream_data->raw_hdl_obj) {
+		dev_dbg(raw_pipe->subdev.v4l2_dev->dev,
+			"%s:%s:%s:raw ctrl set start (seq:%d)\n",
+			__func__, raw_pipe->subdev.name, req->req.debug_str,
+			req_stream_data->frame_seq_no);
+		v4l2_ctrl_request_setup(&req->req, &raw_pipe->ctrl_handler);
+
+		mtk_cam_complete_raw_hdl(req_stream_data);
+	}
+}
+
+static int timer_reqdrained_chk(int fps_ratio)
+{
+	int timer_ms = 0;
+
+	if (fps_ratio > 1)
+		timer_ms = SENSOR_SET_DEADLINE_MS / fps_ratio;
+	else
+		timer_ms = SENSOR_SET_DEADLINE_MS;
+	/* earlier request drained event*/
+	if (fps_ratio > 1)
+		timer_ms = SENSOR_SET_DEADLINE_MS_60FPS;
+
+	return timer_ms;
+}
+
+static int timer_setsensor(int fps_ratio)
+{
+	int timer_ms = 0;
+
+	if (fps_ratio > 1)
+		timer_ms = SENSOR_SET_RESERVED_MS / fps_ratio;
+	else
+		timer_ms = SENSOR_SET_RESERVED_MS;
+
+	/* faster sensor setting*/
+	if (fps_ratio > 1)
+		timer_ms = SENSOR_SET_RESERVED_MS_60FPS;
+
+	return timer_ms;
+}
+
+int mtk_camsys_ctrl_start(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl;
+	struct v4l2_subdev_frame_interval fi = {
+		.pad = 0,
+		.interval = {
+			.numerator = 1,
+			.denominator = 30
+		},
+	};
+	int fps_factor = 1;
+
+	if (ctx->used_raw_num) {
+		v4l2_subdev_call_state_active(ctx->sensor, pad, get_frame_interval, &fi);
+		fps_factor = (fi.interval.numerator > 0) ?
+			(fi.interval.denominator / fi.interval.numerator / 30) : 1;
+	}
+
+	camsys_sensor_ctrl->ctx = ctx;
+	atomic_set(&camsys_sensor_ctrl->sensor_enq_seq_no, 0);
+	atomic_set(&camsys_sensor_ctrl->sensor_request_seq_no, 0);
+	atomic_set(&camsys_sensor_ctrl->isp_request_seq_no, 0);
+	atomic_set(&camsys_sensor_ctrl->isp_enq_seq_no, 0);
+	atomic_set(&camsys_sensor_ctrl->last_drained_seq_no, 0);
+	camsys_sensor_ctrl->initial_cq_done = 0;
+	camsys_sensor_ctrl->sof_time = 0;
+	if (ctx->used_raw_num)
+		atomic_set(&camsys_sensor_ctrl->initial_drop_frame_cnt, 0);
+
+	camsys_sensor_ctrl->timer_req_event =
+		timer_reqdrained_chk(fps_factor);
+	camsys_sensor_ctrl->timer_req_sensor =
+		timer_setsensor(fps_factor);
+	INIT_LIST_HEAD(&camsys_sensor_ctrl->camsys_state_list);
+	spin_lock_init(&camsys_sensor_ctrl->camsys_state_lock);
+	if (ctx->sensor) {
+		hrtimer_init(&camsys_sensor_ctrl->sensor_deadline_timer,
+			     CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		camsys_sensor_ctrl->sensor_deadline_timer.function =
+			sensor_deadline_timer_handler;
+		camsys_sensor_ctrl->sensorsetting_wq = &ctx->sensor_worker;
+	}
+	kthread_init_work(&camsys_sensor_ctrl->work,
+			  mtk_cam_sensor_worker_in_sensorctrl);
+
+	dev_info(ctx->cam->dev,
+		 "[%s] ctx:%d/raw_dev:0x%x drained/sensor (%d)%d/%d\n",
+		 __func__, ctx->stream_id, ctx->used_raw_dev, fps_factor,
+		 camsys_sensor_ctrl->timer_req_event,
+		 camsys_sensor_ctrl->timer_req_sensor);
+
+	return 0;
+}
+
+void mtk_camsys_ctrl_update(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl;
+	struct v4l2_subdev_frame_interval fi = {
+		.pad = 0,
+		.interval = {
+			.numerator = 1,
+			.denominator = 30
+		},
+	};
+	int fps_factor = 1;
+
+	if (ctx->used_raw_num) {
+		fi.pad = 0;
+		v4l2_subdev_call_state_active(ctx->sensor, pad, get_frame_interval, &fi);
+		fps_factor = (fi.interval.numerator > 0) ?
+			(fi.interval.denominator / fi.interval.numerator / 30) : 1;
+	}
+
+	camsys_sensor_ctrl->timer_req_event =
+		timer_reqdrained_chk(fps_factor);
+	camsys_sensor_ctrl->timer_req_sensor =
+		timer_setsensor(fps_factor);
+
+	dev_info(ctx->cam->dev,
+		 "[%s] ctx:%d/raw_dev:0x%x drained/sensor (%d)%d/%d\n",
+		 __func__, ctx->stream_id, ctx->used_raw_dev, fps_factor,
+		 camsys_sensor_ctrl->timer_req_event,
+		 camsys_sensor_ctrl->timer_req_sensor);
+}
+
+void mtk_camsys_ctrl_stop(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_camsys_ctrl_state *state_entry, *state_entry_prev;
+
+	spin_lock(&camsys_sensor_ctrl->camsys_state_lock);
+	list_for_each_entry_safe(state_entry, state_entry_prev,
+				 &camsys_sensor_ctrl->camsys_state_list,
+				 state_element) {
+		list_del(&state_entry->state_element);
+	}
+	spin_unlock(&camsys_sensor_ctrl->camsys_state_lock);
+
+	if (ctx->sensor) {
+		hrtimer_cancel(&camsys_sensor_ctrl->sensor_deadline_timer);
+		camsys_sensor_ctrl->sensorsetting_wq = NULL;
+	}
+	kthread_flush_work(&camsys_sensor_ctrl->work);
+	if (ctx->used_raw_num)
+		mtk_cam_event_eos(ctx->pipe);
+
+	dev_info(ctx->cam->dev, "[%s] ctx:%d/raw_dev:0x%x\n",
+		 __func__, ctx->stream_id, ctx->used_raw_dev);
+}
\ No newline at end of file
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h
new file mode 100755
index 000000000000..c59e0241a706
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_CTRL_H
+#define __MTK_CAM_CTRL_H
+
+#include <linux/hrtimer.h>
+#include <linux/timer.h>
+
+struct mtk_cam_device;
+
+enum MTK_CAMSYS_IRQ_EVENT {
+	/* with normal_data */
+	CAMSYS_IRQ_SETTING_DONE = 0,
+	CAMSYS_IRQ_FRAME_START,
+	CAMSYS_IRQ_AFO_DONE,
+	CAMSYS_IRQ_FRAME_DONE,
+	CAMSYS_IRQ_SUBSAMPLE_SENSOR_SET,
+	CAMSYS_IRQ_FRAME_DROP,
+
+	/* with error_data */
+	CAMSYS_IRQ_ERROR,
+};
+
+struct mtk_camsys_irq_normal_data {
+	/* with normal_status */
+};
+
+struct mtk_camsys_irq_error_data {
+	/* with error_status */
+	int err_status;
+};
+
+struct mtk_camsys_irq_info {
+	enum MTK_CAMSYS_IRQ_EVENT irq_type;
+	u64 ts_ns;
+	int frame_idx;
+	int frame_idx_inner;
+	bool sub_engine;
+	int write_cnt;
+	int fbc_cnt;
+	union {
+		struct mtk_camsys_irq_normal_data n;
+		struct mtk_camsys_irq_error_data e;
+	};
+};
+
+enum MTK_CAMSYS_STATE_IDX {
+	/* For state analysis and controlling for request */
+	E_STATE_READY = 0x0,
+	E_STATE_SENINF,
+	E_STATE_SENSOR,
+	E_STATE_CQ,
+	E_STATE_OUTER,
+	E_STATE_CAMMUX_OUTER_CFG,
+	E_STATE_CAMMUX_OUTER,
+	E_STATE_INNER,
+	E_STATE_DONE_NORMAL,
+	E_STATE_CQ_SCQ_DELAY,
+	E_STATE_CAMMUX_OUTER_CFG_DELAY,
+	E_STATE_OUTER_HW_DELAY,
+	E_STATE_INNER_HW_DELAY,
+	E_STATE_DONE_MISMATCH,
+};
+
+struct mtk_camsys_ctrl_state {
+	enum MTK_CAMSYS_STATE_IDX estate;
+	struct list_head state_element;
+};
+
+struct mtk_camsys_link_ctrl {
+	struct mtk_raw_pipeline *pipe;
+	struct media_pad remote;
+	struct mtk_cam_ctx *swapping_ctx;
+	u8 active;
+	u8 wait_exchange;
+};
+
+/* per stream from sensor */
+struct mtk_camsys_sensor_ctrl {
+	struct mtk_cam_ctx *ctx;
+	struct kthread_worker *sensorsetting_wq;
+	struct kthread_work work;
+	struct hrtimer sensor_deadline_timer;
+	u64 sof_time;
+	int timer_req_sensor;
+	int timer_req_event;
+	atomic_t sensor_enq_seq_no;
+	atomic_t sensor_request_seq_no;
+	atomic_t isp_request_seq_no;
+	atomic_t isp_enq_seq_no;
+	atomic_t last_drained_seq_no;
+	int initial_cq_done;
+	atomic_t initial_drop_frame_cnt;
+	struct list_head camsys_state_list;
+	spinlock_t camsys_state_lock; /* protect camsys_state_list */
+	/* link change ctrl */
+	struct mtk_camsys_link_ctrl link_ctrl;
+	struct mtk_cam_request *link_change_req;
+};
+
+void mtk_camsys_state_delete(struct mtk_cam_ctx *ctx,
+			     struct mtk_camsys_sensor_ctrl *sensor_ctrl,
+			     struct mtk_cam_request *req);
+void mtk_camsys_frame_done(struct mtk_cam_ctx *ctx, unsigned int frame_seq_no,
+			   unsigned int pipe_id);
+int mtk_camsys_isr_event(struct mtk_cam_device *cam,
+			 unsigned int engine_id,
+			 struct mtk_camsys_irq_info *irq_info);
+bool mtk_cam_submit_kwork_in_sensorctrl(struct kthread_worker *worker,
+					struct mtk_camsys_sensor_ctrl *sensor_ctrl);
+void mtk_cam_initial_sensor_setup(struct mtk_cam_request *req,
+				  struct mtk_cam_ctx *ctx);
+void mtk_cam_req_ctrl_setup(struct mtk_raw_pipeline *raw_pipe,
+			    struct mtk_cam_request *req);
+int mtk_camsys_ctrl_start(struct mtk_cam_ctx *ctx); /* ctx_stream_on */
+void mtk_camsys_ctrl_update(struct mtk_cam_ctx *ctx);
+void mtk_camsys_ctrl_stop(struct mtk_cam_ctx *ctx); /* ctx_stream_off */
+void mtk_cam_frame_done_work(struct work_struct *work);
+void mtk_cam_meta1_done_work(struct work_struct *work);
+void mtk_cam_set_sensor_full(struct mtk_cam_request_stream_data *s_data,
+			     struct mtk_camsys_sensor_ctrl *sensor_ctrl);
+void state_transition(struct mtk_camsys_ctrl_state *state_entry,
+		      enum MTK_CAMSYS_STATE_IDX from,
+		      enum MTK_CAMSYS_STATE_IDX to);
+void mtk_cam_set_sensor_switch(struct mtk_cam_request_stream_data *s_data,
+			       struct mtk_camsys_sensor_ctrl *sensor_ctrl);
+
+#endif /* __MTK_CAM_CTRL_H */
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (5 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-15  4:07   ` CK Hu (胡俊光)
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduces the ISP pipeline driver for the MediaTek ISP raw and yuv
modules. Key functionalities include data processing, V4L2 integration,
resource management, debug support, and various control operations.
Additionally, IRQ handling, platform device management, and MediaTek
ISP DMA format support are also included.

Changes in v2:

- Removed mtk_cam-raw.c and mtk_cam-raw.h, along with related code
- Removed M2M related code
- Various fixes per review comments

Question for CK

Hi CK,

May I ask if it is acceptable to keep the id field for the following reason?
When there is more than one RAW engine on the platform, having an id makes it
much easier to manage and coordinate different RAW pipelines. It allows us to
correctly associate events and interrupts with the corresponding RAW device
context, which improves code maintainability and scalability.

Would you agree with keeping the id for this purpose, or do you have a preferred
alternative?

Explanation:

Reply to CK: "Remove resource calculation related code"

Thank you for your suggestion. The resource calculation code is retained even
for the unprocessed IMGO path. All image streams, including IMGO unprocessed,
pass through the raw pipeline and require proper ISP hardware configuration.

Reply to CK: "It seems yuv is an independent function. If so, separate yuv
function to an independent patch."

Thank you for your comment. The raw and yuv functions are not separated into
independent patches because, in our hardware design, both are handled by the
same hardware block and share the same register set. The yuv function is just a
different mode of operation within the same unit, not an independent hardware
module. Splitting them would not reflect the actual hardware architecture and
could make the code harder to maintain.

Please let me know if you have any further suggestions. Thank you!

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.c  | 4883 +++++++++++++++++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.h  |  323 ++
 .../isp_7x/camsys/mtk_camera-v4l2-controls.h  |   63 +
 3 files changed, 5269 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h

diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c
new file mode 100755
index 000000000000..e12271f56ce2
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c
@@ -0,0 +1,4883 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/suspend.h>
+#include <linux/rtc.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+
+#include <soc/mediatek/smi.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-raw.h"
+
+#include "mtk_cam-regs-mt8188.h"
+
+#include "mtk_cam-video.h"
+#include "mtk_cam-seninf-if.h"
+#include "mtk_camera-v4l2-controls.h"
+
+#define MTK_RAW_STOP_HW_TIMEOUT		(33)
+
+#define MTK_CAMSYS_RES_IDXMASK		0xF0
+#define MTK_CAMSYS_RES_BIN_TAG		0x10
+#define MTK_CAMSYS_RES_FRZ_TAG		0x20
+#define MTK_CAMSYS_RES_HWN_TAG		0x30
+#define MTK_CAMSYS_RES_CLK_TAG		0x40
+
+#define MTK_CAMSYS_RES_PLAN_NUM		10
+#define FRZ_PXLMODE_THRES		71
+#define MHz				1000000
+
+/* ISP7_1 */
+#define TGO_MAX_PXLMODE				1
+#define MTK_CAMSYS_PROC_DEFAULT_PIXELMODE	1
+#define sizeof_u32(__struct__) ((sizeof(__struct__) + sizeof(u32) - 1) / \
+				sizeof(u32))
+
+enum MTK_CAMSYS_RES_STEP {
+	E_RES_BASIC,
+	E_RES_BIN_S = MTK_CAMSYS_RES_BIN_TAG,
+	E_RES_BIN0 = E_RES_BIN_S,
+	E_RES_BIN1,
+	E_RES_BIN_E,
+	E_RES_FRZ_S = MTK_CAMSYS_RES_FRZ_TAG,
+	E_RES_FRZ0 = E_RES_FRZ_S,
+	E_RES_FRZ1,
+	E_RES_FRZ_E,
+	E_RES_HWN_S = MTK_CAMSYS_RES_HWN_TAG,
+	E_RES_HWN0 = E_RES_HWN_S,
+	E_RES_HWN1,
+	E_RES_HWN2,
+	E_RES_HWN_E,
+	E_RES_CLK_S = MTK_CAMSYS_RES_CLK_TAG,
+	E_RES_CLK0 = E_RES_CLK_S,
+	E_RES_CLK1,
+	E_RES_CLK2,
+	E_RES_CLK3,
+};
+
+enum MTK_CAMSYS_MAXLB_CHECK_RESULT {
+	LB_CHECK_OK = 0,
+	LB_CHECK_CBN,
+	LB_CHECK_QBN,
+	LB_CHECK_BIN,
+	LB_CHECK_FRZ,
+	LB_CHECK_TWIN,
+	LB_CHECK_RAW,
+};
+
+#define CAM_RAW_PROCESS_MAX_LINE_BUFFER		(6632)
+#define CAM_RAW_FRZ_MAX_LINE_BUFFER		(6632)
+#define CAM_RAW_BIN_MAX_LINE_BUFFER		(12000)
+#define CAM_RAW_QBND_MAX_LINE_BUFFER		(16000)
+#define CAM_RAW_CBN_MAX_LINE_BUFFER		(18472)
+#define CAM_TWIN_PROCESS_MAX_LINE_BUFFER	(12400)
+
+struct cam_resource_plan {
+	int cam_resource[MTK_CAMSYS_RES_STEP_NUM];
+};
+
+enum resource_strategy_id {
+	RESOURCE_STRATEGY_QPR = 0,
+	RESOURCE_STRATEGY_PQR,
+	RESOURCE_STRATEGY_RPQ,
+	RESOURCE_STRATEGY_QRP,
+	RESOURCE_STRATEGY_NUMBER
+};
+
+static const struct cam_resource_plan raw_resource_strategy_plan[] = {
+	[RESOURCE_STRATEGY_QPR] = {
+		.cam_resource = {
+			E_RES_BASIC, E_RES_HWN1, E_RES_CLK1, E_RES_CLK2,
+			E_RES_CLK3, E_RES_FRZ1, E_RES_BIN1, E_RES_HWN2} },
+	[RESOURCE_STRATEGY_PQR] = {
+		.cam_resource = {
+			E_RES_BASIC, E_RES_HWN1, E_RES_HWN2, E_RES_FRZ1,
+			E_RES_BIN1, E_RES_CLK1, E_RES_CLK2, E_RES_CLK3} },
+	[RESOURCE_STRATEGY_RPQ] = {
+		.cam_resource = {
+			E_RES_BASIC, E_RES_FRZ1, E_RES_BIN1, E_RES_CLK1,
+			E_RES_CLK2, E_RES_CLK3, E_RES_HWN1, E_RES_HWN2} },
+	[RESOURCE_STRATEGY_QRP] = {
+		.cam_resource = {
+			E_RES_BASIC, E_RES_CLK1, E_RES_CLK2, E_RES_CLK3,
+			E_RES_HWN1, E_RES_HWN2, E_RES_FRZ1, E_RES_BIN1} },
+};
+
+static const struct v4l2_mbus_framefmt mfmt_default = {
+	.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+	.width = DEFAULT_WIDTH,
+	.height = DEFAULT_HEIGHT,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+	.xfer_func = V4L2_XFER_FUNC_DEFAULT,
+	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+	.quantization = V4L2_QUANTIZATION_DEFAULT,
+};
+
+static bool mtk_cam_raw_resource_calc(struct mtk_cam_device *cam,
+				      struct mtk_cam_resource_config *res,
+				      s64 pixel_rate, int res_plan, int in_w,
+				      int in_h, int *out_w, int *out_h);
+
+static int mtk_cam_raw_res_copy_fmt_from_user(struct mtk_raw_pipeline *pipeline,
+					      struct mtk_cam_resource *res_user,
+					      struct v4l2_mbus_framefmt *dest)
+{
+	long bytes;
+	struct device *dev = pipeline->raw->devs[pipeline->id];
+
+	if (!res_user->sink_fmt) {
+		dev_err(dev,
+			"%s:pipe(%d): sink_fmt can't be NULL for res ctrl\n",
+			__func__, pipeline->id);
+
+		return -EINVAL;
+	}
+
+	bytes = copy_from_user(dest, (void __user *)res_user->sink_fmt,
+			       sizeof(*dest));
+	if (bytes) {
+		dev_err(dev,
+			"%s:pipe(%d): copy_from_user on sink_fmt failed (%ld)\n",
+			__func__, pipeline->id, bytes);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_cam_raw_res_copy_fmt_to_user(struct mtk_raw_pipeline *pipeline,
+					    struct mtk_cam_resource *res_user,
+					    struct v4l2_mbus_framefmt *src)
+{
+	long bytes;
+	struct device *dev = pipeline->raw->devs[pipeline->id];
+
+	/* return the fmt to the users */
+	bytes = copy_to_user((void __user *)res_user->sink_fmt, src, sizeof(*src));
+	if (bytes) {
+		dev_err(dev,
+			"%s:pipe(%d): copy_to_user on sink_fmt failed (%ld)\n",
+			__func__, pipeline->id, bytes);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_cam_raw_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_cam_resource *user_res;
+	struct mtk_raw_pipeline *pipeline;
+	struct device *dev;
+	int ret = 0;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	dev = pipeline->raw->devs[pipeline->id];
+
+	if (ctrl->id == V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC) {
+		user_res = (struct mtk_cam_resource *)ctrl->p_new.p;
+		user_res->sensor_res = pipeline->user_res.sensor_res;
+		user_res->raw_res = pipeline->user_res.raw_res;
+		if (user_res->sink_fmt)
+			ret = mtk_cam_raw_res_copy_fmt_to_user(pipeline,
+							       user_res,
+							       (struct v4l2_mbus_framefmt *)
+							       pipeline->user_res.sink_fmt);
+	} else if (ctrl->id == V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE) {
+		ctrl->val = pipeline->sensor_mode_update;
+		dev_info(dev,
+			 "%s:pipe(%d): V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: %d\n",
+			 __func__, pipeline->id, pipeline->sensor_mode_update);
+	} else if (ctrl->id >= V4L2_CID_MTK_CAM_USED_ENGINE_TRY &&
+		   ctrl->id <= V4L2_CID_MTK_CAM_FRZ_TRY) {
+		/**
+		 * Read the determined resource for the "try" format
+		 * negotiation result
+		 */
+		mutex_lock(&pipeline->try_res_config.resource_lock);
+		switch (ctrl->id) {
+		case V4L2_CID_MTK_CAM_USED_ENGINE_TRY:
+			ctrl->val = pipeline->try_res_config.raw_num_used;
+			break;
+		case V4L2_CID_MTK_CAM_BIN_TRY:
+			ctrl->val = pipeline->try_res_config.bin_enable;
+			break;
+		case V4L2_CID_MTK_CAM_FRZ_TRY:
+			ctrl->val = pipeline->try_res_config.frz_enable ?
+				    pipeline->try_res_config.frz_ratio : 100;
+			break;
+		default:
+			dev_info(dev,
+				 "%s:pipe(%d): unknown resource CID: %d\n",
+				 __func__, pipeline->id, ctrl->id);
+			break;
+		}
+		mutex_unlock(&pipeline->try_res_config.resource_lock);
+	} else if (ctrl->id == V4L2_CID_MTK_CAM_SYNC_ID) {
+		mutex_lock(&pipeline->res_config.resource_lock);
+		*ctrl->p_new.p_s64 = pipeline->sync_id;
+		mutex_unlock(&pipeline->res_config.resource_lock);
+	} else {
+		/**
+		 * Read the determined resource for the "set" format
+		 * negotiations result
+		 */
+		mutex_lock(&pipeline->res_config.resource_lock);
+		switch (ctrl->id) {
+		case V4L2_CID_MTK_CAM_USED_ENGINE:
+			ctrl->val = pipeline->res_config.raw_num_used;
+			break;
+		case V4L2_CID_MTK_CAM_BIN_LIMIT:
+			ctrl->val = pipeline->res_config.bin_limit;
+			break;
+		case V4L2_CID_MTK_CAM_BIN:
+			ctrl->val = pipeline->res_config.bin_enable;
+			break;
+		case V4L2_CID_MTK_CAM_FRZ:
+			ctrl->val = pipeline->res_config.frz_enable ?
+				    pipeline->res_config.frz_ratio : 100;
+			break;
+		default:
+			dev_info(dev,
+				 "%s:pipe(%d): unknown try resource CID: %d\n",
+				 __func__, pipeline->id, ctrl->id);
+			break;
+		}
+		mutex_unlock(&pipeline->res_config.resource_lock);
+	}
+
+	dev_dbg(dev, "%s:pipe(%d):id(%s) val(%d)\n",
+		__func__, pipeline->id, ctrl->name, ctrl->val);
+	return ret;
+}
+
+static int mtk_cam_raw_res_store(struct mtk_raw_pipeline *pipeline,
+				 struct mtk_cam_resource *res_user)
+{
+	struct device *dev = pipeline->raw->devs[pipeline->id];
+
+	dev_info(dev,
+		 "%s:pipe(%d): from user: sensor:%d/%d/%lld/%lld/%d/%d, raw:%lld/%d/%d/%d/%d/%d/%d/%d/%lld\n",
+		 __func__, pipeline->id,
+		 res_user->sensor_res.hblank, res_user->sensor_res.vblank,
+		 res_user->sensor_res.pixel_rate,
+		 res_user->sensor_res.cust_pixel_rate,
+		 res_user->sensor_res.interval.denominator,
+		 res_user->sensor_res.interval.numerator,
+		 res_user->raw_res.feature, res_user->raw_res.bin,
+		 res_user->raw_res.path_sel, res_user->raw_res.raw_max,
+		 res_user->raw_res.raw_min, res_user->raw_res.raw_used,
+		 res_user->raw_res.strategy, res_user->raw_res.pixel_mode,
+		 res_user->raw_res.throughput);
+
+	/* check user value of sensor input parameters */
+	if ( !res_user->sensor_res.pixel_rate || !res_user->sensor_res.hblank ||
+	     !res_user->sensor_res.vblank ||
+	     !res_user->sensor_res.interval.denominator ||
+	     !res_user->sensor_res.interval.numerator) {
+		dev_info(dev,
+			 "%s:pipe(%d): sensor info MUST be provided (TEST_PATTERN case)\n",
+			 __func__, pipeline->id);
+		/*test pattern case resource default copy*/
+		pipeline->res_config.raw_num_used = 1;
+		pipeline->res_config.bin_enable = 0;
+		pipeline->res_config.tgo_pxl_mode = 1;
+		pipeline->res_config.raw_path = 0;
+		pipeline->res_config.hwn_limit_min = 1;
+		pipeline->res_config.raw_feature = res_user->raw_res.feature;
+		pipeline->feature_pending = res_user->raw_res.feature;
+		pipeline->feature_active = res_user->raw_res.feature;
+	}
+
+	/* check user value of raw input parameters */
+	if (res_user->raw_res.feature == 0xFFFFFFFF)
+		res_user->raw_res.feature = 0;
+
+	if (res_user->raw_res.bin == 0xFF)
+		res_user->raw_res.bin = 0;
+
+	if (res_user->raw_res.strategy == 0xFFFF)
+		res_user->raw_res.strategy = RESOURCE_STRATEGY_QRP;
+
+	if (res_user->raw_res.raw_max == 0xFF)
+		res_user->raw_res.raw_max = 2;
+
+	if (res_user->raw_res.raw_min == 0xFF)
+		res_user->raw_res.raw_min = 1;
+
+	if (res_user->raw_res.raw_min > 1)
+		res_user->raw_res.strategy = RESOURCE_STRATEGY_QPR;
+
+	if (res_user->raw_res.path_sel == 0xFF)
+		res_user->raw_res.path_sel = 0;
+
+	dev_info(dev,
+		 "%s:pipe(%d): driver adjusted: raw:%lld/%d/%d/%d/%d/%d/%d/%d/%lld\n",
+		 __func__, pipeline->id,
+		 res_user->raw_res.feature, res_user->raw_res.bin,
+		 res_user->raw_res.path_sel, res_user->raw_res.raw_max,
+		 res_user->raw_res.raw_min, res_user->raw_res.raw_used,
+		 res_user->raw_res.strategy, res_user->raw_res.pixel_mode,
+		 res_user->raw_res.throughput);
+
+	return 0;
+}
+
+static int mtk_cam_raw_try_res_ctrl(struct mtk_raw_pipeline *pipeline,
+				    struct mtk_cam_resource *res_user,
+				    struct mtk_cam_resource_config *res_cfg,
+				    struct v4l2_mbus_framefmt *sink_fmt)
+{
+	s64 prate = 0;
+	int width, height;
+	struct device *dev = pipeline->raw->devs[pipeline->id];
+
+	res_cfg->bin_limit = res_user->raw_res.bin; /* 1: force bin on */
+	res_cfg->frz_limit = 0;
+	res_cfg->hwn_limit_max = res_user->raw_res.raw_max;
+	res_cfg->hwn_limit_min = res_user->raw_res.raw_min;
+	res_cfg->hblank = res_user->sensor_res.hblank;
+	res_cfg->vblank = res_user->sensor_res.vblank;
+	res_cfg->sensor_pixel_rate = res_user->sensor_res.pixel_rate;
+	res_cfg->res_plan = res_user->raw_res.strategy;
+	res_cfg->raw_feature = res_user->raw_res.feature;
+	res_cfg->raw_path = res_user->raw_res.path_sel;
+
+	if (res_user->sensor_res.cust_pixel_rate)
+		prate = res_user->sensor_res.cust_pixel_rate;
+	else
+		prate = mtk_cam_seninf_calc_pixelrate(pipeline->raw->cam_dev,
+						      sink_fmt->width,
+						      sink_fmt->height,
+						      res_user->sensor_res.hblank,
+						      res_user->sensor_res.vblank,
+						      res_user->sensor_res.interval.denominator,
+						      res_user->sensor_res.interval.numerator,
+						      res_user->sensor_res.pixel_rate);
+
+	mtk_cam_raw_resource_calc(dev_get_drvdata(pipeline->raw->cam_dev),
+				  res_cfg, prate, res_cfg->res_plan,
+				  sink_fmt->width, sink_fmt->height,
+				  &width, &height);
+
+	if (res_user->raw_res.bin && !res_cfg->bin_enable) {
+		dev_err(dev,
+			"%s:pipe(%d): res calc failed on fource bin: user(%d)/bin_enable(%d)\n",
+			__func__, pipeline->id,	res_user->raw_res.bin,
+			res_cfg->bin_enable);
+		return -EINVAL;
+	}
+
+	if (res_cfg->raw_num_used > res_user->raw_res.raw_max ||
+	    res_cfg->raw_num_used < res_user->raw_res.raw_min) {
+		dev_err(dev,
+			"%s:pipe(%d): res calc failed on raw used: user(%d/%d)/raw_num_used(%d)\n",
+			__func__, pipeline->id, res_user->raw_res.raw_max,
+			res_user->raw_res.raw_min, res_cfg->raw_num_used);
+	}
+
+	res_user->raw_res.pixel_mode = res_cfg->tgo_pxl_mode;
+	res_user->raw_res.raw_used = res_cfg->raw_num_used;
+	if (res_cfg->bin_limit == BIN_AUTO)
+		res_user->raw_res.bin = res_cfg->bin_enable;
+	else
+		res_user->raw_res.bin = res_cfg->bin_limit;
+
+	dev_info(dev,
+		 "%s:pipe(%d): res calc result: raw_used(%d)/bin(%d)/pixelmode(%d)/strategy(%d)\n",
+		 __func__, pipeline->id, res_user->raw_res.raw_used,
+		 res_user->raw_res.bin, res_user->raw_res.pixel_mode,
+		 res_user->raw_res.strategy);
+
+	/**
+	 * Other output not reveal to user:
+	 * res_cfg->res_strategy[MTK_CAMSYS_RES_STEP_NUM];
+	 * res_cfg->clk_target;
+	 * res_cfg->frz_enable;
+	 * res_cfg->frz_ratio;
+	 * res_cfg->tgo_pxl_mode;
+	 */
+	if (width != sink_fmt->width || height != sink_fmt->height) {
+		dev_info(dev,
+			 "%s:pipe(%d): size adjust info: raw: sink(%d,%d) res:(%d,%d)\n",
+			__func__, pipeline->id, sink_fmt->width,
+			sink_fmt->height, width, height);
+	}
+
+	return 0;
+}
+
+static int mtk_cam_raw_set_res_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_raw_pipeline *pipeline;
+	struct mtk_cam_resource *res_user;
+	struct v4l2_mbus_framefmt sink_fmt;
+	struct device *dev;
+	int ret = 0;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	dev = pipeline->raw->devs[pipeline->id];
+	res_user = (struct mtk_cam_resource *)ctrl->p_new.p;
+
+	ret = mtk_cam_raw_res_store(pipeline, res_user);
+	pipeline->user_res = *res_user;
+	if (media_entity_is_streaming(&pipeline->subdev.entity)) {
+		/* If the pipeline is streaming, pending the change */
+		dev_dbg(dev,
+			"%s:pipe(%d): pending res calc has not been supported except bin\n",
+			__func__, pipeline->id);
+		return ret;
+	}
+
+	dev_dbg(dev,
+		"%s:pipe(%d):streaming(%d), feature_pending(0x%llx), raw_res.feature(0x%llx), feature_active(0x%llx)\n",
+		__func__, pipeline->id,
+		media_entity_is_streaming(&pipeline->subdev.entity),
+		pipeline->feature_pending, pipeline->user_res.raw_res.feature,
+		pipeline->feature_active);
+
+	ret = mtk_cam_raw_res_copy_fmt_from_user(pipeline, res_user, &sink_fmt);
+	if (ret)
+		return ret;
+
+	pipeline->res_config.sink_fmt = sink_fmt;
+	ret = mtk_cam_raw_try_res_ctrl(pipeline, res_user,
+				       &pipeline->res_config, &sink_fmt);
+
+	if (ret)
+		return -EINVAL;
+
+	return ret;
+}
+
+static int mtk_raw_set_res_ctrl(struct device *dev, struct v4l2_ctrl *ctrl,
+				struct mtk_cam_resource_config *res_cfg,
+				int pipe_id)
+{
+	int ret = 0;
+	struct mtk_raw_pipeline *pipeline;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+
+	if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+		dev_dbg(dev, "%s:pipe(%d):(name:%s, val:%lld)\n", __func__,
+			pipe_id, ctrl->name, *ctrl->p_new.p_s64);
+	else
+		dev_dbg(dev, "%s:pipe(%d):(name:%s, val:%d)\n", __func__,
+			pipe_id, ctrl->name, ctrl->val);
+
+	mutex_lock(&res_cfg->resource_lock);
+	switch (ctrl->id) {
+	case V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT:
+		res_cfg->hwn_limit_max = ctrl->val;
+		break;
+	case V4L2_CID_MTK_CAM_BIN_LIMIT:
+		res_cfg->bin_limit = ctrl->val;
+		break;
+	case V4L2_CID_MTK_CAM_FRZ_LIMIT:
+		res_cfg->frz_limit = ctrl->val;
+		break;
+	case V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY:
+		res_cfg->res_plan = ctrl->val;
+		break;
+	case V4L2_CID_MTK_CAM_RAW_PATH_SELECT:
+		res_cfg->raw_path = ctrl->val;
+		break;
+	case V4L2_CID_HBLANK:
+		res_cfg->hblank = ctrl->val;
+		break;
+	case V4L2_CID_VBLANK:
+		res_cfg->vblank = ctrl->val;
+		break;
+	case V4L2_CID_MTK_CAM_PIXEL_RATE:
+		res_cfg->sensor_pixel_rate = *ctrl->p_new.p_s64;
+		break;
+	case V4L2_CID_MTK_CAM_SYNC_ID:
+		pipeline->sync_id = *ctrl->p_new.p_s64;
+		break;
+	default:
+		dev_info(dev,
+			 "%s:pipe(%d):ctrl(id:0x%x,val:%d) not handled\n",
+			 __func__, pipe_id, ctrl->id, ctrl->val);
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&res_cfg->resource_lock);
+
+	return ret;
+}
+
+static int mtk_cam_raw_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct device *dev;
+	struct mtk_raw_pipeline *pipeline;
+	struct mtk_cam_resource *res_user;
+	struct mtk_cam_resource_config res_cfg = {
+		.interval = {
+			.numerator = 1,
+			.denominator = 30
+		},
+	};
+	int ret = 0;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	dev = pipeline->raw->devs[pipeline->id];
+
+	switch (ctrl->id) {
+	case V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC:
+		res_user = (struct mtk_cam_resource *)ctrl->p_new.p;
+		ret = mtk_cam_raw_res_store(pipeline, res_user);
+		if (ret)
+			break;
+
+		ret = mtk_cam_raw_res_copy_fmt_from_user(pipeline, res_user,
+							 &res_cfg.sink_fmt);
+		if (ret) {
+			ret = 0;
+			/* only corret the user's input, it may be request-based try and set fmt */
+			dev_dbg(dev,
+				"%s:pipe(%d): no sink_fmt from user, not calc res\n",
+				__func__, pipeline->id);
+			break;
+		}
+
+		dev_dbg(dev, "%s:pipe(%d): res ctrl start\n",
+			__func__, pipeline->id);
+		ret = mtk_cam_raw_try_res_ctrl(pipeline, res_user, &res_cfg,
+					       &res_cfg.sink_fmt);
+		if (ret)
+			break;
+
+		dev_dbg(dev,
+			"%s:pipe(%d):streaming(%d), feature_pending(0x%llx), feature_active(0x%llx)\n",
+			__func__, pipeline->id,
+			media_entity_is_streaming(&pipeline->subdev.entity),
+			pipeline->feature_pending, pipeline->feature_active);
+
+		dev_dbg(dev, "%s:pipe(%d): res ctrl end\n",
+			__func__, pipeline->id);
+			break;
+	case V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE:
+		dev_info(dev,
+			 "%s:pipe(%d): skip V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: %d\n",
+			 __func__, pipeline->id, ctrl->val);
+		ret = 0; /* no support */
+		break;
+	/* skip control value checks */
+	case V4L2_CID_MTK_CAM_FEATURE:
+	case V4L2_CID_MTK_CAM_CAMSYS_HW_MODE:
+		ret = 0;
+		break;
+	default:
+		ret = mtk_raw_set_res_ctrl(pipeline->raw->devs[pipeline->id],
+					   ctrl, &pipeline->try_res_config,
+					   pipeline->id);
+		break;
+	}
+
+	return ret;
+}
+
+static int mtk_cam_raw_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct device *dev;
+	struct mtk_raw_pipeline *pipeline;
+	int ret = 0;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	dev = pipeline->raw->devs[pipeline->id];
+
+	switch (ctrl->id) {
+	case V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC:
+		/**
+		 * It also updates V4L2_CID_MTK_CAM_FEATURE and
+		 * V4L2_CID_MTK_CAM_RAW_PATH_SELECT to device
+		 */
+		ret = mtk_cam_raw_set_res_ctrl(ctrl);
+		break;
+	case V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE:
+		/**
+		 * sensor_mode_update should be reset by driver after the completion
+		 * of resource updating (seamless switch)
+		 */
+		pipeline->sensor_mode_update = ctrl->val;
+		dev_info(dev,
+			 "%s:pipe(%d):streaming(%d), sensor_mode_update(%d)\n",
+			 __func__, pipeline->id,
+			 media_entity_is_streaming(&pipeline->subdev.entity),
+			 pipeline->sensor_mode_update);
+		break;
+	case V4L2_CID_MTK_CAM_FEATURE:
+		pipeline->feature_pending = *ctrl->p_new.p_s64;
+		dev_dbg(dev,
+			"%s:pipe(%d):streaming(%d), feature_pending(0x%llx), feature_active(0x%llx)\n",
+			__func__, pipeline->id,
+			media_entity_is_streaming(&pipeline->subdev.entity),
+			pipeline->feature_pending, pipeline->feature_active);
+		ret = 0;
+		break;
+	case V4L2_CID_MTK_CAM_CAMSYS_HW_MODE:
+		pipeline->hw_mode = *ctrl->p_new.p_s64;
+		dev_dbg(dev,
+			"%s:pipe(%d):streaming(%d), hw_mode(0x%llx)\n",
+			__func__, pipeline->id,
+			media_entity_is_streaming(&pipeline->subdev.entity),
+			pipeline->hw_mode);
+
+		ret = 0;
+		break;
+	default:
+		ret = mtk_raw_set_res_ctrl(pipeline->raw->devs[pipeline->id],
+					   ctrl, &pipeline->res_config,
+					   pipeline->id);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops cam_ctrl_ops = {
+	.g_volatile_ctrl = mtk_cam_raw_get_ctrl,
+	.s_ctrl = mtk_cam_raw_set_ctrl,
+	.try_ctrl = mtk_cam_raw_try_ctrl,
+};
+
+static int mtk_raw_pde_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_raw_pipeline *pipeline;
+	struct mtk_raw_pde_config *pde_cfg;
+	struct mtk_cam_pde_info *pde_info_p;
+	struct device *dev;
+	int ret = 0;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	pde_cfg = &pipeline->pde_config;
+	pde_info_p = ctrl->p_new.p;
+	dev = pipeline->raw->devs[pipeline->id];
+
+	switch (ctrl->id) {
+	case V4L2_CID_MTK_CAM_PDE_INFO:
+		pde_info_p->pdo_max_size = pde_cfg->pde_info.pdo_max_size;
+		pde_info_p->pdi_max_size = pde_cfg->pde_info.pdi_max_size;
+		pde_info_p->pd_table_offset = pde_cfg->pde_info.pd_table_offset;
+		break;
+	default:
+		dev_info(dev, "%s(id:0x%x,val:%d) is not handled\n",
+			 __func__, ctrl->id, ctrl->val);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mtk_raw_pde_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mtk_raw_pipeline *pipeline;
+	struct mtk_raw_pde_config *pde_cfg;
+	struct mtk_cam_pde_info *pde_info_p;
+	struct device *dev;
+	int ret = 0;
+	struct mtk_cam_video_device *node;
+	struct mtk_cam_dev_node_desc *desc;
+	const struct v4l2_format *default_fmt;
+
+	pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler);
+	pde_cfg = &pipeline->pde_config;
+	pde_info_p = ctrl->p_new.p;
+	dev = pipeline->raw->devs[pipeline->id];
+
+	node = &pipeline->vdev_nodes[MTK_RAW_META_IN - MTK_RAW_SINK_NUM];
+	desc = &node->desc;
+	default_fmt = &desc->fmts[desc->default_fmt_idx].vfmt;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MTK_CAM_PDE_INFO:
+		if (!pde_info_p->pdo_max_size || !pde_info_p->pdi_max_size) {
+			dev_info(dev,
+				 "%s:pdo_max_sz(%d)/pdi_max_sz(%d) cannot be 0\n",
+				 __func__, pde_info_p->pdo_max_size,
+				 pde_info_p->pdi_max_size);
+			ret = -EINVAL;
+			break;
+		}
+
+		pde_cfg->pde_info.pdo_max_size = pde_info_p->pdo_max_size;
+		pde_cfg->pde_info.pdi_max_size = pde_info_p->pdi_max_size;
+		pde_cfg->pde_info.pd_table_offset =
+			default_fmt->fmt.meta.buffersize;
+		break;
+	default:
+		dev_info(dev, "%s(id:0x%x,val:%d) is not handled\n",
+			 __func__, ctrl->id, ctrl->val);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops cam_pde_ctrl_ops = {
+	.g_volatile_ctrl = mtk_raw_pde_get_ctrl,
+	.s_ctrl = mtk_raw_pde_set_ctrl,
+	.try_ctrl = mtk_raw_pde_set_ctrl,
+};
+
+static const struct v4l2_ctrl_config hwn_limit = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT,
+	.name = "Engine resource limitation",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 1,
+	.max = 2,
+	.step = 1,
+	.def = 2,
+};
+
+static const struct v4l2_ctrl_config bin_limit = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_BIN_LIMIT,
+	.name = "Binning limitation",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 0xfff,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config frz_limit = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_FRZ_LIMIT,
+	.name = "Resizer limitation",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 70,
+	.max = 100,
+	.step = 1,
+	.def = 100,
+};
+
+static const struct v4l2_ctrl_config hwn = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_USED_ENGINE,
+	.name = "Engine resource",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 1,
+	.max = 2,
+	.step = 1,
+	.def = 2,
+};
+
+static const struct v4l2_ctrl_config bin = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_BIN,
+	.name = "Binning",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config frz = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_FRZ,
+	.name = "Resizer",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 70,
+	.max = 100,
+	.step = 1,
+	.def = 100,
+};
+
+static const struct v4l2_ctrl_config raw_path = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_RAW_PATH_SELECT,
+	.name = "Raw Path",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config hwn_try = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_USED_ENGINE_TRY,
+	.name = "Engine resource",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 1,
+	.max = 2,
+	.step = 1,
+	.def = 2,
+};
+
+static const struct v4l2_ctrl_config bin_try = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_BIN_TRY,
+	.name = "Binning",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config frz_try = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_FRZ_TRY,
+	.name = "Resizer",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 70,
+	.max = 100,
+	.step = 1,
+	.def = 100,
+};
+
+static const struct v4l2_ctrl_config res_plan_policy = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY,
+	.name = "Resource planning policy",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 10,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config res_pixel_rate = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_PIXEL_RATE,
+	.name = "Resource pixel rate",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = 0,
+	.max = 0xFFFFFFFF,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config frame_sync_id = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_SYNC_ID,
+	.name = "Frame sync id",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = -1,
+	.max = 0x7FFFFFFF,
+	.step = 1,
+	.def = -1,
+};
+
+static const struct v4l2_ctrl_config mtk_feature = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_FEATURE,
+	.name = "mediatek camsys feature",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = 0,
+	.max = RAW_FUNCTION_END,
+	.step = 1,
+	.def = 0,
+};
+
+static struct v4l2_ctrl_config cfg_res_ctrl = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC,
+	.name = "resource ctrl",
+	.type = V4L2_CTRL_COMPOUND_TYPES, /* V4L2_CTRL_TYPE_U32,*/
+	.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
+	.max = 0xffffffff,
+	.step = 1,
+	.dims = {sizeof(struct mtk_cam_resource)},
+};
+
+static struct v4l2_ctrl_config cfg_res_update = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE,
+	.name = "resource update",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 0xf,
+	.step = 1,
+	.def = 0,
+};
+
+static const struct v4l2_ctrl_config cfg_pde_info = {
+	.ops = &cam_pde_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_PDE_INFO,
+	.name = "pde information",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.flags = V4L2_CTRL_FLAG_VOLATILE,
+	.min = 0,
+	.max = 0x1fffffff,
+	.step = 1,
+	.def = 0,
+	.dims = {sizeof_u32(struct mtk_cam_pde_info)},
+};
+
+static const struct v4l2_ctrl_config mtk_camsys_hw_mode = {
+	.ops = &cam_ctrl_ops,
+	.id = V4L2_CID_MTK_CAM_CAMSYS_HW_MODE,
+	.name = "mediatek camsys hardware mode",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = 0,
+	.max = 0x7FFFFFFF,
+	.step = 1,
+	.def = DEFAULT,
+};
+
+static void mtk_cam_raw_toggle_db(struct mtk_raw_device *dev)
+{
+	int value;
+	u32 val_cfg, val_dcif_ctl, val_sen;
+
+	value = readl_relaxed(dev->base + REG_CTL_MISC);
+	val_cfg = readl_relaxed(dev->base_inner + REG_TG_PATH_CFG);
+	val_dcif_ctl = readl_relaxed(dev->base_inner + REG_TG_DCIF_CTL);
+	val_sen = readl_relaxed(dev->base_inner + REG_TG_SEN_MODE);
+	writel_relaxed(value & ~CTL_DB_EN, dev->base + REG_CTL_MISC);
+	wmb(); /* make sure committed */
+	writel_relaxed(value | CTL_DB_EN, dev->base + REG_CTL_MISC);
+	wmb(); /* make sure committed */
+	dev_info(dev->dev,
+		 "%s,  read inner AsIs->ToBe TG_PATH_CFG:0x%x->0x%x, TG_DCIF:0x%x->0x%x, TG_SEN:0x%x->0x%x\n",
+		 __func__, val_cfg,
+		 readl_relaxed(dev->base_inner + REG_TG_PATH_CFG), val_dcif_ctl,
+		 readl_relaxed(dev->base_inner + REG_TG_DCIF_CTL), val_sen,
+		 readl_relaxed(dev->base_inner + REG_TG_SEN_MODE));
+}
+
+void mtk_cam_raw_trigger_rawi(struct mtk_raw_device *dev,
+			      struct mtk_cam_ctx *ctx, signed int hw_scene)
+{
+	#define TRIGGER_RAWI_R6 0x10
+	#define TRIGGER_RAWI_R2 0x01
+	u32 cmd = TRIGGER_RAWI_R2;
+
+	writel_relaxed(cmd, dev->base + REG_CTL_RAWI_TRIG);
+	wmb(); /* make sure committed */
+}
+
+void mtk_cam_raw_apply_cq(struct mtk_raw_device *dev, dma_addr_t cq_addr,
+			  unsigned int cq_size, unsigned int cq_offset,
+			  unsigned int sub_cq_size, unsigned int sub_cq_offset)
+{
+	dma_addr_t main, sub;
+
+	dev_dbg(dev->dev,
+		"apply raw%d cq - addr:0x%pad,size:%d/%d,offset:%d\n",
+		dev->id, &cq_addr, cq_size, sub_cq_size, sub_cq_offset);
+
+	main = cq_addr + cq_offset;
+	sub = cq_addr + sub_cq_offset;
+
+	writel_relaxed(dmaaddr_lsb(main),
+		       dev->base + REG_CQ_THR0_BASEADDR);
+	writel_relaxed(dmaaddr_msb(main),
+		       dev->base + REG_CQ_THR0_BASEADDR_MSB);
+	writel_relaxed(cq_size,
+		       dev->base + REG_CQ_THR0_DESC_SIZE);
+	writel_relaxed(dmaaddr_lsb(sub),
+		       dev->base + REG_CQ_SUB_THR0_BASEADDR_2);
+	writel_relaxed(dmaaddr_msb(sub),
+		       dev->base + REG_CQ_SUB_THR0_BASEADDR_MSB_2);
+	writel_relaxed(sub_cq_size,
+		       dev->base + REG_CQ_SUB_THR0_DESC_SIZE_2);
+
+	/* USINGSCQ and always trigger now */
+	writel_relaxed(CAMCTL_CQ_THR0_DONE_ST,
+		       dev->base + REG_CTL_RAW_INT6_EN);
+	writel_relaxed(CAMCTL_CQ_THRSUB_DONE_EN,
+		       dev->base + REG_CTL_RAW_INT7_EN);
+	writel(CTL_CQ_THR0_START, dev->base + REG_CTL_START);
+
+	wmb(); /* make sure committed */
+}
+
+/* sw check again for rawi dcif case */
+static bool mtk_cam_raw_is_dma_idle(struct mtk_raw_device *dev)
+{
+	bool ret = false;
+	int chasing_stat;
+	int raw_rst_stat = readl(dev->base + REG_DMA_SOFT_RST_STAT);
+	int raw_rst_stat2 = readl(dev->base + REG_DMA_SOFT_RST_STAT2);
+	int yuv_rst_stat = readl(dev->yuv_base + REG_DMA_SOFT_RST_STAT);
+
+	if (raw_rst_stat2 != 0x7 || yuv_rst_stat != 0xfffffff)
+		return false;
+
+	/* check beside rawi_r2/r3/r5 */
+	if (~raw_rst_stat & 0x7fffffda)
+		return false;
+
+	if (~raw_rst_stat & RST_STAT_RAWI_R2) { /* RAWI_R2 */
+		chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS);
+		ret = ((chasing_stat & RAWI_R2_SMI_REQ_ST) == 0 &&
+		       (readl(dev->base + REG_RAWI_R2_BASE + DMA_OFFSET_SPECIAL_DCIF)
+		       & DC_CAMSV_STAGER_EN) &&
+		       (readl(dev->base + REG_CTL_MOD6_EN) & 0x1))
+		      ? true : false;
+		dev_info(dev->dev, "%s: chasing_stat: 0x%x ret=%d\n",
+			 __func__, chasing_stat, ret);
+	}
+
+	if (~raw_rst_stat & RST_STAT_RAWI_R3) {
+		chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS);
+		ret = ((chasing_stat & RAWI_R3_SMI_REQ_ST) == 0 &&
+		       (readl(dev->base + REG_RAWI_R3_BASE + DMA_OFFSET_SPECIAL_DCIF)
+		       & DC_CAMSV_STAGER_EN) &&
+		       (readl(dev->base + REG_CTL_MOD6_EN) & 0x80))
+		      ? true : false;
+		dev_info(dev->dev, "%s: chasing_stat: 0x%x, ret=%d\n",
+			 __func__, chasing_stat, ret);
+	}
+
+	if (~raw_rst_stat & RST_STAT_RAWI_R5) {
+		chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS2);
+		ret = ((chasing_stat & RAWI_R5_SMI_REQ_ST) == 0 &&
+		       (readl(dev->base + REG_RAWI_R5_BASE + DMA_OFFSET_SPECIAL_DCIF)
+		       & DC_CAMSV_STAGER_EN) &&
+		       (readl(dev->base + REG_CTL_MOD6_EN) & 0x1000))
+		      ? true : false;
+		dev_info(dev->dev, "%s: chasing_stat: 0x%x, ret=%d\n",
+			 __func__, chasing_stat, ret);
+	}
+
+	return ret;
+}
+
+void mtk_cam_raw_reset(struct mtk_raw_device *dev)
+{
+	int sw_ctl;
+	int ret;
+
+	/* Disable all DMA DCM before reset */
+	writel(0x00000fff, dev->base + REG_CTL_RAW_MOD5_DCM_DIS);
+	writel(0x0007ffff, dev->base + REG_CTL_RAW_MOD6_DCM_DIS);
+	writel(0xffffffff, dev->yuv_base + REG_CTL_RAW_MOD5_DCM_DIS);
+
+	/* Enable CQI_R1 ~ R4 before reset and make sure loaded */
+	writel(readl(dev->base + REG_CTL_MOD6_EN) | 0x78000,
+	       dev->base + REG_CTL_MOD6_EN);
+	mtk_cam_raw_toggle_db(dev);
+
+	writel(0, dev->base + REG_CTL_SW_CTL);
+	writel(1, dev->base + REG_CTL_SW_CTL);
+	wmb(); /* make sure committed */
+
+	ret = readx_poll_timeout(readl, dev->base + REG_CTL_SW_CTL, sw_ctl,
+				 sw_ctl & 0x2,
+				 1 /* delay, us */, 5000 /* timeout, us */);
+
+	if (ret < 0 && !mtk_cam_raw_is_dma_idle(dev)) {
+		dev_info(dev->dev,
+			 "%s: timeout: tg_sen_mode: 0x%x, ctl_en: 0x%x, mod6_en: 0x%x, ctl_sw_ctl:0x%x, frame_no:0x%x,rst_stat:0x%x,rst_stat2:0x%x,yuv_rst_stat:0x%x\n",
+			 __func__,
+			 readl(dev->base + REG_TG_SEN_MODE),
+			 readl(dev->base + REG_CTL_EN),
+			 readl(dev->base + REG_CTL_MOD6_EN),
+			 readl(dev->base + REG_CTL_SW_CTL),
+			 readl(dev->base + REG_FRAME_SEQ_NUM),
+			 readl(dev->base + REG_DMA_SOFT_RST_STAT),
+			 readl(dev->base + REG_DMA_SOFT_RST_STAT2),
+			 readl(dev->yuv_base + REG_DMA_SOFT_RST_STAT));
+
+		goto RESET_FAILURE;
+	}
+
+	/* do hw rst */
+	writel(4, dev->base + REG_CTL_SW_CTL);
+	writel(0, dev->base + REG_CTL_SW_CTL);
+
+RESET_FAILURE:
+	/* Enable all DMA DCM back */
+	writel(0x0, dev->base + REG_CTL_RAW_MOD5_DCM_DIS);
+	writel(0x0, dev->base + REG_CTL_RAW_MOD6_DCM_DIS);
+	writel(0x0, dev->yuv_base + REG_CTL_RAW_MOD5_DCM_DIS);
+
+	wmb(); /* make sure committed */
+}
+
+static void mtk_cam_raw_reset_reg(struct mtk_raw_device *dev)
+{
+	int cq_en, sw_done;
+
+	dev_dbg(dev->dev,
+		"[%s++] CQ_EN/SW_SUB_CTL/SW_DONE [in] 0x%x/0x%x/0x%x [out] 0x%x/0x%x/0x%x\n",
+		__func__,
+		readl_relaxed(dev->base_inner + REG_CQ_EN),
+		readl_relaxed(dev->base_inner + REG_CTL_SW_SUB_CTL),
+		readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE),
+		readl_relaxed(dev->base + REG_CQ_EN),
+		readl_relaxed(dev->base + REG_CTL_SW_SUB_CTL),
+		readl_relaxed(dev->base + REG_CTL_SW_PASS1_DONE));
+
+	cq_en = readl_relaxed(dev->base_inner + REG_CQ_EN);
+	sw_done = readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE);
+
+	cq_en = cq_en & (~SCQ_SUBSAMPLE_EN) & (~SCQ_STAGGER_MODE);
+	writel(cq_en, dev->base_inner + REG_CQ_EN);
+	writel(cq_en, dev->base + REG_CQ_EN);
+
+	dev_dbg(dev->dev, "[--] try to disable SCQ_STAGGER_MODE: CQ_EN(0x%x)\n",
+		cq_en);
+
+	writel(sw_done & (~SW_DONE_SAMPLE_EN), dev->base_inner + REG_CTL_SW_PASS1_DONE);
+	writel(sw_done & (~SW_DONE_SAMPLE_EN), dev->base + REG_CTL_SW_PASS1_DONE);
+
+	writel(0, dev->base_inner + REG_CTL_SW_SUB_CTL);
+	writel(0, dev->base + REG_CTL_SW_SUB_CTL);
+
+	wmb(); /* make sure committed */
+
+	dev_dbg(dev->dev,
+		"[%s--] CQ_EN/SW_SUB_CTL/SW_DONE [in] 0x%x/0x%x/0x%x [out] 0x%x/0x%x/0x%x\n",
+		__func__, readl_relaxed(dev->base_inner + REG_CQ_EN),
+		readl_relaxed(dev->base_inner + REG_CTL_SW_SUB_CTL),
+		readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE),
+		readl_relaxed(dev->base + REG_CQ_EN),
+		readl_relaxed(dev->base + REG_CTL_SW_SUB_CTL),
+		readl_relaxed(dev->base + REG_CTL_SW_PASS1_DONE));
+}
+
+void mtk_cam_raw_dump_aa_info(struct mtk_cam_ctx *ctx,
+			      struct mtk_ae_debug_data *ae_info)
+{
+	struct mtk_raw_device *raw_dev = NULL;
+	struct mtk_raw_pipeline *pipe = ctx->pipe;
+	int i;
+
+	for (i = 0; i < ctx->cam->num_raw_devices; i++) {
+		if (pipe->enabled_raw & (1 << i)) {
+			struct device *dev = ctx->cam->raw.devs[i];
+
+			raw_dev = dev_get_drvdata(dev);
+			ae_info->obc_r1_sum[0] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R1_R_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R1_R_SUM_L);
+			ae_info->obc_r2_sum[0] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R2_R_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R2_R_SUM_L);
+			ae_info->obc_r3_sum[0] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R3_R_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R3_R_SUM_L);
+			ae_info->ltm_sum[0] +=
+				((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_R_MSB) << 32) |
+				readl(raw_dev->base + REG_LTM_AE_DEBUG_R_LSB);
+			ae_info->aa_sum[0] +=
+				((u64)readl(raw_dev->base + REG_AA_R_SUM_H) << 32) |
+				readl(raw_dev->base + REG_AA_R_SUM_L);
+
+			ae_info->obc_r1_sum[1] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R1_B_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R1_B_SUM_L);
+			ae_info->obc_r2_sum[1] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R2_B_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R2_B_SUM_L);
+			ae_info->obc_r3_sum[1] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R3_B_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R3_B_SUM_L);
+			ae_info->ltm_sum[1] +=
+				((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_B_MSB) << 32) |
+				readl(raw_dev->base + REG_LTM_AE_DEBUG_B_LSB);
+			ae_info->aa_sum[1] +=
+				((u64)readl(raw_dev->base + REG_AA_B_SUM_H) << 32) |
+				readl(raw_dev->base + REG_AA_B_SUM_L);
+
+			ae_info->obc_r1_sum[2] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R1_GR_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R1_GR_SUM_L);
+			ae_info->obc_r2_sum[2] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R2_GR_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R2_GR_SUM_L);
+			ae_info->obc_r3_sum[2] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R3_GR_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R3_GR_SUM_L);
+			ae_info->ltm_sum[2] +=
+				((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_GR_MSB) << 32) |
+				readl(raw_dev->base + REG_LTM_AE_DEBUG_GR_LSB);
+			ae_info->aa_sum[2] +=
+				((u64)readl(raw_dev->base + REG_AA_GR_SUM_H) << 32) |
+				readl(raw_dev->base + REG_AA_GR_SUM_L);
+
+			ae_info->obc_r1_sum[3] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R1_GB_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R1_GB_SUM_L);
+			ae_info->obc_r2_sum[3] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R2_GB_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R2_GB_SUM_L);
+			ae_info->obc_r3_sum[3] +=
+				((u64)readl(raw_dev->base + OFFSET_OBC_R3_GB_SUM_H) << 32) |
+				readl(raw_dev->base + OFFSET_OBC_R3_GB_SUM_L);
+			ae_info->ltm_sum[3] +=
+				((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_GB_MSB) << 32) |
+				readl(raw_dev->base + REG_LTM_AE_DEBUG_GB_LSB);
+			ae_info->aa_sum[3] +=
+				((u64)readl(raw_dev->base + REG_AA_GB_SUM_H) << 32) |
+				readl(raw_dev->base + REG_AA_GB_SUM_L);
+		}
+	}
+}
+
+static int reset_msgfifo(struct mtk_raw_device *dev)
+{
+	atomic_set(&dev->is_fifo_overflow, 0);
+	return kfifo_init(&dev->msg_fifo, dev->msg_buffer, dev->fifo_size);
+}
+
+static int push_msgfifo(struct mtk_raw_device *dev,
+			struct mtk_camsys_irq_info *info)
+{
+	int len;
+
+	if (unlikely(kfifo_avail(&dev->msg_fifo) < sizeof(*info))) {
+		atomic_set(&dev->is_fifo_overflow, 1);
+		return -1;
+	}
+
+	len = kfifo_in(&dev->msg_fifo, info, sizeof(*info));
+	WARN_ON(len != sizeof(*info));
+
+	return 0;
+}
+
+static void set_fifo_size(void __iomem *dma_base, int fifo_size)
+{
+	writel_relaxed((0x1 << 28) | (fifo_size & 0xFFF),
+		       dma_base + DMA_OFFSET_CON0);
+}
+
+static void set_fifo_threshold(void __iomem *dma_base)
+{
+	u32 fifo_size = 0;
+
+	fifo_size = readl_relaxed(dma_base + DMA_OFFSET_CON0) & 0xFFF;
+	writel_relaxed((0x1 << 28) |
+		       ((fifo_size * 1 / 4) & 0xFFF) << 16 |
+		       ((fifo_size * 1 / 8) & 0xFFF),
+		       dma_base + DMA_OFFSET_CON1);
+	writel_relaxed((0x1 << 28) |
+		       ((fifo_size * 1 / 2) & 0xFFF) << 16 |
+		       ((fifo_size * 3 / 8) & 0xFFF),
+		       dma_base + DMA_OFFSET_CON2);
+	writel_relaxed((0x1 << 31) |
+		       ((fifo_size * 2 / 3) & 0xFFF) << 16 |
+		       ((fifo_size * 13 / 24) & 0xFFF),
+		       dma_base + DMA_OFFSET_CON3);
+	writel_relaxed((0x1 << 31) |
+		       ((fifo_size * 3 / 8) & 0xFFF) << 16 |
+		       ((fifo_size * 1 / 4) & 0xFFF),
+		       dma_base + DMA_OFFSET_CON4);
+}
+
+static void init_dma_threshold(struct mtk_raw_device *dev)
+{
+	struct mtk_cam_device *cam_dev;
+
+	cam_dev = dev->cam;
+
+	/* Set mt8188 default fifo size */
+	set_fifo_size(dev->base + REG_IMGO_R1_BASE, 0x3C0);
+	set_fifo_size(dev->yuv_base + REG_YUVCO_R1_BASE, 0x200);
+	set_fifo_size(dev->yuv_base + REG_YUVDO_R1_BASE, 0x80);
+	set_fifo_size(dev->yuv_base + REG_YUVO_R3_BASE, 0xc0);
+	set_fifo_size(dev->yuv_base + REG_YUVBO_R3_BASE, 0x60);
+	set_fifo_size(dev->yuv_base + REG_YUVCO_R3_BASE, 0x40);
+	set_fifo_size(dev->yuv_base + REG_YUVO_R2_BASE, 0x80);
+	set_fifo_size(dev->yuv_base + REG_YUVBO_R2_BASE, 0x40);
+	set_fifo_size(dev->yuv_base + REG_YUVO_R4_BASE, 0x40);
+	set_fifo_size(dev->yuv_base + REG_YUVBO_R4_BASE, 0x40);
+	set_fifo_size(dev->yuv_base + REG_YUVO_R5_BASE, 0x40);
+	set_fifo_threshold(dev->base + REG_IMGO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_FHO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_AAHO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_PDO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_AAO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_AFO_R1_BASE);
+	set_fifo_threshold(dev->base + REG_PDO_R1_BASE);
+
+	set_fifo_threshold(dev->yuv_base + REG_YUVO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVBO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVCO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVDO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVBO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVCO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_LTMSO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TSFSO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TSFSO_R2_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_FLKO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_UFEO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVO_R2_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVBO_R2_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVO_R4_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVBO_R4_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVO_R5_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_YUVBO_R5_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_RZH1N2TBO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R2_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_RZH1N2TBO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R2_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R3_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_ACTSO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TNCSO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TNCSBO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TNCSHO_R1_BASE);
+	set_fifo_threshold(dev->yuv_base + REG_TNCSYO_R1_BASE);
+
+	set_fifo_threshold(dev->base + REG_RAWI_R2_BASE);
+	set_fifo_threshold(dev->base + REG_UFDI_R2_BASE);
+	set_fifo_threshold(dev->base + REG_RAWI_R3_BASE);
+	set_fifo_threshold(dev->base + REG_UFDI_R3_BASE);
+	set_fifo_threshold(dev->base + REG_CQI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_CQI_R2_BASE);
+	set_fifo_threshold(dev->base + REG_CQI_R3_BASE);
+	set_fifo_threshold(dev->base + REG_CQI_R4_BASE);
+	set_fifo_threshold(dev->base + REG_LSCI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_BPCI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_BPCI_R2_BASE);
+	set_fifo_threshold(dev->base + REG_BPCI_R3_BASE);
+	set_fifo_threshold(dev->base + REG_PDI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_AAI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_CACI_R1_BASE);
+	set_fifo_threshold(dev->base + REG_RAWI_R6_BASE);
+
+	writel_relaxed(0x1, cam_dev->base + REG_HALT1_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_HALT2_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_HALT3_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_HALT4_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_HALT5_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_HALT6_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT1_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT2_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT3_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT4_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT5_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT6_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT1_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT2_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT3_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT4_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT5_EN);
+	writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT6_EN);
+}
+
+static int get_fps_ratio(struct mtk_raw_device *dev)
+{
+	int fps = (dev->pipeline->res_config.interval.numerator > 0) ?
+			(dev->pipeline->res_config.interval.denominator /
+			dev->pipeline->res_config.interval.numerator) : 0;
+
+	if (fps <= 30)
+		return 1;
+	else if (fps <= 60)
+		return 2;
+	else
+		return 1;
+}
+
+void mtk_cam_raw_initialize(struct mtk_raw_device *dev, int is_sub)
+{
+	u32 val;
+
+	/* USINGSCQ */
+	val = readl_relaxed(dev->base + REG_CQ_EN);
+	writel_relaxed(val | SCQ_EN, dev->base + REG_CQ_EN);
+	writel_relaxed(0xffffffff, dev->base + REG_SCQ_START_PERIOD);
+
+	writel_relaxed(CQ_THR0_MODE_IMMEDIATE | CQ_THR0_EN,
+		       dev->base + REG_CQ_THR0_CTL);
+	writel_relaxed(CQ_THR0_MODE_IMMEDIATE | CQ_THR0_EN,
+		       dev->base + REG_CQ_SUB_THR0_CTL);
+	writel_relaxed(CAMCTL_CQ_THR0_DONE_ST,
+		       dev->base + REG_CTL_RAW_INT6_EN);
+	writel_relaxed(CAMCTL_CQ_THRSUB_DONE_EN,
+		       dev->base + REG_CTL_RAW_INT7_EN);
+
+	dev->is_sub = is_sub;
+	dev->sof_count = 0;
+	dev->vsync_count = 0;
+	atomic_set(&dev->vf_en, 0);
+	reset_msgfifo(dev);
+
+	init_dma_threshold(dev);
+
+	writel_relaxed(0xFFFE0000,
+		       dev->base + REG_FLKO_R1_BASE + DMA_OFFSET_ERR_STAT);
+
+	dev_dbg(dev->dev, "%s - REG_CQ_EN:0x%x ,REG_CQ_THR0_CTL:0x%8x\n",
+		__func__,
+		readl_relaxed(dev->base + REG_CQ_EN),
+		readl_relaxed(dev->base + REG_CQ_THR0_CTL));
+}
+
+void mtk_cam_raw_stream_on(struct mtk_raw_device *dev, int on)
+{
+	u32 val;
+	u32 chk_val;
+	u32 cfg_val;
+	u32 fps_ratio = 1;
+	struct mtk_cam_ctx *ctx;
+
+	dev_info(dev->dev, "raw %d %s %d\n", dev->id, __func__, on);
+	ctx = mtk_cam_find_ctx(dev->cam, &dev->pipeline->subdev.entity);
+	if (!ctx) {
+		dev_info(dev->dev, "%s: cannot find ctx\n", __func__);
+		return;
+	}
+
+	if (on) {
+		/* USINGSCQ */
+		val = readl_relaxed(dev->base + REG_TG_TIME_STAMP_CNT);
+		val = (val == 0) ? 1 : val;
+		fps_ratio = get_fps_ratio(dev);
+		dev_info(dev->dev,
+			 "VF on - REG_TG_TIME_STAMP_CNT val:%d fps(30x):%d\n",
+			 val, fps_ratio);
+		writel_relaxed(SCQ_DEADLINE_MS * 1000 * SCQ_DEFAULT_CLK_RATE /
+			       (val * 2) / fps_ratio,
+			       dev->base + REG_SCQ_START_PERIOD);
+
+		dev->overrun_debug_dump_cnt = 0;
+		val = readl_relaxed(dev->base + REG_TG_VF_CON);
+		val |= TG_VFDATA_EN;
+		writel_relaxed(val, dev->base + REG_TG_VF_CON);
+		wmb(); /* make sure committed */
+
+		atomic_set(&dev->vf_en, 1);
+		dev_info(dev->dev,
+			 "%s - CQ_EN:0x%x, CQ_THR0_CTL:0x%8x, TG_VF_CON:0x%8x, SCQ_START_PERIOD:%d\n",
+			 __func__,
+			 readl_relaxed(dev->base + REG_CQ_EN),
+			 readl_relaxed(dev->base + REG_CQ_THR0_CTL),
+			 readl_relaxed(dev->base + REG_TG_VF_CON),
+			 readl_relaxed(dev->base + REG_SCQ_START_PERIOD));
+	} else {
+		dev_info(dev->dev, "VF off\n");
+		atomic_set(&dev->vf_en, 0);
+
+		writel_relaxed((u32)~CQ_THR0_EN, dev->base + REG_CQ_THR0_CTL);
+		wmb(); /* make sure committed */
+
+		cfg_val = readl_relaxed(dev->base + REG_TG_PATH_CFG);
+		cfg_val |= 0x100;
+		writel(cfg_val, dev->base + REG_TG_PATH_CFG);
+
+		val = readl_relaxed(dev->base + REG_TG_VF_CON);
+		val &= ~TG_VFDATA_EN;
+		writel(val, dev->base + REG_TG_VF_CON);
+
+		cfg_val = readl_relaxed(dev->base + REG_TG_PATH_CFG);
+		cfg_val &= ~0x100;
+		writel(cfg_val, dev->base + REG_TG_PATH_CFG);
+
+		wmb(); /* make sure committed */
+		/* reset hw after vf off */
+		if (readx_poll_timeout(readl, dev->base_inner + REG_TG_VF_CON,
+				       chk_val, chk_val == val, 1 /* sleep us */,
+				       33000 /* timeout us */) < 0) {
+			dev_err(dev->dev,
+				 "%s: wait vf off timeout: TG_VF_CON 0x%x\n",
+				 __func__, chk_val);
+		}
+
+		mtk_cam_raw_reset_reg(dev);
+	}
+}
+
+static int mtk_raw_linebuf_chk(bool b_twin, bool b_bin, bool b_frz, bool b_qbn,
+			       bool b_cbn, int tg_x, int *frz_ratio)
+{
+	int input_x = tg_x;
+	/* max line buffer check for frontal binning and resizer */
+	if (b_twin) {
+		if (input_x > CAM_TWIN_PROCESS_MAX_LINE_BUFFER)
+			return LB_CHECK_TWIN;
+		input_x = input_x >> 1;
+	}
+	if (b_cbn) {
+		if (input_x > CAM_RAW_CBN_MAX_LINE_BUFFER)
+			return LB_CHECK_CBN;
+		input_x = input_x >> 1;
+	}
+	if (b_qbn) {
+		if (input_x > CAM_RAW_QBND_MAX_LINE_BUFFER)
+			return LB_CHECK_QBN;
+		input_x = input_x >> 1;
+	}
+	if (b_bin) {
+		if (input_x > CAM_RAW_BIN_MAX_LINE_BUFFER)
+			return LB_CHECK_BIN;
+		input_x = input_x >> 1;
+	}
+	if (input_x <= CAM_RAW_PROCESS_MAX_LINE_BUFFER) {
+		return LB_CHECK_OK;
+	} else if (b_frz) {
+		if (input_x > CAM_RAW_FRZ_MAX_LINE_BUFFER)
+			return LB_CHECK_FRZ;
+
+		*frz_ratio = input_x * 100 / CAM_RAW_PROCESS_MAX_LINE_BUFFER;
+		return LB_CHECK_OK;
+	} else {
+		return LB_CHECK_RAW;
+	}
+}
+
+static bool is_cbn_en(int bin_flag)
+{
+	switch (bin_flag) {
+	case CBN_2X2_ON:
+	case CBN_3X3_ON:
+	case CBN_4X4_ON:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool mtk_cam_raw_resource_calc(struct mtk_cam_device *cam,
+				      struct mtk_cam_resource_config *res,
+				      s64 pixel_rate, int res_plan,
+				      int in_w, int in_h, int *out_w, int *out_h)
+{
+	int res_step_type = 0;
+	int tgo_pxl_mode = 1;
+	int pixel_mode[MTK_CAMSYS_RES_STEP_NUM] = {0};
+	int bin_temp = 0, frz_temp = 0, hwn_temp = 0;
+	int bin_en = 0, frz_en = 0, twin_en = 0, clk_cur = 0;
+	int idx = 0, clk_res = 0, idx_res = 0;
+	bool res_found = false;
+	int lb_chk_res = -1;
+	int frz_ratio = 100;
+
+	res->res_plan = res_plan;
+	res->pixel_rate = pixel_rate;
+	/* test pattern */
+	if (res->pixel_rate == 0)
+		res->pixel_rate = 450 * MHz;
+	dev_dbg(cam->dev,
+		"[Res] PR = %lld, w/h=%d/%d HWN(%d)/BIN(%d)/FRZ(%d),Plan:%d\n",
+		res->pixel_rate, in_w, in_h,
+		res->hwn_limit_max, res->bin_limit, res->frz_limit, res->res_plan);
+
+	memcpy(res->res_strategy, raw_resource_strategy_plan + res->res_plan,
+	       MTK_CAMSYS_RES_STEP_NUM * sizeof(int));
+	res->bin_enable = 0;
+	res->raw_num_used = 1;
+	res->frz_enable = 0;
+	res->frz_ratio = frz_ratio;
+	for (idx = 0; idx < MTK_CAMSYS_RES_STEP_NUM ; idx++) {
+		res_step_type = res->res_strategy[idx] & MTK_CAMSYS_RES_IDXMASK;
+		switch (res_step_type) {
+		case MTK_CAMSYS_RES_BIN_TAG:
+			bin_temp = res->res_strategy[idx] - E_RES_BIN_S;
+			if (bin_temp <= res->bin_limit)
+				bin_en = bin_temp;
+			if (bin_en && frz_en)
+				frz_en = 0;
+			break;
+		case MTK_CAMSYS_RES_FRZ_TAG:
+			frz_temp = res->res_strategy[idx] - E_RES_FRZ_S;
+			if (res->frz_limit < 100)
+				frz_en = frz_temp;
+			break;
+		case MTK_CAMSYS_RES_HWN_TAG:
+			hwn_temp = res->res_strategy[idx] - E_RES_HWN_S;
+			if (hwn_temp + 1 <= res->hwn_limit_max)
+				twin_en = hwn_temp;
+			break;
+		case MTK_CAMSYS_RES_CLK_TAG:
+			clk_cur = res->res_strategy[idx] - E_RES_CLK_S;
+			break;
+		default:
+			break;
+		}
+
+		/* 1 for force bin on */
+		if (res->bin_limit >= 1)
+			bin_en = 1;
+
+		if (res->hwn_limit_min > 1)
+			twin_en = 1;
+
+		/* max line buffer check*/
+		lb_chk_res = mtk_raw_linebuf_chk(twin_en, res->bin_limit & BIN_ON,
+						 frz_en, res->bin_limit & QBND_ON,
+						 is_cbn_en(res->bin_limit),
+						 in_w, &frz_ratio);
+
+		/* frz ratio*/
+		if (res_step_type == MTK_CAMSYS_RES_FRZ_TAG) {
+			res->frz_ratio = res->frz_limit < FRZ_PXLMODE_THRES ?
+				res->frz_limit : FRZ_PXLMODE_THRES;
+		}
+
+		/* only support 1-pixel mode */
+		tgo_pxl_mode = 1;
+		pixel_mode[idx] = tgo_pxl_mode;
+
+		if (lb_chk_res == LB_CHECK_OK && !res_found) {
+			res->bin_enable = bin_en;
+			res->frz_enable = frz_en;
+			res->raw_num_used = twin_en + 1;
+			clk_res = clk_cur;
+			idx_res = idx;
+			res_found = true;
+			break;
+		}
+
+		dev_dbg(cam->dev,
+			"Res-%d B/F/H/C=%d/%d/%d/%d -> %d/%d/%d/%d (%d)(%d)\n",
+			idx, bin_temp, frz_temp, hwn_temp, clk_cur, bin_en,
+			frz_en, twin_en, clk_cur, lb_chk_res, pixel_mode[idx]);
+	}
+
+	tgo_pxl_mode = pixel_mode[idx_res];
+	switch (tgo_pxl_mode) {
+	case 1:
+		res->tgo_pxl_mode = 0;
+		break;
+	case 2:
+		res->tgo_pxl_mode = 1;
+		break;
+	case 4:
+		res->tgo_pxl_mode = 2;
+		break;
+	case 8:
+		res->tgo_pxl_mode = 3;
+		break;
+	default:
+		break;
+	}
+
+	if (res_found) {
+		dev_info(cam->dev,
+			 "Res-end:%d BIN/FRZ/HWN/CLK/pxl=%d/%d(%d)/%d/%d/%d, clk:%d\n",
+			 idx_res, res->bin_enable, res->frz_enable, res->frz_ratio,
+			 res->raw_num_used, clk_res, res->tgo_pxl_mode,
+			 res->clk_target);
+	} else {
+		dev_dbg(cam->dev, "[%s] Error resource result\n", __func__);
+	}
+	if (res->bin_enable) {
+		*out_w = in_w >> 1;
+		*out_h = in_h >> 1;
+	} else if (res->frz_enable) {
+		*out_w = in_w * res->frz_ratio / 100;
+		*out_h = in_h * res->frz_ratio / 100;
+	} else {
+		*out_w = in_w;
+		*out_h = in_h;
+	}
+
+	return res_found;
+}
+
+static inline unsigned int mtk_raw_get_err_status(unsigned int irq_status)
+{
+	return irq_status & INT_ST_MASK_CAM_ERR;
+}
+
+static irqreturn_t mtk_irq_raw(int irq, void *data)
+{
+	struct mtk_raw_device *raw_dev = (struct mtk_raw_device *)data;
+	struct device *dev = raw_dev->dev;
+	struct mtk_camsys_irq_info irq_info;
+	unsigned int frame_idx, frame_idx_inner, fbc_fho_ctl2;
+	unsigned int irq_status, err_status, dmao_done_status, dmai_done_status;
+	unsigned int drop_status, dma_ofl_status, cq_done_status, cq2_done_status;
+	bool wake_thread = 0;
+
+	irq_status       = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT_STAT);
+	dmao_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT2_STAT);
+	dmai_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT3_STAT);
+	drop_status      = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT4_STAT);
+	dma_ofl_status   = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT5_STAT);
+	cq_done_status   = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT6_STAT);
+	cq2_done_status  = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT7_STAT);
+
+	frame_idx       = readl_relaxed(raw_dev->base + REG_FRAME_SEQ_NUM);
+	frame_idx_inner = readl_relaxed(raw_dev->base_inner + REG_FRAME_SEQ_NUM);
+
+	fbc_fho_ctl2 =
+		readl_relaxed(REG_FBC_CTL2(raw_dev->base + FBC_R1A_BASE, 1));
+
+	err_status = mtk_raw_get_err_status(irq_status);
+
+	if (unlikely(!raw_dev->pipeline || !raw_dev->pipeline->enabled_raw)) {
+		dev_dbg(dev, "%s: %i: raw pipeline is disabled\n",
+			__func__, raw_dev->id);
+		goto ctx_not_found;
+	}
+
+	irq_info.irq_type = 0;
+	irq_info.ts_ns = ktime_get_boottime_ns();
+	irq_info.frame_idx = frame_idx;
+	irq_info.frame_idx_inner = frame_idx_inner;
+
+	/* CQ done */
+	if (cq_done_status & CAMCTL_CQ_THR0_DONE_ST)
+		irq_info.irq_type |= 1 << CAMSYS_IRQ_SETTING_DONE;
+	/* DMAO done, only for AFO */
+	if (dmao_done_status & AFO_DONE_ST)
+		irq_info.irq_type |= 1 << CAMSYS_IRQ_AFO_DONE;
+		/* enable AFO_DONE_EN at backend manually */
+
+	/* Frame done */
+	if (irq_status & SW_PASS1_DON_ST) {
+		irq_info.irq_type |= 1 << CAMSYS_IRQ_FRAME_DONE;
+		raw_dev->overrun_debug_dump_cnt = 0;
+	}
+	/* Frame start */
+	if (irq_status & SOF_INT_ST) {
+		irq_info.irq_type |= 1 << CAMSYS_IRQ_FRAME_START;
+
+		raw_dev->sof_count++;
+		irq_info.write_cnt = ((fbc_fho_ctl2 & WCNT_BIT_MASK) >> 8) - 1;
+		irq_info.fbc_cnt = (fbc_fho_ctl2 & CNT_BIT_MASK) >> 16;
+	}
+	/* Vsync interrupt */
+	if (irq_status & VS_INT_ST)
+		raw_dev->vsync_count++;
+
+	if (irq_info.irq_type && !raw_dev->is_sub) {
+		if (push_msgfifo(raw_dev, &irq_info) == 0)
+			wake_thread = 1;
+	}
+
+	/* Check ISP error status */
+	if (unlikely(err_status)) {
+		struct mtk_camsys_irq_info err_info;
+
+		err_info.irq_type = 1 << CAMSYS_IRQ_ERROR;
+		err_info.ts_ns = irq_info.ts_ns;
+		err_info.frame_idx = irq_info.frame_idx;
+		err_info.frame_idx_inner = irq_info.frame_idx_inner;
+		err_info.e.err_status = err_status;
+
+		if (push_msgfifo(raw_dev, &err_info) == 0)
+			wake_thread = 1;
+	}
+
+ctx_not_found:
+	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_thread_irq_raw(int irq, void *data)
+{
+	struct mtk_raw_device *raw_dev = (struct mtk_raw_device *)data;
+	struct mtk_camsys_irq_info irq_info;
+
+	if (unlikely(atomic_cmpxchg(&raw_dev->is_fifo_overflow, 1, 0)))
+		dev_info(raw_dev->dev, "msg fifo overflow\n");
+
+	while (kfifo_len(&raw_dev->msg_fifo) >= sizeof(irq_info)) {
+		int len = kfifo_out(&raw_dev->msg_fifo, &irq_info, sizeof(irq_info));
+
+		WARN_ON(len != sizeof(irq_info));
+
+		dev_dbg(raw_dev->dev, "ts=%llu irq_type %d, req:%d/%d\n",
+			irq_info.ts_ns, irq_info.irq_type,
+			irq_info.frame_idx_inner, irq_info.frame_idx);
+
+		/* error case */
+		if (unlikely(irq_info.irq_type == (1 << CAMSYS_IRQ_ERROR))) {
+			//TODO in debug patch
+			continue;
+		}
+
+		/* normal case */
+
+		/* inform interrupt information to camsys controller */
+		mtk_camsys_isr_event(raw_dev->cam, CAMSYS_ENGINE_RAW,
+				     raw_dev->id, &irq_info);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_raw_pm_suspend_prepare(struct mtk_raw_device *dev)
+{
+	u32 val;
+	int ret;
+
+	dev_dbg(dev->dev, "- %s\n", __func__);
+
+	if (pm_runtime_suspended(dev->dev))
+		return 0;
+
+	/* Disable ISP's view finder and wait for TG idle */
+	dev_dbg(dev->dev, "cam suspend, disable VF\n");
+	val = readl(dev->base + REG_TG_VF_CON);
+	writel(val & (~TG_VFDATA_EN), dev->base + REG_TG_VF_CON);
+	ret = readl_poll_timeout_atomic(dev->base + REG_TG_INTER_ST, val,
+					(val & TG_CAM_CS_MASK) == TG_IDLE_ST,
+					USEC_PER_MSEC, MTK_RAW_STOP_HW_TIMEOUT);
+	if (ret)
+		dev_dbg(dev->dev, "can't stop HW:%d:0x%x\n", ret, val);
+
+	/* Disable CMOS */
+	val = readl(dev->base + REG_TG_SEN_MODE);
+	writel(val & (~TG_SEN_MODE_CMOS_EN), dev->base + REG_TG_SEN_MODE);
+
+	/* Force ISP HW to idle */
+	ret = pm_runtime_force_suspend(dev->dev);
+	return ret;
+}
+
+static int mtk_raw_pm_post_suspend(struct mtk_raw_device *dev)
+{
+	u32 val;
+	int ret;
+
+	dev_dbg(dev->dev, "- %s\n", __func__);
+
+	if (pm_runtime_suspended(dev->dev))
+		return 0;
+
+	/* Force ISP HW to resume */
+	ret = pm_runtime_force_resume(dev->dev);
+	if (ret)
+		return ret;
+
+	/* Enable CMOS */
+	dev_dbg(dev->dev, "cam resume, enable CMOS/VF\n");
+	val = readl(dev->base + REG_TG_SEN_MODE);
+	writel(val | TG_SEN_MODE_CMOS_EN, dev->base + REG_TG_SEN_MODE);
+
+	/* Enable VF */
+	val = readl(dev->base + REG_TG_VF_CON);
+	writel(val | TG_VFDATA_EN, dev->base + REG_TG_VF_CON);
+
+	return 0;
+}
+
+static int raw_pm_notifier(struct notifier_block *nb,
+			   unsigned long action, void *data)
+{
+	struct mtk_raw_device *raw_dev =
+			container_of(nb, struct mtk_raw_device, pm_notifier);
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+		mtk_raw_pm_suspend_prepare(raw_dev);
+		break;
+	case PM_POST_SUSPEND:
+		mtk_raw_pm_post_suspend(raw_dev);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int mtk_raw_of_probe(struct platform_device *pdev,
+			    struct mtk_raw_device *raw)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+	int n_clks;
+
+	ret = of_property_read_u32(dev->of_node, "mediatek,cam-id", &raw->id);
+	if (ret) {
+		dev_dbg(dev, "missing camid property\n");
+		return ret;
+	}
+
+	if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) {
+		dev_err(dev, "%s: No suitable DMA available\n", __func__);
+		return -EIO;
+	}
+
+	if (!dev->dma_parms) {
+		dev->dma_parms =
+			devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+		if (!dev->dma_parms)
+			return -ENOMEM;
+	}
+
+	dma_set_max_seg_size(dev, UINT_MAX);
+
+	/* base outer register */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
+	if (!res) {
+		dev_err(dev, "failed to get mem\n");
+		return -ENODEV;
+	}
+
+	raw->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(raw->base)) {
+		dev_err(dev, "failed to map register base\n");
+		return PTR_ERR(raw->base);
+	}
+
+	/* base inner register */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "inner_base");
+	if (!res) {
+		dev_err(dev, "failed to get mem\n");
+		return -ENODEV;
+	}
+
+	raw->base_inner = devm_ioremap_resource(dev, res);
+	if (IS_ERR(raw->base_inner)) {
+		dev_err(dev, "failed to map register inner base\n");
+		return PTR_ERR(raw->base_inner);
+	}
+
+	/* will be assigned later */
+	raw->yuv_base = NULL;
+
+	raw->irq = platform_get_irq(pdev, 0);
+	if (raw->irq < 0) {
+		dev_err(dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_threaded_irq(dev, raw->irq,
+					mtk_irq_raw, mtk_thread_irq_raw,
+					0, dev_name(dev), raw);
+	if (ret) {
+		dev_err(dev, "failed to request irq=%d\n", raw->irq);
+		return ret;
+	}
+
+	disable_irq(raw->irq);
+
+	n_clks = devm_clk_bulk_get_all(dev, &raw->clk_b);
+	if (n_clks < 0)
+		return dev_err_probe(dev, n_clks, "failed to devm_clk_bulk_get_all\n");
+
+
+	raw->num_clks = n_clks;
+
+#ifdef CONFIG_PM_SLEEP
+	raw->pm_notifier.notifier_call = raw_pm_notifier;
+	ret = register_pm_notifier(&raw->pm_notifier);
+	if (ret) {
+		dev_info(dev, "failed to register notifier block.\n");
+		return ret;
+	}
+#endif
+	return 0;
+}
+
+static int mtk_raw_sd_subscribe_event(struct v4l2_subdev *subdev,
+				      struct v4l2_fh *fh,
+				      struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_FRAME_SYNC:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_REQUEST_DRAINED:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_REQUEST_DUMPED:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mtk_raw_available_resource(struct mtk_raw *raw)
+{
+	struct device *dev = raw->cam_dev;
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	int res_status = 0;
+	int i, j;
+
+	for (i = 0; i < cam_dev->num_raw_devices; i++) {
+		struct mtk_raw_pipeline *pipe = raw->pipelines + i;
+
+		for (j = 0; j < ARRAY_SIZE(raw->devs); j++) {
+			if (pipe->enabled_raw & 1 << j)
+				res_status |= 1 << j;
+		}
+	}
+	dev_dbg(raw->cam_dev,
+		"%s raw_status:0x%x Available Engine:A/B/C:%d/%d/%d\n",
+		__func__, res_status,
+		!(res_status & (1 << MTKCAM_SUBDEV_RAW_0)),
+		!(res_status & (1 << MTKCAM_SUBDEV_RAW_1)),
+		!(res_status & (1 << MTKCAM_SUBDEV_RAW_2)));
+
+	return res_status;
+}
+
+int mtk_cam_s_data_raw_select(struct mtk_cam_request_stream_data *s_data,
+			      struct mtkcam_ipi_input_param *cfg_in_param)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_raw_pipeline *pipe;
+	int raw_status = 0;
+	bool selected = false;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	pipe = ctx->pipe;
+	raw_status = mtk_raw_available_resource(pipe->raw);
+	raw_status &= ~pipe->enabled_raw;
+
+	mtk_raw_available_resource(pipe->raw);
+
+	if (!selected)
+		return -EINVAL;
+
+	return 0;
+}
+
+int mtk_cam_raw_select(struct mtk_cam_ctx *ctx,
+		       struct mtkcam_ipi_input_param *cfg_in_param)
+{
+	struct mtk_raw_pipeline *pipe = ctx->pipe;
+	int raw_status = 0;
+	int mask = 0x0;
+	bool selected = false;
+	int m;
+
+	pipe->enabled_raw = 0;
+	raw_status = mtk_raw_available_resource(pipe->raw);
+	if (pipe->res_config.raw_num_used == 3) {
+		mask = 1 << MTKCAM_SUBDEV_RAW_0
+			| 1 << MTKCAM_SUBDEV_RAW_1 | 1 << MTKCAM_SUBDEV_RAW_2;
+		if (!(raw_status & mask)) {
+			pipe->enabled_raw |= mask;
+			selected = true;
+		}
+	} else if (pipe->res_config.raw_num_used == 2) {
+		for (m = MTKCAM_SUBDEV_RAW_0; m >= MTKCAM_SUBDEV_RAW_0; m--) {
+			mask = (1 << m) | (1 << (m + 1));
+			if (!(raw_status & mask)) {
+				pipe->enabled_raw |= mask;
+				selected = true;
+				break;
+			}
+		}
+	} else {
+		for (m = MTKCAM_SUBDEV_RAW_0; m < ARRAY_SIZE(pipe->raw->devs); m++) {
+			mask = 1 << m;
+			if (!(raw_status & mask)) {
+				pipe->enabled_raw |= mask;
+				selected = true;
+				break;
+			}
+		}
+	}
+	mtk_raw_available_resource(pipe->raw);
+	if (!selected)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mtk_raw_sd_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct mtk_raw_pipeline *pipe;
+	struct mtk_raw *raw;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_ctx *ctx;
+	unsigned int i;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	raw = pipe->raw;
+	if (!raw)
+		return -1;
+	cam = dev_get_drvdata(raw->cam_dev);
+	ctx = mtk_cam_find_ctx(cam, &sd->entity);
+
+	if (WARN_ON(!ctx))
+		return -EINVAL;
+
+	if (enable) {
+		pipe->feature_active = pipe->user_res.raw_res.feature;
+		pipe->enabled_dmas = 0;
+		ctx->pipe = pipe;
+		ctx->used_raw_num++;
+		pipe->feature_active = pipe->user_res.raw_res.feature;
+		for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++) {
+			if (!pipe->vdev_nodes[i].enabled)
+				continue;
+			pipe->enabled_dmas |=
+				(1ULL << pipe->vdev_nodes[i].desc.dma_port);
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(raw->devs); i++) {
+			if (pipe->enabled_raw & 1 << i) {
+				dev_info(raw->cam_dev, "%s: power off raw (%d)\n",
+					 __func__, i);
+				pm_runtime_put_sync(raw->devs[i]);
+			}
+		}
+	}
+
+	dev_info(raw->cam_dev, "%s:raw-%d: en %d, dev 0x%x dmas 0x%lx\n",
+		 __func__, pipe->id, enable, pipe->enabled_raw,
+		 pipe->enabled_dmas);
+
+	return 0;
+}
+
+static int mtk_raw_init_state(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *mf;
+	unsigned int i;
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+
+	for (i = 0; i < sd->entity.num_pads; i++) {
+		mf = v4l2_subdev_state_get_format(sd_state, i);
+		*mf = mfmt_default;
+
+		dev_dbg(raw->cam_dev, "%s init pad:%d format:0x%x\n",
+			sd->name, i, mf->code);
+	}
+
+	return 0;
+}
+
+static bool mtk_raw_try_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_subdev_format *fmt)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+	unsigned int user_fmt = mtk_cam_get_sensor_fmt(fmt->format.code);
+
+	dev_dbg(raw->cam_dev, "%s:s_fmt: check format 0x%x, w:%d, h:%d field:%d\n",
+		sd->name, fmt->format.code, fmt->format.width,
+		fmt->format.height, fmt->format.field);
+
+	/* check sensor format */
+	if (fmt->pad == MTK_RAW_SINK) {
+		user_fmt = mtk_cam_get_sensor_fmt(fmt->format.code);
+		if (user_fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN)
+			return false;
+	}
+
+	return true;
+}
+
+static struct v4l2_mbus_framefmt *
+mtk_raw_pipeline_get_fmt(struct mtk_raw_pipeline *pipe,
+			 struct v4l2_subdev_state *sd_state, u32 padid,
+			 int which)
+{
+	struct mtk_raw *raw = pipe->raw;
+
+	if (padid >= MTK_RAW_PIPELINE_PADS_NUM) {
+		dev_err(raw->cam_dev, "Wrong pad id:%d\n", padid);
+		return NULL;
+	}
+	/* format invalid and return default format */
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_state_get_format(sd_state, padid);
+
+	if (WARN_ON(padid >= pipe->subdev.entity.num_pads))
+		return &pipe->cfg[0].mbus_fmt;
+
+	return &pipe->cfg[padid].mbus_fmt;
+}
+
+static struct v4l2_rect *
+mtk_raw_pipeline_get_selection(struct mtk_raw_pipeline *pipe,
+			       struct v4l2_subdev_state *sd_state, u32 pad,
+			       int which)
+{
+	struct mtk_raw *raw = pipe->raw;
+
+	if (pad >= MTK_RAW_PIPELINE_PADS_NUM) {
+		dev_err(raw->cam_dev, "Wrong pad id:%d\n", pad);
+		return NULL;
+	}
+	/* format invalid and return default format */
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return v4l2_subdev_state_get_crop(sd_state, pad);
+
+	if (WARN_ON(pad >= pipe->subdev.entity.num_pads))
+		return &pipe->cfg[0].crop;
+
+	return &pipe->cfg[pad].crop;
+}
+
+static void propagate_fmt(struct v4l2_mbus_framefmt *sink_mf,
+			  struct v4l2_mbus_framefmt *source_mf, int w, int h)
+{
+	source_mf->code = sink_mf->code;
+	source_mf->colorspace = sink_mf->colorspace;
+	source_mf->field = sink_mf->field;
+	source_mf->width = w;
+	source_mf->height = h;
+}
+
+static int mtk_raw_set_src_pad_selection_default(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)
+{
+	struct v4l2_rect *source_sel;
+	struct mtk_raw_pipeline *pipe;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	source_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which);
+	if (source_sel->width > sink_fmt->width)
+		source_sel->width = sink_fmt->width;
+
+	if (source_sel->height > sink_fmt->height)
+		source_sel->height = sink_fmt->height;
+
+	return 0;
+}
+
+static int mtk_raw_set_src_pad_selection_yuv(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)
+{
+	int i;
+	struct v4l2_rect *prev_yuv = NULL, *source_sel, *tmp_sel;
+	struct v4l2_mbus_framefmt *framefmt;
+	struct mtk_raw_pipeline *pipe;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	mtk_raw_set_src_pad_selection_default(sd, sd_state, sink_fmt, res, pad, which);
+	source_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which);
+
+	for (i = MTK_RAW_YUVO_1_OUT; i < pad; i++) {
+		framefmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which);
+		tmp_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which);
+
+		/* Skip disabled YUV pad */
+		if (!mtk_cam_is_pad_fmt_enable(framefmt))
+			continue;
+
+		prev_yuv = tmp_sel;
+	}
+
+	if (prev_yuv) {
+		if (source_sel->width != prev_yuv->width) {
+			source_sel->width = prev_yuv->width;
+			dev_dbg(sd->v4l2_dev->dev, "%s: prev width:%d",
+				__func__, source_sel->width);
+		}
+
+		if (source_sel->height != prev_yuv->height) {
+			source_sel->height = prev_yuv->height;
+			dev_dbg(sd->v4l2_dev->dev, "%s: prev height:%d",
+				__func__, source_sel->height);
+		}
+	}
+
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+mtk_raw_get_sink_pad_framefmt(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *sd_state, int which)
+{
+	struct v4l2_mbus_framefmt *sink_fmt = NULL, *tmp_fmt;
+	struct mtk_raw_pipeline *pipe;
+	int i;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	for (i = MTK_RAW_SINK; i < MTK_RAW_SOURCE_BEGIN; i++) {
+		tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, i, which);
+		if (i != MTK_RAW_META_IN && mtk_cam_is_pad_fmt_enable(tmp_fmt)) {
+			sink_fmt = tmp_fmt;
+			break;
+		}
+	}
+
+	return sink_fmt;
+}
+
+static int mtk_raw_set_pad_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_mbus_framefmt *sink_fmt;
+	struct mtk_raw_pipeline *pipe;
+	struct mtk_cam_video_device *node;
+	struct mtk_cam_resource *res = NULL;
+	struct v4l2_rect *crop;
+	int ret;
+
+	if (sel->pad < MTK_RAW_MAIN_STREAM_OUT ||
+	    sel->pad >= MTK_RAW_META_OUT_BEGIN)
+		return -EINVAL;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+
+	/* The crop rectangle can't be changed while streaming. */
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    !media_entity_is_streaming(&sd->entity))
+		return -EBUSY;
+
+	/*
+	 * Find the sink pad fmt, there must be one eanbled sink pad at least
+	 */
+	sink_fmt = mtk_raw_get_sink_pad_framefmt(sd, sd_state, sel->which);
+	if (!sink_fmt)
+		return -EINVAL;
+
+	node = &pipe->vdev_nodes[sel->pad - MTK_RAW_SINK_NUM];
+	crop = mtk_raw_pipeline_get_selection(pipe, sd_state, sel->pad, sel->which);
+	if (!crop)
+		return -EINVAL;
+
+	*crop = sel->r;
+	ret = node->desc.pad_ops->set_pad_selection(sd, sd_state, sink_fmt,
+						    res, sel->pad, sel->which);
+	if (ret)
+		return -EINVAL;
+
+	sel->r = *crop;
+
+	return 0;
+}
+
+static int mtk_raw_get_pad_selection(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_selection *sel)
+{
+	struct mtk_raw_pipeline *pipe;
+	struct v4l2_rect *crop;
+
+	if (sel->pad < MTK_RAW_MAIN_STREAM_OUT ||
+	    sel->pad >= MTK_RAW_META_OUT_BEGIN)
+		return -EINVAL;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	crop = mtk_raw_pipeline_get_selection(pipe, sd_state, sel->pad, sel->which);
+	if (!crop)
+		return -EINVAL;
+
+	sel->r = *crop;
+
+	return 0;
+}
+
+static int mtk_raw_set_sink_pad_fmt(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *sd_state,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct device *dev;
+	struct mtk_cam_video_device *node;
+	const char *node_str;
+	const struct mtk_cam_format_desc *fmt_desc;
+	struct mtk_raw_pipeline *pipe;
+	int i;
+	int ipi_fmt;
+	struct v4l2_mbus_framefmt *framefmt, *source_fmt = NULL, *tmp_fmt;
+
+	/* Do nothing for pad to meta video device */
+	if (fmt->pad == MTK_RAW_META_IN)
+		return 0;
+
+	dev = sd->v4l2_dev->dev;
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	framefmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which);
+
+	/* If data from sensor, we check the size with max imgo size*/
+	if (fmt->pad < MTK_RAW_SINK_NUM) {
+		/* from sensor */
+		node = &pipe->vdev_nodes[MTK_RAW_MAIN_STREAM_OUT - MTK_RAW_SINK_NUM];
+		node_str = "sink";
+	} else {
+		/* from memory */
+		node = &pipe->vdev_nodes[fmt->pad - MTK_RAW_SINK_NUM];
+		node_str = node->desc.name;
+	}
+
+	ipi_fmt = mtk_cam_get_sensor_fmt(framefmt->code);
+	if (ipi_fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN) {
+		/**
+		 * Set imgo's default fmt, the user must check
+		 * if the pad sink format is the same as the
+		 * source format of the link before stream on.
+		 */
+		fmt_desc = &node->desc.fmts[node->desc.default_fmt_idx];
+		framefmt->code = fmt_desc->pfmt.code;
+		dev_info(dev,
+			 "%s(%d): Adjust unaccept fmt code on sink pad:%d, 0x%x->0x%x\n",
+			 __func__, fmt->which, fmt->pad, fmt->format.code, framefmt->code);
+	}
+
+	/* Reset pads' enable state*/
+	for (i = MTK_RAW_SINK; i < MTK_RAW_META_OUT_BEGIN; i++) {
+		if (i == MTK_RAW_META_IN)
+			continue;
+		tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, i, fmt->which);
+		mtk_cam_pad_fmt_disable(tmp_fmt);
+	}
+
+	*framefmt = fmt->format;
+	if (framefmt->width > node->desc.frmsizes->stepwise.max_width)
+		framefmt->width = node->desc.frmsizes->stepwise.max_width;
+
+	if (framefmt->height > node->desc.frmsizes->stepwise.max_height)
+		framefmt->height = node->desc.frmsizes->stepwise.max_height;
+
+	mtk_cam_pad_fmt_enable(framefmt);
+
+	dev_info(dev,
+		 "%s(%d): Set fmt pad:%d(%s), code/w/h = 0x%x/%d/%d\n",
+		 __func__, fmt->which, fmt->pad, node_str,
+		 framefmt->code, framefmt->width, framefmt->height);
+
+	/* Propagation inside subdev */
+	for (i = MTK_RAW_SOURCE_BEGIN; i < MTK_RAW_META_OUT_BEGIN; i++) {
+		source_fmt =
+			mtk_raw_pipeline_get_fmt(pipe, sd_state, i, fmt->which);
+
+		/* Get default format's desc for the pad */
+		node = &pipe->vdev_nodes[i - MTK_RAW_SINK_NUM];
+
+		/**
+		 * Propagate the size from sink pad to source pades, adjusted
+		 * based on each pad's default format.
+		 */
+		if (source_fmt->width > node->desc.frmsizes->stepwise.max_width)
+			source_fmt->width = node->desc.frmsizes->stepwise.max_width;
+		else
+			source_fmt->width = framefmt->width;
+
+		if (source_fmt->height > node->desc.frmsizes->stepwise.max_height)
+			source_fmt->height = node->desc.frmsizes->stepwise.max_height;
+		else
+			source_fmt->height = framefmt->height;
+
+		dev_dbg(dev,
+			"%s(%d): Propagate to pad:%d(%s), (0x%x/%d/%d)\n",
+			__func__, fmt->which, fmt->pad, node->desc.name,
+			source_fmt->code, source_fmt->width, source_fmt->height);
+	}
+
+	return 0;
+}
+
+static int mtk_raw_set_src_pad_fmt_default(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)
+{
+	struct device *dev;
+	struct v4l2_mbus_framefmt *source_fmt;
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_cam_video_device *node;
+
+	dev = sd->v4l2_dev->dev;
+	node = &pipe->vdev_nodes[pad - MTK_RAW_SINK_NUM];
+	source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which);
+	if (source_fmt->width > sink_fmt->width) {
+		dev_info(dev,
+			 "%s(%d): adjusted: width(%d) over sink (%d)\n",
+			 __func__, which, source_fmt->width, sink_fmt->width);
+		source_fmt->width = sink_fmt->width;
+	}
+
+	if (source_fmt->height > sink_fmt->height) {
+		dev_info(dev,
+			 "%s(%d): adjusted: width(%d) over sink (%d)\n",
+			 __func__, which, source_fmt->height, sink_fmt->height);
+		source_fmt->height = sink_fmt->height;
+	}
+
+	if (source_fmt->width > node->desc.frmsizes->stepwise.max_width) {
+		dev_info(dev,
+			 "%s(%d): adjusted: width(%d) over max (%d)\n",
+			 __func__, which, source_fmt->width,
+			 node->desc.frmsizes->stepwise.max_width);
+		source_fmt->width = node->desc.frmsizes->stepwise.max_width;
+	}
+
+	if (source_fmt->height > node->desc.frmsizes->stepwise.max_height) {
+		dev_info(dev,
+			 "%s(%d): adjusted: height(%d) over max (%d)\n",
+			 __func__, which, source_fmt->height,
+			 node->desc.frmsizes->stepwise.max_height);
+	}
+
+	return 0;
+}
+
+static int mtk_raw_set_src_pad_fmt_rzh1n2(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)
+{
+	struct device *dev;
+	struct v4l2_mbus_framefmt *source_fmt;
+	struct v4l2_mbus_framefmt *tmp_fmt;
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+
+	dev = sd->v4l2_dev->dev;
+	mtk_raw_set_src_pad_fmt_default(sd, sd_state, sink_fmt, res, pad, which);
+	source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which);
+
+	/* rzh1n2to_r1 and rzh1n2to_r3 size must be the same */
+	if (pad == MTK_RAW_RZH1N2TO_3_OUT) {
+		tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state,
+						   MTK_RAW_RZH1N2TO_1_OUT, which);
+		if (mtk_cam_is_pad_fmt_enable(tmp_fmt) &&
+		    source_fmt->height != tmp_fmt->height &&
+		    source_fmt->width != tmp_fmt->width) {
+			dev_info(dev,
+				 "%s(%d): adjusted: rzh1n2to_r3(%d,%d) and rzh1n2to_r1(%d,%d) must have the same sz\n",
+				 __func__, which,
+				 source_fmt->width, source_fmt->height,
+				 tmp_fmt->width, tmp_fmt->height);
+
+			source_fmt->width = tmp_fmt->width;
+			source_fmt->height = tmp_fmt->height;
+		}
+	}
+
+	return 0;
+}
+
+static int mtk_raw_set_src_pad_fmt(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *sd_state,
+				   struct v4l2_subdev_format *fmt)
+{
+	struct device *dev;
+	struct mtk_cam_resource res;
+	struct mtk_cam_video_device *node;
+	struct mtk_raw_pipeline *pipe;
+	int ret = 0;
+	struct v4l2_mbus_framefmt *source_fmt, *sink_fmt;
+
+	/* Do nothing for pad to meta video device */
+	if (fmt->pad >= MTK_RAW_META_OUT_BEGIN)
+		return 0;
+
+	pipe = container_of(sd, struct mtk_raw_pipeline, subdev);
+	dev = sd->v4l2_dev->dev;
+	node = &pipe->vdev_nodes[fmt->pad - MTK_RAW_SINK_NUM];
+
+	/*
+	 * Find the sink pad fmt, there must be one eanbled sink pad at least
+	 */
+	sink_fmt = mtk_raw_get_sink_pad_framefmt(sd, sd_state, fmt->which);
+	if (!sink_fmt) {
+		dev_info(dev,
+			 "%s(%d): Set fmt pad:%d(%s), no s_fmt on sink pad\n",
+			 __func__, fmt->which, fmt->pad, node->desc.name);
+		return -EINVAL;
+	}
+
+	if (node->desc.pad_ops->set_pad_fmt) {
+		/* call source pad's set_pad_fmt op to adjust fmt by pad */
+		source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad,
+						      fmt->which);
+
+		*source_fmt = fmt->format;
+		ret = node->desc.pad_ops->set_pad_fmt(sd, sd_state, sink_fmt,
+						      &res, fmt->pad, fmt->which);
+	}
+
+	if (ret)
+		return ret;
+
+	if (!source_fmt) {
+		dev_info(dev,
+			 "%s(%d): Set fmt pad:%d(%s), no s_fmt on source pad\n",
+			 __func__, fmt->which, fmt->pad, node->desc.name);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev,
+		"%s(%d): s_fmt to pad:%d(%s), user(0x%x/%d/%d) driver(0x%x/%d/%d)\n",
+		__func__, fmt->which, fmt->pad, node->desc.name,
+		fmt->format.code, fmt->format.width, fmt->format.height,
+		source_fmt->code, source_fmt->width, source_fmt->height);
+	mtk_cam_pad_fmt_disable(source_fmt);
+	fmt->format = *source_fmt;
+
+	return 0;
+}
+
+static int mtk_raw_try_pad_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_state *sd_state,
+			       struct v4l2_subdev_format *fmt)
+{
+	if (fmt->pad >= MTK_RAW_SINK && fmt->pad < MTK_RAW_SOURCE_BEGIN)
+		mtk_raw_set_sink_pad_fmt(sd, sd_state, fmt);
+	else if (fmt->pad < MTK_RAW_PIPELINE_PADS_NUM)
+		mtk_raw_set_src_pad_fmt(sd, sd_state, fmt);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mtk_raw_call_set_fmt(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *sd_state,
+				struct v4l2_subdev_format *fmt,
+				bool streaming)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+	struct v4l2_mbus_framefmt *mf;
+
+	if (!sd || !fmt) {
+		dev_dbg(raw->cam_dev, "%s: Required sd(%p), fmt(%p)\n",
+			__func__, sd, fmt);
+		return -EINVAL;
+	}
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY && !sd_state) {
+		dev_dbg(raw->cam_dev,
+			"%s: Required sd(%p), cfg(%p) for FORMAT_TRY\n",
+			__func__, sd, sd_state);
+		return -EINVAL;
+	}
+
+	if (!mtk_raw_try_fmt(sd, fmt)) {
+		mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which);
+		fmt->format = *mf;
+		dev_info(raw->cam_dev,
+			 "sd:%s pad:%d didn't apply and keep format w/h/code %d/%d/0x%x\n",
+			 sd->name, fmt->pad, mf->width, mf->height, mf->code);
+	} else {
+		mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which);
+		*mf = fmt->format;
+		dev_dbg(raw->cam_dev,
+			"sd:%s pad:%d set format w/h/code %d/%d/0x%x\n",
+			sd->name, fmt->pad, mf->width, mf->height, mf->code);
+	}
+
+	/*sink pad format propagate to source pad*/
+	if (fmt->pad == MTK_RAW_SINK) {
+		struct v4l2_mbus_framefmt *source_mf;
+
+		source_mf = mtk_raw_pipeline_get_fmt(pipe, sd_state,
+						     MTK_RAW_MAIN_STREAM_OUT,
+						     fmt->which);
+
+		if (streaming) {
+			propagate_fmt(mf, source_mf, mf->width, mf->height);
+			return 0;
+		}
+
+		/**
+		 * User will trigger resource calc
+		 * with V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC
+		 * so we don't need to trigger it here anymore.
+		 */
+		propagate_fmt(mf, source_mf, mf->width, mf->height);
+	}
+
+	return 0;
+}
+
+static int mtk_raw_set_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_state *sd_state,
+			   struct v4l2_subdev_format *fmt)
+{
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		return mtk_raw_try_pad_fmt(sd, sd_state, fmt);
+
+	/* The format can't be changed while streaming. */
+	if (!media_entity_is_streaming(&sd->entity))
+		return mtk_raw_call_set_fmt(sd, sd_state, fmt, false);
+
+	dev_info(sd->v4l2_dev->dev,
+		 "Pipeline is streaming, cannot change format\n");
+	return -EBUSY;
+}
+
+static int mtk_raw_get_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_state *sd_state,
+			  struct v4l2_subdev_format *fmt)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+	struct v4l2_mbus_framefmt *mf;
+
+	mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which);
+	fmt->format = *mf;
+	dev_dbg(raw->cam_dev, "sd:%s pad:%d get format w/h/code %d/%d/0x%x\n",
+		sd->name, fmt->pad, fmt->format.width, fmt->format.height,
+		fmt->format.code);
+
+	return 0;
+}
+
+static int mtk_cam_media_link_setup(struct media_entity *entity,
+				    const struct media_pad *local,
+				    const struct media_pad *remote, u32 flags)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(entity, struct mtk_raw_pipeline, subdev.entity);
+	struct mtk_raw *raw = pipe->raw;
+	u32 pad = local->index;
+
+	dev_dbg(raw->cam_dev,
+		"%s: raw %d: remote:%s:%d->local:%s:%d flags:0x%x\n",
+		__func__, pipe->id, remote->entity->name, remote->index,
+		local->entity->name, local->index, flags);
+
+	if (pad < MTK_RAW_PIPELINE_PADS_NUM && pad != MTK_RAW_SINK)
+		pipe->vdev_nodes[pad - MTK_RAW_SINK_NUM].enabled =
+			!!(flags & MEDIA_LNK_FL_ENABLED);
+
+	if (!media_entity_is_streaming(entity) && !(flags & MEDIA_LNK_FL_ENABLED))
+		memset(pipe->cfg, 0, sizeof(pipe->cfg));
+
+	if (pad == MTK_RAW_SINK && flags & MEDIA_LNK_FL_ENABLED)
+		pipe->res_config.seninf =
+			media_entity_to_v4l2_subdev(remote->entity);
+
+	return 0;
+}
+
+static int mtk_raw_set_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *state,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+
+	dev_dbg(raw->cam_dev, "%s:pipe(%d):current res: fps = %d/%d",
+		__func__, pipe->id,
+		fi->interval.numerator, fi->interval.denominator);
+	pipe->res_config.interval = fi->interval;
+
+	return 0;
+}
+
+static int mtk_raw_get_frame_interval(struct v4l2_subdev *sd,
+				      struct v4l2_subdev_state *state,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mtk_raw_pipeline *pipe =
+		container_of(sd, struct mtk_raw_pipeline, subdev);
+	struct mtk_raw *raw = pipe->raw;
+
+	dev_dbg(raw->cam_dev, "%s:pipe(%d):current res: fps = %d/%d",
+		__func__, pipe->id,
+		fi->interval.numerator, fi->interval.denominator);
+	fi->interval = pipe->res_config.interval;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops mtk_raw_subdev_core_ops = {
+	.subscribe_event = mtk_raw_sd_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops mtk_raw_subdev_video_ops = {
+	.s_stream =  mtk_raw_sd_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops mtk_raw_subdev_pad_ops = {
+	.link_validate = mtk_cam_link_validate,
+	.set_fmt = mtk_raw_set_fmt,
+	.get_fmt = mtk_raw_get_fmt,
+	.set_selection = mtk_raw_set_pad_selection,
+	.get_selection = mtk_raw_get_pad_selection,
+	.set_frame_interval = mtk_raw_set_frame_interval,
+	.get_frame_interval = mtk_raw_get_frame_interval,
+};
+
+static const struct v4l2_subdev_internal_ops mtk_raw_subdev_internal_ops = {
+	.init_state = mtk_raw_init_state,
+};
+
+static const struct v4l2_subdev_ops mtk_raw_subdev_ops = {
+	.core = &mtk_raw_subdev_core_ops,
+	.video = &mtk_raw_subdev_video_ops,
+	.pad = &mtk_raw_subdev_pad_ops,
+};
+
+static const struct media_entity_operations mtk_cam_media_entity_ops = {
+	.link_setup = mtk_cam_media_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_ioctl_ops mtk_cam_v4l2_vout_ioctl_ops = {
+	.vidioc_querycap = mtk_cam_vidioc_querycap,
+	.vidioc_enum_framesizes = mtk_cam_vidioc_enum_framesizes,
+	.vidioc_enum_fmt_vid_out = mtk_cam_vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_out_mplane = mtk_cam_vidioc_g_fmt,
+	.vidioc_s_fmt_vid_out_mplane = mtk_cam_vidioc_s_fmt,
+	.vidioc_try_fmt_vid_out_mplane = mtk_cam_vidioc_try_fmt,
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ioctl_ops mtk_cam_v4l2_vcap_ioctl_ops = {
+	.vidioc_querycap = mtk_cam_vidioc_querycap,
+	.vidioc_enum_framesizes = mtk_cam_vidioc_enum_framesizes,
+	.vidioc_enum_fmt_vid_cap = mtk_cam_vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap_mplane = mtk_cam_vidioc_g_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = mtk_cam_vidioc_s_fmt,
+	.vidioc_try_fmt_vid_cap_mplane = mtk_cam_vidioc_try_fmt,
+	.vidioc_s_selection = mtk_cam_vidioc_s_selection,
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ioctl_ops mtk_cam_v4l2_meta_cap_ioctl_ops = {
+	.vidioc_querycap = mtk_cam_vidioc_querycap,
+	.vidioc_enum_fmt_meta_cap = mtk_cam_vidioc_meta_enum_fmt,
+	.vidioc_g_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_s_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_try_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static const struct v4l2_ioctl_ops mtk_cam_v4l2_meta_out_ioctl_ops = {
+	.vidioc_querycap = mtk_cam_vidioc_querycap,
+	.vidioc_enum_fmt_meta_out = mtk_cam_vidioc_meta_enum_fmt,
+	.vidioc_g_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_s_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_try_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt,
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static const struct mtk_cam_format_desc  stream_out_fmts[] = {
+	/* This is a default image format */
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR8,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SBGGR10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SBGGR10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SBGGR10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SBGGR12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SBGGR12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SBGGR12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SBGGR14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SBGGR14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SBGGR14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG8,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGBRG8_1X8,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGBRG10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGBRG10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGBRG10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGBRG12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGBRG12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGBRG12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGBRG14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGBRG14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGBRG14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG8,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRBG10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGRBG10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGRBG12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRBG12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGRBG12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGRBG14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRBG14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SGRBG14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB8,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SRGGB8_1X8,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SRGGB10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SRGGB10,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SRGGB10_1X10,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB10P,
+		},
+	},
+
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SRGGB12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SRGGB12,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SRGGB12_1X12,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SRGGB14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SRGGB14,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_MTISP_SRGGB14_1X14,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SBGGR16,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SBGGR16_1X16,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGBRG16,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGBRG16_1X16,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SGRBG16,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SGRBG16_1X16,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_SRGGB16,
+			.num_planes = 1,
+		},
+		.pfmt = {
+			.code = MEDIA_BUS_FMT_SRGGB16_1X16,
+		}
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_BAYER8_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_BAYER10_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_BAYER12_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = IMG_MAX_WIDTH,
+			.height = IMG_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_BAYER14_UFBC,
+		},
+	},
+};
+
+static const struct mtk_cam_format_desc yuv_out_group1_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12_12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21_12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_12P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_12P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_YUV420,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_10_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_10_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_12_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_12_UFBC,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRB8F,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRB10F,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = YUV_GROUP1_MAX_WIDTH,
+			.height = YUV_GROUP1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_SGRB12F,
+		},
+	}
+};
+
+static const struct mtk_cam_format_desc yuv_out_group2_fmts[] = {
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV12,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV21,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV12_10,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV21_10,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV12_12,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_NV21_12,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_MTISP_NV12_12P,
+        },
+    },
+    {
+        .vfmt.fmt.pix_mp = {
+            .pixelformat = V4L2_PIX_FMT_MTISP_NV21_12P,
+        },
+    }
+};
+
+static const struct mtk_cam_format_desc rzh1n2to1_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO1_MAX_WIDTH,
+			.height = RZH1N2TO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO1_MAX_WIDTH,
+			.height = RZH1N2TO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO1_MAX_WIDTH,
+			.height = RZH1N2TO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV16,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO1_MAX_WIDTH,
+			.height = RZH1N2TO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV61,
+		},
+	}
+};
+
+static const struct mtk_cam_format_desc rzh1n2to2_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO2_MAX_WIDTH,
+			.height = RZH1N2TO2_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_YUYV,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO2_MAX_WIDTH,
+			.height = RZH1N2TO2_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_YVYU,
+		},
+	}
+};
+
+static const struct mtk_cam_format_desc rzh1n2to3_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO3_MAX_WIDTH,
+			.height = RZH1N2TO3_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO3_MAX_WIDTH,
+			.height = RZH1N2TO3_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO3_MAX_WIDTH,
+			.height = RZH1N2TO3_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV16,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = RZH1N2TO3_MAX_WIDTH,
+			.height = RZH1N2TO3_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV61,
+		},
+	}
+};
+
+static const struct mtk_cam_format_desc drzs4no1_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_GREY,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV16,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV61,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV16_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV61_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV16_10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV61_10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV12_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_NV21_10,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P,
+		},
+	},
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO1_MAX_WIDTH,
+			.height = DRZS4NO1_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P,
+		},
+	},
+};
+
+static const struct mtk_cam_format_desc drzs4no2_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO2_MAX_WIDTH,
+			.height = DRZS4NO2_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_GREY,
+		},
+	}
+};
+
+static const struct mtk_cam_format_desc drzs4no3_out_fmts[] = {
+	{
+		.vfmt.fmt.pix_mp = {
+			.width = DRZS4NO3_MAX_WIDTH,
+			.height = DRZS4NO3_MAX_HEIGHT,
+			.pixelformat = V4L2_PIX_FMT_GREY,
+		},
+	}
+};
+
+#define MTK_RAW_TOTAL_OUTPUT_QUEUES 4
+
+static const struct
+mtk_cam_dev_node_desc output_queues[] = {
+	{
+		.id = MTK_RAW_META_IN,
+		.name = "meta input",
+		.cap = V4L2_CAP_META_OUTPUT,
+		.buf_type = V4L2_BUF_TYPE_META_OUTPUT,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = false,
+		.smem_alloc = true,
+		/* .need_cache_sync_on_prepare = true, */
+		.dma_port = MTKCAM_ISP_META_STATS_CFG,
+		.default_fmt_idx = 0,
+		.max_buf_count = 16,
+		.ioctl_ops = &mtk_cam_v4l2_meta_out_ioctl_ops,
+	},
+	{
+		.id = MTK_RAW_RAWI_2_IN,
+		.name = "rawi 2",
+		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RAWI_2,
+		.fmts = stream_out_fmts,
+		.num_fmts = ARRAY_SIZE(stream_out_fmts),
+		.default_fmt_idx = 0,
+		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = IMG_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = IMG_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_RAWI_3_IN,
+		.name = "rawi 3",
+		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+		.link_flags = 0,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RAWI_3,
+		.fmts = stream_out_fmts,
+		.num_fmts = ARRAY_SIZE(stream_out_fmts),
+		.default_fmt_idx = 0,
+		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = IMG_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = IMG_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_RAWI_4_IN,
+		.name = "rawi 4",
+		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+		.link_flags = 0,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RAWI_3, /* align backend RAWI_3 */
+		.fmts = stream_out_fmts,
+		.num_fmts = ARRAY_SIZE(stream_out_fmts),
+		.default_fmt_idx = 0,
+		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = IMG_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = IMG_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	}
+};
+
+static const
+char *output_queue_names[RAW_PIPELINE_NUM][MTK_RAW_TOTAL_OUTPUT_QUEUES] = {
+	{"mtk-cam raw-0 meta-input", "mtk-cam raw-0 rawi-2",
+	 "mtk-cam raw-0 rawi-3", "mtk-cam raw-0 rawi-4"},
+
+	{"mtk-cam raw-1 meta-input", "mtk-cam raw-1 rawi-2",
+	 "mtk-cam raw-1 rawi-3", "mtk-cam raw-1 rawi-4"},
+
+	{"mtk-cam raw-2 meta-input", "mtk-cam raw-2 rawi-2",
+	 "mtk-cam raw-2 rawi-3", "mtk-cam raw-2 rawi-4"},
+};
+
+static struct mtk_cam_pad_ops source_pad_ops_default = {
+	.set_pad_fmt = mtk_raw_set_src_pad_fmt_default,
+	.set_pad_selection = mtk_raw_set_src_pad_selection_default,
+};
+
+static struct mtk_cam_pad_ops source_pad_ops_yuv = {
+	.set_pad_fmt = mtk_raw_set_src_pad_fmt_default,
+	.set_pad_selection = mtk_raw_set_src_pad_selection_yuv,
+};
+
+static struct mtk_cam_pad_ops source_pad_ops_drzs4no = {
+	.set_pad_fmt = mtk_raw_set_src_pad_fmt_default,
+	.set_pad_selection = mtk_raw_set_src_pad_selection_default,
+};
+
+static struct mtk_cam_pad_ops source_pad_ops_rzh1n2 = {
+	.set_pad_fmt = mtk_raw_set_src_pad_fmt_rzh1n2,
+	.set_pad_selection = mtk_raw_set_src_pad_selection_default,
+};
+
+#define MTK_RAW_TOTAL_CAPTURE_QUEUES 1
+static const struct
+mtk_cam_dev_node_desc capture_queues[] = {
+	{
+		.id = MTK_RAW_MAIN_STREAM_OUT,
+		.name = "imgo",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_IMGO,
+		.fmts = stream_out_fmts,
+		.num_fmts = ARRAY_SIZE(stream_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_default,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = IMG_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = IMG_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_YUVO_1_OUT,
+		.name = "yuvo 1",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_YUVO_1,
+		.fmts = yuv_out_group1_fmts,
+		.num_fmts = ARRAY_SIZE(yuv_out_group1_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_yuv,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = YUV_GROUP1_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = YUV_GROUP1_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_YUVO_2_OUT,
+		.name = "yuvo 2",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_YUVO_2,
+		.fmts = yuv_out_group2_fmts,
+		.num_fmts = ARRAY_SIZE(yuv_out_group2_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_yuv,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = YUV_GROUP2_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = YUV_GROUP2_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_YUVO_3_OUT,
+		.name = "yuvo 3",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_YUVO_3,
+		.fmts = yuv_out_group1_fmts,
+		.num_fmts = ARRAY_SIZE(yuv_out_group1_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_yuv,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = YUV_GROUP1_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = YUV_GROUP1_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_YUVO_4_OUT,
+		.name = "yuvo 4",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_YUVO_4,
+		.fmts = yuv_out_group2_fmts,
+		.num_fmts = ARRAY_SIZE(yuv_out_group2_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_yuv,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = YUV_GROUP2_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = YUV_GROUP2_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_YUVO_5_OUT,
+		.name = "yuvo 5",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_YUVO_5,
+		.fmts = yuv_out_group2_fmts,
+		.num_fmts = ARRAY_SIZE(yuv_out_group2_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_yuv,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = YUV_GROUP2_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = YUV_GROUP2_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_DRZS4NO_1_OUT,
+		.name = "drzs4no 1",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_DRZS4NO_1,
+		.fmts = drzs4no1_out_fmts,
+		.num_fmts = ARRAY_SIZE(drzs4no1_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_drzs4no,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = DRZS4NO1_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = DRZS4NO1_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_DRZS4NO_2_OUT,
+		.name = "drzs4no 2",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_DRZS4NO_2,
+		.fmts = drzs4no2_out_fmts,
+		.num_fmts = ARRAY_SIZE(drzs4no2_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_drzs4no,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = DRZS4NO2_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = DRZS4NO2_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_DRZS4NO_3_OUT,
+		.name = "drzs4no 3",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_DRZS4NO_3,
+		.fmts = drzs4no3_out_fmts,
+		.num_fmts = ARRAY_SIZE(drzs4no3_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_drzs4no,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = DRZS4NO3_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = DRZS4NO3_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_RZH1N2TO_1_OUT,
+		.name = "rzh1n2to 1",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RZH1N2TO_1,
+		.fmts = rzh1n2to1_out_fmts,
+		.num_fmts = ARRAY_SIZE(rzh1n2to1_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_rzh1n2,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = RZH1N2TO1_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = RZH1N2TO1_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_RZH1N2TO_2_OUT,
+		.name = "rzh1n2to 2",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RZH1N2TO_2,
+		.fmts = rzh1n2to2_out_fmts,
+		.num_fmts = ARRAY_SIZE(rzh1n2to2_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_rzh1n2,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = RZH1N2TO2_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = RZH1N2TO2_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_RZH1N2TO_3_OUT,
+		.name = "rzh1n2to 3",
+		.cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+		.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = true,
+		.smem_alloc = false,
+		.dma_port = MTKCAM_ISP_RZH1N2TO_3,
+		.fmts = rzh1n2to3_out_fmts,
+		.num_fmts = ARRAY_SIZE(rzh1n2to3_out_fmts),
+		.default_fmt_idx = 0,
+		.pad_ops = &source_pad_ops_rzh1n2,
+		.ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops,
+		.frmsizes = &(struct v4l2_frmsizeenum) {
+			.index = 0,
+			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
+			.stepwise = {
+				.max_width = RZH1N2TO3_MAX_WIDTH,
+				.min_width = IMG_MIN_WIDTH,
+				.max_height = RZH1N2TO3_MAX_HEIGHT,
+				.min_height = IMG_MIN_HEIGHT,
+				.step_height = 1,
+				.step_width = 1,
+			},
+		},
+	},
+	{
+		.id = MTK_RAW_META_OUT_0,
+		.name = "partial meta 0",
+		.cap = V4L2_CAP_META_CAPTURE,
+		.buf_type = V4L2_BUF_TYPE_META_CAPTURE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = false,
+		.smem_alloc = true,
+		.dma_port = MTKCAM_ISP_META_STATS_0,
+		.default_fmt_idx = 1,
+		.max_buf_count = 16,
+		.ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops,
+	},
+	{
+		.id = MTK_RAW_META_OUT_1,
+		.name = "partial meta 1",
+		.cap = V4L2_CAP_META_CAPTURE,
+		.buf_type = V4L2_BUF_TYPE_META_CAPTURE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = false,
+		.smem_alloc = true,
+		/* .need_cache_sync_on_finish = true, */
+		.dma_port = MTKCAM_ISP_META_STATS_1,
+		.default_fmt_idx = 2,
+		.max_buf_count = 16,
+		.ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops,
+	},
+	{
+		.id = MTK_RAW_META_OUT_2,
+		.name = "partial meta 2",
+		.cap = V4L2_CAP_META_CAPTURE,
+		.buf_type = V4L2_BUF_TYPE_META_CAPTURE,
+		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
+		.image = false,
+		.smem_alloc = false,
+		/* .need_cache_sync_on_finish = true, */
+		.dma_port = MTKCAM_ISP_META_STATS_2,
+		.default_fmt_idx = 3,
+		.max_buf_count = 16,
+		.ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops,
+	},
+};
+
+static const
+char *capture_queue_names[RAW_PIPELINE_NUM][MTK_RAW_TOTAL_CAPTURE_QUEUES] = {
+    {"mtk-cam raw-0 main-stream"},
+    {"mtk-cam raw-1 main-stream"},
+    {"mtk-cam raw-2 main-stream"},
+};
+
+/* The helper to configure the device context */
+static void mtk_raw_pipeline_queue_setup(struct mtk_raw_pipeline *pipe)
+{
+	unsigned int node_idx, i;
+
+	if (WARN_ON(MTK_RAW_TOTAL_OUTPUT_QUEUES + MTK_RAW_TOTAL_CAPTURE_QUEUES
+	    != MTK_RAW_TOTAL_NODES))
+		return;
+
+	node_idx = 0;
+	/* Setup the output queue */
+	for (i = 0; i < MTK_RAW_TOTAL_OUTPUT_QUEUES; i++) {
+		pipe->vdev_nodes[node_idx].desc = output_queues[i];
+
+		/* set input meta format */
+		if (pipe->vdev_nodes[node_idx].desc.id == MTK_RAW_META_IN)
+			pipe->vdev_nodes[node_idx].desc.fmts =
+				camsys_get_meta_fmts();
+
+		pipe->vdev_nodes[node_idx++].desc.name =
+			output_queue_names[pipe->id][i];
+	}
+
+	/* Setup the capture queue */
+	for (i = 0; i < MTK_RAW_TOTAL_CAPTURE_QUEUES; i++) {
+		pipe->vdev_nodes[node_idx].desc = capture_queues[i];
+
+		/* set partial meta and external meta format */
+		if (pipe->vdev_nodes[node_idx].desc.id >= MTK_RAW_META_OUT_BEGIN &&
+		    pipe->vdev_nodes[node_idx].desc.id <= MTK_RAW_META_OUT_2)
+			pipe->vdev_nodes[node_idx].desc.fmts =
+				camsys_get_meta_fmts();
+
+		pipe->vdev_nodes[node_idx++].desc.name =
+			capture_queue_names[pipe->id][i];
+	}
+}
+
+static void mtk_raw_pipeline_ctrl_setup(struct mtk_raw_pipeline *pipe)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr;
+	struct v4l2_ctrl *ctrl;
+	struct device *dev = pipe->raw->devs[pipe->id];
+	int ret = 0;
+
+	ctrl_hdlr = &pipe->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 5);
+	if (ret) {
+		dev_info(dev, "v4l2_ctrl_handler init failed\n");
+		return;
+	}
+	mutex_init(&pipe->res_config.resource_lock);
+	mutex_init(&pipe->try_res_config.resource_lock);
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn_limit, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz_limit, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin_limit, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn_try, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz_try, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin_try, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	v4l2_ctrl_new_custom(ctrl_hdlr, &res_plan_policy, NULL);
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &res_pixel_rate, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frame_sync_id, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &raw_path, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &cam_ctrl_ops,
+			  V4L2_CID_HBLANK, 0, 65535, 1, 0);
+	v4l2_ctrl_new_std(ctrl_hdlr, &cam_ctrl_ops,
+			  V4L2_CID_VBLANK, 0, 65535, 1, 0);
+
+	/* PDE */
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_pde_info, NULL);
+
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &mtk_feature, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_res_update, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_res_ctrl, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	ctrl = v4l2_ctrl_new_custom(ctrl_hdlr,
+				    &mtk_camsys_hw_mode, NULL);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+
+	pipe->res_config.hwn_limit_max = hwn_limit.def;
+	pipe->res_config.frz_limit = frz_limit.def;
+	pipe->res_config.bin_limit = bin_limit.def;
+	pipe->res_config.res_plan = res_plan_policy.def;
+	pipe->feature_pending = mtk_feature.def;
+	pipe->sync_id = frame_sync_id.def;
+	pipe->sensor_mode_update = cfg_res_update.def;
+	pipe->pde_config.pde_info.pdo_max_size = cfg_pde_info.def;
+	pipe->pde_config.pde_info.pdi_max_size = cfg_pde_info.def;
+	pipe->pde_config.pde_info.pd_table_offset = cfg_pde_info.def;
+	pipe->subdev.ctrl_handler = ctrl_hdlr;
+	pipe->hw_mode = mtk_camsys_hw_mode.def;
+}
+
+static int mtk_raw_pipeline_register(unsigned int id, struct device *dev,
+				     struct mtk_raw_pipeline *pipe,
+				     struct v4l2_device *v4l2_dev)
+{
+	struct mtk_cam_device *cam = dev_get_drvdata(pipe->raw->cam_dev);
+	struct v4l2_subdev *sd = &pipe->subdev;
+	struct mtk_cam_video_device *video;
+	unsigned int i;
+	int ret;
+
+	pipe->id = id;
+
+	/* Initialize raw_pipe subdev */
+	v4l2_subdev_init(sd, &mtk_raw_subdev_ops);
+	sd->internal_ops = &mtk_raw_subdev_internal_ops;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->entity.ops = &mtk_cam_media_entity_ops;
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+	snprintf(sd->name, sizeof(sd->name),
+		 "%s-%d", dev_driver_string(dev), pipe->id);
+	v4l2_set_subdevdata(sd, pipe);
+	mtk_raw_pipeline_ctrl_setup(pipe);
+	dev_info(dev, "%s: %s\n", __func__, sd->name);
+
+	ret = v4l2_device_register_subdev(v4l2_dev, sd);
+	if (ret < 0) {
+		dev_info(dev, "Failed to register subdev: %d\n", ret);
+		return ret;
+	}
+
+	mtk_raw_pipeline_queue_setup(pipe);
+	/* setup pads of raw pipeline */
+	for (i = 0; i < ARRAY_SIZE(pipe->pads); i++) {
+		pipe->pads[i].flags = i < MTK_RAW_SOURCE_BEGIN ?
+			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+	}
+
+	media_entity_pads_init(&sd->entity, ARRAY_SIZE(pipe->pads), pipe->pads);
+
+	/* setup video node */
+	for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++) {
+		video = pipe->vdev_nodes + i;
+
+		switch (pipe->id) {
+		case MTKCAM_SUBDEV_RAW_0:
+		case MTKCAM_SUBDEV_RAW_1:
+		case MTKCAM_SUBDEV_RAW_2:
+			video->uid.pipe_id = pipe->id;
+			break;
+		default:
+			dev_err(dev, "invalid pipe id\n");
+			return -EINVAL;
+		}
+
+		video->uid.id = video->desc.dma_port;
+		video->ctx = &cam->ctxs[id];
+		ret = mtk_cam_video_register(video, v4l2_dev);
+		if (ret)
+			goto fail_unregister_video;
+
+		if (V4L2_TYPE_IS_OUTPUT(video->desc.buf_type))
+			ret = media_create_pad_link(&video->vdev.entity, 0,
+						    &sd->entity,
+						    video->desc.id,
+						    video->desc.link_flags);
+		else
+			ret = media_create_pad_link(&sd->entity,
+						    video->desc.id,
+						    &video->vdev.entity, 0,
+						    video->desc.link_flags);
+
+		if (ret)
+			goto fail_unregister_video;
+	}
+
+	for (i = 0; i < sd->entity.num_pads; i++)
+		pipe->cfg[i].mbus_fmt = mfmt_default;
+
+	return 0;
+
+fail_unregister_video:
+	if (!i)
+		return ret;
+
+	for (i = i - 1; i >= 0; i--)
+		mtk_cam_video_unregister(pipe->vdev_nodes + i);
+
+	return ret;
+}
+
+static void mtk_raw_pipeline_unregister(struct mtk_raw_pipeline *pipe)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++)
+		mtk_cam_video_unregister(pipe->vdev_nodes + i);
+	v4l2_ctrl_handler_free(&pipe->ctrl_handler);
+	mutex_destroy(&pipe->res_config.resource_lock);
+	v4l2_device_unregister_subdev(&pipe->subdev);
+	media_entity_cleanup(&pipe->subdev.entity);
+}
+
+int mtk_cam_raw_setup_dependencies(struct mtk_raw *raw)
+{
+	struct device *dev = raw->cam_dev;
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	struct device *consumer, *supplier;
+	struct device_link *link;
+	struct mtk_raw_device *raw_dev;
+	struct mtk_yuv_device *yuv_dev;
+	int i;
+
+	for (i = 0; i < cam_dev->num_raw_devices; i++) {
+		consumer = raw->devs[i];
+		supplier = raw->yuvs[i];
+		if (!consumer || !supplier) {
+			dev_info(dev, "failed to get raw/yuv dev for id %d\n", i);
+			continue;
+		}
+
+		raw_dev = dev_get_drvdata(consumer);
+		yuv_dev = dev_get_drvdata(supplier);
+		raw_dev->yuv_base = yuv_dev->base;
+
+		link = device_link_add(consumer, supplier,
+				       DL_FLAG_AUTOREMOVE_CONSUMER |
+				       DL_FLAG_PM_RUNTIME);
+		if (!link) {
+			dev_err(dev, "Unable to create link between %s and %s\n",
+				dev_name(consumer), dev_name(supplier));
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+int mtk_cam_raw_register_entities(struct mtk_raw *raw, struct v4l2_device *v4l2_dev)
+{
+	struct device *dev = raw->cam_dev;
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < cam_dev->num_raw_devices; i++) {
+		struct mtk_raw_pipeline *pipe = raw->pipelines + i;
+
+		pipe->raw = raw;
+		memset(pipe->cfg, 0, sizeof(*pipe->cfg));
+		ret = mtk_raw_pipeline_register(MTKCAM_SUBDEV_RAW_0 + i,
+						raw->devs[i],
+						raw->pipelines + i, v4l2_dev);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+void mtk_cam_raw_unregister_entities(struct mtk_raw *raw)
+{
+	struct device *dev = raw->cam_dev;
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	unsigned int i;
+
+	for (i = 0; i < cam_dev->num_raw_devices; i++)
+		mtk_raw_pipeline_unregister(raw->pipelines + i);
+}
+
+static int mtk_raw_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_raw_device *raw_dev;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	raw_dev = devm_kzalloc(dev, sizeof(*raw_dev), GFP_KERNEL);
+	if (!raw_dev)
+		return -ENOMEM;
+
+	raw_dev->dev = dev;
+	dev_set_drvdata(dev, raw_dev);
+
+	ret = mtk_raw_of_probe(pdev, raw_dev);
+	if (ret)
+		return ret;
+
+	raw_dev->fifo_size =
+		roundup_pow_of_two(8 * sizeof(struct mtk_camsys_irq_info));
+	raw_dev->msg_buffer = devm_kzalloc(dev, raw_dev->fifo_size, GFP_KERNEL);
+	if (!raw_dev->msg_buffer)
+		return -ENOMEM;
+
+	/* register raw as mtk_cam async child */
+	sd = &raw_dev->subdev;
+	v4l2_subdev_init(sd, &mtk_raw_subdev_ops);
+	sd->internal_ops = &mtk_raw_subdev_internal_ops;
+	snprintf(sd->name, sizeof(sd->name), "%s",
+		 of_node_full_name(dev->of_node));
+	sd->dev = dev;
+	sd->owner = THIS_MODULE;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret) {
+		dev_err(dev, "%s failed on async_register_subdev\n", __func__);
+		return ret;
+	}
+	dev_dbg(dev, "%s id:%d register subdev\n", __func__, raw_dev->id);
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void mtk_raw_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_raw_device *raw_dev = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &raw_dev->subdev;
+
+	unregister_pm_notifier(&raw_dev->pm_notifier);
+
+	pm_runtime_disable(dev);
+
+	v4l2_async_unregister_subdev(sd);
+}
+
+static int mtk_raw_runtime_suspend(struct device *dev)
+{
+	struct mtk_raw_device *drvdata = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "%s:disable clock\n", __func__);
+
+	disable_irq(drvdata->irq);
+
+	mtk_cam_raw_reset(drvdata);
+
+	clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b);
+
+	return 0;
+}
+
+static int mtk_raw_runtime_resume(struct device *dev)
+{
+	struct mtk_raw_device *drvdata = dev_get_drvdata(dev);
+	int ret;
+
+	/* reset_msgfifo before enable_irq */
+	ret = reset_msgfifo(drvdata);
+	if (ret)
+		return ret;
+
+	enable_irq(drvdata->irq);
+
+	dev_dbg(dev, "%s:enable clock\n", __func__);
+
+	ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clk_b);
+	if (ret) {
+		dev_info(dev, "failed at clk_bulk_prepare_enable, ret = %d\n", ret);
+		clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b);
+		return ret;
+	}
+
+	mtk_cam_raw_reset(drvdata);
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_raw_pm_ops = {
+	SET_RUNTIME_PM_OPS(mtk_raw_runtime_suspend, mtk_raw_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id mtk_raw_of_ids[] = {
+	{.compatible = "mediatek,mt8188-cam-raw",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_raw_of_ids);
+
+struct platform_driver mtk_cam_raw_driver = {
+	.probe   = mtk_raw_probe,
+	.remove  = mtk_raw_remove,
+	.driver  = {
+		.name  = "mtk-cam raw",
+		.of_match_table = mtk_raw_of_ids,
+		.pm     = &mtk_raw_pm_ops,
+	}
+};
+
+static inline unsigned int mtk_yuv_get_err_status(unsigned int irq_status)
+{
+	return irq_status & YUV_DMA_ERR_ST;
+}
+
+static irqreturn_t mtk_irq_yuv(int irq, void *data)
+{
+	struct mtk_yuv_device *drvdata = (struct mtk_yuv_device *)data;
+	struct device *dev = drvdata->dev;
+
+	unsigned int irq_status, err_status, dma_done_status;
+	unsigned int drop_status, dma_ofl_status;
+
+	irq_status =
+		readl_relaxed(drvdata->base + REG_CTL_RAW_INT_STAT);
+	dma_done_status =
+		readl_relaxed(drvdata->base + REG_CTL_RAW_INT2_STAT);
+	drop_status =
+		readl_relaxed(drvdata->base + REG_CTL_RAW_INT4_STAT);
+	dma_ofl_status =
+		readl_relaxed(drvdata->base + REG_CTL_RAW_INT5_STAT);
+
+	err_status = mtk_yuv_get_err_status(irq_status);
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_yuv_pm_suspend_prepare(struct mtk_yuv_device *dev)
+{
+	int ret;
+
+	dev_dbg(dev->dev, "- %s\n", __func__);
+
+	if (pm_runtime_suspended(dev->dev))
+		return 0;
+
+	/* Force ISP HW to idle */
+	ret = pm_runtime_force_suspend(dev->dev);
+	return ret;
+}
+
+static int mtk_yuv_pm_post_suspend(struct mtk_yuv_device *dev)
+{
+	int ret;
+
+	dev_dbg(dev->dev, "- %s\n", __func__);
+
+	if (pm_runtime_suspended(dev->dev))
+		return 0;
+
+	/* Force ISP HW to resume */
+	ret = pm_runtime_force_resume(dev->dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int yuv_pm_notifier(struct notifier_block *nb,
+			   unsigned long action, void *data)
+{
+	struct mtk_yuv_device *yuv_dev =
+			container_of(nb, struct mtk_yuv_device, pm_notifier);
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+		mtk_yuv_pm_suspend_prepare(yuv_dev);
+		break;
+	case PM_POST_SUSPEND:
+		mtk_yuv_pm_post_suspend(yuv_dev);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int mtk_yuv_of_probe(struct platform_device *pdev,
+			    struct mtk_yuv_device *drvdata)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int irq, ret;
+	int n_clks;
+
+	ret = of_property_read_u32(dev->of_node, "mediatek,cam-id",
+				   &drvdata->id);
+	if (ret) {
+		dev_err(dev, "missing camid property\n");
+		return ret;
+	}
+
+	if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) {
+		dev_err(dev, "%s: No suitable DMA available\n", __func__);
+		return -EIO;
+	}
+
+	if (!dev->dma_parms) {
+		dev->dma_parms =
+			devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+		if (!dev->dma_parms)
+			return -ENOMEM;
+	}
+
+	dma_set_max_seg_size(dev, UINT_MAX);
+
+	/* base outer register */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
+	if (!res) {
+		dev_err(dev, "failed to get mem\n");
+		return -ENODEV;
+	}
+
+	drvdata->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(drvdata->base)) {
+		dev_err(dev, "failed to map register base\n");
+		return PTR_ERR(drvdata->base);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_irq(dev, irq, mtk_irq_yuv, 0,
+			       dev_name(dev), drvdata);
+	if (ret) {
+		dev_err(dev, "failed to request irq=%d\n", irq);
+		return ret;
+	}
+
+	n_clks = devm_clk_bulk_get_all(dev, &drvdata->clk_b);
+	if (n_clks < 0)
+		return dev_err_probe(dev, n_clks, "failed to devm_clk_bulk_get_all\n");
+
+	drvdata->num_clks = n_clks;
+
+#ifdef CONFIG_PM_SLEEP
+	drvdata->pm_notifier.notifier_call = yuv_pm_notifier;
+	ret = register_pm_notifier(&drvdata->pm_notifier);
+	if (ret) {
+		dev_err(dev, "failed to register notifier block.\n");
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int mtk_yuv_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_yuv_device *drvdata;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->dev = dev;
+	dev_set_drvdata(dev, drvdata);
+
+	ret = mtk_yuv_of_probe(pdev, drvdata);
+	if (ret)
+    	return ret;
+
+	/* register yuv as mtk_cam async child */
+	sd = &drvdata->subdev;
+	v4l2_subdev_init(sd, &mtk_raw_subdev_ops);
+	sd->internal_ops = &mtk_raw_subdev_internal_ops;
+	snprintf(sd->name, sizeof(sd->name), "%s",
+		 of_node_full_name(dev->of_node));
+	sd->dev = dev;
+	sd->owner = THIS_MODULE;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret) {
+		dev_err(dev, "%s failed on async_register_subdev\n", __func__);
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void mtk_yuv_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev);
+	struct v4l2_subdev *sd = &yuv_dev->subdev;
+
+	unregister_pm_notifier(&yuv_dev->pm_notifier);
+
+	pm_runtime_disable(dev);
+
+	v4l2_async_unregister_subdev(sd);
+}
+
+/* driver for yuv part */
+static int mtk_yuv_runtime_suspend(struct device *dev)
+{
+	struct mtk_yuv_device *drvdata = dev_get_drvdata(dev);
+
+	clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b);
+
+	return 0;
+}
+
+static int mtk_yuv_runtime_resume(struct device *dev)
+{
+	struct mtk_yuv_device *drvdata = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clk_b);
+	if (ret) {
+		dev_info(dev, "failed at clk_bulk_prepare_enable, ret = %d\n", ret);
+		clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_yuv_pm_ops = {
+	SET_RUNTIME_PM_OPS(mtk_yuv_runtime_suspend, mtk_yuv_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id mtk_yuv_of_ids[] = {
+	{.compatible = "mediatek,mt8188-cam-yuv",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_yuv_of_ids);
+
+struct platform_driver mtk_cam_yuv_driver = {
+	.probe   = mtk_yuv_probe,
+	.remove  = mtk_yuv_remove,
+	.driver  = {
+		.name  = "mtk-cam yuv",
+		.of_match_table = mtk_yuv_of_ids,
+		.pm     = &mtk_yuv_pm_ops,
+	}
+};
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h
new file mode 100755
index 000000000000..407de85d82f6
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h
@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_RAW_H
+#define __MTK_CAM_RAW_H
+
+#include <linux/kfifo.h>
+#include <media/v4l2-subdev.h>
+#include "mtk_cam-video.h"
+#include "mtk_camera-v4l2-controls.h"
+
+struct mtk_cam_request_stream_data;
+
+/* ISP7_1 control */
+#define RAW_PIPELINE_NUM 3
+
+#define SCQ_DEADLINE_MS  15 /* ~1/2 frame length */
+#define SCQ_DEFAULT_CLK_RATE 208 /* default 208MHz */
+
+#define MTK_CAMSYS_RES_STEP_NUM	8
+
+/* ISP7_1 image */
+#define IMG_MAX_WIDTH		12000
+#define IMG_MAX_HEIGHT		9000
+
+#define IMG_MIN_WIDTH		80
+#define IMG_MIN_HEIGHT		60
+#define YUV_GROUP1_MAX_WIDTH	8160
+#define YUV_GROUP1_MAX_HEIGHT	3896
+#define YUV_GROUP2_MAX_WIDTH	3060
+#define YUV_GROUP2_MAX_HEIGHT	1145
+#define YUV1_MAX_WIDTH		8160
+#define YUV1_MAX_HEIGHT		2290
+#define YUV2_MAX_WIDTH		3060
+#define YUV2_MAX_HEIGHT		1145
+#define YUV3_MAX_WIDTH		7794
+#define YUV3_MAX_HEIGHT		3896
+#define YUV4_MAX_WIDTH		1530
+#define YUV4_MAX_HEIGHT		572
+#define YUV5_MAX_WIDTH		1530
+#define YUV5_MAX_HEIGHT		572
+#define DRZS4NO1_MAX_WIDTH	2400
+#define DRZS4NO1_MAX_HEIGHT	1080
+#define DRZS4NO2_MAX_WIDTH	2400
+#define DRZS4NO2_MAX_HEIGHT	1080
+#define DRZS4NO3_MAX_WIDTH	576
+#define DRZS4NO3_MAX_HEIGHT	432
+#define RZH1N2TO1_MAX_WIDTH	1280
+#define RZH1N2TO1_MAX_HEIGHT	600
+#define RZH1N2TO2_MAX_WIDTH	512
+#define RZH1N2TO2_MAX_HEIGHT	512
+#define RZH1N2TO3_MAX_WIDTH	1280
+#define RZH1N2TO3_MAX_HEIGHT	600
+
+#define IMG_PIX_ALIGN		2
+
+enum raw_module_id {
+	RAW_A = 0,
+	RAW_B = 1,
+	RAW_C = 2,
+	RAW_NUM,
+};
+
+/* feature mask to categorize all raw functions */
+#define MTK_CAM_FEATURE_HDR_MASK		0x0000000F
+#define MTK_CAM_FEATURE_SUBSAMPLE_MASK		0x000000F0
+
+enum raw_function_id {
+	/* bit [0~3] hdr */
+	/* bit [4~7] fps */
+	/* bit [8~9] m2m */
+	OFFLINE_M2M			= (1 << 8),
+	PURE_OFFLINE_M2M		= (1 << 9),
+	RAW_FUNCTION_END		= 0xF0000000,
+};
+
+enum hardware_mode_id {
+	DEFAULT			= 0,
+	ON_THE_FLY		= 1,
+	DCIF			= 2,
+};
+
+/* enum for pads of raw pipeline */
+enum {
+	MTK_RAW_SINK_BEGIN = 0,
+	MTK_RAW_SINK = MTK_RAW_SINK_BEGIN,
+	MTK_RAW_SINK_NUM,
+	MTK_RAW_META_IN = MTK_RAW_SINK_NUM,
+	MTK_RAW_RAWI_2_IN,
+	MTK_RAW_RAWI_3_IN,
+	MTK_RAW_RAWI_4_IN,
+	MTK_RAW_SOURCE_BEGIN,
+	MTK_RAW_MAIN_STREAM_OUT = MTK_RAW_SOURCE_BEGIN,
+	MTK_RAW_YUVO_1_OUT,
+	MTK_RAW_YUVO_2_OUT,
+	MTK_RAW_YUVO_3_OUT,
+	MTK_RAW_YUVO_4_OUT,
+	MTK_RAW_YUVO_5_OUT,
+	MTK_RAW_DRZS4NO_1_OUT,
+	MTK_RAW_DRZS4NO_2_OUT,
+	MTK_RAW_DRZS4NO_3_OUT,
+	MTK_RAW_RZH1N2TO_1_OUT,
+	MTK_RAW_RZH1N2TO_2_OUT,
+	MTK_RAW_RZH1N2TO_3_OUT,
+	MTK_RAW_META_OUT_BEGIN,
+	MTK_RAW_META_OUT_0 = MTK_RAW_META_OUT_BEGIN,
+	MTK_RAW_META_OUT_1,
+	MTK_RAW_META_OUT_2,
+	MTK_RAW_PIPELINE_PADS_NUM,
+};
+
+static inline bool is_yuv_node(u32 desc_id)
+{
+	switch (desc_id) {
+	case MTK_RAW_YUVO_1_OUT:
+	case MTK_RAW_YUVO_2_OUT:
+	case MTK_RAW_YUVO_3_OUT:
+	case MTK_RAW_YUVO_4_OUT:
+	case MTK_RAW_YUVO_5_OUT:
+	case MTK_RAW_DRZS4NO_1_OUT:
+	case MTK_RAW_DRZS4NO_2_OUT:
+	case MTK_RAW_DRZS4NO_3_OUT:
+	case MTK_RAW_RZH1N2TO_1_OUT:
+	case MTK_RAW_RZH1N2TO_2_OUT:
+	case MTK_RAW_RZH1N2TO_3_OUT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* max(pdi_table1, pdi_table2, ...) */
+#define RAW_STATS_CFG_VARIOUS_SIZE ALIGN(0x7500, SZ_1K)
+
+#define MTK_RAW_TOTAL_NODES (MTK_RAW_PIPELINE_PADS_NUM - MTK_RAW_SINK_NUM)
+
+struct mtk_cam_dev;
+struct mtk_cam_ctx;
+
+struct mtk_raw_pde_config {
+	struct mtk_cam_pde_info pde_info;
+};
+
+struct mtk_cam_resource_config {
+	struct v4l2_subdev *seninf;
+	struct mutex resource_lock; /* protect resource calculation */
+	struct v4l2_fract interval;
+	s64 pixel_rate;
+	u32 bin_limit;
+	u32 frz_limit;
+	u32 hwn_limit_max;
+	u32 hwn_limit_min;
+	s64 hblank;
+	s64 vblank;
+	s64 sensor_pixel_rate;
+	u32 res_plan;
+	u32 raw_feature;
+	u32 res_strategy[MTK_CAMSYS_RES_STEP_NUM];
+	u32 clk_target;
+	u32 raw_num_used;
+	u32 bin_enable;
+	u32 frz_enable;
+	u32 frz_ratio;
+	u32 tgo_pxl_mode;
+	u32 raw_path;
+	/* sink fmt adjusted according resource used*/
+	struct v4l2_mbus_framefmt sink_fmt;
+};
+
+struct mtk_raw_pad_config {
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct v4l2_rect crop;
+};
+
+/*
+ * struct mtk_raw_pipeline - sub dev to use raws.
+ *
+ * @feature_pending: keep the user value of S_CTRL V4L2_CID_MTK_CAM_FEATURE.
+ *		     It it safe save to be used in mtk_cam_vidioc_s_fmt,
+ *		     mtk_cam_vb2_queue_setup and mtk_cam_vb2_buf_queue
+ *		     But considering that we can't when the user calls S_CTRL,
+ *		     please use mtk_cam_request_stream_data's
+ *		     feature.raw_feature field
+ *		     to avoid the CTRL value change tming issue.
+ * @feature_active: The active feature during streaming. It can't be changed
+ *		    during streaming and can only be used after streaming on.
+ *
+ */
+struct mtk_raw_pipeline {
+	unsigned int id;
+	struct v4l2_subdev subdev;
+	struct media_pad pads[MTK_RAW_PIPELINE_PADS_NUM];
+	struct mtk_cam_video_device vdev_nodes[MTK_RAW_TOTAL_NODES];
+	struct mtk_raw *raw;
+	struct mtk_raw_pad_config cfg[MTK_RAW_PIPELINE_PADS_NUM];
+
+	/* cached settings */
+	unsigned int enabled_raw;
+	unsigned long enabled_dmas;
+	/* resource controls */
+	struct v4l2_ctrl_handler ctrl_handler;
+	s64 feature_pending;
+	s64 feature_active;
+
+	struct mtk_cam_resource user_res;
+	struct mtk_cam_resource_config res_config;
+	struct mtk_cam_resource_config try_res_config;
+	int sensor_mode_update;
+	s64 sync_id;
+	/* pde module */
+	struct mtk_raw_pde_config pde_config;
+	s64 hw_mode;
+};
+
+struct mtk_raw_device {
+	struct v4l2_subdev subdev;
+	struct device *dev;
+	struct mtk_cam_device *cam;
+	unsigned int id;
+	int irq;
+	void __iomem *base;
+	void __iomem *base_inner;
+	void __iomem *yuv_base;
+	unsigned int num_clks;
+	struct clk_bulk_data *clk_b;
+#ifdef CONFIG_PM_SLEEP
+	struct notifier_block pm_notifier;
+#endif
+
+	unsigned int	fifo_size;
+	void		*msg_buffer;
+	struct kfifo	msg_fifo;
+	atomic_t	is_fifo_overflow;
+
+	struct mtk_raw_pipeline *pipeline;
+	bool is_sub;
+
+	u64 sof_count;
+	u64 vsync_count;
+
+	atomic_t vf_en;
+	int overrun_debug_dump_cnt;
+};
+
+struct mtk_yuv_device {
+	struct v4l2_subdev subdev;
+	struct device *dev;
+	unsigned int id;
+	void __iomem *base;
+	unsigned int num_clks;
+	struct clk_bulk_data *clk_b;
+#ifdef CONFIG_PM_SLEEP
+	struct notifier_block pm_notifier;
+#endif
+};
+
+/* AE information */
+struct mtk_ae_debug_data {
+	u64 obc_r1_sum[4];
+	u64 obc_r2_sum[4];
+	u64 obc_r3_sum[4];
+	u64 aa_sum[4];
+	u64 ltm_sum[4];
+};
+
+/*
+ * struct mtk_raw - the raw device information
+ */
+struct mtk_raw {
+	struct device *cam_dev;
+	struct device *devs[RAW_PIPELINE_NUM];
+	struct device *yuvs[RAW_PIPELINE_NUM];
+	struct mtk_raw_pipeline pipelines[RAW_PIPELINE_NUM];
+};
+
+static inline struct mtk_raw_pipeline *
+mtk_cam_ctrl_handler_to_raw_pipeline(struct v4l2_ctrl_handler *handler)
+{
+	return container_of(handler, struct mtk_raw_pipeline, ctrl_handler);
+};
+
+int mtk_cam_raw_setup_dependencies(struct mtk_raw *raw);
+
+int mtk_cam_raw_register_entities(struct mtk_raw *raw,
+				  struct v4l2_device *v4l2_dev);
+void mtk_cam_raw_unregister_entities(struct mtk_raw *raw);
+
+int mtk_cam_raw_select(struct mtk_cam_ctx *ctx,
+		       struct mtkcam_ipi_input_param *cfg_in_param);
+
+void mtk_cam_raw_initialize(struct mtk_raw_device *dev, int is_sub);
+
+void mtk_cam_raw_stream_on(struct mtk_raw_device *dev, int on);
+
+void mtk_cam_raw_apply_cq(struct mtk_raw_device *dev, dma_addr_t cq_addr,
+			  unsigned int cq_size, unsigned int cq_offset,
+			  unsigned int sub_cq_size, unsigned int sub_cq_offset);
+
+void mtk_cam_raw_trigger_rawi(struct mtk_raw_device *dev,
+			      struct mtk_cam_ctx *ctx,
+			      signed int hw_scene);
+
+void mtk_cam_raw_reset(struct mtk_raw_device *dev);
+
+void mtk_cam_raw_dump_aa_info(struct mtk_cam_ctx *ctx,
+			      struct mtk_ae_debug_data *ae_info);
+
+extern struct platform_driver mtk_cam_raw_driver;
+extern struct platform_driver mtk_cam_yuv_driver;
+
+static inline u32 dmaaddr_lsb(dma_addr_t addr)
+{
+	return addr & (u32)U32_MAX;
+}
+
+static inline u32 dmaaddr_msb(dma_addr_t addr)
+{
+	return (u64)addr >> 32;
+}
+
+#endif /*__MTK_CAM_RAW_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h
new file mode 100755
index 000000000000..70f59151c03f
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAMERA_V4l2_CONTROLS_H
+#define __MTK_CAMERA_V4l2_CONTROLS_H
+
+#include <linux/mtkisp_camsys.h>
+
+/* Allowed value of V4L2_CID_MTK_CAM_RAW_PATH_SELECT */
+#define V4L2_MTK_CAM_RAW_PATH_SELECT_BPC	1
+#define V4L2_MTK_CAM_RAW_PATH_SELECT_FUS	3
+#define V4L2_MTK_CAM_RAW_PATH_SELECT_DGN	4
+#define V4L2_MTK_CAM_RAW_PATH_SELECT_LSC	5
+#define V4L2_MTK_CAM_RAW_PATH_SELECT_LTM	7
+
+#define V4L2_MBUS_FRAMEFMT_PAD_ENABLE  BIT(1)
+
+#define MEDIA_BUS_FMT_MTISP_SBGGR10_1X10		0x8001
+#define MEDIA_BUS_FMT_MTISP_SBGGR12_1X12		0x8002
+#define MEDIA_BUS_FMT_MTISP_SBGGR14_1X14		0x8003
+#define MEDIA_BUS_FMT_MTISP_SGBRG10_1X10		0x8004
+#define MEDIA_BUS_FMT_MTISP_SGBRG12_1X12		0x8005
+#define MEDIA_BUS_FMT_MTISP_SGBRG14_1X14		0x8006
+#define MEDIA_BUS_FMT_MTISP_SGRBG10_1X10		0x8007
+#define MEDIA_BUS_FMT_MTISP_SGRBG12_1X12		0x8008
+#define MEDIA_BUS_FMT_MTISP_SGRBG14_1X14		0x8009
+#define MEDIA_BUS_FMT_MTISP_SRGGB10_1X10		0x800a
+#define MEDIA_BUS_FMT_MTISP_SRGGB12_1X12		0x800b
+#define MEDIA_BUS_FMT_MTISP_SRGGB14_1X14		0x800c
+#define MEDIA_BUS_FMT_MTISP_BAYER8_UFBC			0x800d
+#define MEDIA_BUS_FMT_MTISP_BAYER10_UFBC		0x800e
+#define MEDIA_BUS_FMT_MTISP_BAYER12_UFBC		0x8010
+#define MEDIA_BUS_FMT_MTISP_BAYER14_UFBC		0x8011
+#define MEDIA_BUS_FMT_MTISP_BAYER16_UFBC		0x8012
+#define MEDIA_BUS_FMT_MTISP_NV12			0x8013
+#define MEDIA_BUS_FMT_MTISP_NV21			0x8014
+#define MEDIA_BUS_FMT_MTISP_NV12_10			0x8015
+#define MEDIA_BUS_FMT_MTISP_NV21_10			0x8016
+#define MEDIA_BUS_FMT_MTISP_NV12_10P			0x8017
+#define MEDIA_BUS_FMT_MTISP_NV21_10P			0x8018
+#define MEDIA_BUS_FMT_MTISP_NV12_12			0x8019
+#define MEDIA_BUS_FMT_MTISP_NV21_12			0x801a
+#define MEDIA_BUS_FMT_MTISP_NV12_12P			0x801b
+#define MEDIA_BUS_FMT_MTISP_NV21_12P			0x801c
+#define MEDIA_BUS_FMT_MTISP_YUV420			0x801d
+#define MEDIA_BUS_FMT_MTISP_NV12_UFBC			0x801e
+#define MEDIA_BUS_FMT_MTISP_NV21_UFBC			0x8020
+#define MEDIA_BUS_FMT_MTISP_NV12_10_UFBC		0x8021
+#define MEDIA_BUS_FMT_MTISP_NV21_10_UFBC		0x8022
+#define MEDIA_BUS_FMT_MTISP_NV12_12_UFBC		0x8023
+#define MEDIA_BUS_FMT_MTISP_NV21_12_UFBC		0x8024
+#define MEDIA_BUS_FMT_MTISP_NV16			0x8025
+#define MEDIA_BUS_FMT_MTISP_NV61			0x8026
+#define MEDIA_BUS_FMT_MTISP_NV16_10			0x8027
+#define MEDIA_BUS_FMT_MTISP_NV61_10			0x8028
+#define MEDIA_BUS_FMT_MTISP_NV16_10P			0x8029
+#define MEDIA_BUS_FMT_MTISP_NV61_10P			0x802a
+
+#define MTK_CAM_RESOURCE_DEFAULT	0xFFFF
+
+#endif /* __MTK_CAMERA_V4l2_CONTROLS_H */
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (6 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  5:58   ` Krzysztof Kozlowski
                     ` (3 more replies)
  2025-07-07  1:31 ` [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility shangyao lin
                   ` (5 subsequent siblings)
  13 siblings, 4 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, MediaTek-specific features, pipeline management, streaming control, and error handling mechanisms. Additionally, it aggregates sub-drivers for the camera interface, raw, and yuv pipelines.

---

Changes in v2:
- Removed mtk_cam-ufbc-def.h along with related code
- Various fixes per review comments

---

[Question for CK]:

Hi CK,

Is your suggestion to simplify buffer management to a single buf_list with a buffer status (estate) state machine, so all buffers stay in one list and only the estate field changes (no more multiple lists)? The buffer life cycle would be: WAITING → SCP_GENERATE_CQ → CQ_READY → CQ_APPLY → DONE.

I have some concerns about concurrency and race conditions:

Multiple lists can use different locks to reduce contention.
With a single list, all state changes need to lock the same list, which may require more careful lock design to avoid race conditions or deadlocks.
When multiple threads (interrupts, workqueues, user requests) operate at the same time, synchronization becomes more difficult.
Do you have any reference code or best practices for this kind of design?

Thanks!

[Question for Markus]:

Hi Markus,

Thank you for your suggestion. Using guard(spinlock)(&cam->running_job_lock) is indeed more concise and helps prevent forgetting to unlock, which can reduce potential bugs.

Do you suggest that we should replace all spin_lock/spin_unlock pairs with guard(spinlock) in the codebase? Are there any exceptions or specific cases where the traditional approach is still preferred?

I appreciate your advice. Thank you!

Reply regarding stream_id and pipe_id naming:

Hi CK,

Thank you for your suggestion. In our current design, stream_id and pipe_id are not always in a 1-to-1 relationship. In some cases, one stream may correspond to multiple pipes, or vice versa. That’s why we use both names in different contexts. If you have any suggestions on how to unify the naming while keeping this distinction clear, please let us know.

Thanks!

Best regards,
Shangyao

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../isp/isp_7x/camsys/mtk_cam-timesync.c      |  125 +
 .../isp/isp_7x/camsys/mtk_cam-timesync.h      |   12 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam.c      | 3977 +++++++++++++++++
 .../mediatek/isp/isp_7x/camsys/mtk_cam.h      |  718 +++
 4 files changed, 4832 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h

diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c
new file mode 100755
index 000000000000..b333434d86c0
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 MediaTek Inc.
+ */
+
+#include <linux/module.h>
+#include <asm/arch_timer.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/math64.h>
+
+#include "mtk_cam-timesync.h"
+
+#define FILTER_DATAPOINTS	16
+#define FILTER_FREQ		10000000ULL /* 10 ms */
+
+struct moving_average {
+	u64 last_time;
+	s64 input[FILTER_DATAPOINTS];
+	s64 output;
+	u8 cnt;
+	u8 tail;
+};
+
+static struct moving_average moving_average_algo_mono;
+static struct moving_average moving_average_algo_boot;
+static DEFINE_SPINLOCK(moving_average_lock);
+
+static u64 arch_counter_to_ns(u64 cyc)
+{
+	/* arch counter is 13M */
+	u64 num, max = ULLONG_MAX;
+	u32 mult = 161319385;
+	u32 shift = 21;
+	s64 nsec = 0;
+
+	do_div(max, mult);
+	if (cyc > max) {
+		num = div64_u64(cyc, max);
+		nsec = (((u64)max * mult) >> shift) * num;
+		cyc -= num * max;
+	}
+	nsec += ((u64)cyc * mult) >> shift;
+	return nsec;
+}
+
+static void moving_average_filter(struct moving_average *filter,
+				  u64 base_time, u64 archcounter_time)
+{
+	int i = 0;
+	s64 avg = 0;
+	s64 ret_avg = 0;
+
+	if (base_time < filter->last_time + FILTER_FREQ)
+		return;
+
+	filter->last_time = base_time;
+
+	filter->input[filter->tail++] = base_time - archcounter_time;
+	filter->tail &= (FILTER_DATAPOINTS - 1);
+	if (filter->cnt < FILTER_DATAPOINTS)
+		filter->cnt++;
+
+	for (i = 1, avg = 0; i < filter->cnt; i++)
+		avg += (filter->input[i] - filter->input[0]);
+	ret_avg = div_s64(avg, filter->cnt) + filter->input[0];
+	WRITE_ONCE(filter->output, ret_avg);
+}
+
+static u64 get_filter_output(struct moving_average *filter)
+{
+	return READ_ONCE(filter->output);
+}
+
+u64 mtk_cam_timesync_to_monotonic(u64 hwclock)
+{
+	unsigned long flags = 0;
+	u64 base_time = 0;
+	u64 archcounter_time = 0;
+	u64 reslut_time = 0;
+
+	spin_lock(&moving_average_lock);
+
+	local_irq_save(flags);
+	base_time = ktime_to_ns(ktime_get());
+	archcounter_time =
+		arch_counter_to_ns(__arch_counter_get_cntvct_stable());
+	local_irq_restore(flags);
+
+	moving_average_filter(&moving_average_algo_mono,
+			      base_time, archcounter_time);
+
+	reslut_time = arch_counter_to_ns(hwclock) +
+		get_filter_output(&moving_average_algo_mono);
+
+	spin_unlock(&moving_average_lock);
+	return reslut_time;
+}
+
+u64 mtk_cam_timesync_to_boot(u64 hwclock)
+{
+	unsigned long flags = 0;
+	u64 base_time = 0;
+	u64 archcounter_time = 0;
+	u64 reslut_time = 0;
+
+	spin_lock(&moving_average_lock);
+
+	local_irq_save(flags);
+	base_time = ktime_get_boottime_ns();
+	archcounter_time =
+		arch_counter_to_ns(__arch_counter_get_cntvct_stable());
+	local_irq_restore(flags);
+
+	moving_average_filter(&moving_average_algo_boot,
+			      base_time, archcounter_time);
+
+	reslut_time = arch_counter_to_ns(hwclock) +
+		get_filter_output(&moving_average_algo_boot);
+
+	spin_unlock(&moving_average_lock);
+	return reslut_time;
+}
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h
new file mode 100755
index 000000000000..7a226bd1c0a9
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ */
+
+#ifndef __ARCHCOUNTER_TIMESYNC__
+#define __ARCHCOUNTER_TIMESYNC__
+
+u64 mtk_cam_timesync_to_monotonic(u64 hwclock);
+u64 mtk_cam_timesync_to_boot(u64 hwclock);
+
+#endif
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c
new file mode 100755
index 000000000000..79131ee15a77
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c
@@ -0,0 +1,3977 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-ctrl.h"
+#include "mtk_cam-pool.h"
+#include "mtk_cam-regs-mt8188.h"
+#include "mtk_camera-v4l2-controls.h"
+#include "mtk_cam-timesync.h"
+
+static unsigned int debug_ae;
+module_param(debug_ae, uint, 0644);
+MODULE_PARM_DESC(debug_ae, "activates debug ae info");
+
+#define MTK_CAM_CIO_PAD_SRC		PAD_SRC_RAW0
+#define MTK_CAM_CIO_PAD_SINK		MTK_RAW_SINK
+#define MTK_CAM_IPI_SEND_TIMEOUT	1000
+/* consider running_job_list depth 3*3 */
+#define RUNNING_JOB_DEPTH		9
+static const struct of_device_id mtk_cam_of_ids[] = {
+	{.compatible = "mediatek,mt8188-camisp",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mtk_cam_of_ids);
+
+/*
+ * All member of mtk_cam_request_stream_data which may be used
+ * after media_request_ioctl_reinit and before the next
+ * media_request_ioctl_queue must be clean here. For
+ * example, the pending set fmt, set selection, and sensor
+ * switch extension of camsys driver.
+ */
+static void
+mtk_cam_req_s_data_clean(struct mtk_cam_request_stream_data *s_data)
+{
+	s_data->sensor = NULL;
+	s_data->flags = 0;
+}
+
+static void
+mtk_cam_req_pipe_s_data_clean(struct mtk_cam_request *req, int pipe_id,
+			      int index)
+{
+	struct mtk_cam_request_stream_data *req_stream_data;
+
+	req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, index);
+	if (req_stream_data) {
+		mtk_cam_req_s_data_clean(req_stream_data);
+		/**
+		 * Notice that the we clean req_stream_data->bufs here so
+		 * we should not use it after this function called on it.
+		 * mtk_cam_vb2_return_all_buffers() uses another list
+		 * of mtk_cam_video_device to keep the vb2 buffers to be clean.
+		 */
+		 memset(req_stream_data->bufs, 0, sizeof(req_stream_data->bufs));
+	}
+}
+
+void mtk_cam_s_data_update_timestamp(struct mtk_cam_buffer *buf,
+				     struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_ctx *ctx;
+	struct vb2_buffer *vb;
+	struct mtk_cam_video_device *node;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	if (!ctx) {
+		pr_info("%s: get ctx from s_data failed", __func__);
+		return;
+	}
+
+	vb = &buf->vbb.vb2_buf;
+	node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+
+	buf->vbb.sequence = s_data->frame_seq_no;
+	if (vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC)
+		vb->timestamp = s_data->timestamp_mono;
+	else
+		vb->timestamp = s_data->timestamp;
+
+	/*check buffer's timestamp*/
+	if (node->desc.dma_port == MTKCAM_ISP_META_STATS_CFG)
+		dev_dbg(ctx->cam->dev,
+			"%s:%s:vb sequence:%d, queue type:%d, timestamp_flags:0x%x, timestamp:%lld\n",
+			__func__, node->desc.name, buf->vbb.sequence,
+			vb->vb2_queue->type, vb->vb2_queue->timestamp_flags,
+			vb->timestamp);
+}
+
+static void mtk_cam_req_return_pipe_buffers(struct mtk_cam_request *req,
+					    int pipe_id, int index)
+{
+	struct mtk_cam_device *cam =
+		container_of(req->req.mdev, struct mtk_cam_device, media_dev);
+	struct mtk_cam_request_stream_data *s_data_pipe;
+	struct mtk_cam_buffer *buf_ret[MTK_RAW_TOTAL_NODES];
+	struct mtk_cam_buffer *buf;
+	struct mtk_cam_video_device *node;
+	struct vb2_buffer *vb;
+	int buf_state;
+	u32 i, buf_ret_cnt = 0, buf_start = 0, buf_end = 0;
+
+	s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, index);
+	if (!s_data_pipe) {
+		pr_info("%s: get s_data pipe failed", __func__);
+		return;
+	}
+
+	if (is_raw_subdev(pipe_id)) {
+		buf_start = MTK_RAW_SINK_NUM;
+		buf_end = MTK_RAW_PIPELINE_PADS_NUM;
+	}
+
+	for (i = buf_start; i < buf_end; i++) {
+		/* make sure do not touch req/s_data after vb2_buffe_done */
+		buf = mtk_cam_s_data_get_vbuf(s_data_pipe, i);
+		if (!buf)
+			continue;
+		buf_ret[buf_ret_cnt++] = buf;
+		/* clean the stream data for req reinit case */
+		mtk_cam_s_data_reset_vbuf(s_data_pipe, i);
+	}
+
+	/* clean the req_stream_data being used right after request reinit */
+	mtk_cam_req_pipe_s_data_clean(req, pipe_id, index);
+
+	buf_state = atomic_read(&s_data_pipe->buf_state);
+	if (buf_state == -1)
+		buf_state = VB2_BUF_STATE_ERROR;
+
+	dev_dbg(cam->dev,
+		"%s:%s: pipe_id(%d) buf_state(%d) buf_ret_cnt(%d)\n", __func__,
+		req->req.debug_str, pipe_id, buf_state, buf_ret_cnt);
+
+	for (i = 0; i < buf_ret_cnt; i++) {
+		buf = buf_ret[i];
+		vb = &buf->vbb.vb2_buf;
+		node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+		if (node->uid.pipe_id != pipe_id) {
+			dev_info(cam->dev,
+				 "%s:%s:node(%s): invalid pipe id (%d), should be (%d)\n",
+				 __func__, req->req.debug_str,
+				 node->desc.name, node->uid.pipe_id, pipe_id);
+			continue;
+		}
+
+		if (atomic_read(&req->state) > MTK_CAM_REQ_STATE_PENDING)
+			mtk_cam_s_data_update_timestamp(buf, s_data_pipe);
+
+		vb2_buffer_done(&buf->vbb.vb2_buf, buf_state);
+	}
+}
+
+struct mtk_cam_request_stream_data*
+mtk_cam_get_req_s_data(struct mtk_cam_ctx *ctx, unsigned int pipe_id,
+		       unsigned int frame_seq_no)
+
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtk_cam_request *req, *req_prev;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	int i;
+
+	spin_lock(&cam->running_job_lock);
+	list_for_each_entry_safe(req, req_prev, &cam->running_job_list, list) {
+		if (req->pipe_used & (1 << pipe_id)) {
+			for (i = 0; i < req->p_data[pipe_id].s_data_num; i++) {
+				req_stream_data = &req->p_data[pipe_id].s_data[i];
+				if (req_stream_data->frame_seq_no == frame_seq_no) {
+					spin_unlock(&cam->running_job_lock);
+					return req_stream_data;
+				}
+			}
+		}
+	}
+	spin_unlock(&cam->running_job_lock);
+
+	return NULL;
+}
+
+struct mtk_cam_request *mtk_cam_get_req(struct mtk_cam_ctx *ctx,
+					unsigned int frame_seq_no)
+{
+	struct mtk_cam_request_stream_data *req_stream_data;
+
+	req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, frame_seq_no);
+	if (!req_stream_data)
+		return NULL;
+
+	return req_stream_data->req;
+}
+
+bool watchdog_scenario(struct mtk_cam_ctx *ctx)
+{
+	if (ctx->sensor && ctx->used_raw_num)
+		return true;
+	else
+		return false;
+}
+
+static bool finish_cq_buf(struct mtk_cam_request_stream_data *req_stream_data)
+{
+	struct mtk_cam_ctx *ctx = req_stream_data->ctx;
+	struct mtk_cam_working_buf_entry *cq_buf_entry;
+
+	if (!ctx->used_raw_num)
+		return false;
+
+	spin_lock(&ctx->processing_buffer_list.lock);
+
+	cq_buf_entry = req_stream_data->working_buf;
+	/* Check if the cq buffer is already finished */
+	if (!cq_buf_entry || !cq_buf_entry->s_data) {
+		dev_info(ctx->cam->dev,
+			 "%s:%s:ctx(%d):req(%d):working_buf is already release\n",
+			 __func__, req_stream_data->req->req.debug_str,
+			 ctx->stream_id, req_stream_data->frame_seq_no);
+		spin_unlock(&ctx->processing_buffer_list.lock);
+		return false;
+	}
+
+	list_del(&cq_buf_entry->list_entry);
+	mtk_cam_s_data_reset_wbuf(req_stream_data);
+	ctx->processing_buffer_list.cnt--;
+	spin_unlock(&ctx->processing_buffer_list.lock);
+
+	mtk_cam_working_buf_put(cq_buf_entry);
+
+	dev_dbg(ctx->cam->dev, "put cq buf:%pad, %s\n",
+		&cq_buf_entry->buffer.iova,
+		req_stream_data->req->req.debug_str);
+
+	return true;
+}
+
+static void update_hw_mapping(struct mtk_cam_ctx *ctx,
+			      struct mtkcam_ipi_config_param *config_param)
+{
+	// raw
+	config_param->maps[0].pipe_id = ctx->pipe->id;
+	config_param->maps[0].dev_mask = MTKCAM_SUBDEV_RAW_MASK & ctx->used_raw_dev;
+}
+
+static void mtk_cam_del_req_from_running(struct mtk_cam_ctx *ctx,
+					 struct mtk_cam_request *req, int pipe_id)
+{
+	struct mtk_cam_request_stream_data *s_data;
+
+	s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
+	dev_dbg(ctx->cam->dev,
+		"%s: %s: removed, req:%d, ctx:(%d/0x%x/0x%x), pipe:(%d/0x%x/0x%x) done_status:0x%x)\n",
+		__func__, req->req.debug_str, s_data->frame_seq_no,
+		ctx->stream_id, req->ctx_used, ctx->cam->streaming_ctx,
+		pipe_id, req->pipe_used, ctx->cam->streaming_pipe,
+		req->done_status);
+
+	atomic_set(&req->state, MTK_CAM_REQ_STATE_COMPLETE);
+	spin_lock(&ctx->cam->running_job_lock);
+	list_del(&req->list);
+	ctx->cam->running_job_count--;
+	spin_unlock(&ctx->cam->running_job_lock);
+}
+
+static void mtk_cam_req_works_clean(struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data);
+	char *dbg_str = mtk_cam_s_data_get_dbg_str(s_data);
+
+	/* flush the sensor work */
+	if (atomic_read(&s_data->sensor_work.is_queued)) {
+		kthread_flush_work(&s_data->sensor_work.work);
+		dev_dbg(ctx->cam->dev,
+			"%s:ctx(%d):%s:seq(%d): flushed sensor_work\n",
+			__func__, ctx->stream_id, dbg_str, s_data->frame_seq_no);
+	}
+}
+
+static void mtk_cam_get_timestamp(struct mtk_cam_ctx *ctx,
+				  struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_buffer *buf;
+	struct vb2_buffer *vb;
+	void *vaddr;
+	u64 *timestamp_addr;
+	u64 *fho_va;
+
+	buf = mtk_cam_s_data_get_vbuf(s_data, MTK_RAW_META_OUT_0);
+	if (!buf) {
+		dev_info(ctx->cam->dev,
+			 "ctx(%d): can't get MTK_RAW_META_OUT_0 buf from req(%d)\n",
+			 ctx->stream_id, s_data->frame_seq_no);
+		return;
+	}
+
+	vb = &buf->vbb.vb2_buf;
+	if (!vb) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get vb2 buf\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	vaddr = vb2_plane_vaddr(&buf->vbb.vb2_buf, 0);
+	if (!vaddr) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get plane_vadd\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	if (!s_data->working_buf->buffer.va ||
+	    s_data->working_buf->buffer.size == 0) {
+		dev_info(ctx->cam->dev,
+			 "%s:ctx(%d): can't get working_buf\n",
+			 __func__, ctx->stream_id);
+		return;
+	}
+
+	fho_va = (u64 *)(s_data->working_buf->buffer.va +
+		s_data->working_buf->buffer.size - 64);
+
+	timestamp_addr = camsys_get_timestamp_addr(vaddr);
+	*timestamp_addr = div_u64(mtk_cam_timesync_to_monotonic(*fho_va), 1000);
+	*(timestamp_addr + 1) =	div_u64(mtk_cam_timesync_to_boot(*fho_va), 1000);
+	dev_dbg(ctx->cam->dev,
+		"timestamp TS:momo %llu us boot %llu us, TS_cnt:%llu\n",
+		*timestamp_addr, *(timestamp_addr + 1),	*fho_va);
+}
+
+int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx,
+			      unsigned int dequeued_frame_seq_no,
+			      int pipe_id)
+{
+	struct mtk_cam_request *req, *req_prev;
+	struct mtk_cam_request_stream_data *s_data, *s_data_pipe;
+	struct mtk_cam_request_stream_data *deq_s_data[RUNNING_JOB_DEPTH];
+	struct mtk_raw_pipeline *pipe = ctx->pipe;
+	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+	struct mtk_ae_debug_data ae_data;
+	int buf_state;
+	u32 dequeue_cnt, s_data_cnt, handled_cnt;
+	bool del_job, del_req;
+	bool unreliable = false;
+	unsigned int done_status_latch;
+
+	memset(&ae_data, 0, sizeof(struct mtk_ae_debug_data));
+	dequeue_cnt = 0;
+	s_data_cnt = 0;
+	spin_lock(&ctx->cam->running_job_lock);
+	list_for_each_entry_safe(req, req_prev, &ctx->cam->running_job_list, list) {
+		if (!(req->pipe_used & (1 << pipe_id)))
+			continue;
+
+		s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
+		if (!s_data) {
+			dev_info(ctx->cam->dev,
+				 "frame_seq:%d[ctx=%d,pipe=%d], de-queue request not found\n",
+				 dequeued_frame_seq_no, ctx->stream_id, pipe_id);
+			continue;
+		}
+
+		if (s_data->frame_seq_no > dequeued_frame_seq_no)
+			goto STOP_SCAN;
+
+		deq_s_data[s_data_cnt++] = s_data;
+		if (s_data_cnt >= RUNNING_JOB_DEPTH) {
+			dev_info(ctx->cam->dev,
+				 "%s:%s:ctx(%d):pipe(%d):seq(%d/%d) dequeue s_data over local buffer cnt(%d)\n",
+				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
+				 s_data->frame_seq_no, dequeued_frame_seq_no,
+				 s_data_cnt);
+			goto STOP_SCAN;
+		}
+	}
+
+STOP_SCAN:
+	spin_unlock(&ctx->cam->running_job_lock);
+
+	for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) {
+		s_data = deq_s_data[handled_cnt];
+		del_req = false;
+		del_job = false;
+		req = mtk_cam_s_data_get_req(s_data);
+		if (!req) {
+			dev_info(ctx->cam->dev,
+				 "%s:ctx(%d):pipe(%d):seq(%d) req not found\n",
+				 __func__, ctx->stream_id, pipe_id,
+				 s_data->frame_seq_no);
+			continue;
+		}
+
+		spin_lock(&req->done_status_lock);
+
+		if (req->done_status & 1 << pipe_id) {
+			/* already handled by another job done work */
+			spin_unlock(&req->done_status_lock);
+			continue;
+		}
+
+		/* Check whether all pipelines of single ctx are done */
+		req->done_status |= 1 << pipe_id;
+		if ((req->done_status & ctx->streaming_pipe) ==
+		    (req->pipe_used & ctx->streaming_pipe))
+			del_job = true;
+
+		if ((req->done_status & ctx->cam->streaming_pipe) ==
+		    (req->pipe_used & ctx->cam->streaming_pipe)) {
+			if (MTK_CAM_REQ_STATE_RUNNING ==
+			    atomic_cmpxchg(&req->state,
+					   MTK_CAM_REQ_STATE_RUNNING,
+					   MTK_CAM_REQ_STATE_DELETING))
+				del_req = true;
+		}
+		done_status_latch = req->done_status;
+		spin_unlock(&req->done_status_lock);
+
+		if (is_raw_subdev(pipe_id) && debug_ae) {
+			mtk_cam_raw_dump_aa_info(ctx, &ae_data);
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d),metaout,size(%u,%u),AA(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)\n",
+				__func__, req->req.debug_str, ctx->stream_id, pipe_id,
+				dequeued_frame_seq_no, s_data->frame_seq_no,
+				done_status_latch, req->pipe_used,
+				ctx->streaming_pipe, ctx->cam->streaming_pipe,
+				del_job, del_req,
+				pipe->res_config.sink_fmt.width,
+				pipe->res_config.sink_fmt.height,
+				ae_data.obc_r1_sum[0], ae_data.obc_r1_sum[1],
+				ae_data.obc_r1_sum[2], ae_data.obc_r1_sum[3],
+				ae_data.obc_r2_sum[0], ae_data.obc_r2_sum[1],
+				ae_data.obc_r2_sum[2], ae_data.obc_r2_sum[3],
+				ae_data.obc_r3_sum[0], ae_data.obc_r3_sum[1],
+				ae_data.obc_r3_sum[2], ae_data.obc_r3_sum[3],
+				ae_data.aa_sum[0], ae_data.aa_sum[1],
+				ae_data.aa_sum[2], ae_data.aa_sum[3],
+				ae_data.ltm_sum[0], ae_data.ltm_sum[1],
+				ae_data.ltm_sum[2], ae_data.ltm_sum[3]);
+		} else {
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d)\n",
+				dequeued_frame_seq_no, s_data->frame_seq_no,
+				done_status_latch, req->pipe_used,
+				ctx->streaming_pipe, ctx->cam->streaming_pipe,
+				del_job, del_req);
+		}
+
+		if (is_raw_subdev(pipe_id)) {
+			mtk_cam_get_timestamp(ctx, s_data);
+			mtk_cam_req_works_clean(s_data);
+		}
+
+		if (del_job) {
+			atomic_dec(&ctx->running_s_data_cnt);
+			mtk_camsys_state_delete(ctx, sensor_ctrl, req);
+
+			/* release internal buffers */
+			finish_cq_buf(s_data);
+		}
+
+		if (del_req) {
+			mtk_cam_del_req_from_running(ctx, req, pipe_id);
+			dequeue_cnt++;
+		}
+
+		/* release vb2 buffers of the pipe */
+		s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0);
+		if (!s_data_pipe) {
+			dev_info(ctx->cam->dev,
+				 "%s:%s:ctx(%d):pipe(%d):seq(%d) s_data_pipe not found\n",
+				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
+				 s_data->frame_seq_no);
+			continue;
+		}
+
+		if (s_data->frame_seq_no < dequeued_frame_seq_no) {
+			buf_state = VB2_BUF_STATE_ERROR;
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:pipe(%d) seq:%d, time:%lld drop, ctx:%d\n",
+				__func__, req->req.debug_str, pipe_id,
+				s_data->frame_seq_no, s_data->timestamp,
+				ctx->stream_id);
+		} else if (s_data->state.estate == E_STATE_DONE_MISMATCH) {
+			buf_state = VB2_BUF_STATE_ERROR;
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:pipe(%d) seq:%d, state done mismatch",
+				__func__, req->req.debug_str, pipe_id,
+				s_data->frame_seq_no);
+		} else if (unreliable) {
+			buf_state = VB2_BUF_STATE_ERROR;
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:pipe(%d) seq:%d, done (unreliable)",
+				__func__, req->req.debug_str, pipe_id,
+				s_data->frame_seq_no);
+		} else {
+			buf_state = VB2_BUF_STATE_DONE;
+			dev_dbg(ctx->cam->dev,
+				"%s:%s:pipe(%d) seq:%d, done success",
+				__func__, req->req.debug_str, pipe_id,
+				s_data->frame_seq_no);
+		}
+
+		if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) {
+			/* handle vb2_buffer_done */
+			if (mtk_cam_req_put(req, pipe_id))
+				dev_dbg(ctx->cam->dev,
+					"%s:%s:pipe(%d) return request",
+					__func__, req->req.debug_str, pipe_id);
+		}
+	}
+
+	return dequeue_cnt;
+}
+
+void mtk_cam_dev_req_clean_pending(struct mtk_cam_device *cam, int pipe_id,
+				   int buf_state)
+{
+	struct mtk_cam_request *req, *req_prev;
+	struct mtk_cam_request_stream_data *s_data_pipe;
+	struct list_head *pending = &cam->pending_job_list;
+	struct list_head req_clean_list;
+
+	/* Consider pipe bufs and pipe_used only */
+
+	INIT_LIST_HEAD(&req_clean_list);
+
+	spin_lock(&cam->pending_job_lock);
+	list_for_each_entry_safe(req, req_prev, pending, list) {
+		/* update pipe_used */
+		req->pipe_used &= ~(1 << pipe_id);
+		list_add_tail(&req->cleanup_list, &req_clean_list);
+		if (!(req->pipe_used & cam->streaming_pipe)) {
+			/* the last pipe */
+			list_del(&req->list);
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d) remove req from pending list\n",
+				 __func__, req->req.debug_str, pipe_id);
+		}
+	}
+	spin_unlock(&cam->pending_job_lock);
+
+	list_for_each_entry_safe(req, req_prev, &req_clean_list, cleanup_list) {
+		list_del(&req->cleanup_list);
+		s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0);
+		if (!s_data_pipe) {
+			dev_dbg(cam->dev,
+				"%s:%s:pipe_used(0x%x):pipe(%d) s_data_pipe not found\n",
+				__func__, req->req.debug_str, req->pipe_used,
+				pipe_id);
+			continue;
+		}
+		if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) {
+			/* handle vb2_buffer_done */
+			if (mtk_cam_req_put(req, pipe_id))
+				dev_dbg(cam->dev,
+					"%s:%s:pipe_used(0x%x):pipe(%d) return request",
+					__func__, req->req.debug_str,
+					req->pipe_used, pipe_id);
+			/* DO NOT touch req after here */
+		}
+	}
+}
+
+void mtk_cam_dev_req_cleanup(struct mtk_cam_ctx *ctx, int pipe_id, int buf_state)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtk_cam_request *req, *req_prev;
+	struct mtk_cam_request_stream_data *s_data, *s_data_pipe;
+	struct mtk_cam_request_stream_data *clean_s_data[RUNNING_JOB_DEPTH];
+	struct list_head *running = &cam->running_job_list;
+	unsigned int other_pipes, done_status;
+	int i;
+	u32 num_s_data, s_data_cnt, handled_cnt;
+	bool need_clean_req;
+
+	mtk_cam_dev_req_clean_pending(cam, pipe_id, buf_state);
+
+	s_data_cnt = 0;
+	spin_lock(&cam->running_job_lock);
+	list_for_each_entry_safe(req, req_prev, running, list) {
+		/* only handle requests belong to current ctx */
+		if (!(req->pipe_used & ctx->streaming_pipe))
+			continue;
+
+		num_s_data = mtk_cam_req_get_num_s_data(req, pipe_id);
+		/* reverse the order for release req with s_data_0 */
+		for (i = num_s_data - 1; i >= 0; i--) {
+			s_data = mtk_cam_req_get_s_data(req, pipe_id, i);
+			if (s_data) {
+				clean_s_data[s_data_cnt++] = s_data;
+				if (s_data_cnt >= RUNNING_JOB_DEPTH) {
+					dev_info(cam->dev,
+						 "%s: over local buffer cnt(%d)\n",
+						 __func__,  s_data_cnt);
+					goto STOP_SCAN;
+				}
+			} else {
+				dev_info(cam->dev,
+					 "%s:%s:pipe(%d): get s_data failed\n",
+					 __func__, req->req.debug_str, pipe_id);
+			}
+		}
+	}
+STOP_SCAN:
+	spin_unlock(&cam->running_job_lock);
+
+	for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) {
+		s_data = clean_s_data[handled_cnt];
+		req = mtk_cam_s_data_get_req(s_data);
+		if (!req) {
+			pr_info("ERR can't be recovered: invalid req found in s_data_clean_list\n");
+			continue;
+		}
+
+		if (ctx->used_raw_num != 0) {
+			if (s_data->index > 0)
+				dev_info(cam->dev,
+					 "%s:%s:pipe(%d):seq(%d): clean s_data_%d, raw_feature(%lld)\n",
+					 __func__, req->req.debug_str, pipe_id,
+					 s_data->frame_seq_no, s_data->index,
+					 ctx->pipe->feature_pending);
+			else
+				dev_dbg(cam->dev,
+					"%s:%s:pipe(%d):seq(%d): clean s_data_%d, raw_feature(%lld)\n",
+					__func__, req->req.debug_str, pipe_id,
+					s_data->frame_seq_no, s_data->index,
+					ctx->pipe->feature_pending);
+		}
+
+		/* Cancel s_data's works before we clean up the data */
+		if (atomic_read(&s_data->sensor_work.is_queued)) {
+			kthread_cancel_work_sync(&s_data->sensor_work.work);
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):seq(%d): cancel sensor_work\n",
+				 __func__, req->req.debug_str, pipe_id,
+				 s_data->frame_seq_no);
+		}
+		atomic_set(&s_data->sensor_work.is_queued, 1);
+
+		if (atomic_read(&s_data->meta1_done_work.is_queued)) {
+			cancel_work_sync(&s_data->meta1_done_work.work);
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):seq(%d): cancel AFO done_work\n",
+				 __func__, req->req.debug_str, pipe_id,
+				 s_data->frame_seq_no);
+		}
+		atomic_set(&s_data->meta1_done_work.is_queued, 1);
+
+		if (atomic_read(&s_data->frame_done_work.is_queued)) {
+			cancel_work_sync(&s_data->frame_done_work.work);
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):seq(%d): cancel frame_done_work\n",
+				 __func__, req->req.debug_str, pipe_id,
+				 s_data->frame_seq_no);
+		}
+		atomic_set(&s_data->frame_done_work.is_queued, 1);
+
+		spin_lock(&req->done_status_lock);
+		dev_dbg(cam->dev,
+			"%s:%s:pipe(%d):seq(%d):req staus before clean:done(0x%x),pipe_used(0x%x)\n",
+			__func__, req->req.debug_str, pipe_id,
+			s_data->frame_seq_no, req->done_status, req->pipe_used);
+
+		need_clean_req = false;
+		if (atomic_read(&req->state) == MTK_CAM_REQ_STATE_RUNNING) {
+			/* mark request status to done for release */
+			req->done_status |= req->pipe_used & (1 << pipe_id);
+			if (req->done_status == req->pipe_used &&
+			    MTK_CAM_REQ_STATE_RUNNING ==
+			    atomic_cmpxchg(&req->state,
+					   MTK_CAM_REQ_STATE_RUNNING,
+					   MTK_CAM_REQ_STATE_DELETING))
+				need_clean_req = true;
+		}
+
+		/* if being the last one, check other pipes in the ctx */
+		other_pipes = 0;
+		done_status = req->done_status;
+		if (need_clean_req)
+			other_pipes = ctx->streaming_pipe & ~(1 << pipe_id);
+		spin_unlock(&req->done_status_lock);
+
+		/**
+		 * Before remove the request, flush other pipe's done work
+		 * in the same ctx to make sure mtk_cam_dev_job_done finished
+		 */
+		if (other_pipes) {
+			for (i = 0; i < MTKCAM_SUBDEV_MAX; i++) {
+				if (!(1 << i & other_pipes & done_status))
+					continue;
+
+				s_data_pipe = mtk_cam_req_get_s_data(req, i, 0);
+				if (!s_data_pipe)
+					continue;
+
+				/**
+				 * if done_status is marked, it means the work
+				 * is running or complete
+				 */
+				if (flush_work(&s_data->frame_done_work.work))
+					dev_info(cam->dev,
+						 "%s:%s:pipe(%d):seq(%d): flush pipe(%d) frame_done_work\n",
+						 __func__, req->req.debug_str,
+						 pipe_id, s_data_pipe->frame_seq_no,
+						 i);
+			}
+		}
+
+		mtk_cam_complete_sensor_hdl(s_data);
+		mtk_cam_complete_raw_hdl(s_data);
+		/*
+		 * reset fs state, if one sensor off and another one alive,
+		 * Let the req be the single sensor case.
+		 */
+		mutex_lock(&req->fs.op_lock);
+		mtk_cam_fs_reset(&req->fs);
+		mutex_unlock(&req->fs.op_lock);
+		if (need_clean_req) {
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):seq(%d): remove req from running list\n",
+				 __func__, req->req.debug_str, pipe_id,
+				 s_data->frame_seq_no);
+			atomic_set(&req->state, MTK_CAM_REQ_STATE_CLEANUP);
+			spin_lock(&cam->running_job_lock);
+			list_del(&req->list);
+			cam->running_job_count--;
+			spin_unlock(&cam->running_job_lock);
+		} else {
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):seq(%d): skip remove req from running list\n",
+				 __func__, req->req.debug_str, pipe_id,
+				 s_data->frame_seq_no);
+		}
+
+		if (mtk_cam_s_data_set_buf_state(s_data, buf_state)) {
+			if (s_data->index > 0) {
+				mtk_cam_req_return_pipe_buffers(req, pipe_id,
+								s_data->index);
+			} else {
+				/* handle vb2_buffer_done */
+				if (mtk_cam_req_put(req, pipe_id))
+					dev_dbg(cam->dev,
+						"%s:%s:pipe(%d) return request",
+						__func__, req->req.debug_str,
+						pipe_id);
+			}
+		}
+	}
+
+	/* all bufs in this node should be returned by req */
+
+	dev_dbg(cam->dev,
+		"%s: cleanup all stream off req, streaming ctx:0x%x, streaming pipe:0x%x)\n",
+		__func__, cam->streaming_ctx, cam->streaming_pipe);
+}
+
+void mtk_cam_req_get(struct mtk_cam_request *req, int pipe_id)
+{
+	atomic_inc(&req->ref_cnt);
+}
+
+bool mtk_cam_req_put(struct mtk_cam_request *req, int pipe_id)
+{
+	bool ret = false;
+
+	if (!atomic_dec_return(&req->ref_cnt))
+		ret = true;
+
+	/* release the pipe buf with s_data_pipe buf state */
+	mtk_cam_req_return_pipe_buffers(req, pipe_id, 0);
+
+	return ret;
+}
+
+static int config_img_in_fmt(struct mtk_cam_device *cam,
+			     struct mtk_cam_video_device *node,
+			     const struct v4l2_format *cfg_fmt,
+			     struct mtkcam_ipi_img_input *in_fmt)
+{
+	/* Check output & input image size dimension */
+	if (node->desc.dma_port != MTKCAM_ISP_RAWI_2) {
+		dev_info(cam->dev,
+			 "pipe(%d):dam_port(%d) only support MTKCAM_ISP_RAWI_2 now\n",
+			 node->uid.pipe_id, node->desc.dma_port);
+		return -EINVAL;
+	}
+
+	in_fmt->fmt.format =
+		mtk_cam_get_img_fmt(cfg_fmt->fmt.pix_mp.pixelformat);
+	if (in_fmt->fmt.format == MTKCAM_IPI_IMG_FMT_UNKNOWN) {
+		dev_info(cam->dev, "pipe: %d, node:%d unknown pixel fmt:%d\n",
+			 node->uid.pipe_id, node->desc.dma_port,
+			 cfg_fmt->fmt.pix_mp.pixelformat);
+		return -EINVAL;
+	}
+
+	in_fmt->fmt.s.w = cfg_fmt->fmt.pix_mp.width;
+	in_fmt->fmt.s.h = cfg_fmt->fmt.pix_mp.height;
+	in_fmt->fmt.stride[0] = cfg_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+	dev_dbg(cam->dev,
+		"pipe: %d dma_port:%d size=%0dx%0d, stride:%d\n",
+		node->uid.pipe_id, node->desc.dma_port, in_fmt->fmt.s.w,
+		in_fmt->fmt.s.h, in_fmt->fmt.stride[0]);
+
+	return 0;
+}
+
+static int config_img_fmt(struct mtk_cam_device *cam,
+			  struct mtk_cam_video_device *node,
+			  const struct v4l2_format *cfg_fmt,
+			  struct mtkcam_ipi_img_output *out_fmt, int sd_width,
+			  int sd_height)
+{
+	/* Check output & input image size dimension */
+	if (node->desc.dma_port == MTKCAM_ISP_IMGO &&
+	    (cfg_fmt->fmt.pix_mp.width > sd_width ||
+			cfg_fmt->fmt.pix_mp.height > sd_height)) {
+		dev_err(cam->dev, "pipe: %d cfg(%d,%d) size is larger than sensor(%d,%d)\n",
+			node->uid.pipe_id,
+			cfg_fmt->fmt.pix_mp.width, cfg_fmt->fmt.pix_mp.height,
+			sd_width, sd_height);
+		return -EINVAL;
+	}
+
+	out_fmt->fmt.format =
+		mtk_cam_get_img_fmt(cfg_fmt->fmt.pix_mp.pixelformat);
+	if (out_fmt->fmt.format == MTKCAM_IPI_IMG_FMT_UNKNOWN) {
+		dev_err(cam->dev, "pipe: %d, node:%d unknown pixel fmt:%d\n",
+			node->uid.pipe_id, node->desc.dma_port,
+			cfg_fmt->fmt.pix_mp.pixelformat);
+		return -EINVAL;
+	}
+	out_fmt->fmt.s.w = cfg_fmt->fmt.pix_mp.width;
+	out_fmt->fmt.s.h = cfg_fmt->fmt.pix_mp.height;
+
+	/* not support multi-plane stride */
+	out_fmt->fmt.stride[0] = cfg_fmt->fmt.pix_mp.plane_fmt[0].bytesperline;
+
+	if (out_fmt->crop.p.x == 0 && out_fmt->crop.s.w == 0) {
+		out_fmt->crop.p.x = 0;
+		out_fmt->crop.p.y = 0;
+		out_fmt->crop.s.w = sd_width;
+		out_fmt->crop.s.h = sd_height;
+	}
+
+	dev_dbg(cam->dev,
+		"pipe: %d dma_port:%d size=%0dx%0d, stride:%d, crop=%0dx%0d\n",
+		node->uid.pipe_id, node->desc.dma_port, out_fmt->fmt.s.w,
+		out_fmt->fmt.s.h, out_fmt->fmt.stride[0], out_fmt->crop.s.w,
+		out_fmt->crop.s.h);
+
+	return 0;
+}
+
+static void mtk_cam_req_set_vfmt(struct mtk_cam_device *cam,
+				 struct mtk_raw_pipeline *raw_pipeline,
+				 struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_video_device *node;
+	struct mtk_cam_request *req;
+	struct v4l2_format *f;
+	struct v4l2_selection *s;
+	int i;
+
+	req = mtk_cam_s_data_get_req(s_data);
+
+	/* force update format to every video device before re-streamon */
+	for (i = MTK_RAW_SINK_NUM + 1; i < MTK_RAW_META_OUT_BEGIN; i++) {
+		node = &raw_pipeline->vdev_nodes[i - MTK_RAW_SINK_NUM];
+		f = mtk_cam_s_data_get_vfmt(s_data, node->desc.id);
+		if (!f) {
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n",
+				 __func__, req->req.debug_str,
+				 node->uid.pipe_id, node->desc.name);
+		} else {
+			*f = node->active_fmt;
+			dev_dbg(cam->dev,
+				"%s:%s:pipe(%d):%s:save v4l2 fmt: pixelfmt(0x%x), w(%d), h(%d)\n",
+				__func__, req->req.debug_str,
+				node->uid.pipe_id, node->desc.name,
+				f->fmt.pix_mp.pixelformat,
+				f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+		}
+
+		s = mtk_cam_s_data_get_vsel(s_data, node->desc.id);
+		if (!s) {
+			dev_info(cam->dev,
+				 "%s:%s:pipe(%d):%s: can't find the vsel field to save\n",
+				 __func__, req->req.debug_str,
+				 node->uid.pipe_id,
+				 node->desc.name);
+		} else {
+			*s = node->active_crop;
+		}
+	}
+}
+
+static int mtk_cam_req_set_fmt(struct mtk_cam_device *cam,
+			       struct mtk_cam_request *req)
+{
+	int pipe_id;
+	int pad;
+	struct mtk_cam_request_stream_data *stream_data;
+	struct mtk_raw_pipeline *raw_pipeline;
+
+	dev_dbg(cam->dev, "%s:%s\n", __func__, req->req.debug_str);
+	for (pipe_id = 0; pipe_id < cam->max_stream_num; pipe_id++) {
+		if (req->pipe_used & (1 << pipe_id)) {
+			if (is_raw_subdev(pipe_id)) {
+				stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0);
+				raw_pipeline = &cam->raw.pipelines[pipe_id];
+				mtk_cam_req_set_vfmt(cam, raw_pipeline,
+						     stream_data);
+				pad = MTK_RAW_SINK;
+
+				/* Set MEDIA_PAD_FL_SINK pad's fmt */
+				for (pad = MTK_RAW_SINK_BEGIN;
+				     pad < MTK_RAW_SOURCE_BEGIN; pad++) {
+					stream_data->pad_fmt[pad].format =
+						raw_pipeline->cfg[pad].mbus_fmt;
+				}
+				/* Set MEDIA_PAD_FL_SOURCE pad's fmt */
+				for (pad = MTK_RAW_SOURCE_BEGIN;
+				     pad < MTK_RAW_PIPELINE_PADS_NUM; pad++) {
+					stream_data->pad_fmt[pad].format =
+						raw_pipeline->cfg[pad].mbus_fmt;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int mtk_cam_req_update_ctrl(struct mtk_raw_pipeline *raw_pipe,
+				   struct mtk_cam_request_stream_data *s_data)
+{
+	char *debug_str = mtk_cam_s_data_get_dbg_str(s_data);
+	struct mtk_cam_request *req;
+	struct mtk_cam_req_raw_pipe_data *raw_pipe_data;
+
+	raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data);
+	if (!raw_pipe_data) {
+		dev_err(raw_pipe->subdev.v4l2_dev->dev,
+			"%s: cannot find raw_pipe_data, pipe_id:%d, frm_seq:%d\n",
+			__func__, s_data->pipe_id, s_data->frame_seq_no);
+		return -EINVAL;
+	}
+	req = mtk_cam_s_data_get_req(s_data);
+	if (!req) {
+		dev_err(raw_pipe->subdev.v4l2_dev->dev,
+			"%s: cannot find req, pipe_id:%d, frm_seq:%d\n",
+			__func__, s_data->pipe_id, s_data->frame_seq_no);
+		return -EINVAL;
+	}
+
+	/* clear seamless switch mode */
+	raw_pipe->sensor_mode_update = 0;
+	mtk_cam_req_ctrl_setup(raw_pipe, req);
+
+	s_data->feature.raw_feature = raw_pipe->feature_pending;
+	atomic_set(&s_data->first_setting_check, 0);
+
+	dev_dbg(raw_pipe->subdev.v4l2_dev->dev,
+		"%s:%s:%s:raw_feature(0x%0x), sensor_mode_update(0x%0x)\n",
+		__func__, raw_pipe->subdev.name, debug_str,
+		s_data->feature.raw_feature,
+		raw_pipe->sensor_mode_update);
+
+	if (raw_pipe->sensor_mode_update)
+		s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1;
+
+	raw_pipe_data->res = raw_pipe->user_res;
+
+	return 0;
+}
+
+static int mtk_cam_fill_img_buf(struct mtkcam_ipi_img_output *img_out,
+				const struct v4l2_format *f, dma_addr_t daddr)
+{
+	u32 pixelformat = f->fmt.pix_mp.pixelformat;
+	u32 width = f->fmt.pix_mp.width;
+	u32 height = f->fmt.pix_mp.height;
+	const struct v4l2_plane_pix_format *plane = &f->fmt.pix_mp.plane_fmt[0];
+	u32 stride = plane->bytesperline;
+	u32 aligned_width;
+	unsigned int addr_offset = 0;
+	int i;
+
+	const struct mtk_format_info *mtk_info = NULL;
+	const struct v4l2_format_info *v4l2_info = NULL;
+	const void *info = NULL;
+	bool is_mtk = is_mtk_format(pixelformat);
+
+	if (is_mtk) {
+		mtk_info = mtk_format_info(pixelformat);
+		info = mtk_info;
+		if (!mtk_info)
+			return -EINVAL;
+	} else {
+		v4l2_info = v4l2_format_info(pixelformat);
+		info = v4l2_info;
+		if (!v4l2_info)
+			return -EINVAL;
+	}
+
+	// get bpp, mem_planes, comp_planes, hdiv, vdiv
+	#define GET_MEMBER(member) (is_mtk ? mtk_info->member : v4l2_info->member)
+
+	aligned_width = stride / GET_MEMBER(bpp[0]);
+
+	if (GET_MEMBER(mem_planes) == 1) {
+		if (is_mtk && is_yuv_ufo(pixelformat)) {
+			aligned_width = ALIGN(width, 64);
+			img_out->buf[0][0].iova = daddr;
+			img_out->fmt.stride[0] = aligned_width * mtk_info->bit_r_num / mtk_info->bit_r_den;
+			img_out->buf[0][0].size = img_out->fmt.stride[0] * height;
+			img_out->buf[0][0].size += img_out->fmt.stride[0] * height / 2;
+			img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height;
+			img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height / 2;
+
+			pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n",
+				 0, img_out->fmt.stride[0], img_out->buf[0][0].size,
+				 (unsigned long)img_out->buf[0][0].iova);
+		} else if (is_mtk && is_raw_ufo(pixelformat)) {
+			aligned_width = ALIGN(width, 64);
+			img_out->buf[0][0].iova = daddr;
+			img_out->fmt.stride[0] = aligned_width * mtk_info->bit_r_num / mtk_info->bit_r_den;
+			img_out->buf[0][0].size = img_out->fmt.stride[0] * height;
+			img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height;
+
+			pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n",
+					0, img_out->fmt.stride[0],
+					img_out->buf[0][0].size,
+					(unsigned long)img_out->buf[0][0].iova);
+		} else {
+			for (i = 0; i < GET_MEMBER(comp_planes); i++) {
+				unsigned int hdiv = (i == 0) ? 1 : GET_MEMBER(hdiv);
+				unsigned int vdiv = (i == 0) ? 1 : GET_MEMBER(vdiv);
+
+				img_out->buf[0][i].iova = daddr + addr_offset;
+				img_out->fmt.stride[i] = GET_MEMBER(bpp[i]) *
+					DIV_ROUND_UP(aligned_width, hdiv);
+				img_out->buf[0][i].size = img_out->fmt.stride[i] *
+					DIV_ROUND_UP(height, vdiv);
+				addr_offset += img_out->buf[0][i].size;
+
+				pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n",
+						i, img_out->fmt.stride[i],
+						img_out->buf[0][i].size,
+						(unsigned long)img_out->buf[0][i].iova);
+			}
+		}
+	} else {
+		pr_debug("do not support non contiguous mplane\n");
+	}
+
+	#undef GET_MEMBER
+
+	return 0;
+}
+
+static void mtk_cam_config_raw_path(struct mtk_cam_device *cam,
+				    struct mtkcam_ipi_frame_param *frame_param,
+				    struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_video_device *node;
+	struct mtk_raw_pipeline *raw_pipeline;
+
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+	raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id);
+	if (!raw_pipeline) {
+		dev_err(cam->dev, "%s: cannot find raw_pipeline, pipe_id:%d\n",
+			__func__, node->uid.pipe_id);
+		return;
+	}
+
+	/* un-processed raw frame */
+	frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_UNPROCESSED;
+
+	dev_dbg(cam->dev, "%s: node:%d fd:%d idx:%d raw_path(%d) ipi imgo_path_sel(%d))\n",
+		__func__, node->desc.id, buf->vbb.request_fd, buf->vbb.vb2_buf.index,
+		raw_pipeline->res_config.raw_path, frame_param->raw_param.imgo_path_sel);
+}
+
+static void mtk_cam_config_raw_img_out_imgo(struct mtk_cam_device *cam,
+					    struct mtkcam_ipi_frame_param *frame_param,
+					    struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_img_output *img_out;
+	unsigned int pixelformat;
+
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+	pixelformat = node->active_fmt.fmt.pix_mp.pixelformat;
+	img_out->buf[0][0].iova = buf->daddr;
+	if (is_raw_ufo(pixelformat))
+		mtk_cam_fill_img_buf(img_out, &node->active_fmt, buf->daddr);
+}
+
+/* Update dmo's buffer information except imgo (address and size) */
+static void mtk_cam_config_raw_img_out(struct mtk_cam_device *cam,
+				       struct mtkcam_ipi_frame_param *frame_param,
+				       struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_img_output *img_out;
+
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+	mtk_cam_fill_img_buf(img_out, &node->active_fmt, buf->daddr);
+}
+
+static int
+mtk_cam_config_raw_img_fmt(struct mtk_cam_device *cam,
+			   struct mtkcam_ipi_frame_param *frame_param,
+			   struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_img_output *img_out;
+	struct v4l2_mbus_framefmt *pfmt;
+	int sd_width, sd_height, ret;
+	struct mtk_raw_pipeline *raw_pipline;
+
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+	raw_pipline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+
+	pfmt = &raw_pipline->cfg[MTK_RAW_SINK].mbus_fmt;
+	sd_width = pfmt->width;
+	sd_height = pfmt->height;
+
+	img_out->uid.pipe_id = node->uid.pipe_id;
+	img_out->uid.id =  node->desc.dma_port;
+
+	img_out->crop.p.x = node->active_crop.r.left;
+	img_out->crop.p.y = node->active_crop.r.top;
+	img_out->crop.s.w = node->active_crop.r.width;
+	img_out->crop.s.h = node->active_crop.r.height;
+
+	ret = config_img_fmt(cam, node, &node->active_fmt, img_out,
+			     sd_width, sd_height);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* Update raw_param.imgo_path_sel */
+static void mtk_cam_req_config_raw_path(struct mtk_cam_request_stream_data *s_data,
+					struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtkcam_ipi_frame_param *frame_param;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	frame_param = &s_data->frame_params;
+
+	mtk_cam_config_raw_path(cam, frame_param, buf);
+}
+
+/*
+ * Update:
+ * 1. imgo's buffer information (address and size)
+ * 2. rawi's buffer information (address and size)
+ */
+static int mtk_cam_req_config_raw_img_out_imgo(struct mtk_cam_request_stream_data *s_data,
+					       struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_request *req;
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_frame_param *frame_param;
+	struct mtkcam_ipi_img_output *img_out;
+	const struct v4l2_format *cfg_fmt;
+	unsigned int pixelformat;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	req = mtk_cam_s_data_get_req(s_data);
+	frame_param = &s_data->frame_params;
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+	cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id);
+	if (!cfg_fmt) {
+		dev_info(cam->dev,
+			 "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n",
+			 __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name);
+		return -EINVAL;
+	}
+	pixelformat = cfg_fmt->fmt.pix_mp.pixelformat;
+	img_out->buf[0][0].iova = buf->daddr;
+	if (is_raw_ufo(pixelformat))
+		mtk_cam_fill_img_buf(img_out, cfg_fmt, buf->daddr);
+
+	return 0;
+}
+
+/* Update dmo's buffer information except imgo (address and size) */
+static int mtk_cam_req_config_raw_img_out(struct mtk_cam_request_stream_data *s_data,
+					  struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_request *req;
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_frame_param *frame_param;
+	struct mtkcam_ipi_img_output *img_out;
+	const struct v4l2_format *cfg_fmt;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	req = mtk_cam_s_data_get_req(s_data);
+	frame_param = &s_data->frame_params;
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+	cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id);
+	if (!cfg_fmt) {
+		dev_info(cam->dev,
+			 "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n",
+			 __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name);
+		return -EINVAL;
+	}
+
+	mtk_cam_fill_img_buf(img_out, cfg_fmt, buf->daddr);
+
+	return 0;
+}
+
+static int
+mtk_cam_req_config_raw_img_fmt(struct mtk_cam_request_stream_data *s_data,
+			       struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_request *req;
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_frame_param *frame_param;
+	struct mtkcam_ipi_img_output *img_out;
+	struct v4l2_mbus_framefmt *pfmt;
+	int sd_width, sd_height, ret;
+	const struct v4l2_format *cfg_fmt;
+	struct v4l2_selection *cfg_selection;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	req = mtk_cam_s_data_get_req(s_data);
+	frame_param = &s_data->frame_params;
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+
+	/* not support sub-sampling multi-plane buffer */
+	img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN];
+	cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id);
+	if (!cfg_fmt) {
+		dev_err(cam->dev,
+			"%s:%s:pipe(%d):%s: can't find the vfmt field to save\n",
+			__func__, req->req.debug_str, node->uid.pipe_id, node->desc.name);
+		return -EINVAL;
+	}
+
+	cfg_selection = mtk_cam_s_data_get_vsel(s_data, node->desc.id);
+	if (!cfg_selection) {
+		dev_err(cam->dev,
+			"%s:%s:pipe(%d):%s: can't find the vsel field to save\n",
+			__func__, req->req.debug_str, node->uid.pipe_id, node->desc.name);
+		return -EINVAL;
+	}
+
+	pfmt = mtk_cam_s_data_get_pfmt(s_data, MTK_RAW_SINK);
+	sd_width = pfmt->width;
+	sd_height = pfmt->height;
+
+	img_out->uid.pipe_id = node->uid.pipe_id;
+	img_out->uid.id =  node->desc.dma_port;
+
+	img_out->crop.p.x = cfg_selection->r.left;
+	img_out->crop.p.y = cfg_selection->r.top;
+	img_out->crop.s.w = cfg_selection->r.width;
+	img_out->crop.s.h = cfg_selection->r.height;
+
+	ret = config_img_fmt(cam, node, cfg_fmt, img_out, sd_width, sd_height);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+mtk_cam_req_config_raw_img_in_rawi2(struct mtk_cam_request_stream_data *s_data,
+				    struct mtk_cam_buffer *buf)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_request *req;
+	struct mtk_cam_video_device *node;
+	struct mtkcam_ipi_frame_param *frame_param;
+	struct mtkcam_ipi_img_input *in_fmt;
+	const struct v4l2_format *cfg_fmt;
+	int ret;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	req = mtk_cam_s_data_get_req(s_data);
+	frame_param = &s_data->frame_params;
+	node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue);
+	in_fmt = &frame_param->img_ins[node->desc.id - MTK_RAW_RAWI_2_IN];
+
+	cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id);
+	if (!cfg_fmt) {
+		dev_info(cam->dev,
+			 "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n",
+			 __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name);
+		return -EINVAL;
+	}
+
+	in_fmt->buf[0].iova = buf->daddr;
+	frame_param->raw_param.hardware_scenario =
+		MTKCAM_IPI_HW_PATH_OFFLINE_M2M;
+
+	in_fmt->uid.pipe_id = node->uid.pipe_id;
+	in_fmt->uid.id = node->desc.dma_port;
+	ret = config_img_in_fmt(cam, node, cfg_fmt, in_fmt);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mtk_cam_req_update(struct mtk_cam_device *cam,
+			      struct mtk_cam_request *req)
+{
+	struct media_request_object *obj, *obj_prev;
+	struct vb2_buffer *vb;
+	struct mtk_cam_buffer *buf;
+	struct mtk_cam_video_device *node;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	int i, ctx_cnt;
+	int ret;
+
+	dev_dbg(cam->dev, "update request:%s\n", req->req.debug_str);
+
+	mtk_cam_req_set_fmt(cam, req);
+
+	list_for_each_entry_safe(obj, obj_prev, &req->req.objects, list) {
+		if (!vb2_request_object_is_buffer(obj))
+			continue;
+		vb = container_of(obj, struct vb2_buffer, req_obj);
+		buf = mtk_cam_vb2_buf_to_dev_buf(vb);
+		node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+
+		ctx = mtk_cam_find_ctx(cam, &node->vdev.entity);
+		if (!ctx)
+			return -EINVAL;
+		req->ctx_used |= 1 << ctx->stream_id;
+
+		req_stream_data = mtk_cam_req_get_s_data(req, node->uid.pipe_id, 0);
+		req_stream_data->ctx = ctx;
+		req_stream_data->no_frame_done_cnt = 0;
+		atomic_set(&req_stream_data->sensor_work.is_queued, 0);
+		atomic_set(&req_stream_data->frame_done_work.is_queued, 0);
+		req->sync_id = (ctx->used_raw_num) ? ctx->pipe->sync_id : 0;
+
+		/* not support TWIN independent AFO  */
+		if (ctx->used_raw_num && ctx->pipe->res_config.raw_num_used == 1)
+			req_stream_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT;
+
+		/* update buffer format */
+		switch (node->desc.dma_port) {
+		case MTKCAM_ISP_RAWI_2:
+			ret = mtk_cam_req_config_raw_img_in_rawi2(req_stream_data, buf);
+			if (ret)
+				return ret;
+			break;
+		case MTKCAM_ISP_IMGO:
+			mtk_cam_req_config_raw_path(req_stream_data, buf);
+			ret = mtk_cam_req_config_raw_img_out_imgo(req_stream_data, buf);
+			if (ret)
+				return ret;
+
+			ret = mtk_cam_req_config_raw_img_fmt(req_stream_data, buf);
+			if (ret)
+				return ret;
+			break;
+		case MTKCAM_ISP_YUVO_1:
+		case MTKCAM_ISP_YUVO_2:
+		case MTKCAM_ISP_YUVO_3:
+		case MTKCAM_ISP_YUVO_4:
+		case MTKCAM_ISP_YUVO_5:
+		case MTKCAM_ISP_RZH1N2TO_1:
+		case MTKCAM_ISP_RZH1N2TO_2:
+		case MTKCAM_ISP_RZH1N2TO_3:
+		case MTKCAM_ISP_DRZS4NO_1:
+		case MTKCAM_ISP_DRZS4NO_2:
+		case MTKCAM_ISP_DRZS4NO_3:
+			ret = mtk_cam_req_config_raw_img_out(req_stream_data, buf);
+			if (ret)
+				return ret;
+
+			ret = mtk_cam_req_config_raw_img_fmt(req_stream_data, buf);
+				if (ret)
+					return ret;
+			break;
+		case MTKCAM_ISP_META_STATS_CFG:
+		case MTKCAM_ISP_META_STATS_0:
+		case MTKCAM_ISP_META_STATS_1:
+		case MTKCAM_ISP_META_STATS_2:
+			break;
+		default:
+			/* Do nothing for the ports not related to crop settings */
+			break;
+		}
+	}
+
+	/* frame sync */
+	/* prepare img working buf */
+	ctx_cnt = 0;
+	for (i = 0; i < cam->max_stream_num; i++) {
+		if (!(1 << i & req->ctx_used))
+			continue;
+
+		/* internal fs */
+		ctx_cnt++;
+
+		ctx = &cam->ctxs[i];
+		req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
+		if (!req_stream_data)
+			continue;
+	}
+	req->fs.target = ctx_cnt > 1 ? ctx_cnt : 0;
+
+	return 0;
+}
+
+/* Check all pipeline involved in the request are streamed on */
+static int mtk_cam_dev_req_is_stream_on(struct mtk_cam_device *cam,
+					struct mtk_cam_request *req)
+{
+	dev_dbg(cam->dev,
+		"%s: pipe_used(0x%x), streaming_pipe(0x%x), req(%s)\n",
+		__func__, req->pipe_used, cam->streaming_pipe,
+		req->req.debug_str);
+	return (req->pipe_used & cam->streaming_pipe) == req->pipe_used;
+}
+
+static void mtk_cam_req_work_init(struct mtk_cam_req_work *work,
+				  struct mtk_cam_request_stream_data *s_data)
+{
+	work->s_data = s_data;
+}
+
+static void mtk_cam_req_s_data_init(struct mtk_cam_request *req,
+				    u32 pipe_id,
+				    u32 s_data_index)
+{
+	struct mtk_cam_request_stream_data *req_stream_data;
+
+	req_stream_data = &req->p_data[pipe_id].s_data[s_data_index];
+	req_stream_data->req = req;
+	req_stream_data->pipe_id = pipe_id;
+	req_stream_data->state.estate = E_STATE_READY;
+	req_stream_data->index = s_data_index;
+	atomic_set(&req_stream_data->buf_state, -1);
+
+	/**
+	 * req_stream_data->flags is cleaned by
+	 * mtk_cam_req_s_data_clean () at previous job done
+	 * and may by updated by qbuf before request enqueue
+	 * so we don't reset it here.
+	 */
+	mtk_cam_req_work_init(&req_stream_data->seninf_s_fmt_work, req_stream_data);
+	mtk_cam_req_work_init(&req_stream_data->frame_work, req_stream_data);
+	mtk_cam_req_work_init(&req_stream_data->frame_done_work, req_stream_data);
+	mtk_cam_req_work_init(&req_stream_data->meta1_done_work, req_stream_data);
+	/**
+	 * clean the param structs since we support req reinit.
+	 * the mtk_cam_request may not be "zero" when it is
+	 * enqueued.
+	 */
+	memset(&req_stream_data->frame_params, 0,
+	       sizeof(req_stream_data->frame_params));
+
+	/* generally is single exposure */
+	req_stream_data->frame_params.raw_param.exposure_num = 1;
+}
+
+void mtk_cam_dev_req_try_queue(struct mtk_cam_device *cam)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request *req, *req_prev;
+	struct mtk_cam_request_stream_data *s_data;
+	int i, s_data_flags;
+	int enqueue_req_cnt, job_count, s_data_cnt;
+	struct list_head equeue_list;
+	struct v4l2_ctrl_handler *hdl;
+	struct media_request_object *sensor_hdl_obj, *raw_hdl_obj, *obj;
+	unsigned long flags;
+
+	if (!cam->streaming_ctx) {
+		dev_info(cam->dev, "streams are off\n");
+		return;
+	}
+
+	INIT_LIST_HEAD(&equeue_list);
+
+	guard(spinlock)(&cam->running_job_lock);
+	job_count = cam->running_job_count;
+
+	/* Pick up requests which are runnable */
+	enqueue_req_cnt = 0;
+	spin_lock(&cam->pending_job_lock);
+	list_for_each_entry_safe(req, req_prev, &cam->pending_job_list, list) {
+		if (likely(mtk_cam_dev_req_is_stream_on(cam, req))) {
+			if (job_count + enqueue_req_cnt >=
+			    RAW_PIPELINE_NUM * MTK_CAM_MAX_RUNNING_JOBS) {
+				dev_dbg(cam->dev, "jobs are full, job cnt(%d)\n",
+					job_count);
+				break;
+			}
+			dev_dbg(cam->dev, "%s job cnt(%d), allow req_enqueue(%s)\n",
+				__func__, job_count + enqueue_req_cnt, req->req.debug_str);
+
+			enqueue_req_cnt++;
+			list_del(&req->list);
+			list_add_tail(&req->list, &equeue_list);
+		}
+	}
+	spin_unlock(&cam->pending_job_lock);
+
+	if (!enqueue_req_cnt)
+		return;
+
+	list_for_each_entry_safe(req, req_prev, &equeue_list, list) {
+		for (i = 0; i < cam->max_stream_num; i++) {
+			if (!(req->pipe_used & 1 << i))
+				continue;
+
+			/* Initialize ctx related s_data fields */
+			ctx = &cam->ctxs[i];
+			sensor_hdl_obj = NULL;
+			raw_hdl_obj = NULL;
+			s_data_flags = 0;
+
+			/* Update frame_seq_no */
+			s_data = mtk_cam_req_get_s_data(req, i, 0);
+			s_data->frame_seq_no =
+				atomic_inc_return(&ctx->enqueued_frame_seq_no);
+			if (is_raw_subdev(i) && ctx->sensor) {
+				s_data_cnt =
+					atomic_inc_return(&ctx->running_s_data_cnt);
+				s_data->sensor = ctx->sensor;
+
+				spin_lock_irqsave(&req->req.lock, flags);
+				list_for_each_entry(obj, &req->req.objects, list) {
+					if (vb2_request_object_is_buffer(obj))
+						continue;
+
+					hdl = (struct v4l2_ctrl_handler *)obj->priv;
+					if (hdl == &ctx->pipe->ctrl_handler)
+						raw_hdl_obj = obj;
+					else if (hdl == ctx->sensor->ctrl_handler)
+						sensor_hdl_obj = obj;
+				}
+				spin_unlock_irqrestore(&req->req.lock, flags);
+
+				if (raw_hdl_obj) {
+					s_data->flags |=
+						MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN;
+					s_data->raw_hdl_obj = raw_hdl_obj;
+					dev_dbg(cam->dev,
+						"%s:%s:ctx(%d): find pipe hdl\n",
+						__func__, req->req.debug_str, i);
+				}
+
+				/* Apply raw subdev's ctrl */
+				mtk_cam_req_update_ctrl(ctx->pipe, s_data);
+
+				if (s_data->sensor && s_data->sensor->ctrl_handler &&
+				    sensor_hdl_obj) {
+					s_data->sensor_hdl_obj = sensor_hdl_obj;
+					dev_dbg(cam->dev,
+						"%s:%s:ctx(%d): find sensor(%s) hdl\n",
+						__func__, req->req.debug_str, i,
+						s_data->sensor->name);
+					s_data->flags |=
+						MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN;
+				}
+
+				s_data_flags = s_data->flags;
+
+				/* reload s_data */
+				s_data->flags = s_data_flags;
+				s_data->raw_hdl_obj = raw_hdl_obj;
+				s_data->sensor_hdl_obj = sensor_hdl_obj;
+
+				/* copy s_data content */
+				if (req->p_data[i].s_data_num == 2)
+					dev_info(cam->dev,
+						 "%s:req(%s): undefined s_data_1, raw_feature(%lld), s_data_cnt(%d)\n",
+						 __func__, req->req.debug_str,
+						 ctx->pipe->feature_pending,
+						 s_data_cnt);
+			} else if (is_raw_subdev(i) && !ctx->sensor) {
+				s_data_cnt =
+					atomic_inc_return(&ctx->running_s_data_cnt);
+
+				spin_lock_irqsave(&req->req.lock, flags);
+				list_for_each_entry(obj, &req->req.objects, list) {
+					if (vb2_request_object_is_buffer(obj))
+						continue;
+
+					hdl = (struct v4l2_ctrl_handler *)obj->priv;
+					if (hdl == &ctx->pipe->ctrl_handler)
+						raw_hdl_obj = obj;
+				}
+				spin_unlock_irqrestore(&req->req.lock, flags);
+
+				if (raw_hdl_obj) {
+					s_data->flags |=
+						MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN;
+					s_data->raw_hdl_obj = raw_hdl_obj;
+					dev_dbg(cam->dev,
+						"%s:%s:ctx(%d): find pipe hdl, s_data_cnt(%d)\n",
+						__func__, req->req.debug_str, i,
+						s_data_cnt);
+				}
+
+				/* Apply raw subdev's ctrl */
+				mtk_cam_req_update_ctrl(ctx->pipe, s_data);
+			}
+		}
+
+		if (mtk_cam_req_update(cam, req)) {
+			dev_info(cam->dev,
+				 "%s:req(%s): invalid req settings which can't be recovered\n",
+				 __func__, req->req.debug_str);
+			WARN_ON(1);
+			return;
+		}
+
+		atomic_set(&req->state, MTK_CAM_REQ_STATE_RUNNING);
+		spin_lock(&cam->running_job_lock);
+		cam->running_job_count++;
+		list_del(&req->list);
+		list_add_tail(&req->list, &cam->running_job_list);
+		spin_unlock(&cam->running_job_lock);
+		mtk_cam_dev_req_enqueue(cam, req);
+	}
+}
+
+static struct media_request *mtk_cam_req_alloc(struct media_device *mdev)
+{
+	struct mtk_cam_request *cam_req;
+
+	cam_req = vzalloc(sizeof(*cam_req));
+	spin_lock_init(&cam_req->done_status_lock);
+	mutex_init(&cam_req->fs.op_lock);
+
+	return &cam_req->req;
+}
+
+static void mtk_cam_req_free(struct media_request *req)
+{
+	struct mtk_cam_request *cam_req = to_mtk_cam_req(req);
+
+	vfree(cam_req);
+}
+
+static int mtk_cam_req_chk_job_list(struct mtk_cam_device *cam,
+				    struct mtk_cam_request *new_req,
+				    struct list_head *job_list,
+				    char *job_list_name)
+{
+	if (!job_list || !job_list->prev || !job_list->prev->next || !new_req) {
+		dev_err(cam->dev,
+			"%s:%s: job_list, job_list->prev, job_list->prev->next, new_req can't be NULL\n",
+			__func__, job_list_name);
+		return -EINVAL;
+	}
+
+	if (job_list->prev->next != job_list) {
+		dev_err(cam->dev,
+			"%s broken: job_list->prev->next(%p), job_list(%p), req(%s)\n",
+			job_list_name, job_list->prev->next, job_list,
+			new_req->req.debug_str);
+		return -EINVAL;
+	}
+
+	if (&new_req->list == job_list->prev || &new_req->list == job_list) {
+		dev_err(cam->dev, "%s job double add: req(%s)\n",
+			job_list_name, new_req->req.debug_str);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void mtk_cam_req_p_data_init(struct mtk_cam_request *req,
+				    u32 pipe_id,
+				    u32 s_data_num)
+{
+	u32 i = 0;
+
+	if (pipe_id >= MTKCAM_SUBDEV_MAX)
+		return;
+
+	req->p_data[pipe_id].s_data_num = s_data_num;
+	for (i = 0; i < s_data_num; i++)
+		mtk_cam_req_s_data_init(req, pipe_id, i);
+}
+
+static inline void mtk_cam_req_cnt_init(struct mtk_cam_request *req)
+{
+	atomic_set(&req->ref_cnt, 0);
+}
+
+static unsigned int mtk_cam_req_get_pipe_used(struct media_request *req)
+{
+	/**
+	 * V4L2 framework doesn't trigger q->ops->buf_queue(q, buf) when it is
+	 * stream off. We have to check the used context through the request directly
+	 * before streaming on.
+	 */
+	struct media_request_object *obj;
+	unsigned int pipe_used = 0;
+	struct mtk_cam_request *cam_req = to_mtk_cam_req(req);
+	unsigned int i;
+	struct mtk_cam_device *cam =
+		container_of(req->mdev, struct mtk_cam_device, media_dev);
+
+	list_for_each_entry(obj, &req->objects, list) {
+		struct vb2_buffer *vb;
+		struct mtk_cam_video_device *node;
+
+		if (!vb2_request_object_is_buffer(obj))
+			continue;
+		vb = container_of(obj, struct vb2_buffer, req_obj);
+		node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+		pipe_used |= 1 << node->uid.pipe_id;
+	}
+
+	mtk_cam_req_cnt_init(cam_req);
+
+	/* Initialize per pipe's stream data (without ctx)*/
+	for (i = 0; i < cam->max_stream_num; i++) {
+		if (pipe_used & (1 << i)) {
+			mtk_cam_req_p_data_init(cam_req, i, 1);
+			mtk_cam_req_get(cam_req, i); /* pipe id */
+		}
+	}
+
+	return pipe_used;
+}
+
+static void mtk_cam_req_queue(struct media_request *req)
+{
+	struct mtk_cam_request *cam_req = to_mtk_cam_req(req);
+	struct mtk_cam_device *cam =
+		container_of(req->mdev, struct mtk_cam_device, media_dev);
+
+	/* reset done status */
+	cam_req->done_status = 0;
+	cam_req->pipe_used = mtk_cam_req_get_pipe_used(req);
+	cam_req->ctx_used = 0; /* will update after stream on */
+	mtk_cam_fs_reset(&cam_req->fs);
+
+	/* update frame_params's dma_bufs in mtk_cam_vb2_buf_queue */
+	vb2_request_queue(req);
+
+	/* add to pending job list */
+	spin_lock(&cam->pending_job_lock);
+	if (mtk_cam_req_chk_job_list(cam, cam_req, &cam->pending_job_list,
+				     "pending_job_list")) {
+		spin_unlock(&cam->pending_job_lock);
+		return;
+	}
+
+	/**
+	 * Add req's ref cnt since it is used by pending_job_list and running
+	 * pending_job_list.
+	 */
+	atomic_set(&cam_req->state, MTK_CAM_REQ_STATE_PENDING);
+	list_add_tail(&cam_req->list, &cam->pending_job_list);
+	spin_unlock(&cam->pending_job_lock);
+	mutex_lock(&cam->queue_lock);
+	mtk_cam_dev_req_try_queue(cam);
+	mutex_unlock(&cam->queue_lock);
+}
+
+static int mtk_cam_link_notify(struct media_link *link, u32 flags,
+			       unsigned int notification)
+{
+	struct media_entity *source = link->source->entity;
+	struct media_entity *sink = link->sink->entity;
+	struct v4l2_subdev *subdev;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+
+	if (source->function != MEDIA_ENT_F_VID_IF_BRIDGE ||
+	    notification != MEDIA_DEV_NOTIFY_POST_LINK_CH)
+		return v4l2_pipeline_link_notify(link, flags, notification);
+
+	subdev = media_entity_to_v4l2_subdev(sink);
+	if (!subdev)
+		return -EINVAL;
+	cam = container_of(subdev->v4l2_dev->mdev, struct mtk_cam_device, media_dev);
+	ctx = mtk_cam_find_ctx(cam, sink);
+
+	if (!ctx || !ctx->streaming || !(flags & MEDIA_LNK_FL_ENABLED))
+		return v4l2_pipeline_link_notify(link, flags, notification);
+
+	dev_info(cam->dev, "stream_id(%d) is streaming, can't change link\n",
+		 ctx->stream_id);
+
+	return -EBUSY;
+}
+
+static const struct media_device_ops mtk_cam_dev_ops = {
+	.link_notify = mtk_cam_link_notify,
+	.req_alloc = mtk_cam_req_alloc,
+	.req_free = mtk_cam_req_free,
+	.req_validate = vb2_request_validate,
+	.req_queue = mtk_cam_req_queue,
+};
+
+static int mtk_cam_of_rproc(struct mtk_cam_device *cam,
+			    struct platform_device *pdev)
+{
+	struct device *dev = cam->dev;
+
+	cam->scp = scp_get(pdev);
+	if (!cam->scp) {
+		dev_err(dev, "failed to get scp device\n");
+		return -ENODEV;
+	}
+
+	cam->rproc_handle = scp_get_rproc(cam->scp);
+	dev_dbg(dev, "camsys rproc_phandle: 0x%pK\n", cam->rproc_handle);
+	cam->smem_dev = scp_get_device(cam->scp);
+
+	return 0;
+}
+
+struct mtk_raw_device *get_main_raw_dev(struct mtk_cam_device *cam,
+					struct mtk_raw_pipeline *pipe)
+{
+	struct device *dev_main = NULL;
+	unsigned int i;
+
+	for (i = 0; i < cam->num_raw_devices; i++) {
+		if (pipe->enabled_raw & (1 << i)) {
+			dev_main = cam->raw.devs[i];
+			break;
+		}
+	}
+
+	if (!dev_main) {
+		dev_err(cam->dev, "Not found main raw device\n");
+		return NULL;
+	}
+
+	return dev_get_drvdata(dev_main);
+}
+
+struct mtk_raw_device *get_sub_raw_dev(struct mtk_cam_device *cam,
+				       struct mtk_raw_pipeline *pipe)
+{
+	struct device *dev_sub = NULL;
+	unsigned int i;
+
+	for (i = 0; i < cam->num_raw_devices - 1; i++) {
+		if (pipe->enabled_raw & (1 << i)) {
+			dev_sub = cam->raw.devs[i + 1];
+			break;
+		}
+	}
+
+	if (!dev_sub) {
+		dev_err(cam->dev, "Not found sub raw device\n");
+		return NULL;
+	}
+
+	return dev_get_drvdata(dev_sub);
+}
+
+struct mtk_raw_device *get_sub2_raw_dev(struct mtk_cam_device *cam,
+					struct mtk_raw_pipeline *pipe)
+{
+	struct device *dev_sub = NULL;
+	unsigned int i;
+
+	for (i = 0; i < cam->num_raw_devices; i++) {
+		if (pipe->enabled_raw & (1 << i)) {
+			dev_sub = cam->raw.devs[i + 2];
+			break;
+		}
+	}
+
+	if (!dev_sub) {
+		dev_err(cam->dev, "Not found second sub raw device\n");
+		return NULL;
+	}
+
+	return dev_get_drvdata(dev_sub);
+}
+
+static int isp_composer_handle_ack(struct mtk_cam_device *cam,
+				   struct mtkcam_ipi_event *ipi_msg)
+{
+	struct device *dev = cam->dev;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_working_buf_entry *buf_entry;
+	struct mtk_cam_request_stream_data *s_data;
+	struct mtk_raw_device *raw_dev;
+	bool is_m2m_apply_cq = false;
+
+	ctx = &cam->ctxs[ipi_msg->cookie.session_id];
+
+	spin_lock(&ctx->using_buffer_list.lock);
+
+	ctx->composed_frame_seq_no = ipi_msg->cookie.frame_no;
+	dev_dbg(dev, "ctx:%d ack frame_num:%d\n",
+		ctx->stream_id, ctx->composed_frame_seq_no);
+
+	/* get from using list */
+	if (list_empty(&ctx->using_buffer_list.list)) {
+		spin_unlock(&ctx->using_buffer_list.lock);
+		return -EINVAL;
+	}
+	/* assign raw using buf */
+	buf_entry = list_first_entry(&ctx->using_buffer_list.list,
+				     struct mtk_cam_working_buf_entry,
+				     list_entry);
+	list_del(&buf_entry->list_entry);
+	ctx->using_buffer_list.cnt--;
+
+	spin_lock(&cam->dma_processing_lock);
+	if (!list_empty(&cam->dma_processing)) {
+		spin_unlock(&cam->dma_processing_lock);
+		buf_entry->cq_desc_offset =
+			ipi_msg->ack_data.frame_result.cq_desc_offset;
+		buf_entry->cq_desc_size =
+			ipi_msg->ack_data.frame_result.cq_desc_size;
+		buf_entry->sub_cq_desc_offset =
+			ipi_msg->ack_data.frame_result.sub_cq_desc_offset;
+		buf_entry->sub_cq_desc_size =
+			ipi_msg->ack_data.frame_result.sub_cq_desc_size;
+
+		goto skip_req;
+	}
+	spin_unlock(&cam->dma_processing_lock);
+
+	s_data = buf_entry->s_data;
+	if (!s_data) {
+		dev_dbg(dev, "ctx:%d no req for ack frame_num:%d\n",
+			ctx->stream_id, ctx->composed_frame_seq_no);
+		spin_unlock(&ctx->using_buffer_list.lock);
+		return -EINVAL;
+	}
+
+	buf_entry->cq_desc_offset =
+		ipi_msg->ack_data.frame_result.cq_desc_offset;
+	buf_entry->cq_desc_size =
+		ipi_msg->ack_data.frame_result.cq_desc_size;
+	buf_entry->sub_cq_desc_offset =
+		ipi_msg->ack_data.frame_result.sub_cq_desc_offset;
+	buf_entry->sub_cq_desc_size =
+		ipi_msg->ack_data.frame_result.sub_cq_desc_size;
+
+skip_req:
+	if (ctx->composed_frame_seq_no == 1 || is_m2m_apply_cq) {
+		struct device *dev;
+		/* apply raw CQ */
+		spin_lock(&ctx->processing_buffer_list.lock);
+		list_add_tail(&buf_entry->list_entry, &ctx->processing_buffer_list.list);
+		ctx->processing_buffer_list.cnt++;
+		spin_unlock(&ctx->processing_buffer_list.lock);
+		spin_unlock(&ctx->using_buffer_list.lock);
+
+		dev = mtk_cam_find_raw_dev(cam, ctx->pipe->enabled_raw);
+		if (!dev) {
+			dev_dbg(dev, "frm#1 raw device not found\n");
+			return -EINVAL;
+		}
+
+		raw_dev = dev_get_drvdata(dev);
+
+		mtk_cam_raw_apply_cq(raw_dev, buf_entry->buffer.iova,
+				     buf_entry->cq_desc_size,
+				     buf_entry->cq_desc_offset,
+				     buf_entry->sub_cq_desc_size,
+				     buf_entry->sub_cq_desc_offset);
+		if (s_data) {
+			s_data->timestamp = ktime_get_boottime_ns();
+			s_data->timestamp_mono = ktime_get_ns();
+		}
+
+		return 0;
+	}
+
+	spin_lock(&ctx->composed_buffer_list.lock);
+	list_add_tail(&buf_entry->list_entry, &ctx->composed_buffer_list.list);
+	ctx->composed_buffer_list.cnt++;
+	spin_unlock(&ctx->composed_buffer_list.lock);
+	spin_unlock(&ctx->using_buffer_list.lock);
+
+	return 0;
+}
+
+static void isp_composer_cmd_handler(void *data, unsigned int len, void *priv)
+{
+    struct mtk_cam_device *cam = (struct mtk_cam_device *)priv;
+    struct device *dev = cam->dev;
+    struct mtkcam_ipi_event *ipi_msg;
+    struct mtk_cam_ctx *ctx;
+
+    ipi_msg = (struct mtkcam_ipi_event *)data;
+
+    if (len < offsetofend(struct mtkcam_ipi_event, ack_data)) {
+        dev_dbg(dev, "CMD: wrong IPI len:%d\n", len);
+        return;
+    }
+
+    if (ipi_msg->cmd_id != CAM_CMD_ACK)
+        return;
+
+    if (ipi_msg->ack_data.ack_cmd_id == CAM_CMD_DESTROY_SESSION) {
+        ctx = &cam->ctxs[ipi_msg->cookie.session_id];
+        complete(&ctx->session_complete);
+        dev_info(dev, "%s:ctx(%d): session destroyed",
+                 __func__, ctx->stream_id);
+    }
+}
+
+static void isp_composer_frame_handler(void *data, unsigned int len, void *priv)
+{
+    struct mtk_cam_device *cam = (struct mtk_cam_device *)priv;
+    struct device *dev = cam->dev;
+    struct mtkcam_ipi_event *ipi_msg;
+
+    ipi_msg = (struct mtkcam_ipi_event *)data;
+
+    if (len < offsetofend(struct mtkcam_ipi_event, ack_data)) {
+        dev_dbg(dev, "FRAME: wrong IPI len:%d\n", len);
+        return;
+    }
+
+    if (ipi_msg->cmd_id != CAM_CMD_ACK)
+        return;
+
+    if (ipi_msg->ack_data.ack_cmd_id == CAM_CMD_FRAME) {
+        isp_composer_handle_ack(cam, ipi_msg);
+    }
+}
+
+static int isp_composer_init(struct mtk_cam_device *cam)
+{
+	struct device *dev = cam->dev;
+	int ret;
+
+	ret = rproc_boot(cam->rproc_handle);
+	if (ret) {
+		dev_err(dev, "failed to rproc_boot\n");
+		return ret;
+	}
+
+	ret = scp_ipi_register(cam->scp, SCP_IPI_ISP_CMD,
+			       isp_composer_cmd_handler, cam);
+	if (ret) {
+		dev_err(dev, "failed to register IPI cmd\n");
+		return ret;
+	}
+
+	ret = scp_ipi_register(cam->scp, SCP_IPI_ISP_FRAME,
+			       isp_composer_frame_handler, cam);
+	if (ret) {
+		dev_err(dev, "failed to register IPI frame\n");
+		goto unreg_ipi_cmd;
+	}
+
+	return 0;
+
+unreg_ipi_cmd:
+	scp_ipi_unregister(cam->scp, SCP_IPI_ISP_CMD);
+
+	return ret;
+}
+
+static void isp_composer_uninit(struct mtk_cam_device *cam)
+{
+	scp_ipi_unregister(cam->scp, SCP_IPI_ISP_CMD);
+	scp_ipi_unregister(cam->scp, SCP_IPI_ISP_FRAME);
+}
+
+int isp_composer_create_session(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtkcam_ipi_event event;
+	struct mtkcam_ipi_session_cookie *session = &event.cookie;
+	struct mtkcam_ipi_session_param	*session_data = &event.session_data;
+
+	memset(&event, 0, sizeof(event));
+	event.cmd_id = CAM_CMD_CREATE_SESSION;
+	session->session_id = ctx->stream_id;
+	session_data->workbuf.iova = ctx->buf_pool.working_buf_iova;
+	session_data->workbuf.scp_addr = ctx->buf_pool.working_buf_scp_addr;
+	session_data->workbuf.size = ctx->buf_pool.working_buf_size;
+	session_data->msg_buf.scp_addr = ctx->buf_pool.msg_buf_scp_addr;
+	session_data->msg_buf.size = ctx->buf_pool.msg_buf_size;
+	session_data->raw_workbuf.scp_addr = ctx->buf_pool.raw_workbuf_scp_addr;
+	session_data->raw_workbuf.size = ctx->buf_pool.raw_workbuf_size;
+	session_data->priv_workbuf.scp_addr = ctx->buf_pool.priv_workbuf_scp_addr;
+	session_data->priv_workbuf.size = ctx->buf_pool.priv_workbuf_size;
+	session_data->session_buf.scp_addr = ctx->buf_pool.session_buf_scp_addr;
+	session_data->session_buf.size = ctx->buf_pool.session_buf_size;
+
+	scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event,
+		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
+	dev_dbg(cam->dev,
+		"%s: IPI send id: %d, cq_buf(scp addr:%x,sz:%d, msg_buf(scp addr:%x,sz%d)\n",
+		__func__, event.cmd_id, session_data->workbuf.scp_addr,
+		session_data->workbuf.size, session_data->msg_buf.scp_addr,
+		session_data->msg_buf.size);
+	return 0;
+}
+
+void isp_composer_destroy_session(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtkcam_ipi_event event;
+	struct mtkcam_ipi_session_cookie *session = &event.cookie;
+
+	memset(&event, 0, sizeof(event));
+	event.cmd_id = CAM_CMD_DESTROY_SESSION;
+	session->session_id = ctx->stream_id;
+	scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event,
+		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
+	dev_info(cam->dev, "IPI send id: %d\n", event.cmd_id);
+}
+
+static void
+isp_composer_hw_config(struct mtk_cam_device *cam,
+		       struct mtk_cam_ctx *ctx,
+		       struct mtkcam_ipi_config_param *config_param)
+{
+	struct mtkcam_ipi_event event;
+	struct mtkcam_ipi_session_cookie *session = &event.cookie;
+	struct mtkcam_ipi_config_param *config = &event.config_data;
+
+	memset(&event, 0, sizeof(event));
+	event.cmd_id = CAM_CMD_CONFIG;
+	session->session_id = ctx->stream_id;
+	memcpy(config, config_param, sizeof(*config_param));
+	dev_dbg(cam->dev, "%s sw_feature:%d\n", __func__, config->sw_feature);
+	scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event,
+		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
+	dev_dbg(cam->dev, "IPI send id: %d\n", event.cmd_id);
+
+	/* For debug dump file */
+	memcpy(&ctx->config_params, config_param, sizeof(*config_param));
+	dev_dbg(cam->dev, "%s:ctx(%d): save config_param to ctx, sz:%zu\n",
+		__func__, ctx->stream_id, sizeof(*config_param));
+}
+
+static int mtk_cam_s_data_dev_config(struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct device *dev;
+	struct mtkcam_ipi_config_param config_param;
+	struct mtkcam_ipi_input_param *cfg_in_param;
+	struct mtk_raw_pipeline *pipe;
+	struct mtk_raw *raw;
+	struct v4l2_mbus_framefmt *mf;
+	struct device *dev_raw;
+	struct mtk_raw_device *raw_dev;
+	struct v4l2_format *img_fmt;
+	unsigned int i;
+	u32 mf_code;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	cam = ctx->cam;
+	dev = cam->dev;
+	pipe = ctx->pipe;
+	raw = pipe->raw;
+	mf = &pipe->cfg[MTK_RAW_SINK].mbus_fmt;
+	s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data);
+	if (!s_raw_pipe_data)
+		return -EINVAL;
+
+	memset(&config_param, 0, sizeof(config_param));
+
+	/* Update cfg_in_param */
+	cfg_in_param = &config_param.input;
+	cfg_in_param->pixel_mode = ctx->pipe->res_config.tgo_pxl_mode;
+
+	cfg_in_param->data_pattern = MTKCAM_IPI_SENSOR_PATTERN_NORMAL;
+	img_fmt = &pipe->vdev_nodes[MTK_RAW_SINK].pending_fmt;
+	cfg_in_param->in_crop.s.w = img_fmt->fmt.pix_mp.width;
+	cfg_in_param->in_crop.s.h = img_fmt->fmt.pix_mp.height;
+	dev_dbg(dev, "sink pad code:0x%x, tg size:%d %d\n", mf->code,
+		cfg_in_param->in_crop.s.w, cfg_in_param->in_crop.s.h);
+
+	mf_code = mf->code & 0xffff; /* sensor mode */
+	cfg_in_param->raw_pixel_id = mtk_cam_get_sensor_pixel_id(mf_code);
+	cfg_in_param->fmt = mtk_cam_get_sensor_fmt(mf_code);
+	if (cfg_in_param->fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN ||
+	    cfg_in_param->raw_pixel_id == MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN) {
+		dev_err(dev, "unknown sd code:%d\n", mf_code);
+		return -EINVAL;
+	}
+
+	s_raw_pipe_data->enabled_raw = ctx->pipe->enabled_raw &
+		MTKCAM_SUBDEV_RAW_MASK;
+	config_param.flags = MTK_CAM_IPI_CONFIG_TYPE_INPUT_CHANGE;
+
+	dev_dbg(dev, "%s: config_param flag:0x%x enabled_raw:0x%x\n",
+		__func__, config_param.flags, ctx->pipe->enabled_raw);
+
+	update_hw_mapping(ctx, &config_param);
+
+	config_param.sw_feature = MTKCAM_IPI_SW_FEATURE_NORMAL;
+
+	dev_raw = mtk_cam_find_raw_dev(cam, s_raw_pipe_data->enabled_raw);
+	if (!dev_raw) {
+		dev_err(dev, "config raw device not found\n");
+		return -EINVAL;
+	}
+
+	raw_dev = dev_get_drvdata(dev_raw);
+	for (i = 0; i < RAW_PIPELINE_NUM; i++)
+		if (raw->pipelines[i].enabled_raw & 1 << raw_dev->id) {
+			raw_dev->pipeline = &raw->pipelines[i];
+			/* TWIN case */
+			if (raw->pipelines[i].res_config.raw_num_used != 1) {
+				struct mtk_raw_device *raw_dev_sub =
+						get_sub_raw_dev(cam, ctx->pipe);
+				raw_dev_sub->pipeline = &raw->pipelines[i];
+				dev_dbg(dev, "twin main/sub raw_id:%d/%d\n",
+					raw_dev->id, raw_dev_sub->id);
+				if (raw->pipelines[i].res_config.raw_num_used == 3) {
+					struct mtk_raw_device *raw_dev_sub2 =
+						get_sub2_raw_dev(cam, ctx->pipe);
+					raw_dev_sub2->pipeline = &raw->pipelines[i];
+					dev_dbg(dev,
+						"triplet m/s/s2 raw_id:%d/%d/%d\n",
+						raw_dev->id, raw_dev_sub->id,
+						raw_dev_sub2->id);
+				}
+			}
+			break;
+		}
+
+	isp_composer_hw_config(cam, ctx, &config_param);
+	dev_dbg(dev, "raw %d %s done\n", raw_dev->id, __func__);
+
+	return 0;
+}
+
+static void mtk_cam_res_init(struct mtk_cam_resource_config *res_cfg)
+{
+	res_cfg->raw_num_used = 1;
+	res_cfg->bin_enable = 0;
+	res_cfg->raw_path = 0;
+	res_cfg->hwn_limit_min = 1;
+	res_cfg->raw_feature = 0;
+}
+
+static int mtk_cam_buf_config(struct mtk_cam_device *cam,
+			      struct mtkcam_ipi_frame_param *frame_param,
+			      struct mtk_cam_buffer *buf)
+{
+	struct vb2_buffer *vb;
+	struct mtk_cam_video_device *node;
+	int ret;
+
+	vb = &buf->vbb.vb2_buf;
+	node = mtk_cam_vbq_to_vdev(vb->vb2_queue);
+
+	/* update buffer format */
+	switch (node->desc.dma_port) {
+	case MTKCAM_ISP_IMGO:
+		mtk_cam_config_raw_path(cam, frame_param, buf);
+		mtk_cam_config_raw_img_out_imgo(cam, frame_param, buf);
+		ret = mtk_cam_config_raw_img_fmt(cam, frame_param, buf);
+		if (ret)
+			return ret;
+		break;
+	case MTKCAM_ISP_YUVO_1:
+	case MTKCAM_ISP_YUVO_2:
+	case MTKCAM_ISP_YUVO_3:
+	case MTKCAM_ISP_YUVO_4:
+	case MTKCAM_ISP_YUVO_5:
+	case MTKCAM_ISP_RZH1N2TO_1:
+	case MTKCAM_ISP_RZH1N2TO_2:
+	case MTKCAM_ISP_RZH1N2TO_3:
+	case MTKCAM_ISP_DRZS4NO_1:
+	case MTKCAM_ISP_DRZS4NO_2:
+	case MTKCAM_ISP_DRZS4NO_3:
+		mtk_cam_config_raw_img_out(cam, frame_param, buf);
+		break;
+	default:
+		/* Do nothing for the ports not related to crop settings */
+		break;
+	}
+
+	return 0;
+}
+
+void mtk_cam_buf_try_queue(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_device *cam;
+	struct mtk_cam_buffer *buf, *buf_prev;
+	struct mtkcam_ipi_event event;
+	struct mtkcam_ipi_session_cookie *session = &event.cookie;
+	struct mtkcam_ipi_frame_info *frame_info = &event.frame_data;
+	struct mtkcam_ipi_frame_param *frame_param;
+	struct mtkcam_ipi_frame_param *frame_data;
+	struct mtk_cam_working_buf_entry *buf_entry;
+	struct list_head equeue_list;
+	unsigned int processing_cnt, enque_cnt;
+
+	cam = ctx->cam;
+	if (!cam->streaming_ctx) {
+		dev_info(cam->dev, "streams are off\n");
+		return;
+	}
+
+	INIT_LIST_HEAD(&equeue_list);
+
+	spin_lock(&cam->dma_processing_lock);
+	processing_cnt = cam->dma_processing_count;
+	spin_unlock(&cam->dma_processing_lock);
+
+	enque_cnt = 0;
+	spin_lock(&cam->dma_pending_lock);
+	list_for_each_entry_safe(buf, buf_prev, &cam->dma_pending, list) {
+		if (processing_cnt + enque_cnt >= MTK_CAM_MAX_PROCESSING_BUFS) {
+			dev_dbg(cam->dev,
+				"processing bufs are full, buf cnt(%d)\n",
+				processing_cnt);
+			break;
+		}
+		dev_dbg(cam->dev, "%s buf cnt(%d)\n",
+			__func__, processing_cnt + enque_cnt);
+
+		enque_cnt++;
+		list_del(&buf->list);
+		list_add_tail(&buf->list, &equeue_list);
+	}
+	spin_unlock(&cam->dma_pending_lock);
+
+	if (!enque_cnt)
+		return;
+
+	frame_param = kzalloc(sizeof(*frame_param), GFP_KERNEL);
+	if (!frame_param)
+		return;
+
+	list_for_each_entry_safe(buf, buf_prev, &equeue_list, list) {
+		memset(&event, 0, sizeof(event));
+		event.cmd_id = CAM_CMD_FRAME;
+		session->session_id = ctx->stream_id;
+		/* prepare working buffer */
+		buf_entry = mtk_cam_working_buf_get(ctx);
+		if (!buf_entry) {
+			dev_info(cam->dev,
+				 "%s: No CQ buf availablle: enqueued_frame_seq_no:%d\n",
+				 __func__, atomic_read(&ctx->enqueued_frame_seq_no));
+			WARN_ON(1);
+			goto EXIT;
+		}
+
+		spin_lock(&ctx->using_buffer_list.lock);
+		list_add_tail(&buf_entry->list_entry, &ctx->using_buffer_list.list);
+		ctx->using_buffer_list.cnt++;
+		spin_unlock(&ctx->using_buffer_list.lock);
+
+		spin_lock(&cam->dma_processing_lock);
+		list_del(&buf->list);
+		list_add_tail(&buf->list, &cam->dma_processing);
+		cam->dma_processing_count++;
+		spin_unlock(&cam->dma_processing_lock);
+		/* Prepare rp message */
+		frame_info->cur_msgbuf_offset =
+			buf_entry->msg_buffer.va -
+			cam->ctxs[session->session_id].buf_pool.msg_buf_va;
+		frame_info->cur_msgbuf_size = buf_entry->msg_buffer.size;
+		frame_data = (struct mtkcam_ipi_frame_param *)buf_entry->msg_buffer.va;
+		session->frame_no = atomic_inc_return(&ctx->enqueued_frame_seq_no);
+
+		if (mtk_cam_buf_config(cam, frame_param, buf)) {
+			dev_err(cam->dev, "%s: Buffer config failed\n",	__func__);
+			continue;
+		}
+		memcpy(frame_data, frame_param, sizeof(*frame_param));
+		frame_data->cur_workbuf_offset =
+			buf_entry->buffer.iova -
+			cam->ctxs[session->session_id].buf_pool.working_buf_iova;
+		frame_data->cur_workbuf_size = buf_entry->buffer.size;
+
+		if (ctx->pipe->res_config.bin_limit == BIN_AUTO)
+			frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_enable;
+		else
+			frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_limit;
+
+		scp_ipi_send(cam->scp, SCP_IPI_ISP_FRAME, &event,
+			     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
+		buf->state.estate = E_BUF_STATE_COMPOSED;
+	}
+EXIT:
+	kfree(frame_param);
+}
+
+static void isp_tx_frame_worker(struct work_struct *work)
+{
+	struct mtk_cam_req_work *req_work = (struct mtk_cam_req_work *)work;
+	struct mtkcam_ipi_event event;
+	struct mtkcam_ipi_session_cookie *session = &event.cookie;
+	struct mtkcam_ipi_frame_info *frame_info = &event.frame_data;
+	struct mtkcam_ipi_frame_param *frame_data;
+	struct mtk_cam_request *req;
+	struct mtk_cam_request_stream_data *req_stream_data;
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_device *cam;
+	struct mtk_cam_working_buf_entry *buf_entry;
+	struct mtk_cam_resource *res_user;
+	struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data;
+
+	req_stream_data = mtk_cam_req_work_get_s_data(req_work);
+	if (!req_stream_data) {
+		pr_info("%s mtk_cam_req_work(%p), req_stream_data(%p), dropped\n",
+			__func__, req_work, req_stream_data);
+		return;
+	}
+	req = mtk_cam_s_data_get_req(req_stream_data);
+	if (!req) {
+		pr_info("%s req_stream_data(%p), req(%p), dropped\n",
+			__func__, req_stream_data, req);
+		return;
+	}
+	ctx = mtk_cam_s_data_get_ctx(req_stream_data);
+	if (!ctx) {
+		pr_info("%s req_stream_data(%p), ctx(%p), dropped\n",
+			__func__, req_stream_data, ctx);
+		return;
+	}
+
+	cam = ctx->cam;
+	if (ctx->used_raw_num == 0) {
+		dev_dbg(cam->dev, "raw is un-used, skip frame work");
+		return;
+	}
+	/* check if the ctx is streaming */
+	spin_lock(&ctx->streaming_lock);
+	if (!ctx->streaming) {
+		dev_info(cam->dev,
+			 "%s: skip frame work, for stream off ctx:%d, req:%d\n",
+			 __func__, ctx->stream_id, req_stream_data->frame_seq_no);
+		spin_unlock(&ctx->streaming_lock);
+		return;
+	}
+	spin_unlock(&ctx->streaming_lock);
+
+	s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(req_stream_data);
+
+	/* Send CAM_CMD_CONFIG if the sink pad fmt is changed */
+	if (req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE)
+		mtk_cam_s_data_dev_config(req_stream_data);
+
+	if (!s_raw_pipe_data) {
+		dev_info(cam->dev, "error: %s: s_raw_pipe_data = NULL\n", __func__);
+		return;
+	}
+
+	memset(&event, 0, sizeof(event));
+	event.cmd_id = CAM_CMD_FRAME;
+	session->session_id = ctx->stream_id;
+	/* prepare working buffer */
+	buf_entry = mtk_cam_working_buf_get(ctx);
+	if (!buf_entry) {
+		dev_info(cam->dev, "%s: No CQ buf availablle: req:%d(%s)\n",
+			 __func__, req_stream_data->frame_seq_no,
+			 req->req.debug_str);
+		WARN_ON(1);
+		return;
+	}
+	mtk_cam_s_data_set_wbuf(req_stream_data, buf_entry);
+	/* put to using list */
+	spin_lock(&ctx->using_buffer_list.lock);
+	list_add_tail(&buf_entry->list_entry, &ctx->using_buffer_list.list);
+	ctx->using_buffer_list.cnt++;
+	spin_unlock(&ctx->using_buffer_list.lock);
+
+	/* Prepare rp message */
+	frame_info->cur_msgbuf_offset =
+		buf_entry->msg_buffer.va -
+		cam->ctxs[session->session_id].buf_pool.msg_buf_va;
+	frame_info->cur_msgbuf_size = buf_entry->msg_buffer.size;
+	frame_data = (struct mtkcam_ipi_frame_param *)buf_entry->msg_buffer.va;
+	session->frame_no = req_stream_data->frame_seq_no;
+
+	memcpy(frame_data, &req_stream_data->frame_params,
+	       sizeof(req_stream_data->frame_params));
+	frame_data->cur_workbuf_offset =
+		buf_entry->buffer.iova -
+		cam->ctxs[session->session_id].buf_pool.working_buf_iova;
+	frame_data->cur_workbuf_size = buf_entry->buffer.size;
+
+	res_user = mtk_cam_s_data_get_res(req_stream_data);
+	if (res_user && res_user->raw_res.bin) {
+		frame_data->raw_param.bin_flag = res_user->raw_res.bin;
+	} else {
+		if (ctx->pipe->res_config.bin_limit == BIN_AUTO)
+			frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_enable;
+		else
+			frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_limit;
+	}
+
+	scp_ipi_send(cam->scp, SCP_IPI_ISP_FRAME, &event,
+		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
+	dev_dbg(cam->dev,
+		"%s: IPI send id: %d, ctx:%d, seq:%d, bin:(0x%x)\n",
+		req->req.debug_str, event.cmd_id, session->session_id,
+		req_stream_data->frame_seq_no,
+		frame_data->raw_param.bin_flag);
+}
+
+static void mtk_cam_dev_summit_sensor_work(struct mtk_cam_ctx *ctx,
+					   struct mtk_camsys_sensor_ctrl *sensor_ctrl)
+{
+	unsigned int drained_seq_no = 0;
+
+	if (ctx->pipe->feature_active == 0 && ctx->dequeued_frame_seq_no > 3) {
+		drained_seq_no = atomic_read(&sensor_ctrl->last_drained_seq_no);
+		if (atomic_read(&sensor_ctrl->sensor_enq_seq_no) == drained_seq_no)
+			mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq,
+							   sensor_ctrl);
+	}
+}
+
+void mtk_cam_dev_req_enqueue(struct mtk_cam_device *cam,
+			     struct mtk_cam_request *req)
+{
+	unsigned int i, j;
+
+	for (i = 0; i < cam->max_stream_num; i++) {
+		if (req->pipe_used & (1 << i))  {
+			unsigned int stream_id = i;
+			struct mtk_cam_req_work *frame_work, *done_work;
+			struct mtk_cam_request_stream_data *req_stream_data;
+			struct mtk_cam_request_stream_data *pipe_stream_data;
+			struct mtk_cam_ctx *ctx = &cam->ctxs[stream_id];
+			struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
+			unsigned int initial_frame = 0;
+
+			if (!ctx->streaming)
+				continue;
+			atomic_set(&ctx->sensor_ctrl.sensor_enq_seq_no,
+				   atomic_read(&ctx->enqueued_frame_seq_no));
+			/*sensor setting after request drained check*/
+			if (ctx->used_raw_num) {
+			if (ctx->used_raw_num)
+				mtk_cam_dev_summit_sensor_work(ctx, sensor_ctrl);
+			req_stream_data = mtk_cam_req_get_s_data(req, stream_id, 0);
+
+			if (req_stream_data->frame_seq_no == 1)
+				initial_frame = 1;
+			frame_work = &req_stream_data->frame_work;
+			mtk_cam_req_work_init(frame_work, req_stream_data);
+
+			for (j = 0 ; j < MTKCAM_SUBDEV_MAX ; j++) {
+				if ((1 << j & ctx->streaming_pipe) &&
+				    (1 << j & req->pipe_used)) {
+					pipe_stream_data = mtk_cam_req_get_s_data(req, j, 0);
+					done_work = &pipe_stream_data->frame_done_work;
+					INIT_WORK(&done_work->work, mtk_cam_frame_done_work);
+
+					done_work = &pipe_stream_data->meta1_done_work;
+					atomic_set(&done_work->is_queued, 0);
+					INIT_WORK(&done_work->work, mtk_cam_meta1_done_work);
+				}
+			}
+
+			if (ctx->sensor && initial_frame)
+				mtk_cam_initial_sensor_setup(req, ctx);
+
+			if (ctx->used_raw_num != 0) {
+				if (ctx->sensor &&
+				    ctx->pipe->feature_active == 0 &&
+				    req_stream_data->frame_seq_no == 2)
+					mtk_cam_initial_sensor_setup(req, ctx);
+			} else {
+				if (ctx->sensor &&
+				    req_stream_data->frame_seq_no == 2)
+					mtk_cam_initial_sensor_setup(req, ctx);
+			}
+
+			/* Prepare CQ compose work */
+			INIT_WORK(&frame_work->work, isp_tx_frame_worker);
+			queue_work(ctx->composer_wq, &frame_work->work);
+
+			dev_dbg(cam->dev,
+				"%s:ctx:%d:req:%d(%s) enqueue ctx_used:0x%x,streaming_ctx:0x%x,job cnt:%d, running(%d)\n",
+				__func__, stream_id, req_stream_data->frame_seq_no,
+				req->req.debug_str, req->ctx_used,
+				cam->streaming_ctx, cam->running_job_count,
+				atomic_read(&ctx->running_s_data_cnt));
+		}
+	}
+}
+
+struct mtk_raw_pipeline*
+mtk_cam_dev_get_raw_pipeline(struct mtk_cam_device *cam, unsigned int pipe_id)
+{
+	if (pipe_id < MTKCAM_SUBDEV_RAW_START ||
+	    pipe_id >= MTKCAM_SUBDEV_RAW_START + cam->num_raw_devices)
+		return NULL;
+	else
+		return &cam->raw.pipelines[pipe_id - MTKCAM_SUBDEV_RAW_0];
+}
+
+static int
+mtk_cam_raw_pipeline_config(struct mtk_cam_ctx *ctx,
+			    struct mtkcam_ipi_input_param *cfg_in_param)
+{
+	struct mtk_raw_pipeline *pipe = ctx->pipe;
+	struct mtk_raw *raw = pipe->raw;
+	int ret, i;
+
+	/* reset pm_runtime during streaming dynamic change */
+	if (ctx->streaming) {
+		for (i = 0; i < ARRAY_SIZE(raw->devs); i++) {
+			if (pipe->enabled_raw & 1 << i) {
+				dev_info(raw->cam_dev,
+					 "%s: power off raw (%d) for reset\n",
+					 __func__, i);
+				pm_runtime_put_sync(raw->devs[i]);
+			}
+		}
+	}
+
+	ret = mtk_cam_raw_select(ctx, cfg_in_param);
+	if (ret) {
+		dev_info(raw->cam_dev, "failed select raw: %d\n",
+			 ctx->stream_id);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(raw->devs); i++) {
+		if (pipe->enabled_raw & 1 << i) {
+			dev_info(raw->cam_dev, "%s: power on raw (%d)\n",
+				 __func__, i);
+			ret = pm_runtime_get_sync(raw->devs[i]);
+
+			if (ret < 0) {
+				dev_info(raw->cam_dev,
+					 "failed at pm_runtime_get_sync: %s\n",
+					 dev_driver_string(raw->devs[i]));
+
+				/* put devices already get */
+				for (; i >= 0; i--) {
+					pm_runtime_put_sync(raw->devs[i]);
+					dev_info(raw->cam_dev,
+						 "%s: power off raw (%d)\n",
+						 __func__, i);
+				}
+
+				return ret;
+			}
+		}
+	}
+
+	ctx->used_raw_dev = pipe->enabled_raw;
+	dev_info(raw->cam_dev, "ctx_id %d used_raw_dev 0x%x pipe_id %d\n",
+		 ctx->stream_id, ctx->used_raw_dev, pipe->id);
+	return 0;
+}
+
+void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data)
+{
+	struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data;
+	struct mtk_cam_ctx *ctx;
+	char *debug_str = mtk_cam_s_data_get_dbg_str(s_data);
+
+	s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data);
+	if (!s_raw_pipe_data)
+		return;
+
+	ctx = mtk_cam_s_data_get_ctx(s_data);
+	if (!ctx)
+		return;
+	ctx->pipe->feature_active = ctx->pipe->user_res.raw_res.feature;
+	ctx->pipe->enabled_raw = s_raw_pipe_data->enabled_raw;
+	ctx->used_raw_dev = s_raw_pipe_data->enabled_raw;
+
+	dev_info(ctx->cam->dev,
+		 "%s:%s:pipe(%d):seq(%d):feature_active(0x%llx), ctx->pipe->user_res.raw_res.feature(%lld), enabled_raw(0x%x)\n",
+		 __func__, debug_str, ctx->stream_id, s_data->frame_seq_no,
+		 ctx->pipe->feature_active,
+		 ctx->pipe->user_res.raw_res.feature,
+		 ctx->pipe->enabled_raw);
+}
+
+static int mtk_cam_dev_config(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct device *dev = cam->dev;
+	struct mtkcam_ipi_config_param config_param;
+	struct mtkcam_ipi_input_param *cfg_in_param;
+	struct mtk_raw_pipeline *pipe = ctx->pipe;
+	struct mtk_raw *raw = pipe->raw;
+	struct v4l2_mbus_framefmt *mf = &pipe->cfg[MTK_RAW_SINK].mbus_fmt;
+	struct device *dev_raw;
+	struct mtk_raw_device *raw_dev;
+	unsigned int i;
+	int ret;
+	u32 mf_code;
+
+	/**
+	 * If don't want to get the first req's raw_feature (not the max exp. num),
+	 * you can use read ctx->pipe->feature_pending here.
+	 */
+
+	memset(&config_param, 0, sizeof(config_param));
+
+	/* Update cfg_in_param */
+	cfg_in_param = &config_param.input;
+	cfg_in_param->pixel_mode = ctx->pipe->res_config.tgo_pxl_mode;
+
+	cfg_in_param->data_pattern = MTKCAM_IPI_SENSOR_PATTERN_NORMAL;
+	cfg_in_param->in_crop.s.w = mf->width;
+	cfg_in_param->in_crop.s.h = mf->height;
+
+	dev_dbg(dev, "sink pad code:0x%x, tg size:%d %d\n", mf->code,
+		cfg_in_param->in_crop.s.w, cfg_in_param->in_crop.s.h);
+
+
+	mf_code = mf->code & 0xffff; /* sensor mode */
+	cfg_in_param->raw_pixel_id = mtk_cam_get_sensor_pixel_id(mf_code);
+	cfg_in_param->fmt = mtk_cam_get_sensor_fmt(mf_code);
+	if (cfg_in_param->fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN ||
+	    cfg_in_param->raw_pixel_id == MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN) {
+		dev_err(dev, "unknown sd code:%d\n", mf_code);
+		return -EINVAL;
+	}
+
+	config_param.flags = MTK_CAM_IPI_CONFIG_TYPE_INIT;
+	ret = mtk_cam_raw_pipeline_config(ctx, cfg_in_param);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "%s: config_param flag:0x%x enabled_raw:0x%x\n",
+		__func__, config_param.flags, ctx->pipe->enabled_raw);
+
+	update_hw_mapping(ctx, &config_param);
+	config_param.sw_feature = MTKCAM_IPI_SW_FEATURE_NORMAL;
+
+	dev_raw = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev);
+	if (!dev_raw) {
+		dev_err(dev, "config raw device not found\n");
+		return -EINVAL;
+	}
+	raw_dev = dev_get_drvdata(dev_raw);
+	for (i = 0; i < RAW_PIPELINE_NUM; i++)
+		if (raw->pipelines[i].enabled_raw & 1 << raw_dev->id) {
+			raw_dev->pipeline = &raw->pipelines[i];
+			if (raw->pipelines[i].res_config.raw_num_used == 0)
+				mtk_cam_res_init(&raw->pipelines[i].res_config);
+			break;
+		}
+
+	mtk_cam_raw_reset(raw_dev);
+	isp_composer_hw_config(cam, ctx, &config_param);
+	dev_dbg(dev, "raw %d %s done\n", raw_dev->id, __func__);
+
+	return 0;
+}
+
+static void mtk_cam_ctx_watchdog_worker(struct work_struct *work)
+{
+	struct mtk_cam_ctx *ctx;
+	struct mtk_raw_device *raw;
+	// struct v4l2_subdev *seninf;
+	static u64 last_vsync_count;
+
+	ctx = container_of(work, struct mtk_cam_ctx, watchdog_work);
+
+	/* dump cam-raw */
+	raw = get_main_raw_dev(ctx->cam, ctx->pipe);
+	if (!raw)
+		goto EXIT;
+	dev_info(ctx->cam->dev,
+		 "%s:ctx(%d):[timeout] VF(%d) vsync count(%lld) sof count(%lld) timeout_tg(%d)(>%dms)\n",
+		 __func__, ctx->stream_id, atomic_read(&raw->vf_en),
+		 raw->vsync_count, raw->sof_count, ctx->watchdog_timeout_tg,
+		 ctx->watchdog_timeout_tg * MTK_CAM_CTX_WATCHDOG_INTERVAL);
+
+	if (last_vsync_count == raw->vsync_count)
+		dev_err(ctx->cam->dev, "%s:cam-raw abnormal vsync\n", __func__);
+	last_vsync_count = raw->vsync_count;
+
+EXIT:
+	atomic_inc(&ctx->watchdog_dump);
+}
+
+#define WDT_DUMP_CNT 4
+
+static void mtk_ctx_watchdog_callback(struct timer_list *t)
+{
+	struct mtk_cam_ctx *ctx = timer_container_of(ctx, t, watchdog_timer);
+
+	/* disable if not streaming */
+	if (!ctx->streaming)
+		return;
+
+	if (atomic_read(&ctx->watchdog_dump) < WDT_DUMP_CNT)
+		schedule_work(&ctx->watchdog_work);
+
+	dev_info_ratelimited(ctx->cam->dev,
+			     "%s:ctx(%d):[TIMEOUT] no_sync_tg:%d(>%dms)\n",
+			     __func__, ctx->stream_id, ctx->watchdog_timeout_tg,
+			     jiffies_to_msecs(jiffies -
+					atomic_long_read(&ctx->watchdog_prev)));
+
+	/* update timer */
+	mod_timer(&ctx->watchdog_timer,
+		  jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL));
+}
+
+void mtk_ctx_watchdog_kick(struct mtk_cam_ctx *ctx)
+{
+	dev_dbg(ctx->cam->dev, "%s:ctx(%d)\n", __func__, ctx->stream_id);
+	atomic_set(&ctx->watchdog_dump, 0);
+
+	/* delay timer */
+	mod_timer(&ctx->watchdog_timer,
+		  jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL *
+					     ctx->watchdog_timeout_tg));
+	atomic_long_set(&ctx->watchdog_prev, jiffies);
+}
+
+static void mtk_ctx_watchdog_init(struct mtk_cam_ctx *ctx)
+{
+	INIT_WORK(&ctx->watchdog_work, mtk_cam_ctx_watchdog_worker);
+	timer_setup(&ctx->watchdog_timer, mtk_ctx_watchdog_callback, 0);
+}
+
+static void mtk_ctx_watchdog_start(struct mtk_cam_ctx *ctx, int timeout_tg)
+{
+	dev_info(ctx->cam->dev,
+		 "%s:ctx(%d):start the watchdog, timeout setting(%dms)\n",
+		 __func__, ctx->stream_id,
+		 MTK_CAM_CTX_WATCHDOG_INTERVAL * timeout_tg);
+
+	ctx->watchdog_timeout_tg = timeout_tg;
+	atomic_set(&ctx->watchdog_dump, 0);
+
+	mod_timer(&ctx->watchdog_timer,
+		  jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL *
+					     ctx->watchdog_timeout_tg));
+	atomic_long_set(&ctx->watchdog_prev, jiffies);
+}
+
+static void mtk_ctx_watchdog_stop(struct mtk_cam_ctx *ctx)
+{
+	dev_info(ctx->cam->dev, "%s:ctx(%d):stop the watchdog\n",
+		 __func__, ctx->stream_id);
+	del_timer_sync(&ctx->watchdog_timer);
+}
+
+static int __maybe_unused mtk_cam_runtime_suspend(struct device *dev)
+{
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+
+	struct mtk_cam_ctx *ctx = cam_dev->ctxs;
+
+	mtk_ctx_watchdog_stop(ctx);
+
+	return 0;
+}
+
+static int __maybe_unused mtk_cam_runtime_resume(struct device *dev)
+{
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+
+	struct mtk_cam_ctx *ctx = cam_dev->ctxs;
+
+	mtk_ctx_watchdog_start(ctx, 4);
+
+	return 0;
+}
+
+struct mtk_cam_ctx *mtk_cam_find_ctx(struct mtk_cam_device *cam,
+				     struct media_entity *entity)
+{
+	unsigned int i;
+
+	for (i = 0;  i < cam->max_stream_num; i++) {
+		if (media_entity_pipeline(entity) == &cam->ctxs[i].pipeline)
+			return &cam->ctxs[i];
+	}
+
+	return NULL;
+}
+
+struct mtk_cam_ctx *mtk_cam_start_ctx(struct mtk_cam_device *cam,
+				      struct mtk_cam_video_device *node)
+{
+	struct mtk_cam_ctx *ctx = node->ctx;
+	struct device *dev;
+	struct v4l2_subdev **target_sd;
+	int ret, i, is_first_ctx;
+	struct media_entity *entity = &node->vdev.entity;
+	struct media_graph graph;
+
+	dev_info(cam->dev, "%s:ctx(%d): triggered by %s\n",
+		 __func__, ctx->stream_id, entity->name);
+
+	atomic_set(&ctx->enqueued_frame_seq_no, 0);
+	ctx->composed_frame_seq_no = 0;
+	ctx->dequeued_frame_seq_no = 0;
+	atomic_set(&ctx->running_s_data_cnt, 0);
+	init_completion(&ctx->session_complete);
+
+	is_first_ctx = !cam->composer_cnt;
+	if (is_first_ctx) {
+		spin_lock(&cam->dma_processing_lock);
+		cam->dma_processing_count = 0;
+		spin_unlock(&cam->dma_processing_lock);
+		spin_lock(&cam->running_job_lock);
+		cam->running_job_count = 0;
+		spin_unlock(&cam->running_job_lock);
+
+		dev_info(cam->dev, "%s: power on camsys\n", __func__);
+		ret = pm_runtime_resume_and_get(cam->dev);
+		if (ret < 0) {
+			dev_info(cam->dev, "%s: power on camsys failed\n",
+				 __func__);
+			return NULL;
+		}
+
+		ret = isp_composer_init(cam);
+		if (ret)
+			goto fail_shutdown;
+	}
+	cam->composer_cnt++;
+	if (is_yuv_node(node->desc.id))
+		dev = cam->raw.yuvs[0];
+	else
+		dev = cam->raw.devs[0];
+
+	ret = mtk_cam_working_buf_pool_init(ctx, dev);
+	if (ret) {
+		dev_info(cam->dev, "failed to reserve DMA memory:%d\n", ret);
+		goto fail_uninit_composer;
+	}
+
+	kthread_init_worker(&ctx->sensor_worker);
+	ctx->sensor_worker_task = kthread_run(kthread_worker_fn,
+					      &ctx->sensor_worker,
+					      "sensor_worker-%d",
+					      ctx->stream_id);
+	if (IS_ERR(ctx->sensor_worker_task)) {
+		dev_info(cam->dev,
+			 "%s:ctx(%d): could not create sensor_worker_task\n",
+			 __func__, ctx->stream_id);
+		goto fail_release_buffer_pool;
+	}
+
+	sched_set_fifo(ctx->sensor_worker_task);
+
+	ctx->composer_wq = alloc_ordered_workqueue(dev_name(cam->dev),
+						   WQ_HIGHPRI | WQ_FREEZABLE);
+	if (!ctx->composer_wq) {
+		dev_info(cam->dev, "failed to alloc composer workqueue\n");
+		goto fail_uninit_sensor_worker_task;
+	}
+
+	ctx->frame_done_wq = alloc_ordered_workqueue(dev_name(cam->dev),
+						     WQ_HIGHPRI | WQ_FREEZABLE);
+	if (!ctx->frame_done_wq) {
+		dev_info(cam->dev, "failed to alloc frame_done workqueue\n");
+		goto fail_uninit_composer_wq;
+	}
+
+	ret = media_pipeline_start(&entity->pads[0], &ctx->pipeline);
+	if (ret) {
+		dev_warn(cam->dev,
+			 "%s:pipe(%d):failed in media_pipeline_start:%d\n",
+			 __func__, node->uid.pipe_id, ret);
+		goto fail_uninit_frame_done_wq;
+	}
+
+	/* traverse to update used subdevs & number of nodes */
+	i = 0;
+	ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
+	if (ret)
+		goto fail_stop_pipeline;
+
+	media_graph_walk_start(&graph, entity);
+	while ((entity = media_graph_walk_next(&graph))) {
+		dev_dbg(cam->dev, "linked entity %s\n", entity->name);
+
+		target_sd = NULL;
+
+		switch (entity->function) {
+		case MEDIA_ENT_F_IO_V4L:
+			ctx->enabled_node_cnt++;
+			break;
+		case MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER: /* pipeline */
+			if (i >= MAX_PIPES_PER_STREAM)
+				goto fail_stop_pipeline;
+			target_sd = ctx->pipe_subdevs + i;
+			i++;
+			break;
+		case MEDIA_ENT_F_VID_IF_BRIDGE: /* seninf */
+			target_sd = &ctx->seninf;
+			break;
+		case MEDIA_ENT_F_CAM_SENSOR:
+			target_sd = &ctx->sensor;
+			break;
+		default:
+			break;
+		}
+
+		if (!target_sd)
+			continue;
+
+		if (*target_sd) {
+			dev_info(cam->dev, "duplicated subdevs!!!\n");
+			goto fail_traverse_subdev;
+		}
+
+		if (is_media_entity_v4l2_subdev(entity))
+			*target_sd = media_entity_to_v4l2_subdev(entity);
+	}
+	media_graph_walk_cleanup(&graph);
+
+	return ctx;
+
+fail_traverse_subdev:
+	media_graph_walk_cleanup(&graph);
+fail_stop_pipeline:
+	media_pipeline_stop(&entity->pads[0]);
+fail_uninit_frame_done_wq:
+	destroy_workqueue(ctx->frame_done_wq);
+fail_uninit_composer_wq:
+	destroy_workqueue(ctx->composer_wq);
+fail_uninit_sensor_worker_task:
+	kthread_stop(ctx->sensor_worker_task);
+	ctx->sensor_worker_task = NULL;
+fail_release_buffer_pool:
+	mtk_cam_working_buf_pool_release(ctx, dev);
+fail_uninit_composer:
+	isp_composer_uninit(cam);
+	cam->composer_cnt--;
+fail_shutdown:
+	if (is_first_ctx)
+		rproc_shutdown(cam->rproc_handle);
+
+	return NULL;
+}
+
+void mtk_cam_stop_ctx(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct media_entity *entity = &node->vdev.entity;
+	struct device *dev;
+	unsigned int i;
+
+	if (is_yuv_node(node->desc.id))
+		dev = cam->raw.yuvs[0];
+	else
+		dev = cam->raw.devs[0];
+
+	dev_info(cam->dev, "%s:ctx(%d): triggered by %s\n",
+		 __func__, ctx->stream_id, entity->name);
+
+	media_pipeline_stop(&entity->pads[0]);
+
+	if (ctx->session_created) {
+		dev_dbg(cam->dev,
+			"%s:ctx(%d): session_created, wait for composer session destroy\n",
+			__func__, ctx->stream_id);
+		if (wait_for_completion_timeout(&ctx->session_complete,
+						msecs_to_jiffies(300)) == 0)
+			dev_info(cam->dev, "%s:ctx(%d): complete timeout\n",
+				 __func__, ctx->stream_id);
+	}
+
+	if (!cam->streaming_ctx) {
+		struct v4l2_subdev *sd;
+
+		v4l2_device_for_each_subdev(sd, &cam->v4l2_dev) {
+			if (sd->entity.function == MEDIA_ENT_F_VID_IF_BRIDGE) {
+				int ret;
+
+				ret = v4l2_subdev_call(sd, video, s_stream, 0);
+				if (ret)
+					dev_err(cam->dev,
+						"failed to streamoff %s:%d\n",
+						sd->name, ret);
+			}
+		}
+	}
+
+	drain_workqueue(ctx->composer_wq);
+	destroy_workqueue(ctx->composer_wq);
+	ctx->composer_wq = NULL;
+	drain_workqueue(ctx->frame_done_wq);
+	destroy_workqueue(ctx->frame_done_wq);
+	ctx->frame_done_wq = NULL;
+	kthread_flush_worker(&ctx->sensor_worker);
+	kthread_stop(ctx->sensor_worker_task);
+	ctx->sensor_worker_task = NULL;
+	ctx->session_created = 0;
+	ctx->enabled_node_cnt = 0;
+	ctx->streaming_node_cnt = 0;
+	ctx->streaming_pipe = 0;
+	ctx->sensor = NULL;
+	ctx->seninf = NULL;
+	atomic_set(&ctx->enqueued_frame_seq_no, 0);
+	ctx->composed_frame_seq_no = 0;
+	ctx->is_first_cq_done = 0;
+	ctx->cq_done_status = 0;
+	ctx->used_raw_num = 0;
+
+	INIT_LIST_HEAD(&ctx->using_buffer_list.list);
+	INIT_LIST_HEAD(&ctx->composed_buffer_list.list);
+	INIT_LIST_HEAD(&ctx->processing_buffer_list.list);
+
+	INIT_LIST_HEAD(&ctx->processing_img_buffer_list.list);
+	for (i = 0; i < MAX_PIPES_PER_STREAM; i++)
+		ctx->pipe_subdevs[i] = NULL;
+
+	isp_composer_uninit(cam);
+		cam->composer_cnt--;
+
+	dev_info(cam->dev, "%s: ctx-%d:  composer_cnt:%d\n",
+		 __func__, ctx->stream_id, cam->composer_cnt);
+
+	mtk_cam_working_buf_pool_release(ctx, dev);
+
+	if (ctx->cam->rproc_handle && !ctx->cam->composer_cnt) {
+		dev_info(cam->dev, "%s power off camsys\n", __func__);
+		pm_runtime_put_sync(cam->dev);
+		rproc_shutdown(cam->rproc_handle);
+	}
+}
+
+static int pipeid_to_tgidx(int pipe_id)
+{
+	switch (pipe_id) {
+	case MTKCAM_SUBDEV_RAW_0:
+		return 0;
+	case MTKCAM_SUBDEV_RAW_1:
+		return 1;
+	case MTKCAM_SUBDEV_RAW_2:
+		return 2;
+	default:
+		break;
+	}
+	return -1;
+}
+
+int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx,
+				      struct v4l2_subdev *sd,
+				      int pad_id, int pixel_mode)
+{
+	int ret;
+
+	ret = mtk_cam_seninf_set_pixelmode(sd, pad_id, pixel_mode);
+	dev_dbg(ctx->cam->dev,
+		"%s:ctx(%d): seninf(%s): pad(%d), pixel_mode(%d)\n, ret(%d)",
+		__func__, ctx->stream_id, sd->name, pad_id, pixel_mode,
+		ret);
+
+	return ret;
+}
+
+int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct device *dev;
+	struct mtk_raw_device *raw_dev;
+	int i, ret;
+	int tgo_pxl_mode;
+	unsigned int streaming_ctx_latch;
+
+	dev_dbg(cam->dev, "ctx %d stream on, streaming_pipe:0x%x\n",
+		ctx->stream_id, ctx->streaming_pipe);
+
+	if (ctx->streaming) {
+		dev_dbg(cam->dev, "ctx-%d is already streaming on\n", ctx->stream_id);
+		return 0;
+	}
+
+	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) {
+		ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 1);
+		if (ret) {
+			dev_info(cam->dev, "failed to stream on %s: %d\n",
+				 ctx->pipe_subdevs[i]->name, ret);
+			goto fail_pipe_off;
+		}
+	}
+
+	if (ctx->used_raw_num) {
+		tgo_pxl_mode = ctx->pipe->res_config.tgo_pxl_mode;
+
+		ret = mtk_cam_dev_config(ctx);
+		if (ret)
+			goto fail_pipe_off;
+		dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev);
+		if (!dev) {
+			dev_info(cam->dev, "streamon raw device not found\n");
+			goto fail_pipe_off;
+		}
+		raw_dev = dev_get_drvdata(dev);
+
+		mtk_cam_call_seninf_set_pixelmode(ctx, ctx->seninf,
+							PAD_SRC_RAW0,
+							tgo_pxl_mode);
+		mtk_cam_seninf_set_camtg(ctx->seninf, PAD_SRC_RAW0,
+						pipeid_to_tgidx(raw_dev->id));
+	}
+
+
+	ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 1);
+	if (ret) {
+		dev_info(cam->dev, "failed to stream on seninf %s:%d\n",
+				ctx->seninf->name, ret);
+		goto fail_pipe_off;
+	}
+
+	if (ctx->used_raw_num) {
+		mtk_cam_raw_initialize(raw_dev, 0);
+		/* Twin */
+		if (ctx->pipe->res_config.raw_num_used != 1) {
+			struct mtk_raw_device *raw_dev_sub =
+			get_sub_raw_dev(cam, ctx->pipe);
+			mtk_cam_raw_initialize(raw_dev_sub, 1);
+			if (ctx->pipe->res_config.raw_num_used == 3) {
+				struct mtk_raw_device *raw_dev_sub2 =
+					get_sub2_raw_dev(cam, ctx->pipe);
+				mtk_cam_raw_initialize(raw_dev_sub2, 1);
+			}
+		}
+	}
+
+	spin_lock(&ctx->streaming_lock);
+
+	streaming_ctx_latch = cam->streaming_ctx;
+	ctx->streaming = true;
+	cam->streaming_ctx |= 1 << ctx->stream_id;
+	spin_unlock(&ctx->streaming_lock);
+
+	ret = mtk_camsys_ctrl_start(ctx);
+	if (ret)
+		goto fail_streaming_off;
+
+	mutex_lock(&cam->queue_lock);
+	mtk_cam_dev_req_try_queue(cam);  /* request moved into working list */
+	mutex_unlock(&cam->queue_lock);
+	if (watchdog_scenario(ctx))
+		mtk_ctx_watchdog_start(ctx, 4);
+
+	dev_dbg(cam->dev, "streamed on camsys ctx:%d\n", ctx->stream_id);
+
+	return 0;
+
+fail_streaming_off:
+	spin_lock(&ctx->streaming_lock);
+	ctx->streaming = false;
+	cam->streaming_ctx &= ~(1 << ctx->stream_id);
+	spin_unlock(&ctx->streaming_lock);
+	v4l2_subdev_call(ctx->seninf, video, s_stream, 0);
+fail_pipe_off:
+	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++)
+		v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0);
+
+	return ret;
+}
+
+int mtk_cam_ctx_stream_off(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+	struct device *dev;
+	struct mtk_raw_device *raw_dev;
+	unsigned int i;
+	int ret;
+
+	if (!ctx->streaming) {
+		dev_dbg(cam->dev, "ctx-%d is already streaming off\n",
+			ctx->stream_id);
+		return 0;
+	}
+
+	if (watchdog_scenario(ctx))
+		mtk_ctx_watchdog_stop(ctx);
+
+	dev_info(cam->dev, "%s: ctx-%d:  composer_cnt:%d, streaming_pipe:0x%x\n",
+		 __func__, ctx->stream_id, cam->composer_cnt, ctx->streaming_pipe);
+
+	spin_lock(&ctx->streaming_lock);
+	ctx->streaming = false;
+	cam->streaming_ctx &= ~(1 << ctx->stream_id);
+	spin_unlock(&ctx->streaming_lock);
+
+	if (ctx->synced)
+		ctx->synced = 0;
+
+	ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 0);
+	if (ret) {
+		dev_err(cam->dev, "failed to stream off %s:%d\n",
+			ctx->seninf->name, ret);
+		return -EPERM;
+	}
+
+	if (ctx->used_raw_num) {
+		dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev);
+		if (!dev) {
+			dev_info(cam->dev, "streamoff raw device not found\n");
+			goto fail_stream_off;
+		}
+		raw_dev = dev_get_drvdata(dev);
+		mtk_cam_raw_stream_on(raw_dev, 0);
+		/* Twin */
+		if (ctx->pipe->res_config.raw_num_used != 1) {
+			struct mtk_raw_device *raw_dev_sub =
+						get_sub_raw_dev(cam, ctx->pipe);
+			mtk_cam_raw_stream_on(raw_dev_sub, 0);
+			if (ctx->pipe->res_config.raw_num_used == 3) {
+				struct mtk_raw_device *raw_dev_sub2 =
+					get_sub2_raw_dev(cam, ctx->pipe);
+				mtk_cam_raw_stream_on(raw_dev_sub2, 0);
+			}
+		}
+	}
+
+	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) {
+		ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0);
+		if (ret) {
+			dev_err(cam->dev, "failed to stream off %s: %d\n",
+				ctx->pipe_subdevs[i]->name, ret);
+			return -EPERM;
+		}
+	}
+
+	if (ctx->img_buf_pool.working_img_buf_size > 0) {
+		if (is_yuv_node(node->desc.id))
+			dev = cam->raw.yuvs[0];
+		else
+			dev = cam->raw.devs[0];
+
+		mtk_cam_img_working_buf_pool_release(ctx, dev);
+	}
+
+	mtk_camsys_ctrl_stop(ctx);
+
+fail_stream_off:
+	if (ctx->used_raw_num)
+		isp_composer_destroy_session(ctx);
+
+	dev_dbg(cam->dev, "streamed off camsys ctx:%d\n", ctx->stream_id);
+
+	return 0;
+}
+
+static int config_bridge_pad_links(struct mtk_cam_device *cam,
+				   struct v4l2_subdev *seninf)
+{
+	struct media_entity *pipe_entity;
+	unsigned int i;
+	int ret;
+
+	for (i = MTKCAM_SUBDEV_RAW_START;
+	     i < MTKCAM_SUBDEV_RAW_START + cam->num_raw_devices; i++) {
+		pipe_entity = &cam->raw.pipelines[i].subdev.entity;
+
+		dev_info(cam->dev, "create pad link %s %s\n",
+			 seninf->entity.name, pipe_entity->name);
+
+		ret = media_create_pad_link(&seninf->entity,
+					    MTK_CAM_CIO_PAD_SRC,
+					    pipe_entity,
+					    MTK_CAM_CIO_PAD_SINK,
+					    MEDIA_LNK_FL_DYNAMIC);
+
+		if (ret) {
+			dev_warn(cam->dev,
+				 "failed to create pad link %s %s err:%d\n",
+				 seninf->entity.name, pipe_entity->name,
+				 ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int mtk_cam_create_links(struct mtk_cam_device *cam)
+{
+	struct v4l2_subdev *sd;
+	int ret = 0;
+
+	v4l2_device_for_each_subdev(sd, &cam->v4l2_dev) {
+		if (sd->entity.function == MEDIA_ENT_F_VID_IF_BRIDGE)
+			ret = config_bridge_pad_links(cam, sd);
+	}
+
+	return ret;
+}
+
+static int mtk_cam_master_register(struct device *dev)
+{
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	struct media_device *media_dev = &cam_dev->media_dev;
+	int ret;
+
+	dev_info(dev, "camsys | start %s\n", __func__);
+
+	media_dev->dev = cam_dev->dev;
+	strscpy(media_dev->model, dev_driver_string(dev),
+		sizeof(media_dev->model));
+	snprintf(media_dev->bus_info, sizeof(media_dev->bus_info),
+		 "platform:%s", dev_name(dev));
+	media_dev->hw_revision = 0;
+	media_dev->ops = &mtk_cam_dev_ops;
+	media_device_init(media_dev);
+
+	cam_dev->v4l2_dev.mdev = media_dev;
+	ret = v4l2_device_register(cam_dev->dev, &cam_dev->v4l2_dev);
+	if (ret) {
+		dev_dbg(dev, "Failed to register V4L2 device: %d\n", ret);
+		goto fail_media_device_cleanup;
+	}
+
+	ret = media_device_register(media_dev);
+	if (ret) {
+		dev_dbg(dev, "Failed to register media device: %d\n",
+			ret);
+		goto fail_v4l2_device_unreg;
+	}
+
+	dev_info(dev, "%s success\n", __func__);
+	return 0;
+
+fail_v4l2_device_unreg:
+	v4l2_device_unregister(&cam_dev->v4l2_dev);
+
+fail_media_device_cleanup:
+	media_device_cleanup(&cam_dev->media_dev);
+
+	return ret;
+}
+
+static void mtk_cam_master_unregister(struct device *dev)
+{
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+
+	dev_info(dev, "camsys | start %s\n", __func__);
+
+	media_device_unregister(&cam_dev->media_dev);
+	v4l2_device_unregister(&cam_dev->v4l2_dev);
+	media_device_cleanup(&cam_dev->media_dev);
+}
+
+static int mtk_cam_async_add_by_driver(struct device *dev,
+				       struct platform_driver *drv,
+				       struct v4l2_async_notifier *notifier)
+{
+	struct fwnode_handle *fwnode;
+	struct device *p;
+	struct v4l2_async_connection *asc;
+	int dev_num = 0;
+
+	p = platform_find_device_by_driver(NULL, &drv->driver);
+	while (p) {
+		dev_info(dev, "camsys | %s add %s\n", __func__, p->kobj.name);
+
+		fwnode = dev_fwnode(p);
+		asc = v4l2_async_nf_add_fwnode(notifier, fwnode,
+					       struct v4l2_async_connection);
+		put_device(p);
+
+		if (IS_ERR(asc)) {
+			dev_info(dev, "%s add fwnode fail %ld\n", __func__,
+				 PTR_ERR(asc));
+
+			return PTR_ERR(asc);
+		}
+		++dev_num;
+
+		p = platform_find_device_by_driver(p, &drv->driver);
+	}
+
+	return dev_num;
+}
+
+static int mtk_cam_async_subdev_add(struct device *dev)
+{
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+	struct v4l2_async_notifier *notifier = &cam_dev->notifier;
+	int raw_num, yuv_num, seninf_num;
+
+	raw_num = mtk_cam_async_add_by_driver(dev, &mtk_cam_raw_driver,
+					      notifier);
+	yuv_num = mtk_cam_async_add_by_driver(dev, &mtk_cam_yuv_driver,
+					      notifier);
+	seninf_num = mtk_cam_async_add_by_driver(dev, &seninf_pdrv, notifier);
+
+	if (raw_num < 0 || yuv_num < 0 || seninf_num < 0) {
+		dev_err(dev, "%s failed\n", __func__);
+		return -ENODEV;
+	}
+
+	cam_dev->num_raw_devices = raw_num;
+	cam_dev->num_seninf_devices = seninf_num;
+	dev_info(dev, "dependent module #: raw %d, yuv %d, seninf %d\n",
+		 cam_dev->num_raw_devices, yuv_num,
+		 cam_dev->num_seninf_devices);
+
+	return 0;
+}
+
+static void mtk_cam_ctx_init(struct mtk_cam_ctx *ctx,
+			     struct mtk_cam_device *cam,
+			     unsigned int stream_id)
+{
+	ctx->cam = cam;
+	ctx->stream_id = stream_id;
+	ctx->sensor = NULL;
+
+	ctx->streaming_pipe = 0;
+	ctx->streaming_node_cnt = 0;
+
+	ctx->used_raw_num = 0;
+	ctx->used_raw_dev = 0;
+	ctx->processing_buffer_list.cnt = 0;
+	ctx->composed_buffer_list.cnt = 0;
+	ctx->is_first_cq_done = 0;
+	ctx->cq_done_status = 0;
+	ctx->session_created = 0;
+
+	INIT_LIST_HEAD(&ctx->using_buffer_list.list);
+	INIT_LIST_HEAD(&ctx->composed_buffer_list.list);
+	INIT_LIST_HEAD(&ctx->processing_buffer_list.list);
+	INIT_LIST_HEAD(&ctx->processing_img_buffer_list.list);
+	spin_lock_init(&ctx->using_buffer_list.lock);
+	spin_lock_init(&ctx->composed_buffer_list.lock);
+	spin_lock_init(&ctx->processing_buffer_list.lock);
+	spin_lock_init(&ctx->streaming_lock);
+	spin_lock_init(&ctx->first_cq_lock);
+	spin_lock_init(&ctx->processing_img_buffer_list.lock);
+
+	mtk_ctx_watchdog_init(ctx);
+}
+
+int mtk_cam_link_validate(struct v4l2_subdev *sd,
+			  struct media_link *link,
+			  struct v4l2_subdev_format *source_fmt,
+			  struct v4l2_subdev_format *sink_fmt)
+{
+	int ret = 0;
+
+	/* The width, height and code must match. */
+	if (source_fmt->format.width != sink_fmt->format.width) {
+		dev_err(sd->entity.graph_obj.mdev->dev,
+			"%s: width does not match (source %u, sink %u)\n",
+			__func__,
+			source_fmt->format.width, sink_fmt->format.width);
+		ret = -EPIPE;
+	}
+
+	if (source_fmt->format.height != sink_fmt->format.height) {
+		dev_err(sd->entity.graph_obj.mdev->dev,
+			"%s: height does not match (source %u, sink %u)\n",
+			__func__,
+			source_fmt->format.height, sink_fmt->format.height);
+		ret = -EPIPE;
+	}
+
+	if (source_fmt->format.code != sink_fmt->format.code) {
+		dev_err(sd->entity.graph_obj.mdev->dev,
+			"%s: warn: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n",
+			__func__,
+			source_fmt->format.code, sink_fmt->format.code);
+		ret = -EPIPE;
+	}
+
+	dev_dbg(sd->entity.graph_obj.mdev->dev,
+		"%s: link was \"%s\":%u -> \"%s\":%u\n", __func__,
+		link->source->entity->name, link->source->index,
+		link->sink->entity->name, link->sink->index);
+
+	if (ret)
+		dev_info(sd->v4l2_dev->dev,
+			 "%s: link validate failed pad/code/w/h: SRC(%d/0x%x/%d/%d), SINK(%d:0x%x/%d/%d)\n",
+			 sd->name, source_fmt->pad, source_fmt->format.code,
+			 source_fmt->format.width, source_fmt->format.height,
+			 sink_fmt->pad, sink_fmt->format.code,
+			 sink_fmt->format.width, sink_fmt->format.height);
+
+	return ret;
+}
+
+static int register_sub_drivers(struct device *dev)
+{
+	int ret;
+
+	ret = platform_driver_register(&seninf_pdrv);
+	if (ret) {
+		dev_info(dev, "%s seninf_pdrv fail\n", __func__);
+		goto REGISTER_SENINF_FAIL;
+	}
+
+	ret = platform_driver_register(&seninf_core_pdrv);
+	if (ret) {
+		dev_info(dev, "%s seninf_core_pdrv fail\n", __func__);
+		goto REGISTER_SENINF_CORE_FAIL;
+	}
+
+	ret = platform_driver_register(&mtk_cam_raw_driver);
+	if (ret) {
+		dev_info(dev, "%s mtk_cam_raw_driver fail\n", __func__);
+		goto REGISTER_RAW_FAIL;
+	}
+
+	ret = platform_driver_register(&mtk_cam_yuv_driver);
+	if (ret) {
+		dev_info(dev, "%s mtk_cam_raw_driver fail\n", __func__);
+		goto REGISTER_YUV_FAIL;
+	}
+
+	ret = mtk_cam_master_register(dev);
+	if (ret) {
+		dev_err(dev, "%s mtk_cam_master_register fail\n", __func__);
+		goto ADD_CAM_MASTER_FAIL;
+	}
+
+	return 0;
+
+ADD_CAM_MASTER_FAIL:
+	platform_driver_unregister(&mtk_cam_yuv_driver);
+
+REGISTER_YUV_FAIL:
+	platform_driver_unregister(&mtk_cam_raw_driver);
+
+REGISTER_RAW_FAIL:
+	platform_driver_unregister(&seninf_core_pdrv);
+
+REGISTER_SENINF_CORE_FAIL:
+	platform_driver_unregister(&seninf_pdrv);
+
+REGISTER_SENINF_FAIL:
+	return ret;
+}
+
+static void unregister_sub_drivers(struct device *dev)
+{
+	mtk_cam_master_unregister(dev);
+
+	platform_driver_unregister(&mtk_cam_yuv_driver);
+	platform_driver_unregister(&mtk_cam_raw_driver);
+	platform_driver_unregister(&seninf_core_pdrv);
+	platform_driver_unregister(&seninf_pdrv);
+}
+
+static int mtk_cam_master_complete(struct v4l2_async_notifier *notifier)
+{
+	struct mtk_cam_device *cam_dev =
+		container_of(notifier, struct mtk_cam_device, notifier);
+	struct device *dev = cam_dev->dev;
+	int ret;
+
+	dev_info(dev, "cmasys | trigger %s\n", __func__);
+
+	/* set raw and yuv internal */
+	ret = mtk_cam_raw_setup_dependencies(&cam_dev->raw);
+	if (ret) {
+		dev_err(dev, "Failed to mtk_cam_raw_setup_dependencies: %d\n", ret);
+		goto fail_unbind_all;
+	}
+
+	/* register raw subdev */
+	ret = mtk_cam_raw_register_entities(&cam_dev->raw, &cam_dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "Failed to init raw subdevs: %d\n", ret);
+		goto fail_remove_dependencies;
+	}
+
+	mtk_cam_create_links(cam_dev);
+
+	/* Expose all subdev's nodes */
+	ret = v4l2_device_register_subdev_nodes(&cam_dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register subdev nodes\n");
+		goto fail_unreg_raw_entities;
+	}
+
+	dev_info(dev, "%s success\n", __func__);
+
+	return 0;
+
+fail_unreg_raw_entities:
+	mtk_cam_raw_unregister_entities(&cam_dev->raw);
+
+fail_remove_dependencies:
+	/* nothing to do for now */
+
+fail_unbind_all:
+	return ret;
+}
+
+static int mtk_cam_master_bound(struct v4l2_async_notifier *notifier,
+				struct v4l2_subdev *subdev,
+				struct v4l2_async_connection *asc)
+{
+	struct mtk_cam_device *cam_dev =
+		container_of(notifier, struct mtk_cam_device, notifier);
+	struct mtk_raw *raw = &cam_dev->raw;
+	struct device *cam = cam_dev->dev;
+	struct device *dev = subdev->dev;
+
+	dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__);
+
+	if (strcmp(dev_driver_string(dev), "seninf") == 0) {
+		dev_dbg(cam, "%s@(seninf) done\n", __func__);
+	} else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) {
+		struct mtk_raw_device *raw_dev = dev_get_drvdata(dev);
+
+		raw_dev->cam = cam_dev;
+		raw->devs[raw_dev->id] = dev;
+		raw->cam_dev = cam_dev->dev;
+		dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__);
+	} else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) {
+		struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev);
+
+		raw->yuvs[yuv_dev->id] = dev;
+		dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__);
+	} else {
+		dev_warn(cam, "%s got unrecongized device\n", __func__);
+	}
+
+	return 0;
+}
+
+static void mtk_cam_master_unbound(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *subdev,
+				   struct v4l2_async_connection *asc)
+{
+	struct mtk_cam_device *cam_dev =
+		container_of(notifier, struct mtk_cam_device, notifier);
+	struct mtk_raw *raw = &cam_dev->raw;
+	struct device *cam = cam_dev->dev;
+	struct device *dev = subdev->dev;
+
+	dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__);
+
+	if (strcmp(dev_driver_string(dev), "seninf") == 0) {
+		dev_dbg(cam, "%s@(seninf) done\n", __func__);
+	} else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) {
+		struct mtk_raw_device *raw_dev = dev_get_drvdata(dev);
+
+		mtk_cam_raw_unregister_entities(&cam_dev->raw);
+
+		raw_dev->cam = NULL;
+		raw->devs[raw_dev->id] = NULL;
+		raw->cam_dev = NULL;
+		dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__);
+	} else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) {
+		struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev);
+
+		raw->yuvs[yuv_dev->id] = NULL;
+		dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__);
+	} else {
+		dev_warn(cam, "%s got unrecongized device\n", __func__);
+	}
+}
+
+static const struct v4l2_async_notifier_operations mtk_cam_async_nf_ops = {
+	.complete = mtk_cam_master_complete,
+	.bound = mtk_cam_master_bound,
+	.unbind = mtk_cam_master_unbound,
+};
+
+static int mtk_cam_probe(struct platform_device *pdev)
+{
+	struct mtk_cam_device *cam_dev;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+	unsigned int i;
+
+	/* initialize structure */
+	cam_dev = devm_kzalloc(dev, sizeof(*cam_dev), GFP_KERNEL);
+	if (!cam_dev)
+		return -ENOMEM;
+
+	if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) {
+		dev_err(dev, "%s: No suitable DMA available\n", __func__);
+		return -EIO;
+	}
+
+	if (!dev->dma_parms) {
+		dev->dma_parms =
+			devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+		if (!dev->dma_parms)
+			return -ENOMEM;
+	}
+
+	dma_set_max_seg_size(dev, UINT_MAX);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "failed to get mem\n");
+		return -ENODEV;
+	}
+
+	cam_dev->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cam_dev->base)) {
+		dev_err(dev, "failed to map register base\n");
+		return PTR_ERR(cam_dev->base);
+	}
+
+	cam_dev->dev = dev;
+	dev_set_drvdata(dev, cam_dev);
+
+	cam_dev->composer_cnt = 0;
+	cam_dev->num_seninf_devices = 0;
+
+	cam_dev->max_stream_num = MTKCAM_SUBDEV_MAX;
+	cam_dev->ctxs = devm_kcalloc(dev, cam_dev->max_stream_num,
+				     sizeof(*cam_dev->ctxs), GFP_KERNEL);
+	if (!cam_dev->ctxs)
+		return -ENOMEM;
+
+	cam_dev->streaming_ctx = 0;
+	for (i = 0; i < cam_dev->max_stream_num; i++)
+		mtk_cam_ctx_init(cam_dev->ctxs + i, cam_dev, i);
+
+	cam_dev->running_job_count = 0;
+	spin_lock_init(&cam_dev->pending_job_lock);
+	spin_lock_init(&cam_dev->running_job_lock);
+	INIT_LIST_HEAD(&cam_dev->pending_job_list);
+	INIT_LIST_HEAD(&cam_dev->running_job_list);
+
+	cam_dev->dma_processing_count = 0;
+	spin_lock_init(&cam_dev->dma_pending_lock);
+	spin_lock_init(&cam_dev->dma_processing_lock);
+	INIT_LIST_HEAD(&cam_dev->dma_pending);
+	INIT_LIST_HEAD(&cam_dev->dma_processing);
+
+	mutex_init(&cam_dev->queue_lock);
+
+	pm_runtime_enable(dev);
+
+	ret = mtk_cam_of_rproc(cam_dev, pdev);
+	if (ret)
+		goto fail_destroy_mutex;
+
+	ret = register_sub_drivers(dev);
+	if (ret) {
+		dev_err(dev, "fail to register_sub_drivers\n");
+		goto fail_destroy_mutex;
+	}
+
+    cam_dev->clks_pdev = platform_device_register_data(
+        dev, "clk-mt8188-cam", PLATFORM_DEVID_AUTO, NULL, 0);
+    if (IS_ERR(cam_dev->clks_pdev)) {
+        ret = PTR_ERR(cam_dev->clks_pdev);
+        dev_err(dev, "Failed to register cam clk device: %d\n", ret);
+        goto fail_unregister_sub_drivers;
+    }
+	
+	/* register mtk_cam as all isp subdev async parent */
+	cam_dev->notifier.ops = &mtk_cam_async_nf_ops;
+	v4l2_async_nf_init(&cam_dev->notifier, &cam_dev->v4l2_dev);
+	ret = mtk_cam_async_subdev_add(dev); /* wait all isp sub drivers */
+	if (ret) {
+		dev_err(dev, "%s failed mtk_cam_async_subdev_add\n", __func__);
+		goto fail_unregister_clks;
+	}
+
+	ret = v4l2_async_nf_register(&cam_dev->notifier);
+	if (ret) {
+		dev_err(dev, "%s async_nf_register ret:%d\n", __func__, ret);
+		v4l2_async_nf_cleanup(&cam_dev->notifier);
+		goto fail_unregister_clks;
+	}
+
+	dev_info(dev, "camsys | [%s] success\n", __func__);
+
+	return 0;
+
+fail_unregister_clks:
+    if (cam_dev->clks_pdev)
+        platform_device_unregister(cam_dev->clks_pdev);
+
+fail_unregister_sub_drivers:
+	unregister_sub_drivers(dev);
+
+fail_destroy_mutex:
+	mutex_destroy(&cam_dev->queue_lock);
+
+	return ret;
+}
+
+static void mtk_cam_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+
+	if (cam_dev->clks_pdev)
+		platform_device_unregister(cam_dev->clks_pdev);
+
+	unregister_sub_drivers(dev);
+
+	mutex_destroy(&cam_dev->queue_lock);
+}
+
+static const struct dev_pm_ops mtk_cam_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mtk_cam_runtime_suspend, mtk_cam_runtime_resume)
+	SET_RUNTIME_PM_OPS(mtk_cam_runtime_suspend, mtk_cam_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver mtk_cam_driver = {
+	.probe   = mtk_cam_probe,
+	.remove  = mtk_cam_remove,
+	.driver  = {
+		.name  = "mtk-cam",
+		.of_match_table = mtk_cam_of_ids,
+		.pm     = &mtk_cam_pm_ops,
+	}
+};
+
+module_platform_driver(mtk_cam_driver);
+
+MODULE_DESCRIPTION("MediaTek camera ISP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h
new file mode 100755
index 000000000000..48852f4e7c51
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h
@@ -0,0 +1,718 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_H
+#define __MTK_CAM_H
+
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/rpmsg.h>
+#include <linux/timer.h>
+#include <media/media-device.h>
+#include <media/media-request.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+
+#include "mtk_cam-raw.h"
+#include "mtk_cam-ipi.h"
+#include "kd_imgsensor_define_v4l2.h"
+#include "mtk_cam-seninf-def.h"
+#include "mtk_cam-seninf-drv.h"
+#include "mtk_cam-seninf-if.h"
+#include "mtk_cam-ctrl.h"
+#include "mtk_cam-plat-util.h"
+
+#define MTK_CAM_REQ_MAX_S_DATA	2
+/* for SCP internal working buffers, need to align it with SCP */
+#define SIZE_OF_RAW_PRIV		20788
+#define SIZE_OF_RAW_WORKBUF		18600
+#define SIZE_OF_SESSION			22596
+
+/* for cq working buffers */
+#define CQ_BUF_SIZE	0x8000 /* ISP7_1 */
+
+#define CAM_CQ_BUF_NUM 16
+#define IPI_FRAME_BUF_SIZE ALIGN(sizeof(struct mtkcam_ipi_frame_param), SZ_1K)
+#define CAM_IMG_BUF_NUM			6
+#define MAX_PIPES_PER_STREAM		5
+#define MTK_CAM_CTX_WATCHDOG_INTERVAL	100
+
+struct mtk_cam_request;
+struct mtk_raw_pipeline;
+
+#define SENSOR_FMT_MASK			0xFFFF
+
+/* flags of mtk_cam_request */
+#define MTK_CAM_REQ_FLAG_SENINF_IMMEDIATE_UPDATE	BIT(1)
+
+/* flags of mtk_cam_request_stream_data */
+#define MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH		BIT(0)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT	BIT(1)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE		BIT(2)
+
+/* Apply sensor mode and the timing is 1 vsync before */
+#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1	BIT(3)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN		BIT(4)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN		BIT(5)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE	BIT(6)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE	BIT(7)
+
+#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED	BIT(8)
+
+struct mtk_cam_working_buf {
+	void *va;
+	dma_addr_t iova;
+	dma_addr_t scp_addr;
+	unsigned int size;
+};
+
+struct mtk_cam_msg_buf {
+	void *va;
+	dma_addr_t scp_addr;
+	unsigned int size;
+};
+
+struct mtk_cam_working_buf_entry {
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request_stream_data *s_data;
+	struct mtk_cam_working_buf buffer;
+	struct mtk_cam_msg_buf msg_buffer;
+	struct list_head list_entry;
+	int cq_desc_offset;
+	unsigned int cq_desc_size;
+	int sub_cq_desc_offset;
+	unsigned int sub_cq_desc_size;
+};
+
+struct mtk_cam_img_working_buf_entry {
+	struct mtk_cam_ctx *ctx;
+	struct mtk_cam_request_stream_data *s_data;
+	struct mtk_cam_working_buf img_buffer;
+	struct list_head list_entry;
+};
+
+struct mtk_cam_working_buf_list {
+	struct list_head list;
+	u32 cnt;
+	spinlock_t lock; /* protect the list and cnt */
+};
+
+struct mtk_cam_req_work {
+	struct work_struct work;
+	struct mtk_cam_request_stream_data *s_data;
+	struct list_head list;
+	atomic_t is_queued;
+};
+
+static inline struct mtk_cam_request_stream_data*
+mtk_cam_req_work_get_s_data(struct mtk_cam_req_work *work)
+{
+	return work->s_data;
+}
+
+struct mtk_cam_req_feature {
+	int raw_feature;
+	bool switch_prev_frame_done;
+	bool switch_curr_setting_done;
+	bool switch_done;
+};
+
+struct mtk_cam_sensor_work {
+	struct kthread_work work;
+	atomic_t is_queued;
+};
+
+/*
+ * struct mtk_cam_request_stream_data - per stream members of a request
+ *
+ * @pad_fmt: pad format configurtion for sensor switch.
+ * @frame_params: The frame info. & address info. of enabled DMA nodes.
+ * @frame_work: work queue entry for frame transmission to SCP.
+ * @working_buf: command queue buffer associated to this request
+ * @deque_list_node: the entry node of s_data for deque
+ * @cleanup_list_node: the entry node of s_data for cleanup
+ *
+ */
+struct mtk_cam_request_stream_data {
+	u32 index;
+	struct mtk_cam_request *req;
+	struct mtk_cam_ctx *ctx;
+	u32 pipe_id;
+	u32 frame_seq_no;
+	u32 flags;
+	unsigned long raw_dmas;
+	u64 timestamp;
+	u64 timestamp_mono;
+	atomic_t buf_state; /* default: -1 */
+	struct mtk_cam_buffer *bufs[MTK_RAW_TOTAL_NODES];
+	struct v4l2_subdev *sensor;
+	struct media_request_object *sensor_hdl_obj;  /* for complete only */
+	struct media_request_object *raw_hdl_obj;  /* for complete only */
+	struct v4l2_subdev_format seninf_fmt;
+	struct v4l2_subdev_format pad_fmt[MTK_RAW_PIPELINE_PADS_NUM];
+	struct v4l2_rect pad_selection[MTK_RAW_PIPELINE_PADS_NUM];
+	struct v4l2_format vdev_fmt[MTK_RAW_TOTAL_NODES];
+	struct v4l2_selection vdev_selection[MTK_RAW_TOTAL_NODES];
+	struct mtkcam_ipi_frame_param frame_params;
+	struct mtk_cam_sensor_work sensor_work;
+	struct mtk_cam_req_work seninf_s_fmt_work;
+	struct mtk_cam_req_work frame_work;
+	struct mtk_cam_req_work meta1_done_work;
+	struct mtk_cam_req_work frame_done_work;
+	struct mtk_camsys_ctrl_state state;
+	struct mtk_cam_working_buf_entry *working_buf;
+	unsigned int no_frame_done_cnt;
+	atomic_t seninf_dump_state;
+	struct mtk_cam_req_feature feature;
+	struct list_head deque_list_node;
+	struct list_head cleanup_list_node;
+	atomic_t first_setting_check;
+};
+
+struct mtk_cam_req_pipe {
+	int s_data_num;
+	int req_seq;
+	struct mtk_cam_request_stream_data s_data[MTK_CAM_REQ_MAX_S_DATA];
+};
+
+enum mtk_cam_request_state {
+	MTK_CAM_REQ_STATE_PENDING,
+	MTK_CAM_REQ_STATE_RUNNING,
+	MTK_CAM_REQ_STATE_DELETING,
+	MTK_CAM_REQ_STATE_COMPLETE,
+	MTK_CAM_REQ_STATE_CLEANUP,
+	NR_OF_MTK_CAM_REQ_STATE,
+};
+
+enum mtk_cam_pixel_mode {
+	PXL_MOD_1 = 0,
+	PXL_MOD_2,
+	PXL_MOD_4,
+	PXL_MOD_8,
+};
+
+/**
+ * mtk_cam_frame_sync: the frame sync state of one request
+ *
+ * @target: the num of ctx(sensor) which should be synced
+ * @on_cnt: the count of frame sync on called by ctx
+ * @off_cnt: the count of frame sync off called by ctx
+ * @op_lock: protect frame sync state variables
+ */
+struct mtk_cam_frame_sync {
+	unsigned int target;
+	unsigned int on_cnt;
+	unsigned int off_cnt;
+	struct mutex op_lock; /* protect frame sync state */
+};
+
+struct mtk_cam_req_raw_pipe_data {
+	struct mtk_cam_resource res;
+	int enabled_raw;
+};
+
+/*
+ * struct mtk_cam_request - MTK camera request.
+ *
+ * @req: Embedded struct media request.
+ * @pipe_used: pipe used in this request. Two or more pipes may share
+ * the same context.
+ * @ctx_used: context used in this request.
+ * @done_status: Record context done status.
+ * @done_status_lock: Spinlock for context done status.
+ * @fs: the frame sync state.
+ * @list: List entry of the object for pending_job_list
+ * or running_job_list.
+ * @cleanup_list: List entry of the request to cleanup.
+ * @p_data: restore stream request data in a pipe.
+ * @p_data: restore raw pipe resource data.
+ * @sync_id: frame sync index.
+ */
+struct mtk_cam_request {
+	struct media_request req;
+	unsigned int pipe_used;
+	unsigned int ctx_used;
+	unsigned int done_status;
+	spinlock_t done_status_lock; /* protect done_status */
+	atomic_t state;
+	struct mtk_cam_frame_sync fs;
+	struct list_head list;
+	struct list_head cleanup_list;
+	struct mtk_cam_req_pipe p_data[MTKCAM_SUBDEV_MAX];
+	struct mtk_cam_req_raw_pipe_data raw_pipe_data[MTKCAM_SUBDEV_RAW_END -
+						       MTKCAM_SUBDEV_RAW_START];
+	s64 sync_id;
+	atomic_t ref_cnt;
+};
+
+struct mtk_cam_working_buf_pool {
+	struct mtk_cam_ctx *ctx;
+
+	struct dma_buf *working_buf_dmabuf;
+
+	void *working_buf_va;
+	dma_addr_t working_buf_iova;
+	dma_addr_t working_buf_scp_addr;
+	unsigned int working_buf_size;
+
+	void *msg_buf_va;
+	dma_addr_t msg_buf_scp_addr;
+	unsigned int msg_buf_size;
+
+	void *raw_workbuf_va;
+	dma_addr_t raw_workbuf_scp_addr;
+	unsigned int raw_workbuf_size;
+	void *priv_workbuf_va;
+	dma_addr_t priv_workbuf_scp_addr;
+	unsigned int priv_workbuf_size;
+	void *session_buf_va;
+	dma_addr_t session_buf_scp_addr;
+	unsigned int session_buf_size;
+
+	struct mtk_cam_working_buf_entry working_buf[CAM_CQ_BUF_NUM];
+	struct mtk_cam_working_buf_list cam_freelist;
+};
+
+struct mtk_cam_img_working_buf_pool {
+	struct mtk_cam_ctx *ctx;
+	struct dma_buf *working_img_buf_dmabuf;
+	void *working_img_buf_va;
+	dma_addr_t working_img_buf_iova;
+	dma_addr_t working_img_buf_scp_addr;
+	unsigned int working_img_buf_size;
+	struct mtk_cam_img_working_buf_entry img_working_buf[CAM_IMG_BUF_NUM];
+	struct mtk_cam_working_buf_list cam_freeimglist;
+};
+
+struct mtk_cam_device;
+
+struct mtk_cam_ctx {
+	struct mtk_cam_device *cam;
+	unsigned int stream_id;
+	unsigned int streaming;
+	unsigned int synced;
+	struct media_pipeline pipeline;
+	struct mtk_raw_pipeline *pipe;
+	unsigned int enabled_node_cnt;
+	unsigned int streaming_pipe;
+	unsigned int streaming_node_cnt;
+	unsigned int is_first_cq_done;
+	unsigned int cq_done_status;
+	atomic_t running_s_data_cnt;
+	struct v4l2_subdev *sensor;
+	struct v4l2_subdev *seninf;
+	struct v4l2_subdev *pipe_subdevs[MAX_PIPES_PER_STREAM];
+	struct mtk_camsys_sensor_ctrl sensor_ctrl;
+
+	unsigned int used_raw_num;
+	unsigned int used_raw_dev;
+
+	struct task_struct *sensor_worker_task;
+	struct kthread_worker sensor_worker;
+	struct workqueue_struct *composer_wq;
+	struct workqueue_struct *frame_done_wq;
+
+	struct completion session_complete;
+	int session_created;
+
+	struct mtk_cam_working_buf_pool buf_pool;
+	struct mtk_cam_working_buf_list using_buffer_list;
+	struct mtk_cam_working_buf_list composed_buffer_list;
+	struct mtk_cam_working_buf_list processing_buffer_list;
+
+	/* sensor image buffer pool handling from kernel */
+	struct mtk_cam_img_working_buf_pool img_buf_pool;
+	struct mtk_cam_working_buf_list processing_img_buffer_list;
+
+	atomic_t enqueued_frame_seq_no;
+	unsigned int composed_frame_seq_no;
+	unsigned int dequeued_frame_seq_no;
+
+	spinlock_t streaming_lock; /* protect streaming */
+	spinlock_t first_cq_lock; /* protect is_first_cq_done */
+
+	/* watchdog */
+	int watchdog_timeout_tg;
+	atomic_t watchdog_dump;
+	atomic_long_t watchdog_prev;
+	struct timer_list watchdog_timer;
+	struct work_struct watchdog_work;
+
+	/* To support debug dump */
+	struct mtkcam_ipi_config_param config_params;
+};
+
+struct mtk_cam_device {
+	struct device *dev;
+
+	struct platform_device *clks_pdev;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_async_notifier notifier;
+	struct media_device media_dev;
+	void __iomem *base;
+
+	struct mtk_scp *scp;
+	struct device *smem_dev;
+	struct rproc *rproc_handle;
+
+	unsigned int composer_cnt;
+
+	unsigned int num_seninf_devices;
+	unsigned int num_raw_devices;
+
+	/* raw_pipe controller subdev */
+	struct mtk_raw raw;
+	struct mutex queue_lock; /* protect queue request */
+
+	unsigned int max_stream_num;
+	unsigned int streaming_ctx;
+	unsigned int streaming_pipe;
+	struct mtk_cam_ctx *ctxs;
+
+	/* request related */
+	struct list_head pending_job_list;
+	spinlock_t pending_job_lock; /* protect pending_job_list */
+	struct list_head running_job_list;
+	unsigned int running_job_count;
+	spinlock_t running_job_lock; /* protect running_job_list */
+
+	/* standard v4l2 buffer control */
+	struct list_head dma_pending;
+	spinlock_t dma_pending_lock; /* protect dma_pending_list */
+	struct list_head dma_processing;
+	spinlock_t dma_processing_lock; /* protect dma_processing_list and dma_processing_count */
+	unsigned int dma_processing_count;
+
+	struct workqueue_struct *debug_wq;
+	struct workqueue_struct *debug_exception_wq;
+};
+
+static inline struct mtk_cam_request_stream_data*
+mtk_cam_ctrl_state_to_req_s_data(struct mtk_camsys_ctrl_state *state)
+{
+	return container_of(state, struct mtk_cam_request_stream_data, state);
+}
+
+static inline struct mtk_cam_request*
+mtk_cam_ctrl_state_get_req(struct mtk_camsys_ctrl_state *state)
+{
+	struct mtk_cam_request_stream_data *request_stream_data;
+
+	request_stream_data = mtk_cam_ctrl_state_to_req_s_data(state);
+	return request_stream_data->req;
+}
+
+static inline u32
+mtk_cam_req_get_num_s_data(struct mtk_cam_request *req, u32 pipe_id)
+{
+	if (pipe_id >= MTKCAM_SUBDEV_MAX)
+		return 0;
+
+	return req->p_data[pipe_id].s_data_num;
+}
+
+/**
+ * Be used operation between request reinit and enqueue.
+ * For example, request-based set fmt and selection.
+ */
+static inline struct mtk_cam_request_stream_data*
+mtk_cam_req_get_s_data_no_chk(struct mtk_cam_request *req, u32 pipe_id, u32 idx)
+{
+	return &req->p_data[pipe_id].s_data[idx];
+}
+
+static inline struct mtk_cam_request_stream_data*
+mtk_cam_req_get_s_data(struct mtk_cam_request *req, u32 pipe_id, u32 idx)
+{
+	if (!req || pipe_id >= MTKCAM_SUBDEV_MAX)
+		return NULL;
+
+	if (idx >= req->p_data[pipe_id].s_data_num)
+		return NULL;
+
+	return mtk_cam_req_get_s_data_no_chk(req, pipe_id, idx);
+}
+
+static inline struct mtk_cam_ctx*
+mtk_cam_s_data_get_ctx(struct mtk_cam_request_stream_data *s_data)
+{
+	if (!s_data)
+		return NULL;
+
+	return s_data->ctx;
+}
+
+static inline char*
+mtk_cam_s_data_get_dbg_str(struct mtk_cam_request_stream_data *s_data)
+{
+	return s_data->req->req.debug_str;
+}
+
+static inline struct mtk_cam_request*
+mtk_cam_s_data_get_req(struct mtk_cam_request_stream_data *s_data)
+{
+	if (!s_data)
+		return NULL;
+
+	return s_data->req;
+}
+
+static inline struct mtk_cam_req_raw_pipe_data*
+mtk_cam_s_data_get_raw_pipe_data(struct mtk_cam_request_stream_data *s_data)
+{
+	if (!is_raw_subdev(s_data->pipe_id))
+		return NULL;
+
+	return &s_data->req->raw_pipe_data[s_data->pipe_id];
+}
+
+static inline struct mtk_cam_resource*
+mtk_cam_s_data_get_res(struct mtk_cam_request_stream_data *s_data)
+{
+	if (!s_data)
+		return NULL;
+
+	if (!is_raw_subdev(s_data->pipe_id))
+		return NULL;
+
+	return &s_data->req->raw_pipe_data[s_data->pipe_id].res;
+}
+
+static inline int
+mtk_cam_s_data_get_res_feature(struct mtk_cam_request_stream_data *s_data)
+{
+	return (!s_data || !is_raw_subdev(s_data->pipe_id)) ?
+		0 : s_data->req->raw_pipe_data[s_data->pipe_id].res.raw_res.feature;
+}
+
+static inline int
+mtk_cam_s_data_get_vbuf_idx(struct mtk_cam_request_stream_data *s_data, int node_id)
+{
+	if (s_data->pipe_id >= MTKCAM_SUBDEV_RAW_START &&
+	    s_data->pipe_id < MTKCAM_SUBDEV_RAW_END)
+		return node_id - MTK_RAW_SINK_NUM;
+
+	return -1;
+}
+
+static inline void
+mtk_cam_s_data_set_vbuf(struct mtk_cam_request_stream_data *s_data,
+			struct mtk_cam_buffer *buf,
+			int node_id)
+{
+	int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id);
+
+	if (idx >= 0)
+		s_data->bufs[idx] = buf;
+}
+
+static inline struct mtk_cam_buffer*
+mtk_cam_s_data_get_vbuf(struct mtk_cam_request_stream_data *s_data, int node_id)
+{
+	int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id);
+
+	if (idx >= 0)
+		return s_data->bufs[idx];
+	return NULL;
+}
+
+static inline struct v4l2_format*
+mtk_cam_s_data_get_vfmt(struct mtk_cam_request_stream_data *s_data, int node_id)
+{
+	int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id);
+
+	if (idx >= 0)
+		return &s_data->vdev_fmt[idx];
+
+	return NULL;
+}
+
+static inline struct v4l2_mbus_framefmt*
+mtk_cam_s_data_get_pfmt(struct mtk_cam_request_stream_data *s_data, int pad)
+{
+	if (pad >= 0)
+		return &s_data->pad_fmt[pad].format;
+
+	return NULL;
+}
+
+static inline struct v4l2_selection*
+mtk_cam_s_data_get_vsel(struct mtk_cam_request_stream_data *s_data, int node_id)
+{
+	int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id);
+
+	if (idx >= 0)
+		return &s_data->vdev_selection[idx];
+
+	return NULL;
+}
+
+static inline void
+mtk_cam_s_data_reset_vbuf(struct mtk_cam_request_stream_data *s_data, int node_id)
+{
+	int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id);
+
+	if (idx >= 0)
+		s_data->bufs[idx] = NULL;
+}
+
+static inline void
+mtk_cam_s_data_set_wbuf(struct mtk_cam_request_stream_data *s_data,
+			struct mtk_cam_working_buf_entry *buf_entry)
+{
+	buf_entry->s_data = s_data;
+	s_data->working_buf = buf_entry;
+}
+
+static inline void
+mtk_cam_s_data_reset_wbuf(struct mtk_cam_request_stream_data *s_data)
+{
+	if (!s_data->working_buf)
+		return;
+
+	s_data->working_buf->s_data = NULL;
+	s_data->working_buf = NULL;
+}
+
+static inline bool
+mtk_cam_s_data_set_buf_state(struct mtk_cam_request_stream_data *s_data,
+			     enum vb2_buffer_state state)
+{
+	if (!s_data)
+		return false;
+
+	if (-1 == atomic_cmpxchg(&s_data->buf_state, -1, state))
+		return true;
+
+	return false;
+}
+
+int mtk_cam_s_data_raw_select(struct mtk_cam_request_stream_data *s_data,
+			      struct mtkcam_ipi_input_param *cfg_in_param);
+
+static inline struct mtk_cam_request_stream_data*
+mtk_cam_sensor_work_to_s_data(struct kthread_work *work)
+{
+	return container_of(work, struct mtk_cam_request_stream_data,
+			    sensor_work.work);
+}
+
+static inline struct mtk_cam_request *
+to_mtk_cam_req(struct media_request *__req)
+{
+	return container_of(__req, struct mtk_cam_request, req);
+}
+
+static inline void
+mtk_cam_pad_fmt_enable(struct v4l2_mbus_framefmt *framefmt)
+{
+	framefmt->flags |= V4L2_MBUS_FRAMEFMT_PAD_ENABLE;
+}
+
+static inline void
+mtk_cam_pad_fmt_disable(struct v4l2_mbus_framefmt *framefmt)
+{
+	framefmt->flags &= ~V4L2_MBUS_FRAMEFMT_PAD_ENABLE;
+}
+
+static inline bool
+mtk_cam_is_pad_fmt_enable(struct v4l2_mbus_framefmt *framefmt)
+{
+	return framefmt->flags & V4L2_MBUS_FRAMEFMT_PAD_ENABLE;
+}
+
+static inline void mtk_cam_fs_reset(struct mtk_cam_frame_sync *fs)
+{
+	fs->target = 0;
+	fs->on_cnt = 0;
+	fs->off_cnt = 0;
+}
+
+static inline struct device *mtk_cam_find_raw_dev(struct mtk_cam_device *cam,
+						  unsigned int raw_mask)
+{
+	unsigned int i;
+
+	for (i = 0; i < cam->num_raw_devices; i++)
+		if (raw_mask & (1 << i))
+			return cam->raw.devs[i];
+
+	return NULL;
+}
+
+void mtk_cam_buf_try_queue(struct mtk_cam_ctx *ctx);
+struct mtk_cam_ctx *mtk_cam_start_ctx(struct mtk_cam_device *cam,
+				      struct mtk_cam_video_device *node);
+struct mtk_cam_ctx *mtk_cam_find_ctx(struct mtk_cam_device *cam,
+				     struct media_entity *entity);
+void mtk_cam_stop_ctx(struct mtk_cam_ctx *ctx,
+		      struct mtk_cam_video_device *node);
+void mtk_cam_complete_raw_hdl(struct mtk_cam_request_stream_data *s_data);
+void mtk_cam_complete_sensor_hdl(struct mtk_cam_request_stream_data *s_data);
+int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx,
+			  struct mtk_cam_video_device *node);
+int mtk_cam_ctx_stream_off(struct mtk_cam_ctx *ctx,
+			   struct mtk_cam_video_device *node);
+bool watchdog_scenario(struct mtk_cam_ctx *ctx);
+void mtk_ctx_watchdog_kick(struct mtk_cam_ctx *ctx);
+
+int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx,
+				      struct v4l2_subdev *sd,
+				      int pad_id, int pixel_mode);
+void mtk_cam_dev_req_enqueue(struct mtk_cam_device *cam,
+			     struct mtk_cam_request *req);
+void mtk_cam_dev_req_cleanup(struct mtk_cam_ctx *ctx, int pipe_id,
+			     int buf_state);
+void mtk_cam_dev_req_clean_pending(struct mtk_cam_device *cam, int pipe_id,
+				   int buf_state);
+
+void mtk_cam_req_get(struct mtk_cam_request *req, int pipe_id);
+bool mtk_cam_req_put(struct mtk_cam_request *req, int pipe_id);
+
+void mtk_cam_dev_req_try_queue(struct mtk_cam_device *cam);
+
+void mtk_cam_s_data_update_timestamp(struct mtk_cam_buffer *buf,
+				     struct mtk_cam_request_stream_data *s_data);
+
+int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx,
+			      unsigned int dequeued_frame_seq_no,
+			      int pipe_id);
+
+void mtk_cam_dev_job_done(struct mtk_cam_ctx *ctx,
+			  struct mtk_cam_request *req,
+			  int pipe_id,
+			  enum vb2_buffer_state state);
+
+void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data);
+
+int mtk_cam_link_validate(struct v4l2_subdev *sd,
+			  struct media_link *link,
+			  struct v4l2_subdev_format *source_fmt,
+			  struct v4l2_subdev_format *sink_fmt);
+
+struct mtk_cam_request *mtk_cam_get_req(struct mtk_cam_ctx *ctx,
+					unsigned int frame_seq_no);
+struct mtk_cam_request_stream_data*
+mtk_cam_get_req_s_data(struct mtk_cam_ctx *ctx, unsigned int pipe_id,
+		       unsigned int frame_seq_no);
+struct mtk_raw_pipeline *mtk_cam_dev_get_raw_pipeline(struct mtk_cam_device *cam,
+						      unsigned int id);
+
+struct mtk_raw_device *get_main_raw_dev(struct mtk_cam_device *cam,
+					struct mtk_raw_pipeline *pipe);
+struct mtk_raw_device *get_sub_raw_dev(struct mtk_cam_device *cam,
+				       struct mtk_raw_pipeline *pipe);
+struct mtk_raw_device *get_sub2_raw_dev(struct mtk_cam_device *cam,
+					struct mtk_raw_pipeline *pipe);
+int isp_composer_create_session(struct mtk_cam_ctx *ctx);
+void isp_composer_destroy_session(struct mtk_cam_ctx *ctx);
+
+#endif /*__MTK_CAM_H*/
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (7 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-22  2:19   ` CK Hu (胡俊光)
  2025-07-07  1:31 ` [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops shangyao lin
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduce utility files for the MediaTek ISP7.x camsys driver. These utilities
provide essential platform definitions, debugging tools, and management
functions to support ISP operations and SCP communication.

Key functionalities include:
- Hardware pipeline and register definitions for managing image processing
  modules
- Buffer management functions
- Definitions of supported image formats for proper data handling
- IPI and SCP communication structures for module state management and ISP
  configuration
- Metadata parameters for configuring image processing

Changes in v2:
- Removed mtk_cam-dmadbg.h along with related code
- Various fixes per review comments

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../mediatek/isp/isp_7x/camsys/mtk_cam-defs.h |  161 ++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h  |   87 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h  |  213 ++
 .../isp/isp_7x/camsys/mtk_cam-meta-mt8188.h   | 2296 +++++++++++++++++
 .../isp/isp_7x/camsys/mtk_cam-plat-util.c     |  141 +
 .../isp/isp_7x/camsys/mtk_cam-plat-util.h     |   15 +
 .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.c |  394 +++
 .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.h |   28 +
 .../isp/isp_7x/camsys/mtk_cam-regs-mt8188.h   |  374 +++
 9 files changed, 3709 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h

diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h
new file mode 100755
index 000000000000..815fb77c7304
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTKCAM_DEFS_H
+#define __MTKCAM_DEFS_H
+
+#include <linux/types.h>
+#include "mtk_cam-fmt.h"
+
+/*
+ * Note:
+ *	Following definitions are used in IPI-messaging.
+ *	Values are used in software control flow only and cannot be applied to
+ *	hw registers directly.
+ */
+
+/* camsys hw pipelines */
+enum mtkcam_pipe_subdev {
+	MTKCAM_SUBDEV_RAW_START = 0,
+	MTKCAM_SUBDEV_RAW_0	= MTKCAM_SUBDEV_RAW_START,
+	MTKCAM_SUBDEV_RAW_1,
+	MTKCAM_SUBDEV_RAW_2,
+	MTKCAM_SUBDEV_RAW_END,
+	MTKCAM_SUBDEV_MAX = MTKCAM_SUBDEV_RAW_END,
+};
+
+#define MTKCAM_SUBDEV_RAW_MASK (BIT(MTKCAM_SUBDEV_RAW_0) | \
+				BIT(MTKCAM_SUBDEV_RAW_1) | \
+				BIT(MTKCAM_SUBDEV_RAW_2))
+
+static inline int is_raw_subdev(unsigned char subdev_id)
+{
+	return (subdev_id == MTKCAM_SUBDEV_RAW_0 ||
+		subdev_id == MTKCAM_SUBDEV_RAW_1 ||
+		subdev_id == MTKCAM_SUBDEV_RAW_2);
+}
+
+enum mtkcam_pipe_dev {
+	MTKCAM_PIPE_RAW_A	= 0,
+	MTKCAM_PIPE_RAW_B,
+	MTKCAM_PIPE_RAW_C,
+	MTKCAM_PIPE_MAX
+};
+
+enum mtkcam_ISP_video_id {
+	MTKCAM_ISP_ID_UNKNOWN	= 0,
+	MTKCAM_ISP_RAWI_2,		/* RAWI_R2 */
+	MTKCAM_ISP_RAWI_3,		/* RAWI_R3 */
+	MTKCAM_ISP_RAWI_5,		/* RAWI_R5 */
+	MTKCAM_ISP_RAWI_6,		/* RAWI_R6 */
+	MTKCAM_ISP_IMGO,		/* IMGO_R1 */
+	MTKCAM_ISP_UFEO,		/* UFEO_R1 */
+	MTKCAM_ISP_RRZO,		/* RRZO_R1 */
+	MTKCAM_ISP_UFGO,		/* UFGO_R1 */
+	MTKCAM_ISP_YUVO_1,		/* YUVO_R1 */
+	MTKCAM_ISP_YUVO_2,		/* YUVO_R2 */
+	MTKCAM_ISP_YUVO_3,		/* YUVO_R3 */
+	MTKCAM_ISP_YUVO_4,		/* YUVO_R4 */
+	MTKCAM_ISP_YUVO_5,		/* YUVO_R5 */
+	MTKCAM_ISP_RZH1N2TO_2,	/* RZH1N2TO_R2 */
+	MTKCAM_ISP_DRZS4NO_1,	/* DRZS4NO_R1 */
+	MTKCAM_ISP_DRZS4NO_2,	/* DRZS4NO_R2 */
+	MTKCAM_ISP_DRZS4NO_3,	/* DRZS4NO_R3 */
+	MTKCAM_ISP_RZH1N2TO_3,	/* RZH1N2TO_R3 */
+	MTKCAM_ISP_RZH1N2TO_1,	/* RZH1N2TO_R1 */
+	MTKCAM_ISP_META_STATS_CFG,	/* All settings */
+	MTKCAM_ISP_META_STATS_0,	/* statistics */
+
+	/*
+	 * MTKCAM_ISP_META_STATS_1 is for AFO only, the buffer can be
+	 * dequeued once we got the  dma done.
+	 */
+	MTKCAM_ISP_META_STATS_1,
+
+	/* statistics may be pass to DIP */
+	MTKCAM_ISP_META_STATS_2,
+	MTKCAM_ISP_ID_MAX,
+};
+
+/* Supported bayer pixel order */
+enum mtkcam_ipi_bayer_pxl_id {
+	MTKCAM_IPI_BAYER_PXL_ID_B		= 0,
+	MTKCAM_IPI_BAYER_PXL_ID_GB		= 1,
+	MTKCAM_IPI_BAYER_PXL_ID_GR		= 2,
+	MTKCAM_IPI_BAYER_PXL_ID_R		= 3,
+	MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN		= 4,
+};
+
+/* special input patterns */
+enum mtkcam_ipi_sensor_pattern {
+	MTKCAM_IPI_SENSOR_PATTERN_NORMAL		= 0,
+	MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX		= 1,
+	MTKCAM_IPI_SENSOR_PATTERN_QUADCODE		= 2,
+	MTKCAM_IPI_SENSOR_PATTERN_4CELL			= 3,
+	MTKCAM_IPI_SENSOR_PATTERN_MONO			= 4,
+	MTKCAM_IPI_SENSOR_PATTERN_IVHDR			= 5,
+	MTKCAM_IPI_SENSOR_PATTERN_ZVHDR			= 6,
+	MTKCAM_IPI_SENSOR_PATTERN_4CELL_IVHDR		= 7,
+	MTKCAM_IPI_SENSOR_PATTERN_4CELL_ZVHDR		= 8,
+	MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX_IVHDR	= 9,
+	MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX_ZVHDR	= 10,
+	MTKCAM_IPI_SENSOR_PATTERN_YUV			= 11,
+	MTKCAM_IPI_SENSOR_PATTERN_NORMAL_PD		= 12,
+};
+
+enum mtkcam_ISP_path_control {
+	MTKCAM_IPI_IMGO_UNPROCESSED		= 0,
+	MTKCAM_IPI_IMGO_AFTER_BPC,
+	MTKCAM_IPI_IMGO_AFTER_FRZ,
+	MTKCAM_IPI_IMGO_AFTER_FUS,
+	MTKCAM_IPI_IMGO_AFTER_DGN,
+	MTKCAM_IPI_IMGO_AFTER_LSC,
+	MTKCAM_IPI_IMGO_AFTER_HLR,
+	MTKCAM_IPI_IMGO_AFTER_LTM,
+	MTKCAM_IPI_IMGO_FULLY_PROCESSED = MTKCAM_IPI_IMGO_AFTER_LTM,
+};
+
+/* For LBIT_MODE G2 */
+enum mtkcam_ipi_sw_feature_control {
+	MTKCAM_IPI_SW_FEATURE_NORMAL		= 0,
+	/* Normal */
+};
+
+enum mtkcam_ipi_hw_path_control {
+	MTKCAM_IPI_HW_PATH_ON_THE_FLY			= 0,
+	/* TG direct link */
+	MTKCAM_IPI_HW_PATH_ON_THE_FLY_M2M		= 1,
+	/* On device tuning */
+	MTKCAM_IPI_HW_PATH_OFFLINE_M2M			= 7,
+	/* SW trigger rawi */
+};
+
+enum mtkcam_ipi_meta_valid_num_control {
+	MTKCAM_IPI_FBCX_AAO = 0,
+	MTKCAM_IPI_FBCX_AAHO,
+	MTKCAM_IPI_FBCX_AFO,
+	MTKCAM_IPI_FBCX_TSFSO_1,
+	MTKCAM_IPI_FBCX_TSFSO_2,
+	MTKCAM_IPI_FBCX_LTMSO,
+	MTKCAM_IPI_FBCX_FLKO,
+	MTKCAM_IPI_FBCX_ACTSO,
+	MTKCAM_IPI_FBCX_PDO,
+	MTKCAM_IPI_FBCX_TNCSYO,
+	MTKCAM_IPI_FBCX_RZH1N2TO_R1,
+	MTKCAM_IPI_FBCX_RZH1N2TO_R2,
+	MTKCAM_IPI_FBCX_RZH1N2TO_R3,
+};
+
+enum {
+	BIN_AUTO	= 0,
+	BIN_OFF		= BIN_AUTO,
+	BIN_ON		= (1 << 0),
+	CBN_2X2_ON	= (1 << 4),
+	CBN_3X3_ON	= (1 << 5),
+	CBN_4X4_ON	= (1 << 6),
+	QBND_ON		= (1 << 8)
+};
+
+#endif /* __MTKCAM_DEFS_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h
new file mode 100755
index 000000000000..2eb54a2332ef
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTKCAM_FMT_H
+#define __MTKCAM_FMT_H
+
+/* camsys supported format */
+enum mtkcam_ipi_fmt {
+	MTKCAM_IPI_IMG_FMT_UNKNOWN		= -1,
+	MTKCAM_IPI_IMG_FMT_BAYER8		= 0,
+	MTKCAM_IPI_IMG_FMT_BAYER10		= 1,
+	MTKCAM_IPI_IMG_FMT_BAYER12		= 2,
+	MTKCAM_IPI_IMG_FMT_BAYER14		= 3,
+	MTKCAM_IPI_IMG_FMT_BAYER16		= 4,
+	MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED	= 5,
+	MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED	= 6,
+	MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED	= 7,
+	MTKCAM_IPI_IMG_FMT_RGB565		= 8,
+	MTKCAM_IPI_IMG_FMT_RGB888		= 9,
+	MTKCAM_IPI_IMG_FMT_JPEG			= 10,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER8		= 11,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER10		= 12,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER12		= 13,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER14		= 14,
+	MTKCAM_IPI_IMG_FMT_YUYV			= 15,
+	MTKCAM_IPI_IMG_FMT_YVYU			= 16,
+	MTKCAM_IPI_IMG_FMT_UYVY			= 17,
+	MTKCAM_IPI_IMG_FMT_VYUY			= 18,
+	MTKCAM_IPI_IMG_FMT_YUV_422_2P		= 19,
+	MTKCAM_IPI_IMG_FMT_YVU_422_2P		= 20,
+	MTKCAM_IPI_IMG_FMT_YUV_422_3P		= 21,
+	MTKCAM_IPI_IMG_FMT_YVU_422_3P		= 22,
+	MTKCAM_IPI_IMG_FMT_YUV_420_2P		= 23,
+	MTKCAM_IPI_IMG_FMT_YVU_420_2P		= 24,
+	MTKCAM_IPI_IMG_FMT_YUV_420_3P		= 25,
+	MTKCAM_IPI_IMG_FMT_YVU_420_3P		= 26,
+	MTKCAM_IPI_IMG_FMT_Y8			= 27,
+	MTKCAM_IPI_IMG_FMT_YUYV_Y210		= 28,
+	MTKCAM_IPI_IMG_FMT_YVYU_Y210		= 29,
+	MTKCAM_IPI_IMG_FMT_UYVY_Y210		= 30,
+	MTKCAM_IPI_IMG_FMT_VYUY_Y210		= 31,
+	MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED	= 32,
+	MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED	= 33,
+	MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED	= 34,
+	MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED	= 35,
+	MTKCAM_IPI_IMG_FMT_YUV_P210		= 36,
+	MTKCAM_IPI_IMG_FMT_YVU_P210		= 37,
+	MTKCAM_IPI_IMG_FMT_YUV_P010		= 38,
+	MTKCAM_IPI_IMG_FMT_YVU_P010		= 39,
+	MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED	= 40,
+	MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED	= 41,
+	MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED	= 42,
+	MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED	= 43,
+	MTKCAM_IPI_IMG_FMT_YUV_P212		= 44,
+	MTKCAM_IPI_IMG_FMT_YVU_P212		= 45,
+	MTKCAM_IPI_IMG_FMT_YUV_P012		= 46,
+	MTKCAM_IPI_IMG_FMT_YVU_P012		= 47,
+	MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED	= 48,
+	MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED	= 49,
+	MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED	= 50,
+	MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED	= 51,
+	MTKCAM_IPI_IMG_FMT_RGB_8B_3P		= 52,
+	MTKCAM_IPI_IMG_FMT_RGB_10B_3P		= 53,
+	MTKCAM_IPI_IMG_FMT_RGB_12B_3P		= 54,
+	MTKCAM_IPI_IMG_FMT_RGB_10B_3P_PACKED	= 55,
+	MTKCAM_IPI_IMG_FMT_RGB_12B_3P_PACKED	= 56,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P		= 57,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P	= 58,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P	= 59,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED	= 60,
+	MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED	= 61,
+	MTKCAM_IPI_IMG_FMT_UFBC_NV12		= 62,
+	MTKCAM_IPI_IMG_FMT_UFBC_NV21		= 63,
+	MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010	= 64,
+	MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010	= 65,
+	MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012	= 66,
+	MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012	= 67,
+	MTKCAM_IPI_IMG_FMT_UFBC_BAYER8		= 68,
+	MTKCAM_IPI_IMG_FMT_UFBC_BAYER10		= 69,
+	MTKCAM_IPI_IMG_FMT_UFBC_BAYER12		= 70,
+	MTKCAM_IPI_IMG_FMT_UFBC_BAYER14		= 71,
+	MTKCAM_IPI_IMG_FMT_BAYER10_MIPI		= 72
+};
+
+#endif /* __MTKCAM_FMT_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h
new file mode 100755
index 000000000000..68a4fa54efad
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_IPI_H__
+#define __MTK_CAM_IPI_H__
+
+#include <linux/types.h>
+#include "mtk_cam-defs.h"
+
+#define MTK_CAM_MAX_RUNNING_JOBS	(3)
+#define CAM_MAX_PLANENUM		(3)
+#define CAM_MAX_SUBSAMPLE		(32)
+#define MTK_CAM_MAX_PROCESSING_BUFS	(2)
+
+/*
+ * struct mtkcam_ipi_point - Point
+ *
+ * @x: x-coordinate of the point (zero-based).
+ * @y: y-coordinate of the point (zero-based).
+ */
+struct mtkcam_ipi_point {
+	u16 x;
+	u16 y;
+} __packed;
+
+/*
+ * struct mtkcam_ipi_size - Size
+ *
+ * @w: width (in pixels).
+ * @h: height (in pixels).
+ */
+struct mtkcam_ipi_size {
+	u16 w;
+	u16 h;
+} __packed;
+
+/*
+ * struct mtkcam_ipi_fract - fraction
+ *
+ * @numerator: numerator part of the fraction.
+ * @denominator: denominator part of the fraction.
+ */
+struct mtkcam_ipi_fract {
+	u8 numerator;
+	u8 denominator;
+};
+
+/*
+ * struct mtkcam_ipi_sw_buffer
+ *	- Shared buffer between cam-device and co-processor.
+ *
+ * @iova: DMA address for CAM DMA device. isp7_1: u64.
+ * @scp_addr: SCP address for external co-processor unit.
+ * @size: buffer size.
+ */
+struct mtkcam_ipi_sw_buffer {
+	u64 iova;
+	u32 scp_addr;
+	u32 size;
+} __packed;
+
+struct mtkcam_ipi_pix_fmt {
+	u32	format;
+	struct mtkcam_ipi_size	s;
+	u16	stride[CAM_MAX_PLANENUM];
+} __packed;
+
+struct mtkcam_ipi_crop {
+	struct mtkcam_ipi_point p;
+	struct mtkcam_ipi_size s;
+} __packed;
+
+struct mtkcam_ipi_uid {
+	u8 pipe_id;
+	u8 id;
+} __packed;
+
+struct mtkcam_ipi_img_input {
+	struct mtkcam_ipi_uid		uid;
+	struct mtkcam_ipi_pix_fmt	fmt;
+	struct mtkcam_ipi_sw_buffer	buf[CAM_MAX_PLANENUM];
+} __packed;
+
+struct mtkcam_ipi_img_output {
+	struct mtkcam_ipi_uid		uid;
+	struct mtkcam_ipi_pix_fmt	fmt;
+	struct mtkcam_ipi_sw_buffer	buf[CAM_MAX_SUBSAMPLE][CAM_MAX_PLANENUM];
+	struct mtkcam_ipi_crop		crop;
+} __packed;
+
+struct mtkcam_ipi_meta_input {
+	struct mtkcam_ipi_uid		uid;
+	struct mtkcam_ipi_sw_buffer	buf;
+} __packed;
+
+struct mtkcam_ipi_meta_output {
+	struct mtkcam_ipi_uid		uid;
+	struct mtkcam_ipi_sw_buffer	buf;
+} __packed;
+
+struct mtkcam_ipi_input_param {
+	u32	fmt;
+	u8	raw_pixel_id;
+	u8	data_pattern;
+	u8	pixel_mode;
+	u8	subsample;
+	struct mtkcam_ipi_crop in_crop;
+} __packed;
+
+struct mtkcam_ISP_frame_param {
+	u8	imgo_path_sel; /* mtkcam_ISP_path_control */
+	u8	hardware_scenario;
+	u32	bin_flag;
+	u8    exposure_num;
+	u8    previous_exposure_num;
+	struct mtkcam_ipi_fract	frz_ratio;
+} __packed;
+
+struct mtkcam_ipi_session_cookie {
+	u8 session_id;
+	u32 frame_no;
+} __packed;
+
+struct mtkcam_ipi_session_param {
+	struct mtkcam_ipi_sw_buffer workbuf;
+	struct mtkcam_ipi_sw_buffer msg_buf;
+	struct mtkcam_ipi_sw_buffer raw_workbuf;
+	struct mtkcam_ipi_sw_buffer priv_workbuf;
+	struct mtkcam_ipi_sw_buffer session_buf;
+} __packed;
+
+struct mtkcam_ipi_hw_mapping {
+	u8 pipe_id; /* ref. to mtkcam_pipe_subdev */
+	u16 dev_mask; /* ref. to mtkcam_pipe_dev */
+} __packed;
+
+/*  Control flags of CAM_CMD_CONFIG */
+#define MTK_CAM_IPI_CONFIG_TYPE_INIT			0x0001
+#define MTK_CAM_IPI_CONFIG_TYPE_INPUT_CHANGE		0x0002
+
+struct mtkcam_ipi_config_param {
+	u8	flags;
+	struct mtkcam_ipi_input_param	input;
+	/* maximum # of pipes per stream */
+	struct mtkcam_ipi_hw_mapping maps[6];
+	/* sub_ratio:8, valid number: 8 */
+	u8	sw_feature;
+} __packed;
+
+#define CAM_MAX_IMAGE_INPUT	(5)
+#define CAM_MAX_IMAGE_OUTPUT	(15)
+#define CAM_MAX_META_OUTPUT	(4)
+#define CAM_MAX_PIPE_USED	(4)
+
+struct mtkcam_ipi_frame_param {
+	u32 cur_workbuf_offset;
+	u32 cur_workbuf_size;
+
+	struct mtkcam_ISP_frame_param raw_param;
+	struct mtkcam_ipi_img_input img_ins[CAM_MAX_IMAGE_INPUT];
+	struct mtkcam_ipi_img_output img_outs[CAM_MAX_IMAGE_OUTPUT];
+	struct mtkcam_ipi_meta_output meta_outputs[CAM_MAX_META_OUTPUT];
+	struct mtkcam_ipi_meta_input meta_inputs[CAM_MAX_PIPE_USED];
+} __packed;
+
+struct mtkcam_ipi_frame_info {
+	u32	cur_msgbuf_offset;
+	u32	cur_msgbuf_size;
+} __packed;
+
+struct mtkcam_ipi_frame_ack_result {
+	u32	cq_desc_offset;
+	u32	sub_cq_desc_offset;
+	u32	cq_desc_size;
+	u32	sub_cq_desc_size;
+} __packed;
+
+struct mtkcam_ipi_ack_info {
+	u8	ack_cmd_id;
+	s32	ret;
+	struct mtkcam_ipi_frame_ack_result frame_result;
+} __packed;
+
+/*
+ * The IPI command enumeration.
+ */
+enum mtkcam_ipi_cmds {
+	/* request for a new streaming: mtkcam_ipi_session_param */
+	CAM_CMD_CREATE_SESSION,
+	/* config the stream: mtkcam_ipi_config_param */
+	CAM_CMD_CONFIG,
+	/* per-frame: mtkcam_ipi_frame_param */
+	CAM_CMD_FRAME,
+	/* release certain streaming: mtkcam_ipi_session_param */
+	CAM_CMD_DESTROY_SESSION,
+	/* ack: mtkcam_ipi_ack_info */
+	CAM_CMD_ACK,
+};
+
+struct mtkcam_ipi_event  {
+	struct mtkcam_ipi_session_cookie cookie;
+	u8 cmd_id;
+	union {
+		struct mtkcam_ipi_session_param	session_data;
+		struct mtkcam_ipi_config_param	config_data;
+		struct mtkcam_ipi_frame_info	frame_data;
+		struct mtkcam_ipi_ack_info	ack_data;
+	};
+} __packed;
+
+#endif /* __MTK_CAM_IPI_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h
new file mode 100755
index 000000000000..3e8d23aed31d
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h
@@ -0,0 +1,2296 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_META_H__
+#define __MTK_CAM_META_H__
+
+/*
+ * struct mtk_cam_uapi_meta_rect - rect info
+ *
+ * @left: The X coordinate of the left side of the rectangle
+ * @top:  The Y coordinate of the left side of the rectangle
+ * @width:  The width of the rectangle
+ * @height: The height of the rectangle
+ *
+ * rect containing the width and height fields.
+ *
+ */
+struct mtk_cam_uapi_meta_rect {
+	s32 left;
+	s32 top;
+	u32 width;
+	u32 height;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_meta_size - size info
+ *
+ * @width:  The width of the size
+ * @height: The height of the size
+ *
+ * size containing the width and height fields.
+ *
+ */
+struct mtk_cam_uapi_meta_size {
+	u32 width;
+	u32 height;
+} __packed;
+
+/*
+ *  A U T O  E X P O S U R E
+ */
+
+/*
+ *  struct mtk_cam_uapi_ae_hist_cfg - histogram info for AE
+ *
+ *  @hist_en:    enable bit for current histogram, each histogram can
+ *      be 0/1 (disabled/enabled) separately
+ *  @hist_opt:   color mode config for current histogram (0/1/2/3/4:
+ *      R/G/B/RGB mix/Y)
+ *  @hist_bin:   bin mode config for current histogram (1/4: 256/1024 bin)
+ *  @hist_y_hi:  ROI Y range high bound for current histogram
+ *  @hist_y_low: ROI Y range low bound for current histogram
+ *  @hist_x_hi:  ROI X range high bound for current histogram
+ *  @hist_x_low: ROI X range low bound for current histogram
+ */
+struct mtk_cam_uapi_ae_hist_cfg {
+	s32 hist_en;
+	u8 hist_opt;
+	u8 hist_bin;
+	u16 hist_y_hi;
+	u16 hist_y_low;
+	u16 hist_x_hi;
+	u16 hist_x_low;
+	u16 rsv;
+} __packed;
+
+#define MTK_CAM_UAPI_ROI_MAP_BLK_NUM (128 * 128)
+/*
+ *  struct mtk_cam_uapi_ae_param - parameters for AE configurtion
+ *
+ *  @pixel_hist_win_cfg_le: window config for le histogram 0~5
+ *           separately, uAEHistBin shold be the same
+ *           for these 6 histograms
+ *  @pixel_hist_win_cfg_se: window config for se histogram 0~5
+ *           separately, uAEHistBin shold be the same
+ *           for these 6 histograms
+ *  @roi_hist_cfg_le : config for roi le histogram 0~3
+ *           color mode/enable
+ *  @roi_hist_cfg_se : config for roi se histogram 0~3
+ *           color mode/enable
+ *  @hdr_ratio: in HDR scenario, AE calculated hdr ratio
+ *           (LE exp*iso/SE exp*iso*100) for current frame,
+ *           default non-HDR scenario ratio=1000
+ */
+struct mtk_cam_uapi_ae_param {
+	struct mtk_cam_uapi_ae_hist_cfg pixel_hist_win_cfg_le[6];
+	struct mtk_cam_uapi_ae_hist_cfg pixel_hist_win_cfg_se[6];
+	struct mtk_cam_uapi_ae_hist_cfg roi_hist_cfg_le[4];
+	struct mtk_cam_uapi_ae_hist_cfg roi_hist_cfg_se[4];
+	u8  aai_r1_enable;
+	u8  aai_roi_map[MTK_CAM_UAPI_ROI_MAP_BLK_NUM];
+	u8  rsv;
+	u16 hdr_ratio; /* base 1 x= 1000 */
+	u32 act_win_x_start;
+	u32 act_win_x_end;
+	u32 act_win_y_start;
+	u32 act_win_y_end;
+} __packed;
+
+/*
+ *  A U T O  W H I T E  B A L A N C E
+ */
+
+/* Maximum blocks that Mediatek AWB supports */
+#define MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM (10)
+
+/*
+ *  struct mtk_cam_uapi_awb_param - parameters for AWB configurtion
+ *
+ *  @stat_en:                  AWB stat enable
+ *  @windownum_y:              Number of vertical AWB windows
+ *  @lowthreshold_r:           Low threshold of R
+ *  @lowthreshold_g:           Low threshold of G
+ *  @lowthreshold_b:           Low threshold of B
+ *  @highthreshold_r:          High threshold of R
+ *  @highthreshold_g:          High threshold of G
+ *  @highthreshold_b:          High threshold of B
+ *  @lightsrc_lowthreshold_r:  Low threshold of R for light source estimation
+ *  @lightsrc_lowthreshold_g:  Low threshold of G for light source estimation
+ *  @lightsrc_lowthreshold_b:  Low threshold of B for light source estimation
+ *  @lightsrc_highthreshold_r: High threshold of R for light source estimation
+ *  @lightsrc_highthreshold_g: High threshold of G for light source estimation
+ *  @lightsrc_highthreshold_b: High threshold of B for light source estimation
+ *  @pregainlimit_r:           Maximum limit clipping for R color
+ *  @pregainlimit_g:           Maximum limit clipping for G color
+ *  @pregainlimit_b:           Maximum limit clipping for B color
+ *  @pregain_r:                unit module compensation gain for R color
+ *  @pregain_g:                unit module compensation gain for G color
+ *  @pregain_b:                unit module compensation gain for B color
+ *  @valid_datawidth:          valid bits of statistic data
+ *  @hdr_support_en:           support HDR mode
+ *  @stat_mode:                Output format select <1>sum mode <0>average mode
+ *  @error_ratio:              Programmable error pixel count by AWB window size
+ *              (base : 256)
+ *  @awbxv_win_r:              light area of right bound, the size is defined in
+ *              MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM
+ *  @awbxv_win_l:              light area of left bound the size is defined in
+ *              MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM
+ *  @awbxv_win_d:              light area of lower bound the size is defined in
+ *              MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM
+ *  @awbxv_win_u:              light area of upper bound the size is defined in
+ *              MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM
+ *  @pregain2_r:               white balance gain of R color
+ *  @pregain2_g:               white balance gain of G color
+ *  @pregain2_b:               white balance gain of B color
+ */
+struct mtk_cam_uapi_awb_param {
+	u32 stat_en;
+	u32 windownum_y;
+	u32 lowthreshold_r;
+	u32 lowthreshold_g;
+	u32 lowthreshold_b;
+	u32 highthreshold_r;
+	u32 highthreshold_g;
+	u32 highthreshold_b;
+	u32 lightsrc_lowthreshold_r;
+	u32 lightsrc_lowthreshold_g;
+	u32 lightsrc_lowthreshold_b;
+	u32 lightsrc_highthreshold_r;
+	u32 lightsrc_highthreshold_g;
+	u32 lightsrc_highthreshold_b;
+	u32 pregainlimit_r;
+	u32 pregainlimit_g;
+	u32 pregainlimit_b;
+	u32 pregain_r;
+	u32 pregain_g;
+	u32 pregain_b;
+	u32 valid_datawidth;
+	u32 hdr_support_en;
+	u32 stat_mode;
+	u32 format_shift;
+	u32 error_ratio;
+	u32 postgain_r;
+	u32 postgain_g;
+	u32 postgain_b;
+	u32 postgain2_hi_r;
+	u32 postgain2_hi_g;
+	u32 postgain2_hi_b;
+	u32 postgain2_med_r;
+	u32 postgain2_med_g;
+	u32 postgain2_med_b;
+	u32 postgain2_low_r;
+	u32 postgain2_low_g;
+	u32 postgain2_low_b;
+	s32 awbxv_win_r[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM];
+	s32 awbxv_win_l[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM];
+	s32 awbxv_win_d[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM];
+	s32 awbxv_win_u[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM];
+	u32 csc_ccm[9];
+	u32 acc;
+	u32 med_region[4];
+	u32 low_region[4];
+	u32 pregain2_r;
+	u32 pregain2_g;
+	u32 pregain2_b;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_dgn_param
+ *
+ *  @gain: digital gain to increase image brightness, 1 x= 1024
+ */
+struct mtk_cam_uapi_dgn_param {
+	u32 gain;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_wb_param
+ *
+ *  @gain_r: white balance gain of R channel
+ *  @gain_g: white balance gain of G channel
+ *  @gain_b: white balance gain of B channel
+ */
+struct mtk_cam_uapi_wb_param {
+	u32 gain_r;
+	u32 gain_g;
+	u32 gain_b;
+	u32 clip;
+} __packed;
+
+/*
+ *  A U T O  F O C U S
+ */
+
+/*
+ * struct mtk_cam_uapi_af_param - af statistic parameters
+ *  @roi: AF roi rectangle (in pixel) for AF statistic covered, including
+ *    x, y, width, height
+ *  @th_sat_g:  green channel pixel value saturation threshold (0~255)
+ *  @th_h[3]: horizontal AF filters response threshold (0~50) for H0, H1,
+ *    and H2
+ *  @th_v:  vertical AF filter response threshold (0~50)
+ *  @blk_pixel_xnum: horizontal number of pixel per block
+ *  @blk_pixel_ynum: vertical number of pixel per block
+ *  @fir_type: to select FIR filter by AF target type (0,1,2,3)
+ *  @iir_type: to select IIR filter by AF target type (0,1,2,3)
+ *  @data_gain[7]: gamma curve gain for AF source data
+ */
+struct mtk_cam_uapi_af_param {
+	struct mtk_cam_uapi_meta_rect roi;
+	u32 th_sat_g;
+	u32 th_h[3];
+	u32 th_v;
+	u32 blk_pixel_xnum;
+	u32 blk_pixel_ynum;
+	u32 fir_type;
+	u32 iir_type;
+	u32 data_gain[7];
+} __packed;
+
+enum mtk_cam_uapi_flk_hdr_path_control {
+	MTKCAM_UAPI_FKLO_HDR_1ST_FRAME = 0,
+	MTKCAM_UAPI_FKLO_HDR_2ND_FRAME,
+	MTKCAM_UAPI_FKLO_HDR_3RD_FRAME,
+} __packed;
+
+/*
+ *  struct mtk_cam_uapi_flk_param
+ *
+ *  @input_bit_sel: maximum pixel value of flicker statistic input
+ *  @offset_y: initial position for flicker statistic calculation in y direction
+ *  @crop_y: number of rows which will be cropped from bottom
+ *  @sgg_val[8]: Simple Gain and Gamma for noise reduction, sgg_val[0] is
+ *               gain and sgg_val[1] - sgg_val[7] are gamma table
+ *  @noise_thr: the noise threshold of pixel value, pixel value lower than
+ *              this value is considered as noise
+ *  @saturate_thr: the saturation threshold of pixel value, pixel value
+ *                 higher than this value is considered as saturated
+ *  @hdr_flk_src: flk source tap point selection
+ */
+struct mtk_cam_uapi_flk_param {
+	u32 input_bit_sel;
+	u32 offset_y;
+	u32 crop_y;
+	u32 sgg_val[8];
+	u32 noise_thr;
+	u32 saturate_thr;
+	u32 hdr_flk_src;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tsf_param
+ *
+ *  @horizontal_num: block number of horizontal direction
+ *  @vertical_num:   block number of vertical direction
+ */
+struct mtk_cam_uapi_tsf_param {
+	u32 horizontal_num;
+	u32 vertical_num;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_pde_param
+ *
+ * @pdi_max_size: the max required memory size for pd table
+ * @pdo_max_size: the max required memory size for pd point output
+ * @pdo_x_size: the pd points out x size
+ * @pdo_y_size: the pd points out y size
+ * @pd_table_offset: the offset of pd table in the meta_cfg
+ */
+struct mtk_cam_uapi_pde_param {
+	u32 pdi_max_size;
+	u32 pdo_max_size;
+	u32 pdo_x_size;
+	u32 pdo_y_size;
+	u32 pd_table_offset;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_meta_hw_buf - hardware buffer info
+ *
+ * @offset: offset from the start of the device memory associated to the
+ *    v4l2 meta buffer
+ * @size: size of the buffer
+ *
+ * Some part of the meta buffers are read or written by statistic related
+ * hardware DMAs. The hardware buffers may have different size among
+ * difference pipeline.
+ */
+struct mtk_cam_uapi_meta_hw_buf {
+	u32 offset;
+	u32 size;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_pdp_stats - statistics of pd
+ *
+ * @stats_src:     source width and heitgh of the statistics.
+ * @stride:     stride value used by
+ * @pdo_buf:     The buffer for PD statistic hardware output.
+ *
+ * This is the PD statistic returned to user.
+ */
+struct mtk_cam_uapi_pdp_stats {
+	struct  mtk_cam_uapi_meta_size stats_src;
+	u32   stride;
+	struct  mtk_cam_uapi_meta_hw_buf pdo_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_cpi_stats - statistics of pd
+ *
+ * @stats_src:     source width and heitgh of the statistics.
+ * @stride:     stride value used by
+ * @pdo_buf:     The buffer for PD statistic hardware output.
+ *
+ * This is the PD statistic returned to user.
+ */
+struct mtk_cam_uapi_cpi_stats {
+	struct  mtk_cam_uapi_meta_size stats_src;
+	u32   stride;
+	struct  mtk_cam_uapi_meta_hw_buf cpio_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_mqe_param
+ *
+ * @mqe_mode:
+ */
+struct mtk_cam_uapi_mqe_param {
+	u32 mqe_mode;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_mobc_param
+ *
+ *
+ */
+struct mtk_cam_uapi_mobc_param {
+	u32 mobc_offst0;
+	u32 mobc_offst1;
+	u32 mobc_offst2;
+	u32 mobc_offst3;
+	u32 mobc_gain0;
+	u32 mobc_gain1;
+	u32 mobc_gain2;
+	u32 mobc_gain3;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_lsc_param
+ *
+ *
+ */
+struct mtk_cam_uapi_lsc_param {
+	u32 lsc_ctl1;
+	u32 lsc_ctl2;
+	u32 lsc_ctl3;
+	u32 lsc_lblock;
+	u32 lsc_fblock;
+	u32 lsc_ratio;
+	u32 lsc_tpipe_ofst;
+	u32 lsc_tpipe_size;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_sgg_param
+ *
+ *
+ */
+struct mtk_cam_uapi_sgg_param {
+	u32 sgg_pgn;
+	u32 sgg_gmrc_1;
+	u32 sgg_gmrc_2;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_mbn_param
+ *
+ *
+ */
+struct mtk_cam_uapi_mbn_param {
+	u32 mbn_pow;
+	u32 mbn_dir;
+	u32 mbn_spar_hei;
+	u32 mbn_spar_pow;
+	u32 mbn_spar_fac;
+	u32 mbn_spar_con1;
+	u32 mbn_spar_con0;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_cpi_param
+ *
+ *
+ */
+struct mtk_cam_uapi_cpi_param {
+	u32 cpi_th;
+	u32 cpi_pow;
+	u32 cpi_dir;
+	u32 cpi_spar_hei;
+	u32 cpi_spar_pow;
+	u32 cpi_spar_fac;
+	u32 cpi_spar_con1;
+	u32 cpi_spar_con0;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_lsci_param
+ *
+ *
+ */
+struct mtk_cam_uapi_lsci_param {
+	u32 lsci_xsize;
+	u32 lsci_ysize;
+} __packed;
+
+/*
+ * Common stuff for all statistics
+ */
+
+#define MTK_CAM_UAPI_MAX_CORE_NUM (2)
+
+/*
+ * struct mtk_cam_uapi_pipeline_config - pipeline configuration
+ *
+ * @num_of_core: The number of isp cores
+ */
+struct mtk_cam_uapi_pipeline_config {
+	u32	num_of_core;
+	struct	mtk_cam_uapi_meta_size core_data_size;
+	u32	core_pxl_mode_lg2;
+} __packed;
+
+/*
+ *  A U T O  E X P O S U R E
+ */
+
+/* please check the size of MTK_CAM_AE_HIST_MAX_BIN*/
+#define MTK_CAM_UAPI_AE_STATS_HIST_MAX_BIN (1024)
+
+/*
+ *  A E  A N D   A W B
+ */
+
+#define MTK_CAM_UAPI_AAO_BLK_SIZE (32)
+#define MTK_CAM_UAPI_AAO_MAX_BLK_X (128)
+#define MTK_CAM_UAPI_AAO_MAX_BLK_Y (128)
+#define MTK_CAM_UAPI_AAO_MAX_BUF_SIZE (MTK_CAM_UAPI_AAO_BLK_SIZE \
+					* MTK_CAM_UAPI_AAO_MAX_BLK_X \
+					* MTK_CAM_UAPI_AAO_MAX_BLK_Y)
+
+#define MTK_CAM_UAPI_AHO_BLK_SIZE (3)
+#define MTK_CAM_UAPI_AAHO_HIST_SIZE  (6 * 1024 * MTK_CAM_UAPI_AHO_BLK_SIZE \
+					+ 14 * 256 * MTK_CAM_UAPI_AHO_BLK_SIZE)
+#define MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE  (MTK_CAM_UAPI_MAX_CORE_NUM * \
+					MTK_CAM_UAPI_AAHO_HIST_SIZE)
+
+/*
+ * struct mtk_cam_uapi_ae_awb_stats - statistics of ae and awb
+ *
+ * @aao_buf:       The buffer for AAHO statistic hardware output.
+ *        The maximum size of the buffer is defined with
+ *        MTK_CAM_UAPI_AAO_MAX_BUF_SIZE
+ * @aaho_buf:      The buffer for AAHO statistic hardware output.
+ *        The maximum size of the buffer is defined with
+ *        MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE.
+ *
+ * This is the AE and AWB statistic returned to user. From  our hardware's
+ * point of view, we can't separate the AE and AWB output result, so I use
+ * a struct to retutn them.
+ */
+struct mtk_cam_uapi_ae_awb_stats {
+	u32 awb_stat_en_status;
+	u32 awb_qbn_acc;
+	u32 ae_stat_en_status;
+	struct mtk_cam_uapi_meta_hw_buf aao_buf;
+	struct mtk_cam_uapi_meta_hw_buf aaho_buf;
+} __packed;
+
+/*
+ *  A U T O  F O C U S
+ */
+
+#define MTK_CAM_UAPI_AFO_BLK_SIZ    (32)
+#define MTK_CAM_UAPI_AFO_MAX_BLK_NUM (128 * 128)
+#define MTK_CAM_UAPI_AFO_MAX_BUF_SIZE   (MTK_CAM_UAPI_AFO_BLK_SIZ \
+						* MTK_CAM_UAPI_AFO_MAX_BLK_NUM)
+
+/*
+ * struct mtk_cam_uapi_af_stats - af statistics
+ *
+ * @blk_num_x: block number of horizontal direction
+ * @blk_num_y: block number of vertical direction
+ * @afo_buf:    the buffer for AAHO statistic hardware output. The maximum
+ *      size of the buffer is defined with
+ *      MTK_CAM_UAPI_AFO_MAX_BUF_SIZE.
+ */
+struct mtk_cam_uapi_af_stats {
+	u32 blk_num_x;
+	u32 blk_num_y;
+	struct mtk_cam_uapi_meta_hw_buf afo_buf;
+} __packed;
+
+/*
+ *  F L I C K E R
+ */
+
+/* FLK's hardware output block size: 64 bits */
+#define MTK_CAM_UAPI_FLK_BLK_SIZE (8)
+
+/* Maximum block size (each line) of Mediatek flicker statistic */
+#define MTK_CAM_UAPI_FLK_MAX_STAT_BLK_NUM (6)
+
+/* Maximum height (in pixel) that driver can support */
+#define MTK_CAM_UAPI_FLK_MAX_FRAME_HEIGHT (9000)
+#define MTK_CAM_UAPI_FLK_MAX_BUF_SIZE                              \
+	(MTK_CAM_UAPI_FLK_BLK_SIZE * MTK_CAM_UAPI_FLK_MAX_STAT_BLK_NUM * \
+	MTK_CAM_UAPI_FLK_MAX_FRAME_HEIGHT)
+
+/*
+ * struct mtk_cam_uapi_flk_stats
+ *
+ * @flko_buf: the buffer for FLKO statistic hardware output. The maximum
+ *         size of the buffer is defined with MTK_CAM_UAPI_FLK_MAX_BUF_SIZE.
+ */
+struct mtk_cam_uapi_flk_stats {
+	struct mtk_cam_uapi_meta_hw_buf flko_buf;
+} __packed;
+
+/*
+ *  T S F
+ */
+
+#define MTK_CAM_UAPI_TSFSO_SIZE (40 * 30 * 3 * 4)
+
+/*
+ * struct mtk_cam_uapi_tsf_stats - TSF statistic data
+ *
+ * @tsfo_buf: The buffer for tsf statistic hardware output. The buffer size
+ *        is defined in MTK_CAM_UAPI_TSFSO_SIZE.
+ *
+ * This output is for Mediatek proprietary algorithm
+ */
+struct mtk_cam_uapi_tsf_stats {
+	struct mtk_cam_uapi_meta_hw_buf tsfo_r1_buf;
+	struct mtk_cam_uapi_meta_hw_buf tsfo_r2_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_pd_stats - statistics of pd
+ *
+ * @stats_src:     source width and heitgh of the statistics.
+ * @stride:	   stride value used by
+ * @pdo_buf:	   The buffer for PD statistic hardware output.
+ *
+ * This is the PD statistic returned to user.
+ */
+struct mtk_cam_uapi_pd_stats {
+	struct	mtk_cam_uapi_meta_size stats_src;
+	u32	stride;
+	struct	mtk_cam_uapi_meta_hw_buf pdo_buf;
+} __packed;
+
+struct mtk_cam_uapi_timestamp {
+	u64 timestamp_buf[128];
+} __packed;
+
+/*
+ *  T O N E
+ */
+#define MTK_CAM_UAPI_LTMSO_SIZE ((37 * 12 * 9 + 258) * 8)
+#define MTK_CAM_UAPI_TNCSO_SIZE (680 * 510 * 2)
+#define MTK_CAM_UAPI_TNCSHO_SIZE (1544)
+#define MTK_CAM_UAPI_TNCSBO_SIZE (3888)
+#define MTK_CAM_UAPI_TNCSYO_SIZE (68)
+
+/*
+ * struct mtk_cam_uapi_ltm_stats - Tone1 statistic data for
+ *            Mediatek proprietary algorithm
+ *
+ * @ltmso_buf:  The buffer for ltm statistic hardware output. The buffer size
+ *    is defined in MTK_CAM_UAPI_LTMSO_SIZE.
+ * @blk_num_x: block number of horizontal direction
+ * @blk_num_y:  block number of vertical direction
+ *
+ * For Mediatek proprietary algorithm
+ */
+struct mtk_cam_uapi_ltm_stats {
+	struct mtk_cam_uapi_meta_hw_buf ltmso_buf;
+	u8  blk_num_x;
+	u8  blk_num_y;
+	u8  rsv[2];
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tnc_stats - Tone2 statistic data for
+ *                 Mediatek proprietary algorithm
+ *
+ * @tncso_buf: The buffer for tnc statistic hardware output. The buffer size
+ *           is defined in MTK_CAM_UAPI_TNCSO_SIZE (680*510*2)
+ */
+struct mtk_cam_uapi_tnc_stats {
+	struct mtk_cam_uapi_meta_hw_buf tncso_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tnch_stats - Tone3 statistic data for Mediatek
+ *                                  proprietary algorithm
+ *
+ * @tncsho_buf: The buffer for tnch statistic hardware output. The buffer size
+ *           is defined in MTK_CAM_UAPI_TNCSHO_SIZE (1544)
+ */
+struct mtk_cam_uapi_tnch_stats {
+	struct mtk_cam_uapi_meta_hw_buf tncsho_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tncb_stats - Tone4 statistic data for Mediatek
+ *                                  proprietary algorithm
+ *
+ * @tncsbo_buf: The buffer for tncb statistic hardware output. The buffer size
+ *           is defined in MTK_CAM_UAPI_TNCSBO_SIZE (3888)
+ */
+struct mtk_cam_uapi_tncb_stats {
+	struct mtk_cam_uapi_meta_hw_buf tncsbo_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tncy_stats - Tone3 statistic data for Mediatek
+ *                                  proprietary algorithm
+ *
+ * @tncsyo_buf: The buffer for tncy statistic hardware output. The buffer size
+ *           is defined in MTK_CAM_UAPI_TNCSYO_SIZE (68)
+ */
+struct mtk_cam_uapi_tncy_stats {
+	struct mtk_cam_uapi_meta_hw_buf tncsyo_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_act_stats - act statistic data for Mediatek
+ *                                  proprietary algorithm
+ *
+ * @actso_buf: The buffer for tncy statistic hardware output. The buffer size
+ *           is defined in MTK_CAM_UAPI_ACTSO_SIZE (768)
+ */
+#define MTK_CAM_UAPI_ACTSO_SIZE (768)
+struct mtk_cam_uapi_act_stats {
+	struct mtk_cam_uapi_meta_hw_buf actso_buf;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_awb_param_prot - AWB parameters
+ *
+ * @rot_cos: rotation matrix (cos part)
+ * @rot_sin: rotation matrix (sin part)
+ *
+ */
+struct mtk_cam_uapi_awb_param_prot {
+	s32 rot_cos;
+	s32 rot_sin;
+} __packed;
+
+/*
+ *  T U N I N G S
+ */
+
+/*
+ * struct mtk_cam_uapi_bpc_param_prot - BPC parameters
+ *
+ */
+#define MTK_CAM_BPCI_TABLE_SIZE (32)
+struct mtk_cam_uapi_bpc_param_prot {
+	u32 x_size;
+	u32 y_size;
+	u32 stride;
+
+	u8  table[MTK_CAM_BPCI_TABLE_SIZE];
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_drzs8t_param_prot
+ *
+ *  @tbl_shift: adjust the computed table
+ *  @tbl_min: use to limit the min table
+ */
+struct mtk_cam_uapi_drzs8t_param_prot {
+	u32 tbl_shift;
+	u32 tbl_min;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_lsc_param_prot - LSC parameters
+ *
+ */
+#define MTK_CAM_LSCI_TABLE_SIZE (32768)
+struct mtk_cam_uapi_lsc_param_prot {
+	u32 x_blk_num;
+	u32 y_blk_num;
+	u32 x_size;
+	u32 y_size;
+	u32 stride;
+	u8 table[MTK_CAM_LSCI_TABLE_SIZE];
+} __packed;
+
+/* *
+ * struct mtk_cam_uapi_slk_param_prot - slk tuning setting from userspace
+ *
+ */
+struct mtk_cam_uapi_slk_param_prot {
+	u32 center_x;
+	u32 center_y;
+	u32 radius_0;
+	u32 radius_1;
+	u32 radius_2;
+	u32 gain0;
+	u32 gain1;
+	u32 gain2;
+	u32 gain3;
+	u32 gain4;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_wb_param_prot - WB parameters
+ *
+ */
+struct mtk_cam_uapi_wb_param_prot {
+	u32 debug_info[39];
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_ltms_param_prot - LTMS parameters
+ *
+ *  @ratio_x_start: adjusted start point of width related to original width
+ *  @ratio_y_start: adjusted start point of height related to original height
+ *  @ratio_x_end: adjusted end point of width related to original width
+ *  @ratio_y_end: adjusted end point of height related to original height
+ */
+struct mtk_cam_uapi_ltms_param_prot {
+	u32 ltms_gamma_en;
+	u32 ratio_x_start;
+	u32 ratio_y_start;
+	u32 ratio_x_end;
+	u32 ratio_y_end;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_yuvo_param_prot - YUVO parameters
+ *
+ *  @drzh2n_fixed_down_ratio: down scale ratio
+ */
+struct mtk_cam_uapi_yuvo_param_prot {
+	u32 drzh2n_fixed_down_ratio;
+} __packed;
+/* The following sw setting are generated by script */
+/*
+ * struct mtk_cam_uapi_ccm_param_prot - CCM parameters *
+ */
+struct mtk_cam_uapi_ccm_param_prot {
+	u32 ccm_acc;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_drzh2n_param_prot - DRZH2N parameters *
+ */
+struct mtk_cam_uapi_drzh2n_param_prot {
+	u32 drzh2n_vert_tbl_sel;
+	u32 drzh2n_hori_tbl_sel;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_drzs4n_param_prot - DRZS4N parameters *
+ */
+struct mtk_cam_uapi_drzs4n_param_prot {
+	u32 drzs4n_vert_tbl_sel;
+	u32 drzs4n_hori_tbl_sel;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_tncs_param_prot - TNCS parameters *
+ */
+struct mtk_cam_uapi_tncs_param_prot {
+	u32 tncs_ggm_lnr;
+	u32 tncs_ggm_end_var;
+} __packed;
+
+/*
+ * Mediatek camera bpc tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_bpc {
+	u32 bpc_func_con;
+	u32 rsv0[49];
+};
+
+/*
+ * Mediatek camera ccm tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_ccm {
+	u32 ccm_cnv_1;
+	u32 ccm_cnv_2;
+	u32 ccm_cnv_3;
+	u32 ccm_cnv_4;
+	u32 ccm_cnv_5;
+	u32 ccm_cnv_6;
+};
+
+/*
+ * Mediatek camera dm tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_dm {
+	u32 rsv0;
+	u32 dm_intp_nat;
+	u32 rsv1[3];
+	u32 dm_sl_ctl;
+	u32 rsv2;
+	u32 dm_nr_str;
+	u32 dm_nr_act;
+	u32 dm_hf_str;
+	u32 dm_hf_act1;
+	u32 dm_hf_act2;
+	u32 dm_clip;
+	u32 rsv3[8];
+	u32 dm_ee;
+	u32 rsv4[4];
+};
+
+/*
+ * Mediatek camera g2c tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_g2c {
+	u32 g2c_conv_0a;
+	u32 g2c_conv_0b;
+	u32 g2c_conv_1a;
+	u32 g2c_conv_1b;
+	u32 g2c_conv_2a;
+	u32 g2c_conv_2b;
+};
+
+#define MTK_CAM_UAPI_GGM_LUT (256)
+/*
+ * Mediatek camera ggm tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_ggm {
+	u32 ggm_lut[MTK_CAM_UAPI_GGM_LUT];
+	u32 ggm_ctrl;
+};
+
+/*
+ * Mediatek camera lsc tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_lsc {
+	u32 lsc_ratio;
+};
+
+#define MTK_CAM_UAPI_LTM_CURVE_SIZE_2 (1728)
+#define MTK_CAM_UAPI_LTM_CLP_SIZE_2 (108)
+
+/*
+ * Mediatek camera ltm tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_ltm {
+	u32 ltm_ctrl;
+	u32 ltm_blk_num;
+	u32 ltm_max_div;
+	u32 ltm_clip;
+	u32 ltm_cfg;
+	u32 ltm_clip_th;
+	u32 ltm_gain_map;
+	u32 ltm_cvnode_grp0;
+	u32 ltm_cvnode_grp1;
+	u32 ltm_cvnode_grp2;
+	u32 ltm_cvnode_grp3;
+	u32 ltm_cvnode_grp4;
+	u32 ltm_cvnode_grp5;
+	u32 ltm_cvnode_grp6;
+	u32 ltm_cvnode_grp7;
+	u32 ltm_cvnode_grp8;
+	u32 ltm_cvnode_grp9;
+	u32 ltm_cvnode_grp10;
+	u32 ltm_cvnode_grp11;
+	u32 ltm_cvnode_grp12;
+	u32 ltm_cvnode_grp13;
+	u32 ltm_cvnode_grp14;
+	u32 ltm_cvnode_grp15;
+	u32 ltm_cvnode_grp16;
+	u32 ltm_out_str;
+	u32 ltm_act_win_x;
+	u32 ltm_act_win_y;
+	u32 ltmtc_curve[MTK_CAM_UAPI_LTM_CURVE_SIZE_2];
+	u32 ltmtc_clp[MTK_CAM_UAPI_LTM_CLP_SIZE_2];
+};
+
+/*
+ * Mediatek camera ltms tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_ltms {
+	u32 ltms_max_div;
+	u32 ltms_blkhist_lb;
+	u32 ltms_blkhist_mb;
+	u32 ltms_blkhist_ub;
+	u32 ltms_blkhist_int;
+	u32 ltms_clip_th_cal;
+	u32 ltms_clip_th_lb;
+	u32 ltms_clip_th_hb;
+	u32 ltms_glbhist_int;
+};
+
+/*
+ * Mediatek camera obc tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_obc {
+	u32 obc_dbs;
+	u32 obc_gray_bld_0;
+	u32 obc_gray_bld_1;
+	u32 obc_wbg_rb;
+	u32 obc_wbg_g;
+	u32 obc_wbig_rb;
+	u32 obc_wbig_g;
+	u32 obc_obg_rb;
+	u32 obc_obg_g;
+	u32 obc_offset_r;
+	u32 obc_offset_gr;
+	u32 obc_offset_gb;
+	u32 obc_offset_b;
+	u32 rsv1[2];
+};
+
+/*
+ * Mediatek camera tsfs tuning setting
+ */
+struct mtk_cam_uapi_regmap_raw_tsfs {
+	u32 tsfs_dgain;
+};
+
+/*
+ * Usage example: To print value of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val"
+ * > printf("%x", GET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN));
+ */
+#define GET_MTK_CAM(val, field) (((val) & field##_MASK) >> \
+				 field##_SHIFT)
+/*
+ * Usage example: To set "val_of_bpc_lut_bit_extend_en" to bits
+ * of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val"
+ * > val = SET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN,
+ * val_of_bpc_lut_bit_extend_en);
+ */
+#define SET_MTK_CAM(val, field, set_val) (((val) & ~field##_MASK) | \
+					  (((set_val) << field##_SHIFT) & field##_MASK))
+
+/*
+ * Bit Feild of BPC_FUNC_CON: BPC_EN
+ * MTK_CAM_BPC_FUNC_CON_BPC_EN: [31, 31]
+ * Enable/disable for BPC Correction
+ * 1'd1: enable the function
+ * 1'd0: disable the function
+ */
+#define MTK_CAM_BPC_FUNC_CON_BPC_EN_MASK   0x80000000
+#define MTK_CAM_BPC_FUNC_CON_BPC_EN_SHIFT  31
+
+/*
+ * Bit Feild of BPC_FUNC_CON: BPC_CT_EN
+ * MTK_CAM_BPC_FUNC_CON_BPC_CT_EN: [30, 30]
+ * Enable/disable for Cross-Talk compensation
+ * 1'd1: enable
+ * 1'd0: disable
+ */
+#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_MASK   0x40000000
+#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_SHIFT  30
+
+/*
+ * Bit Feild of BPC_FUNC_CON: BPC_PDC_EN
+ * MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN: [29, 29]
+ * Enable/disable for PDC correction
+ * 1'd1: enable
+ * 1'd0: disable
+ */
+#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_MASK   0x20000000
+#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_SHIFT  29
+
+/*
+ * Bit Feild of BPC_FUNC_CON: BPC_LUT_EN
+ * MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN: [28, 28]
+ * Enable table lookup
+ * 1'd1:  enable BPC with default table mode
+ * 1'd0:  disable BPC with default table mode
+ */
+#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_MASK   0x10000000
+#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_SHIFT  28
+
+/*
+ * Bit Feild of BPC_FUNC_CON: BPC_LUT_BIT_EXTEND_EN
+ * MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN: [0, 0]
+ * Enable table 24 bits mode
+ * 1'd1: Table format to be 24 bits
+ * 1'd0: @ the original format, tbale to be 16 bits mode
+ */
+#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_MASK   0x00000001
+#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_1: CCM_CNV_01
+ * MTK_CAM_CCM_CNV_1_CCM_CNV_01: [16, 28]
+ * matrix 0,1 coefficient
+ */
+#define MTK_CAM_CCM_CNV_1_CCM_CNV_01_MASK   0x1fff0000
+#define MTK_CAM_CCM_CNV_1_CCM_CNV_01_SHIFT  16
+
+/*
+ * Bit Feild of CCM_CNV_1: CCM_CNV_00
+ * MTK_CAM_CCM_CNV_1_CCM_CNV_00: [0, 12]
+ * matrix 0,0 coefficient
+ */
+#define MTK_CAM_CCM_CNV_1_CCM_CNV_00_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_1_CCM_CNV_00_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_2: CCM_CNV_02
+ * MTK_CAM_CCM_CNV_2_CCM_CNV_02: [0, 12]
+ * matrix 0,2 coefficient
+ */
+#define MTK_CAM_CCM_CNV_2_CCM_CNV_02_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_2_CCM_CNV_02_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_3: CCM_CNV_11
+ * MTK_CAM_CCM_CNV_3_CCM_CNV_11: [16, 28]
+ * matrix 1,1 coefficient
+ */
+#define MTK_CAM_CCM_CNV_3_CCM_CNV_11_MASK   0x1fff0000
+#define MTK_CAM_CCM_CNV_3_CCM_CNV_11_SHIFT  16
+
+/*
+ * Bit Feild of CCM_CNV_3: CCM_CNV_10
+ * MTK_CAM_CCM_CNV_3_CCM_CNV_10: [0, 12]
+ * matrix 1,0 coefficient
+ */
+#define MTK_CAM_CCM_CNV_3_CCM_CNV_10_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_3_CCM_CNV_10_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_4: CCM_CNV_12
+ * MTK_CAM_CCM_CNV_4_CCM_CNV_12: [0, 12]
+ * matrix 1,2 coefficient
+ */
+#define MTK_CAM_CCM_CNV_4_CCM_CNV_12_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_4_CCM_CNV_12_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_5: CCM_CNV_21
+ * MTK_CAM_CCM_CNV_5_CCM_CNV_21: [16, 28]
+ * matrix 2,1 coefficient
+ */
+#define MTK_CAM_CCM_CNV_5_CCM_CNV_21_MASK   0x1fff0000
+#define MTK_CAM_CCM_CNV_5_CCM_CNV_21_SHIFT  16
+
+/*
+ * Bit Feild of CCM_CNV_5: CCM_CNV_20
+ * MTK_CAM_CCM_CNV_5_CCM_CNV_20: [0, 12]
+ * matrix 2,0 coefficient
+ */
+#define MTK_CAM_CCM_CNV_5_CCM_CNV_20_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_5_CCM_CNV_20_SHIFT  0
+
+/*
+ * Bit Feild of CCM_CNV_6: CCM_CNV_22
+ * MTK_CAM_CCM_CNV_6_CCM_CNV_22: [0, 12]
+ * matrix 2,2 coefficient
+ */
+#define MTK_CAM_CCM_CNV_6_CCM_CNV_22_MASK   0x00001fff
+#define MTK_CAM_CCM_CNV_6_CCM_CNV_22_SHIFT  0
+
+/*
+ * Bit Feild of DM_INTP_NAT: DM_L0_OFST
+ * MTK_CAM_DM_INTP_NAT_DM_L0_OFST: [12, 19]
+ * luma blending LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_INTP_NAT_DM_L0_OFST_MASK   0x000ff000
+#define MTK_CAM_DM_INTP_NAT_DM_L0_OFST_SHIFT  12
+
+/*
+ * Bit Feild of DM_SL_CTL: DM_SL_Y1
+ * MTK_CAM_DM_SL_CTL_DM_SL_Y1: [14, 21]
+ * shading link modulation LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_SL_CTL_DM_SL_Y1_MASK   0x003fc000
+#define MTK_CAM_DM_SL_CTL_DM_SL_Y1_SHIFT  14
+
+/*
+ * Bit Feild of DM_SL_CTL: DM_SL_Y2
+ * MTK_CAM_DM_SL_CTL_DM_SL_Y2: [6, 13]
+ * shading link modulation LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_SL_CTL_DM_SL_Y2_MASK   0x00003fc0
+#define MTK_CAM_DM_SL_CTL_DM_SL_Y2_SHIFT  6
+
+/*
+ * Bit Feild of DM_SL_CTL: DM_SL_EN
+ * MTK_CAM_DM_SL_CTL_DM_SL_EN: [0, 0]
+ * shading link enable
+ * 0: disable SL
+ * 1: enable SL
+ */
+#define MTK_CAM_DM_SL_CTL_DM_SL_EN_MASK   0x00000001
+#define MTK_CAM_DM_SL_CTL_DM_SL_EN_SHIFT  0
+
+/*
+ * Bit Feild of DM_NR_STR: DM_N0_STR
+ * MTK_CAM_DM_NR_STR_DM_N0_STR: [10, 14]
+ * noise reduction strength
+ * 0 ~ 16
+ */
+#define MTK_CAM_DM_NR_STR_DM_N0_STR_MASK   0x00007c00
+#define MTK_CAM_DM_NR_STR_DM_N0_STR_SHIFT  10
+
+/*
+ * Bit Feild of DM_NR_ACT: DM_N0_OFST
+ * MTK_CAM_DM_NR_ACT_DM_N0_OFST: [24, 31]
+ * noise reduction activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_NR_ACT_DM_N0_OFST_MASK   0xff000000
+#define MTK_CAM_DM_NR_ACT_DM_N0_OFST_SHIFT  24
+
+/*
+ * Bit Feild of DM_HF_STR: DM_HA_STR
+ * MTK_CAM_DM_HF_STR_DM_HA_STR: [27, 31]
+ * overall high frequency strength
+ * 0 ~ 31
+ */
+#define MTK_CAM_DM_HF_STR_DM_HA_STR_MASK   0xf8000000
+#define MTK_CAM_DM_HF_STR_DM_HA_STR_SHIFT  27
+
+/*
+ * Bit Feild of DM_HF_STR: DM_H1_GN
+ * MTK_CAM_DM_HF_STR_DM_H1_GN: [22, 26]
+ * individual high frequency strength
+ * 0 ~ 31
+ */
+#define MTK_CAM_DM_HF_STR_DM_H1_GN_MASK   0x07c00000
+#define MTK_CAM_DM_HF_STR_DM_H1_GN_SHIFT  22
+
+/*
+ * Bit Feild of DM_HF_STR: DM_H2_GN
+ * MTK_CAM_DM_HF_STR_DM_H2_GN: [17, 21]
+ * individual high frequency strength
+ * 0 ~ 31
+ */
+#define MTK_CAM_DM_HF_STR_DM_H2_GN_MASK   0x003e0000
+#define MTK_CAM_DM_HF_STR_DM_H2_GN_SHIFT  17
+
+/*
+ * Bit Feild of DM_HF_STR: DM_H3_GN
+ * MTK_CAM_DM_HF_STR_DM_H3_GN: [12, 16]
+ * individual high frequency strength
+ * 0 ~ 31
+ */
+#define MTK_CAM_DM_HF_STR_DM_H3_GN_MASK   0x0001f000
+#define MTK_CAM_DM_HF_STR_DM_H3_GN_SHIFT  12
+
+/*
+ * Bit Feild of DM_HF_ACT1: DM_H1_LWB
+ * MTK_CAM_DM_HF_ACT1_DM_H1_LWB: [24, 31]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT1_DM_H1_LWB_MASK   0xff000000
+#define MTK_CAM_DM_HF_ACT1_DM_H1_LWB_SHIFT  24
+
+/*
+ * Bit Feild of DM_HF_ACT1: DM_H1_UPB
+ * MTK_CAM_DM_HF_ACT1_DM_H1_UPB: [16, 23]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT1_DM_H1_UPB_MASK   0x00ff0000
+#define MTK_CAM_DM_HF_ACT1_DM_H1_UPB_SHIFT  16
+
+/*
+ * Bit Feild of DM_HF_ACT1: DM_H2_LWB
+ * MTK_CAM_DM_HF_ACT1_DM_H2_LWB: [8, 15]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT1_DM_H2_LWB_MASK   0x0000ff00
+#define MTK_CAM_DM_HF_ACT1_DM_H2_LWB_SHIFT  8
+
+/*
+ * Bit Feild of DM_HF_ACT1: DM_H2_UPB
+ * MTK_CAM_DM_HF_ACT1_DM_H2_UPB: [0, 7]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT1_DM_H2_UPB_MASK   0x000000ff
+#define MTK_CAM_DM_HF_ACT1_DM_H2_UPB_SHIFT  0
+
+/*
+ * Bit Feild of DM_HF_ACT2: DM_H3_LWB
+ * MTK_CAM_DM_HF_ACT2_DM_H3_LWB: [16, 23]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT2_DM_H3_LWB_MASK   0x00ff0000
+#define MTK_CAM_DM_HF_ACT2_DM_H3_LWB_SHIFT  16
+
+/*
+ * Bit Feild of DM_HF_ACT2: DM_H3_UPB
+ * MTK_CAM_DM_HF_ACT2_DM_H3_UPB: [8, 15]
+ * high frequency activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_HF_ACT2_DM_H3_UPB_MASK   0x0000ff00
+#define MTK_CAM_DM_HF_ACT2_DM_H3_UPB_SHIFT  8
+
+/*
+ * Bit Feild of DM_CLIP: DM_OV_TH
+ * MTK_CAM_DM_CLIP_DM_OV_TH: [16, 23]
+ * over/undershoot brightness LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_CLIP_DM_OV_TH_MASK   0x00ff0000
+#define MTK_CAM_DM_CLIP_DM_OV_TH_SHIFT  16
+
+/*
+ * Bit Feild of DM_CLIP: DM_UN_TH
+ * MTK_CAM_DM_CLIP_DM_UN_TH: [8, 15]
+ * over/undershoot brightness LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_CLIP_DM_UN_TH_MASK   0x0000ff00
+#define MTK_CAM_DM_CLIP_DM_UN_TH_SHIFT  8
+
+/*
+ * Bit Feild of DM_CLIP: DM_CLIP_TH
+ * MTK_CAM_DM_CLIP_DM_CLIP_TH: [0, 7]
+ * over/undershoot activity LUT
+ * 0 ~ 255
+ */
+#define MTK_CAM_DM_CLIP_DM_CLIP_TH_MASK   0x000000ff
+#define MTK_CAM_DM_CLIP_DM_CLIP_TH_SHIFT  0
+
+/*
+ * Bit Feild of DM_EE: DM_HNEG_GN
+ * MTK_CAM_DM_EE_DM_HNEG_GN: [5, 9]
+ * edge enhancement negative gain
+ * 0~16
+ */
+#define MTK_CAM_DM_EE_DM_HNEG_GN_MASK   0x000003e0
+#define MTK_CAM_DM_EE_DM_HNEG_GN_SHIFT  5
+
+/*
+ * Bit Feild of DM_EE: DM_HPOS_GN
+ * MTK_CAM_DM_EE_DM_HPOS_GN: [0, 4]
+ * edge enhancement positive gain
+ * 0~16
+ */
+#define MTK_CAM_DM_EE_DM_HPOS_GN_MASK   0x0000001f
+#define MTK_CAM_DM_EE_DM_HPOS_GN_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_0A: G2C_CNV_01
+ * MTK_CAM_G2C_CONV_0A_G2C_CNV_01: [16, 26]
+ * DIP RGB 2 YUV Matrix 0,1 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_0A_G2C_CNV_01_MASK   0x07ff0000
+#define MTK_CAM_G2C_CONV_0A_G2C_CNV_01_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_0A: G2C_CNV_00
+ * MTK_CAM_G2C_CONV_0A_G2C_CNV_00: [0, 10]
+ * DIP RGB 2 YUV Matrix 0,0 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_0A_G2C_CNV_00_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_0A_G2C_CNV_00_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_0B: G2C_Y_OFST
+ * MTK_CAM_G2C_CONV_0B_G2C_Y_OFST: [16, 30]
+ * Y offset. Q1.10.0 (mobile) or Q1.14.0 (non-mobile)
+ */
+#define MTK_CAM_G2C_CONV_0B_G2C_Y_OFST_MASK   0x7fff0000
+#define MTK_CAM_G2C_CONV_0B_G2C_Y_OFST_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_0B: G2C_CNV_02
+ * MTK_CAM_G2C_CONV_0B_G2C_CNV_02: [0, 10]
+ * DIP RGB 2 YUV Matrix 0,2 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_0B_G2C_CNV_02_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_0B_G2C_CNV_02_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_1A: G2C_CNV_11
+ * MTK_CAM_G2C_CONV_1A_G2C_CNV_11: [16, 26]
+ * DIP RGB 2 YUV Matrix 1,1 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_1A_G2C_CNV_11_MASK   0x07ff0000
+#define MTK_CAM_G2C_CONV_1A_G2C_CNV_11_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_1A: G2C_CNV_10
+ * MTK_CAM_G2C_CONV_1A_G2C_CNV_10: [0, 10]
+ * DIP RGB 2 YUV Matrix 1,0 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_1A_G2C_CNV_10_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_1A_G2C_CNV_10_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_1B: G2C_U_OFST
+ * MTK_CAM_G2C_CONV_1B_G2C_U_OFST: [16, 29]
+ * U offset. Q1.9.0 (mobile) or Q1.13.0 (non-mobile)
+ */
+#define MTK_CAM_G2C_CONV_1B_G2C_U_OFST_MASK   0x3fff0000
+#define MTK_CAM_G2C_CONV_1B_G2C_U_OFST_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_1B: G2C_CNV_12
+ * MTK_CAM_G2C_CONV_1B_G2C_CNV_12: [0, 10]
+ * DIP RGB 2 YUV Matrix 1,2 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_1B_G2C_CNV_12_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_1B_G2C_CNV_12_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_2A: G2C_CNV_21
+ * MTK_CAM_G2C_CONV_2A_G2C_CNV_21: [16, 26]
+ * DIP RGB 2 YUV Matrix 2,1 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_2A_G2C_CNV_21_MASK   0x07ff0000
+#define MTK_CAM_G2C_CONV_2A_G2C_CNV_21_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_2A: G2C_CNV_20
+ * MTK_CAM_G2C_CONV_2A_G2C_CNV_20: [0, 10]
+ * DIP RGB 2 YUV Matrix 2,0 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_2A_G2C_CNV_20_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_2A_G2C_CNV_20_SHIFT  0
+
+/*
+ * Bit Feild of G2C_CONV_2B: G2C_V_OFST
+ * MTK_CAM_G2C_CONV_2B_G2C_V_OFST: [16, 29]
+ * V offset. Q1.9.0 (mobile) or Q1.13.0 (non-mobile)
+ */
+#define MTK_CAM_G2C_CONV_2B_G2C_V_OFST_MASK   0x3fff0000
+#define MTK_CAM_G2C_CONV_2B_G2C_V_OFST_SHIFT  16
+
+/*
+ * Bit Feild of G2C_CONV_2B: G2C_CNV_22
+ * MTK_CAM_G2C_CONV_2B_G2C_CNV_22: [0, 10]
+ * DIP RGB 2 YUV Matrix 2,2 coefficient in Q1.1.9
+ */
+#define MTK_CAM_G2C_CONV_2B_G2C_CNV_22_MASK   0x000007ff
+#define MTK_CAM_G2C_CONV_2B_G2C_CNV_22_SHIFT  0
+
+/*
+ * Bit Feild of GGM_LUT: GGM_LUT
+ * MTK_CAM_GGM_LUT_GGM_LUT: [0, 9]
+ * Gamma table entry
+ * Do NOT read/write this control register when GGM is
+ * enabled (ISP pipeline processing is on-going) or output
+ * data of GGM will be gated
+ */
+#define MTK_CAM_GGM_LUT_GGM_LUT_MASK   0x000003ff
+#define MTK_CAM_GGM_LUT_GGM_LUT_SHIFT  0
+
+/*
+ * Bit Feild of GGM_CTRL: GGM_LNR
+ * MTK_CAM_GGM_CTRL_GGM_LNR: [0, 0]
+ * Enable linear output
+ */
+#define MTK_CAM_GGM_CTRL_GGM_LNR_MASK   0x00000001
+#define MTK_CAM_GGM_CTRL_GGM_LNR_SHIFT  0
+
+/*
+ * Bit Feild of GGM_CTRL: GGM_END_VAR
+ * MTK_CAM_GGM_CTRL_GGM_END_VAR: [1, 10]
+ * end point value
+ */
+#define MTK_CAM_GGM_CTRL_GGM_END_VAR_MASK   0x000007fe
+#define MTK_CAM_GGM_CTRL_GGM_END_VAR_SHIFT  1
+
+/*
+ * Bit Feild of GGM_CTRL: GGM_RMP_VAR
+ * MTK_CAM_GGM_CTRL_GGM_RMP_VAR: [16, 20]
+ * 5-bit: can support mapping to 14-bit output, (RMP_VAR+out limiter)/1024
+ */
+#define MTK_CAM_GGM_CTRL_GGM_RMP_VAR_MASK   0x001f0000
+#define MTK_CAM_GGM_CTRL_GGM_RMP_VAR_SHIFT  16
+
+/*
+ * Bit Feild of LSC_RATIO: LSC_RA00
+ * MTK_CAM_LSC_RATIO_LSC_RA00: [0, 5]
+ * Shading ratio
+ */
+#define MTK_CAM_LSC_RATIO_LSC_RA00_MASK   0x0000003f
+#define MTK_CAM_LSC_RATIO_LSC_RA00_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_MAX_DIV: LTMS_CLIP_TH_ALPHA_BASE
+ * MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE: [0, 9]
+ * Divider for Maxvalue
+ */
+#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_MASK   0x000003ff
+#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_MAX_DIV: LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT
+ * MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT: [16, 20]
+ * Divider for Maxvalue
+ */
+#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT_MASK   0x001f0000
+#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT_SHIFT  16
+
+/*
+ * Bit Feild of LTMS_BLKHIST_LB: LTMS_BLKHIST_LB
+ * MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB: [0, 17]
+ * block histogram low bound,
+ * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB
+ */
+#define MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB_MASK   0x0003ffff
+#define MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_BLKHIST_MB: LTMS_BLKHIST_MB
+ * MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB: [0, 17]
+ * block histogram middle bound,
+ * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB
+ */
+#define MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB_MASK   0x0003ffff
+#define MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_BLKHIST_UB: LTMS_BLKHIST_UB
+ * MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB: [0, 17]
+ * block histogram up bound,
+ * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB
+ */
+#define MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB_MASK   0x0003ffff
+#define MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_BLKHIST_INT: LTMS_BLKHIST_INT2
+ * MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2: [16, 29]
+ * block histogram interval 2
+ */
+#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2_MASK   0x3fff0000
+#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2_SHIFT  16
+
+/*
+ * Bit Feild of LTMS_CLIP_TH_CAL: LTMS_CLP_HLTHD
+ * MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD: [0, 10]
+ * control percentage of histogram to calculate clip_th, 10-bits precision.
+ */
+#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD_MASK   0x000007ff
+#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_CLIP_TH_CAL: LTMS_CLP_STARTBIN
+ * MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN: [16, 23]
+ * start bin of histogram.
+ */
+#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN_MASK   0x00ff0000
+#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN_SHIFT  16
+
+/*
+ * Bit Feild of LTMS_CLIP_TH_LB: LTMS_CLP_LB
+ * MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB: [0, 21]
+ * Low bound of clip threshold output.
+ */
+#define MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB_MASK   0x003fffff
+#define MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_CLIP_TH_HB: LTMS_CLP_HB
+ * MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB: [0, 21]
+ * High bound of clip threshold output.
+ */
+#define MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB_MASK   0x003fffff
+#define MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB_SHIFT  0
+
+/*
+ * Bit Feild of LTMS_GLBHIST_INT: LTMS_GLBHIST_INT
+ * MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT: [0, 14]
+ * Interval of global histogram
+ */
+#define MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT_MASK   0x00007fff
+#define MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT_SHIFT  0
+
+/*
+ * Bit Feild of LTMTC_CURVE: LTMTC_TONECURVE_LUT_L
+ * MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L: [0, 13]
+ * SRAM_PING_PONG
+ * [u8.6-bits]x12x9
+ */
+#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L_MASK   0x00003fff
+#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L_SHIFT  0
+
+/*
+ * Bit Feild of LTMTC_CURVE: LTMTC_TONECURVE_LUT_H
+ * MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H: [16, 29]
+ * SRAM_PING_PONG
+ * [u8.6-bits]x12x9
+ */
+#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H_MASK   0x3fff0000
+#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H_SHIFT  16
+
+/*
+ * Bit Feild of LTMTC_CLP: LTMTC_TONECURVE_CLP
+ * MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP: [0, 23]
+ * LTM block CT
+ */
+#define MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP_MASK   0x00ffffff
+#define MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CTRL: LTM_GAMMA_EN
+ * MTK_CAM_LTM_CTRL_LTM_GAMMA_EN: [4, 4]
+ * Enable gamma domain
+ */
+#define MTK_CAM_LTM_CTRL_LTM_GAMMA_EN_MASK   0x00000010
+#define MTK_CAM_LTM_CTRL_LTM_GAMMA_EN_SHIFT  4
+
+/*
+ * Bit Feild of LTM_CTRL: LTM_CURVE_CP_MODE
+ * MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE: [5, 5]
+ * Mode of curve control point, [0]: 33 fixed cp, [1]: 16 XY cp
+ */
+#define MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE_MASK   0x00000020
+#define MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE_SHIFT  5
+
+/*
+ * Bit Feild of LTM_BLK_NUM: LTM_BLK_X_NUM
+ * MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM: [0, 4]
+ * block X number supports 2~12
+ */
+#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM_MASK   0x0000001f
+#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM_SHIFT  0
+
+/*
+ * Bit Feild of LTM_BLK_NUM: LTM_BLK_Y_NUM
+ * MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM: [8, 12]
+ * block Y number supports 2~9
+ */
+#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM_MASK   0x00001f00
+#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM_SHIFT  8
+
+/*
+ * Bit Feild of LTM_MAX_DIV: LTM_CLIP_TH_ALPHA_BASE
+ * MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE: [0, 9]
+ * Divider for Maxvalue
+ */
+#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_MASK   0x000003ff
+#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT  0
+
+/*
+ * Bit Feild of LTM_MAX_DIV: LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT
+ * MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT: [16, 20]
+ * Divider for Maxvalue
+ */
+#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT_MASK   0x001f0000
+#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CLIP: LTM_GAIN_TH
+ * MTK_CAM_LTM_CLIP_LTM_GAIN_TH: [0, 5]
+ * Threshold to clip output gain
+ */
+#define MTK_CAM_LTM_CLIP_LTM_GAIN_TH_MASK   0x0000003f
+#define MTK_CAM_LTM_CLIP_LTM_GAIN_TH_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CFG: LTM_ENGINE_EN
+ * MTK_CAM_LTM_CFG_LTM_ENGINE_EN: [0, 0]
+ * None
+ */
+#define MTK_CAM_LTM_CFG_LTM_ENGINE_EN_MASK   0x00000001
+#define MTK_CAM_LTM_CFG_LTM_ENGINE_EN_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CFG: LTM_CG_DISABLE
+ * MTK_CAM_LTM_CFG_LTM_CG_DISABLE: [4, 4]
+ * None
+ */
+#define MTK_CAM_LTM_CFG_LTM_CG_DISABLE_MASK   0x00000010
+#define MTK_CAM_LTM_CFG_LTM_CG_DISABLE_SHIFT  4
+
+/*
+ * Bit Feild of LTM_CFG: LTM_CHKSUM_EN
+ * MTK_CAM_LTM_CFG_LTM_CHKSUM_EN: [28, 28]
+ * None
+ */
+#define MTK_CAM_LTM_CFG_LTM_CHKSUM_EN_MASK   0x10000000
+#define MTK_CAM_LTM_CFG_LTM_CHKSUM_EN_SHIFT  28
+
+/*
+ * Bit Feild of LTM_CFG: LTM_CHKSUM_SEL
+ * MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL: [29, 30]
+ * None
+ */
+#define MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL_MASK   0x60000000
+#define MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL_SHIFT  29
+
+/*
+ * Bit Feild of LTM_CLIP_TH: LTM_CLIP_TH
+ * MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH: [0, 23]
+ * clipping threshold, enabled if #define LTM_USE_PREVIOUS_MAXVALUE=1
+ */
+#define MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH_MASK   0x00ffffff
+#define MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CLIP_TH: LTM_WGT_BSH
+ * MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH: [24, 27]
+ * rightward bit shift for weighting data
+ */
+#define MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH_MASK   0x0f000000
+#define MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH_SHIFT  24
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_MAP_LOG_EN
+ * MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN: [0, 0]
+ * switch for map log
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN_MASK   0x00000001
+#define MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN_SHIFT  0
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_WGT_LOG_EN
+ * MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN: [1, 1]
+ * switch for weight log
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN_MASK   0x00000002
+#define MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN_SHIFT  1
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_NONTRAN_MAP_TYPE
+ * MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE: [4, 7]
+ * type of nontran map
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE_MASK   0x000000f0
+#define MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE_SHIFT  4
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_TRAN_MAP_TYPE
+ * MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE: [8, 11]
+ * type of tran map
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE_MASK   0x00000f00
+#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE_SHIFT  8
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_TRAN_WGT
+ * MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT: [16, 20]
+ * static tran weight
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_MASK   0x001f0000
+#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_SHIFT  16
+
+/*
+ * Bit Feild of LTM_GAIN_MAP: LTM_RANGE_SCL
+ * MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL: [24, 29]
+ * scale of maxTran
+ */
+#define MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL_MASK   0x3f000000
+#define MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL_SHIFT  24
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP0: LTM_CVNODE_0
+ * MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0: [0, 11]
+ * cvnode-0 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP0: LTM_CVNODE_1
+ * MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1: [16, 27]
+ * cvnode-1 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP1: LTM_CVNODE_2
+ * MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2: [0, 11]
+ * cvnode-2 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP1: LTM_CVNODE_3
+ * MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3: [16, 27]
+ * cvnode-3 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP2: LTM_CVNODE_4
+ * MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4: [0, 11]
+ * cvnode-4 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP2: LTM_CVNODE_5
+ * MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5: [16, 27]
+ * cvnode-5 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP3: LTM_CVNODE_6
+ * MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6: [0, 11]
+ * cvnode-6 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP3: LTM_CVNODE_7
+ * MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7: [16, 27]
+ * cvnode-7 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP4: LTM_CVNODE_8
+ * MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8: [0, 11]
+ * cvnode-8 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP4: LTM_CVNODE_9
+ * MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9: [16, 27]
+ * cvnode-9 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP5: LTM_CVNODE_10
+ * MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10: [0, 11]
+ * cvnode-10 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP5: LTM_CVNODE_11
+ * MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11: [16, 27]
+ * cvnode-11 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP6: LTM_CVNODE_12
+ * MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12: [0, 11]
+ * cvnode-12 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP6: LTM_CVNODE_13
+ * MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13: [16, 27]
+ * cvnode-13 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP7: LTM_CVNODE_14
+ * MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14: [0, 11]
+ * cvnode-14 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP7: LTM_CVNODE_15
+ * MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15: [16, 27]
+ * cvnode-15 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP8: LTM_CVNODE_16
+ * MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16: [0, 11]
+ * cvnode-16 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP8: LTM_CVNODE_17
+ * MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17: [16, 27]
+ * cvnode-17 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP9: LTM_CVNODE_18
+ * MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18: [0, 11]
+ * cvnode-18 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP9: LTM_CVNODE_19
+ * MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19: [16, 27]
+ * cvnode-19 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP10: LTM_CVNODE_20
+ * MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20: [0, 11]
+ * cvnode-20 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP10: LTM_CVNODE_21
+ * MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21: [16, 27]
+ * cvnode-21 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP11: LTM_CVNODE_22
+ * MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22: [0, 11]
+ * cvnode-22 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP11: LTM_CVNODE_23
+ * MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23: [16, 27]
+ * cvnode-23 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP12: LTM_CVNODE_24
+ * MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24: [0, 11]
+ * cvnode-24 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP12: LTM_CVNODE_25
+ * MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25: [16, 27]
+ * cvnode-25 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP13: LTM_CVNODE_26
+ * MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26: [0, 11]
+ * cvnode-26 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP13: LTM_CVNODE_27
+ * MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27: [16, 27]
+ * cvnode-27 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP14: LTM_CVNODE_28
+ * MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28: [0, 11]
+ * cvnode-28 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP14: LTM_CVNODE_29
+ * MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29: [16, 27]
+ * cvnode-29 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP15: LTM_CVNODE_30
+ * MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30: [0, 11]
+ * cvnode-30 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30_SHIFT  0
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP15: LTM_CVNODE_31
+ * MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31: [16, 27]
+ * cvnode-31 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31_MASK   0x0fff0000
+#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31_SHIFT  16
+
+/*
+ * Bit Feild of LTM_CVNODE_GRP16: LTM_CVNODE_32
+ * MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32: [0, 11]
+ * cvnode-32 for gain map
+ */
+#define MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32_MASK   0x00000fff
+#define MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32_SHIFT  0
+
+/*
+ * Bit Feild of LTM_OUT_STR: LTM_OUT_STR
+ * MTK_CAM_LTM_OUT_STR_LTM_OUT_STR: [0, 4]
+ * output strength
+ */
+#define MTK_CAM_LTM_OUT_STR_LTM_OUT_STR_MASK   0x0000001f
+#define MTK_CAM_LTM_OUT_STR_LTM_OUT_STR_SHIFT  0
+
+/*
+ * Bit Feild of LTM_ACT_WIN_X: LTM_ACT_WIN_X_START
+ * MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START: [0, 15]
+ * Horizontal setting for active window of AE debug
+ */
+#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START_MASK   0x0000ffff
+#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START_SHIFT  0
+
+/*
+ * Bit Feild of LTM_ACT_WIN_X: LTM_ACT_WIN_X_END
+ * MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END: [16, 31]
+ * Horizontal setting for active window of AE debug
+ */
+#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END_MASK   0xffff0000
+#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END_SHIFT  16
+
+/*
+ * Bit Feild of LTM_ACT_WIN_Y: LTM_ACT_WIN_Y_START
+ * MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START: [0, 15]
+ * Vertical setting for active window of AE debug
+ */
+#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START_MASK   0x0000ffff
+#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START_SHIFT  0
+
+/*
+ * Bit Feild of LTM_ACT_WIN_Y: LTM_ACT_WIN_Y_END
+ * MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END: [16, 31]
+ * Vertical setting for active window of AE debug
+ */
+#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END_MASK   0xffff0000
+#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END_SHIFT  16
+
+/*
+ * Bit Feild of OBC_DBS: OBC_DBS_RATIO
+ * MTK_CAM_OBC_DBS_OBC_DBS_RATIO: [0, 4]
+ * Ratio of "bias" being eliminated
+ */
+#define MTK_CAM_OBC_DBS_OBC_DBS_RATIO_MASK   0x0000001f
+#define MTK_CAM_OBC_DBS_OBC_DBS_RATIO_SHIFT  0
+
+/*
+ * Bit Feild of OBC_DBS: OBC_POSTTUNE_EN
+ * MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN: [8, 8]
+ * Enable gray-blending and LUT-subtraction processing
+ */
+#define MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN_MASK   0x00000100
+#define MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN_SHIFT  8
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_0: OBC_LUMA_MODE
+ * MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE: [0, 0]
+ * Selection between max mode or mean mode for luma computation
+ */
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE_MASK   0x00000001
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE_SHIFT  0
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_0: OBC_GRAY_MODE
+ * MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE: [1, 2]
+ * Method of gray value computation
+ */
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE_MASK   0x00000006
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE_SHIFT  1
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_0: OBC_NORM_BIT
+ * MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT: [3, 7]
+ * Data scale to be normalized to 12-bit
+ */
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT_MASK   0x000000f8
+#define MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT_SHIFT  3
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_MXRT
+ * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT: [0, 7]
+ * (normal and LE)Maximum weight for gray blending
+ */
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT_MASK   0x000000ff
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT_SHIFT  0
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_LOW
+ * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW: [8, 19]
+ * (normal and LE)Luma level below which the gray value is
+ * bleneded with the specified maximum weight.
+ */
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW_MASK   0x000fff00
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW_SHIFT  8
+
+/*
+ * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_SLP
+ * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP: [20, 31]
+ * (normal and LE)Slope of the blending ratio curve between zero and maximum weight.
+ */
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP_MASK   0xfff00000
+#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP_SHIFT  20
+
+/*
+ * Bit Feild of OBC_WBG_RB: OBC_PGN_R
+ * MTK_CAM_OBC_WBG_RB_OBC_PGN_R: [0, 12]
+ * WB gain for R channel
+ */
+#define MTK_CAM_OBC_WBG_RB_OBC_PGN_R_MASK   0x00001fff
+#define MTK_CAM_OBC_WBG_RB_OBC_PGN_R_SHIFT  0
+
+/*
+ * Bit Feild of OBC_WBG_RB: OBC_PGN_B
+ * MTK_CAM_OBC_WBG_RB_OBC_PGN_B: [16, 28]
+ * WB gain for R channel
+ */
+#define MTK_CAM_OBC_WBG_RB_OBC_PGN_B_MASK   0x1fff0000
+#define MTK_CAM_OBC_WBG_RB_OBC_PGN_B_SHIFT  16
+
+/*
+ * Bit Feild of OBC_WBG_G: OBC_PGN_G
+ * MTK_CAM_OBC_WBG_G_OBC_PGN_G: [0, 12]
+ * WB gain for G channel
+ */
+#define MTK_CAM_OBC_WBG_G_OBC_PGN_G_MASK   0x00001fff
+#define MTK_CAM_OBC_WBG_G_OBC_PGN_G_SHIFT  0
+
+/*
+ * Bit Feild of OBC_WBIG_RB: OBC_IVGN_R
+ * MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R: [0, 9]
+ * Inverse WB gain for R channel
+ */
+#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R_MASK   0x000003ff
+#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R_SHIFT  0
+
+/*
+ * Bit Feild of OBC_WBIG_RB: OBC_IVGN_B
+ * MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B: [16, 25]
+ * Inverse WB gain for B channel
+ */
+#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B_MASK   0x03ff0000
+#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B_SHIFT  16
+
+/*
+ * Bit Feild of OBC_WBIG_G: OBC_IVGN_G
+ * MTK_CAM_OBC_WBIG_G_OBC_IVGN_G: [0, 9]
+ * Inverse WB gain for G channel
+ */
+#define MTK_CAM_OBC_WBIG_G_OBC_IVGN_G_MASK   0x000003ff
+#define MTK_CAM_OBC_WBIG_G_OBC_IVGN_G_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OBG_RB: OBC_GAIN_R
+ * MTK_CAM_OBC_OBG_RB_OBC_GAIN_R: [0, 11]
+ * OB gain for R channel
+ */
+#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_R_MASK   0x00000fff
+#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_R_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OBG_RB: OBC_GAIN_B
+ * MTK_CAM_OBC_OBG_RB_OBC_GAIN_B: [16, 27]
+ * OB gain for B channel
+ */
+#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_B_MASK   0x0fff0000
+#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_B_SHIFT  16
+
+/*
+ * Bit Feild of OBC_OBG_G: OBC_GAIN_GR
+ * MTK_CAM_OBC_OBG_G_OBC_GAIN_GR: [0, 11]
+ * OB gain for Gr channel
+ */
+#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GR_MASK   0x00000fff
+#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GR_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OBG_G: OBC_GAIN_GB
+ * MTK_CAM_OBC_OBG_G_OBC_GAIN_GB: [16, 27]
+ * OB gain for Gb channel
+ */
+#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GB_MASK   0x0fff0000
+#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GB_SHIFT  16
+
+/*
+ * Bit Feild of OBC_OFFSET_R: OBC_OFST_R
+ * MTK_CAM_OBC_OFFSET_R_OBC_OFST_R: [0, 21]
+ * OB offset for R channel
+ */
+#define MTK_CAM_OBC_OFFSET_R_OBC_OFST_R_MASK   0x003fffff
+#define MTK_CAM_OBC_OFFSET_R_OBC_OFST_R_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OFFSET_GR: OBC_OFST_GR
+ * MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR: [0, 21]
+ * OB offset for Gr channel
+ */
+#define MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR_MASK   0x003fffff
+#define MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OFFSET_GB: OBC_OFST_GB
+ * MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB: [0, 21]
+ * OB offset for Gb channel
+ */
+#define MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB_MASK   0x003fffff
+#define MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB_SHIFT  0
+
+/*
+ * Bit Feild of OBC_OFFSET_B: OBC_OFST_B
+ * MTK_CAM_OBC_OFFSET_B_OBC_OFST_B: [0, 21]
+ * OB offset for B channel
+ */
+#define MTK_CAM_OBC_OFFSET_B_OBC_OFST_B_MASK   0x003fffff
+#define MTK_CAM_OBC_OFFSET_B_OBC_OFST_B_SHIFT  0
+
+/*
+ * Bit Feild of TSFS_DGAIN: TSFS_REGEN_Y_EN
+ * MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN: [0, 0]
+ * Digital gain control
+ */
+#define MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN_MASK   0x00000001
+#define MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN_SHIFT  0
+
+/*
+ * Bit Feild of TSFS_DGAIN: TSFS_GAIN
+ * MTK_CAM_TSFS_DGAIN_TSFS_GAIN: [1, 16]
+ * Digital gain
+ */
+#define MTK_CAM_TSFS_DGAIN_TSFS_GAIN_MASK   0x0001fffe
+#define MTK_CAM_TSFS_DGAIN_TSFS_GAIN_SHIFT  1
+
+/*
+ *  V 4 L 2  M E T A  B U F F E R  L A Y O U T
+ */
+
+/*
+ * struct mtk_cam_uapi_meta_raw_stats_0 - capture buffer returns from camsys
+ *    after the frame is done. The buffer are not be pushed the other
+ *    driver such as dip.
+ *
+ * @ae_awb_stats_enabled: indicate that ae_awb_stats is ready or not in
+ *       this buffer
+ * @ltm_stats_enabled:    indicate that ltm_stats is ready or not in
+ *       this buffer
+ * @flk_stats_enabled:    indicate that flk_stats is ready or not in
+ *       this buffer
+ * @tsf_stats_enabled:    indicate that tsf_stats is ready or not in
+ *       this buffer
+ * @pde_stats_enabled:    indicate that pde_stats is ready or not in
+ *       this buffer
+ * @pipeline_config:      the pipeline configuration during processing
+ * @pde_stats: the pde module stats
+ */
+struct mtk_cam_uapi_meta_raw_stats_0 {
+	u8 ae_awb_stats_enabled;
+	u8 ltm_stats_enabled;
+	u8 flk_stats_enabled;
+	u8 tsf_stats_enabled;
+	u8 tncy_stats_enabled;
+	u8 pde_stats_enabled;
+	u8 rsv[2];
+
+	struct mtk_cam_uapi_pipeline_config pipeline_config;
+
+	struct mtk_cam_uapi_ae_awb_stats ae_awb_stats;
+	struct mtk_cam_uapi_ltm_stats ltm_stats;
+	struct mtk_cam_uapi_flk_stats flk_stats;
+	struct mtk_cam_uapi_tsf_stats tsf_stats;
+	struct mtk_cam_uapi_tncy_stats tncy_stats;
+	struct mtk_cam_uapi_pd_stats pde_stats;
+	struct mtk_cam_uapi_timestamp timestamp;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_meta_raw_stats_1 - statistics before frame done
+ *
+ * @af_stats_enabled: indicate that lce_stats is ready or not in this buffer
+ * @af_stats: AF statistics
+ *
+ * Any statistic output put in this structure should be careful.
+ * The meta buffer needs copying overhead to return the buffer before the
+ * all the ISP hardware's processing is finished.
+ */
+struct mtk_cam_uapi_meta_raw_stats_1 {
+	u8 af_stats_enabled;
+	u8 af_qbn_r6_enabled;
+	u8 rsv[2];
+	struct mtk_cam_uapi_af_stats af_stats;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_meta_raw_stats_2 - shared statistics buffer
+ *
+ * @act_stats_enabled:  indicate that act_stats is ready or not in this
+ * buffer
+ * @act_stats:  act statistics
+ *
+ * The statistic output in this structure may be pushed to the other
+ * driver such as dip.
+ *
+ */
+struct mtk_cam_uapi_meta_raw_stats_2 {
+	u8 act_stats_enabled;
+	u8 rsv[3];
+
+	struct mtk_cam_uapi_act_stats act_stats;
+} __packed;
+
+/*
+ * struct mtk_cam_uapi_meta_camsv_stats_0 - capture buffer returns from
+ *	 camsys's camsv module after the frame is done. The buffer are
+ *	 not be pushed the other driver such as dip.
+ *
+ * @pd_stats_enabled:	 indicate that pd_stats is ready or not in
+ *			 this buffer
+ */
+struct mtk_cam_uapi_meta_camsv_stats_0 {
+	u8   pd_stats_enabled;
+	u8   rsv[3];
+
+	struct mtk_cam_uapi_pd_stats pd_stats;
+} __packed;
+
+#define MTK_CAM_META_VERSION_MAJOR 2
+#define MTK_CAM_META_VERSION_MINOR 3
+#define MTK_CAM_META_PLATFORM_NAME "isp71"
+#define MTK_CAM_META_CHIP_NAME "mt8188"
+
+#endif /* __MTK_CAM_META_H__ */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c
new file mode 100755
index 000000000000..ca8681eb3632
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2022 MediaTek Inc.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
+
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-memops.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-raw.h"
+#include "mtk_cam-video.h"
+#include "mtk_cam-plat-util.h"
+#include "mtk_cam-meta-mt8188.h"
+
+/* meta out max size include 1k meta info and dma buffer size */
+#define RAW_STATS_0_SIZE \
+	ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_0), SZ_1K) + \
+	      MTK_CAM_UAPI_AAO_MAX_BUF_SIZE + MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE + \
+	      MTK_CAM_UAPI_LTMSO_SIZE + \
+	      MTK_CAM_UAPI_FLK_MAX_BUF_SIZE + \
+	      MTK_CAM_UAPI_TSFSO_SIZE * 2 + /* r1 & r2 */ \
+	      MTK_CAM_UAPI_TNCSYO_SIZE, (4 * SZ_1K))
+
+#define RAW_STATS_1_SIZE \
+	ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_1), SZ_1K) + \
+	      MTK_CAM_UAPI_AFO_MAX_BUF_SIZE, (4 * SZ_1K))
+
+#define RAW_STATS_2_SIZE \
+	ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_2), SZ_1K) + \
+	      MTK_CAM_UAPI_ACTSO_SIZE, (4 * SZ_1K))
+
+/* ISP platform meta format */
+static const struct mtk_cam_format_desc meta_fmts[] = {
+	{
+		.vfmt.fmt.meta = {
+			.dataformat = V4L2_META_FMT_MTISP_3A,
+			.buffersize = RAW_STATS_0_SIZE,
+		},
+	},
+	{
+		.vfmt.fmt.meta = {
+			.dataformat = V4L2_META_FMT_MTISP_AF,
+			.buffersize = RAW_STATS_1_SIZE,
+		},
+	},
+	{
+		.vfmt.fmt.meta = {
+			.dataformat = V4L2_META_FMT_MTISP_LCS,
+			.buffersize = RAW_STATS_2_SIZE,
+		},
+	},
+};
+
+static void set_payload(struct mtk_cam_uapi_meta_hw_buf *buf,
+			unsigned int size, unsigned long *offset)
+{
+	buf->offset = *offset;
+	buf->size = size;
+	*offset += size;
+}
+
+uint64_t *camsys_get_timestamp_addr(void *vaddr)
+{
+	struct mtk_cam_uapi_meta_raw_stats_0 *stats0;
+
+	stats0 = (struct mtk_cam_uapi_meta_raw_stats_0 *)vaddr;
+	return (uint64_t *)(stats0->timestamp.timestamp_buf);
+}
+EXPORT_SYMBOL_GPL(camsys_get_timestamp_addr);
+
+void camsys_set_meta_stats_info(u32 dma_port, struct vb2_buffer *vb,
+				struct mtk_raw_pde_config *pde_cfg)
+{
+	struct mtk_cam_uapi_meta_raw_stats_0 *stats0;
+	struct mtk_cam_uapi_meta_raw_stats_1 *stats1;
+	unsigned long offset;
+	void *vaddr = vb2_plane_vaddr(vb, 0);
+
+	switch (dma_port) {
+	case MTKCAM_ISP_META_STATS_0:
+		stats0 = (struct mtk_cam_uapi_meta_raw_stats_0 *)vaddr;
+		offset = sizeof(*stats0);
+		set_payload(&stats0->ae_awb_stats.aao_buf,
+			    MTK_CAM_UAPI_AAO_MAX_BUF_SIZE, &offset);
+		set_payload(&stats0->ae_awb_stats.aaho_buf,
+			    MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE, &offset);
+		set_payload(&stats0->ltm_stats.ltmso_buf,
+			    MTK_CAM_UAPI_LTMSO_SIZE, &offset);
+		set_payload(&stats0->flk_stats.flko_buf,
+			    MTK_CAM_UAPI_FLK_MAX_BUF_SIZE, &offset);
+		set_payload(&stats0->tsf_stats.tsfo_r1_buf,
+			    MTK_CAM_UAPI_TSFSO_SIZE, &offset);
+		set_payload(&stats0->tsf_stats.tsfo_r2_buf,
+			    MTK_CAM_UAPI_TSFSO_SIZE, &offset);
+		set_payload(&stats0->tncy_stats.tncsyo_buf,
+			    MTK_CAM_UAPI_TNCSYO_SIZE, &offset);
+		if (pde_cfg) {
+			if (pde_cfg->pde_info.pd_table_offset) {
+				set_payload(&stats0->pde_stats.pdo_buf,
+					    pde_cfg->pde_info.pdo_max_size, &offset);
+			}
+		}
+		break;
+	case MTKCAM_ISP_META_STATS_1:
+		stats1 = (struct mtk_cam_uapi_meta_raw_stats_1 *)vaddr;
+		offset = sizeof(*stats1);
+		set_payload(&stats1->af_stats.afo_buf,
+			    MTK_CAM_UAPI_AFO_MAX_BUF_SIZE, &offset);
+		break;
+	case MTKCAM_ISP_META_STATS_2:
+		pr_info("stats 2 not support");
+		break;
+	default:
+		pr_debug("%s: dma_port err\n", __func__);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(camsys_set_meta_stats_info);
+
+int camsys_get_meta_version(bool major)
+{
+	if (major)
+		return MTK_CAM_META_VERSION_MAJOR;
+	else
+		return MTK_CAM_META_VERSION_MINOR;
+}
+EXPORT_SYMBOL_GPL(camsys_get_meta_version);
+
+const struct mtk_cam_format_desc *camsys_get_meta_fmts(void)
+{
+	return meta_fmts;
+}
+EXPORT_SYMBOL_GPL(camsys_get_meta_fmts);
+
+MODULE_DESCRIPTION("MediaTek camera platform utility");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h
new file mode 100755
index 000000000000..c606be8838a3
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_PLAT_UTIL_H
+#define __MTK_CAM_PLAT_UTIL_H
+
+int camsys_get_meta_version(bool major);
+const struct mtk_cam_format_desc *camsys_get_meta_fmts(void);
+void camsys_set_meta_stats_info(u32 dma_port, struct vb2_buffer *vb,
+				struct mtk_raw_pde_config *pde_cfg);
+uint64_t *camsys_get_timestamp_addr(void *vaddr);
+
+#endif /*__MTK_CAM_PLAT_UTIL_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c
new file mode 100755
index 000000000000..92df0adac0ec
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Louis Kuo <louis.kuo@mediatek.com>
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-buf.h>
+#include <linux/mm.h>
+#include <linux/remoteproc.h>
+#include <linux/spinlock.h>
+
+#include "mtk_cam.h"
+#include "mtk_cam-pool.h"
+
+int mtk_cam_working_buf_pool_init(struct mtk_cam_ctx *ctx, struct device *dev)
+{
+	int i, ret;
+	void *ptr;
+	dma_addr_t addr;
+	struct mtk_cam_device *cam = ctx->cam;
+	const unsigned int working_buf_size = round_up(CQ_BUF_SIZE, PAGE_SIZE);
+	const unsigned int msg_buf_size = round_up(IPI_FRAME_BUF_SIZE, PAGE_SIZE);
+
+	INIT_LIST_HEAD(&ctx->buf_pool.cam_freelist.list);
+	spin_lock_init(&ctx->buf_pool.cam_freelist.lock);
+	ctx->buf_pool.cam_freelist.cnt = 0;
+	ctx->buf_pool.working_buf_size = CAM_CQ_BUF_NUM * working_buf_size;
+	ctx->buf_pool.msg_buf_size = CAM_CQ_BUF_NUM * msg_buf_size;
+	ctx->buf_pool.raw_workbuf_size = round_up(SIZE_OF_RAW_WORKBUF, PAGE_SIZE);
+	ctx->buf_pool.priv_workbuf_size = round_up(SIZE_OF_RAW_PRIV, PAGE_SIZE);
+	ctx->buf_pool.session_buf_size = round_up(SIZE_OF_SESSION, PAGE_SIZE);
+
+	/* raw working buffer */
+	ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.raw_workbuf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	ctx->buf_pool.raw_workbuf_scp_addr = addr;
+	ctx->buf_pool.raw_workbuf_va = ptr;
+	dev_dbg(dev, "[%s] raw working buf scp addr:%pad va:%pK size %u\n",
+		__func__,
+		&ctx->buf_pool.raw_workbuf_scp_addr,
+		ctx->buf_pool.raw_workbuf_va,
+		ctx->buf_pool.raw_workbuf_size);
+
+	/* raw priv working buffer */
+	ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.priv_workbuf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	ctx->buf_pool.priv_workbuf_scp_addr = addr;
+	ctx->buf_pool.priv_workbuf_va = ptr;
+	dev_dbg(dev, "[%s] raw pri working buf scp addr:%pad va:%pK size %u\n",
+		__func__,
+		&ctx->buf_pool.priv_workbuf_scp_addr,
+		ctx->buf_pool.priv_workbuf_va,
+		ctx->buf_pool.priv_workbuf_size);
+
+	/* session buffer */
+	ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.session_buf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	ctx->buf_pool.session_buf_scp_addr = addr;
+	ctx->buf_pool.session_buf_va = ptr;
+	dev_dbg(dev, "[%s] session buf scp addr:%pad va:%pK size %u\n",
+		__func__,
+		&ctx->buf_pool.session_buf_scp_addr,
+		ctx->buf_pool.session_buf_va,
+		ctx->buf_pool.session_buf_size);
+
+	/* working buffer */
+	ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	ctx->buf_pool.working_buf_scp_addr = addr;
+	ctx->buf_pool.working_buf_va = ptr;
+	addr = dma_map_resource(dev, addr, ctx->buf_pool.working_buf_size,
+				DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
+	if (dma_mapping_error(dev, addr)) {
+		dev_err(dev, "failed to map scp iova\n");
+		ret = -ENOMEM;
+		goto fail_free_mem;
+	}
+	ctx->buf_pool.working_buf_iova = addr;
+	dev_dbg(dev, "[%s] CQ buf scp addr:%pad va:%pK iova:%pad size %u\n",
+		__func__,
+		&ctx->buf_pool.working_buf_scp_addr,
+		ctx->buf_pool.working_buf_va,
+		&ctx->buf_pool.working_buf_iova,
+		ctx->buf_pool.working_buf_size);
+
+	/* msg buffer */
+	ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.msg_buf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr) {
+		ret = -ENOMEM;
+		goto fail_free_mem;
+	}
+	ctx->buf_pool.msg_buf_scp_addr = addr;
+	ctx->buf_pool.msg_buf_va = ptr;
+	dev_dbg(dev, "[%s] msg buf scp addr:%pad va:%pK size %u\n",
+		__func__, &ctx->buf_pool.msg_buf_scp_addr,
+		ctx->buf_pool.msg_buf_va, ctx->buf_pool.msg_buf_size);
+
+	for (i = 0; i < CAM_CQ_BUF_NUM; i++) {
+		struct mtk_cam_working_buf_entry *buf = &ctx->buf_pool.working_buf[i];
+		unsigned int offset = i * working_buf_size;
+		unsigned int offset_msg = i * msg_buf_size;
+
+		buf->ctx = ctx;
+		buf->buffer.va = ctx->buf_pool.working_buf_va + offset;
+		buf->buffer.iova = ctx->buf_pool.working_buf_iova + offset;
+		buf->buffer.scp_addr = ctx->buf_pool.working_buf_scp_addr + offset;
+		buf->buffer.size = working_buf_size;
+		buf->msg_buffer.va = ctx->buf_pool.msg_buf_va + offset_msg;
+		buf->msg_buffer.scp_addr = ctx->buf_pool.msg_buf_scp_addr + offset_msg;
+		buf->msg_buffer.size = msg_buf_size;
+		buf->s_data = NULL;
+
+		list_add_tail(&buf->list_entry, &ctx->buf_pool.cam_freelist.list);
+		ctx->buf_pool.cam_freelist.cnt++;
+	}
+
+	dev_dbg(ctx->cam->dev,
+		"%s: ctx(%d): cq buffers init, freebuf cnt(%d)\n",
+		__func__, ctx->stream_id, ctx->buf_pool.cam_freelist.cnt);
+
+	return 0;
+fail_free_mem:
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size,
+			  ctx->buf_pool.working_buf_va,
+			  ctx->buf_pool.working_buf_scp_addr);
+	ctx->buf_pool.working_buf_scp_addr = 0;
+
+	return ret;
+}
+
+void mtk_cam_working_buf_pool_release(struct mtk_cam_ctx *ctx, struct device *dev)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+
+	/* msg buffer */
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.msg_buf_size,
+			  ctx->buf_pool.msg_buf_va,
+			  ctx->buf_pool.msg_buf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):msg buffers release, va:%pK scp_addr %pad sz %u\n",
+		__func__, ctx->stream_id,
+		ctx->buf_pool.msg_buf_va,
+		&ctx->buf_pool.msg_buf_scp_addr,
+		ctx->buf_pool.msg_buf_size);
+
+	/* working buffer */
+	dma_unmap_page_attrs(dev, ctx->buf_pool.working_buf_iova,
+			     ctx->buf_pool.working_buf_size,
+			     DMA_BIDIRECTIONAL,
+			     DMA_ATTR_SKIP_CPU_SYNC);
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size,
+			  ctx->buf_pool.working_buf_va,
+			  ctx->buf_pool.working_buf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):cq buffers release, iova %pad scp_addr %pad sz %u\n",
+		__func__, ctx->stream_id,
+		&ctx->buf_pool.working_buf_iova,
+		&ctx->buf_pool.working_buf_scp_addr,
+		ctx->buf_pool.working_buf_size);
+
+	/* session buffer */
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.session_buf_size,
+			  ctx->buf_pool.session_buf_va,
+			  ctx->buf_pool.session_buf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):session buffers release, scp_addr %pad sz %u\n",
+		__func__, ctx->stream_id,
+		&ctx->buf_pool.session_buf_scp_addr,
+		ctx->buf_pool.session_buf_size);
+
+	/* raw priv working buffer */
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.priv_workbuf_size,
+			  ctx->buf_pool.priv_workbuf_va,
+			  ctx->buf_pool.priv_workbuf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):raw pri working buffers release, scp_addr %pad sz %u\n",
+		__func__, ctx->stream_id,
+		&ctx->buf_pool.priv_workbuf_scp_addr,
+		ctx->buf_pool.priv_workbuf_size);
+
+	/* raw working buffer */
+	dma_free_coherent(cam->smem_dev, ctx->buf_pool.raw_workbuf_size,
+			  ctx->buf_pool.raw_workbuf_va,
+			  ctx->buf_pool.raw_workbuf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):raw working buffers release, scp_addr %pad sz %u\n",
+		__func__, ctx->stream_id,
+		&ctx->buf_pool.raw_workbuf_scp_addr,
+		ctx->buf_pool.raw_workbuf_size);
+}
+
+void mtk_cam_working_buf_put(struct mtk_cam_working_buf_entry *buf_entry)
+{
+	struct mtk_cam_ctx *ctx = buf_entry->ctx;
+	int cnt;
+
+	spin_lock(&ctx->buf_pool.cam_freelist.lock);
+
+	list_add_tail(&buf_entry->list_entry,
+		      &ctx->buf_pool.cam_freelist.list);
+	cnt = ++ctx->buf_pool.cam_freelist.cnt;
+
+	spin_unlock(&ctx->buf_pool.cam_freelist.lock);
+
+	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(%pad), free cnt(%d)\n",
+		__func__, ctx->stream_id, &buf_entry->buffer.iova, cnt);
+}
+
+struct mtk_cam_working_buf_entry *mtk_cam_working_buf_get(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_working_buf_entry *buf_entry;
+	int cnt;
+
+	/* get from free list */
+	spin_lock(&ctx->buf_pool.cam_freelist.lock);
+	if (list_empty(&ctx->buf_pool.cam_freelist.list)) {
+		spin_unlock(&ctx->buf_pool.cam_freelist.lock);
+
+		dev_info(ctx->cam->dev, "%s:ctx(%d):no free buf\n",
+			 __func__, ctx->stream_id);
+		return NULL;
+	}
+
+	buf_entry = list_first_entry(&ctx->buf_pool.cam_freelist.list,
+				     struct mtk_cam_working_buf_entry,
+				     list_entry);
+	list_del(&buf_entry->list_entry);
+	cnt = --ctx->buf_pool.cam_freelist.cnt;
+	buf_entry->ctx = ctx;
+
+	spin_unlock(&ctx->buf_pool.cam_freelist.lock);
+
+	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(%pad), free cnt(%d)\n",
+		__func__, ctx->stream_id, &buf_entry->buffer.iova, cnt);
+
+	return buf_entry;
+}
+
+int mtk_cam_img_working_buf_pool_init(struct mtk_cam_ctx *ctx, int buf_num,
+				      struct device *dev)
+{
+	int i, ret;
+	u32 working_buf_size;
+	void *ptr;
+	dma_addr_t addr;
+	struct mtk_cam_device *cam = ctx->cam;
+	struct mtk_cam_video_device *vdev;
+
+	if (buf_num > CAM_IMG_BUF_NUM) {
+		dev_err(ctx->cam->dev,
+			"%s: ctx(%d): image buffers number too large(%d)\n",
+			__func__, ctx->stream_id, buf_num);
+		WARN_ON(1);
+		return 0;
+	}
+
+	vdev = &ctx->pipe->vdev_nodes[MTK_RAW_MAIN_STREAM_OUT - MTK_RAW_SINK_NUM];
+	working_buf_size = vdev->active_fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+	INIT_LIST_HEAD(&ctx->img_buf_pool.cam_freeimglist.list);
+	spin_lock_init(&ctx->img_buf_pool.cam_freeimglist.lock);
+	ctx->img_buf_pool.cam_freeimglist.cnt = 0;
+	ctx->img_buf_pool.working_img_buf_size = buf_num * working_buf_size;
+	ptr = dma_alloc_coherent(cam->smem_dev,
+				 ctx->img_buf_pool.working_img_buf_size,
+				 &addr, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	ctx->img_buf_pool.working_img_buf_scp_addr = addr;
+	ctx->img_buf_pool.working_img_buf_va = ptr;
+	addr = dma_map_resource(dev, addr, ctx->img_buf_pool.working_img_buf_size,
+				DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
+	if (dma_mapping_error(dev, addr)) {
+		dev_err(dev, "failed to map scp iova\n");
+		ret = -ENOMEM;
+		goto fail_free_mem;
+	}
+	ctx->img_buf_pool.working_img_buf_iova = addr;
+	dev_dbg(dev,
+		"[%s] img working buf scp addr:%pad va:%pK iova: %pad size %d\n",
+		__func__,
+		&ctx->img_buf_pool.working_img_buf_scp_addr,
+		ctx->img_buf_pool.working_img_buf_va,
+		&ctx->img_buf_pool.working_img_buf_iova,
+		ctx->img_buf_pool.working_img_buf_size);
+
+	for (i = 0; i < buf_num; i++) {
+		struct mtk_cam_img_working_buf_entry *buf =
+			&ctx->img_buf_pool.img_working_buf[i];
+		int offset = i * working_buf_size;
+
+		buf->ctx = ctx;
+		buf->img_buffer.va =
+			ctx->img_buf_pool.working_img_buf_va + offset;
+		buf->img_buffer.scp_addr =
+			ctx->img_buf_pool.working_img_buf_scp_addr + offset;
+		buf->img_buffer.iova =
+			ctx->img_buf_pool.working_img_buf_iova + offset;
+		buf->img_buffer.size = working_buf_size;
+
+		list_add_tail(&buf->list_entry,
+			      &ctx->img_buf_pool.cam_freeimglist.list);
+		ctx->img_buf_pool.cam_freeimglist.cnt++;
+	}
+
+	dev_dbg(dev, "%s: ctx(%d): image buffers init, freebuf cnt(%d)\n",
+		__func__, ctx->stream_id, ctx->img_buf_pool.cam_freeimglist.cnt);
+	return 0;
+
+fail_free_mem:
+	dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size,
+			  ctx->img_buf_pool.working_img_buf_va,
+			  ctx->img_buf_pool.working_img_buf_scp_addr);
+	return ret;
+}
+
+void mtk_cam_img_working_buf_pool_release(struct mtk_cam_ctx *ctx,
+					  struct device *dev)
+{
+	struct mtk_cam_device *cam = ctx->cam;
+
+	dma_unmap_page_attrs(dev, ctx->img_buf_pool.working_img_buf_iova,
+			     ctx->img_buf_pool.working_img_buf_size,
+			     DMA_BIDIRECTIONAL,
+			     DMA_ATTR_SKIP_CPU_SYNC);
+	dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size,
+			  ctx->img_buf_pool.working_img_buf_va,
+			  ctx->img_buf_pool.working_img_buf_scp_addr);
+	dev_dbg(dev,
+		"%s:ctx(%d):img working buf release, scp addr %pad va %pK iova %pad, sz %u\n",
+		__func__, ctx->stream_id,
+		&ctx->img_buf_pool.working_img_buf_scp_addr,
+		ctx->img_buf_pool.working_img_buf_va,
+		&ctx->img_buf_pool.working_img_buf_iova,
+		ctx->img_buf_pool.working_img_buf_size);
+}
+
+void mtk_cam_img_working_buf_put(struct mtk_cam_img_working_buf_entry *buf_entry)
+{
+	struct mtk_cam_ctx *ctx = buf_entry->ctx;
+	int cnt;
+
+	spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock);
+
+	list_add_tail(&buf_entry->list_entry,
+		      &ctx->img_buf_pool.cam_freeimglist.list);
+	cnt = ++ctx->img_buf_pool.cam_freeimglist.cnt;
+
+	spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
+
+	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n",
+		__func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt);
+}
+
+struct mtk_cam_img_working_buf_entry *
+mtk_cam_img_working_buf_get(struct mtk_cam_ctx *ctx)
+{
+	struct mtk_cam_img_working_buf_entry *buf_entry;
+	int cnt;
+
+	/* get from free list */
+	spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock);
+	if (list_empty(&ctx->img_buf_pool.cam_freeimglist.list)) {
+		spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
+
+		dev_info(ctx->cam->dev, "%s:ctx(%d):no free buf\n",
+			 __func__, ctx->stream_id);
+		return NULL;
+	}
+
+	buf_entry = list_first_entry(&ctx->img_buf_pool.cam_freeimglist.list,
+				     struct mtk_cam_img_working_buf_entry,
+				     list_entry);
+	list_del(&buf_entry->list_entry);
+	cnt = --ctx->img_buf_pool.cam_freeimglist.cnt;
+
+	spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
+
+	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n",
+		__func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt);
+
+	return buf_entry;
+}
+
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h
new file mode 100755
index 000000000000..24cc8382f93d
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+
+#ifndef __MTK_CAM_POOL_H
+#define __MTK_CAM_POOL_H
+
+struct mtk_cam_ctx;
+
+int mtk_cam_working_buf_pool_init(struct mtk_cam_ctx *ctx, struct device *dev);
+void mtk_cam_working_buf_pool_release(struct mtk_cam_ctx *ctx,
+				      struct device *dev);
+
+void mtk_cam_working_buf_put(struct mtk_cam_working_buf_entry *buf_entry);
+struct mtk_cam_working_buf_entry *
+	mtk_cam_working_buf_get(struct mtk_cam_ctx *ctx);
+
+int mtk_cam_img_working_buf_pool_init(struct mtk_cam_ctx *ctx, int buf_num,
+				      struct device *dev);
+void mtk_cam_img_working_buf_pool_release(struct mtk_cam_ctx *ctx,
+					  struct device *dev);
+
+void mtk_cam_img_working_buf_put(struct mtk_cam_img_working_buf_entry *buf_entry);
+struct mtk_cam_img_working_buf_entry *
+	mtk_cam_img_working_buf_get(struct mtk_cam_ctx *ctx);
+
+#endif /* __MTK_CAM_POOL_H */
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h
new file mode 100755
index 000000000000..0ba0c3e73b72
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef _CAM_REGS_H
+#define _CAM_REGS_H
+
+/* Raw Part */
+
+/* normal siganl */
+#define VS_INT_ST						BIT(0)
+#define TG_INT1_ST						BIT(1)
+#define TG_INT2_ST						BIT(2)
+#define EXPDON_ST						BIT(5)
+#define SOF_INT_ST						BIT(8)
+#define HW_PASS1_DON_ST						BIT(20)
+#define SW_PASS1_DON_ST						BIT(22)
+#define TG_VS_INT_ORG_ST					BIT(11)
+
+/* YUV siganl */
+#define YUV_SW_PASS1_DON_ST					BIT(0)
+#define YUV_PASS1_DON_ST					BIT(1)
+#define YUV_DMA_ERR_ST						BIT(2)
+
+/* err status */
+#define TG_OVRUN_ST						BIT(6)
+#define TG_GBERR_ST						BIT(7)
+#define CQ_DB_LOAD_ERR_ST					BIT(12)
+#define CQ_MAIN_CODE_ERR_ST					BIT(14)
+#define CQ_MAIN_VS_ERR_ST					BIT(15)
+#define CQ_MAIN_TRIG_DLY_ST					BIT(16)
+#define LSCI_ERR_ST						BIT(24)
+#define DMA_ERR_ST						BIT(26)
+
+/* CAM DMA done status */
+#define AFO_DONE_ST						BIT(8)
+#define CQI_R1_DONE_ST						BIT(15)
+
+/* IRQ signal mask */
+#define INT_ST_MASK_CAM (VS_INT_ST	 |\
+			 TG_INT1_ST	 |\
+			 TG_INT2_ST	 |\
+			 EXPDON_ST       |\
+			 HW_PASS1_DON_ST |\
+			 SOF_INT_ST      |\
+			 SW_PASS1_DON_ST)
+
+/* IRQ Error Mask */
+#define INT_ST_MASK_CAM_ERR	(TG_OVRUN_ST		|\
+				 TG_GBERR_ST		|\
+				 CQ_DB_LOAD_ERR_ST	|\
+				 CQ_MAIN_CODE_ERR_ST	|\
+				 CQ_MAIN_VS_ERR_ST	|\
+				 DMA_ERR_ST)
+
+/* camsys */
+#define REG_CAMSYS_CG_SET				0x0004
+#define REG_CAMSYS_CG_CLR				0x0008
+
+#define REG_HALT1_EN					0x0350
+#define REG_HALT2_EN					0x0354
+#define REG_HALT3_EN					0x0358
+#define REG_HALT4_EN					0x035c
+#define REG_HALT5_EN					0x0360
+#define REG_HALT6_EN					0x0364
+#define REG_FLASH					0x03A0
+#define REG_ULTRA_HALT1_EN				0x03c0
+#define REG_ULTRA_HALT2_EN				0x03c4
+#define REG_ULTRA_HALT3_EN				0x03c8
+#define REG_ULTRA_HALT4_EN				0x03cc
+#define REG_ULTRA_HALT5_EN				0x03d0
+#define REG_ULTRA_HALT6_EN				0x03d4
+#define REG_PREULTRA_HALT1_EN				0x03f0
+#define REG_PREULTRA_HALT2_EN				0x03f4
+#define REG_PREULTRA_HALT3_EN				0x03f8
+#define REG_PREULTRA_HALT4_EN				0x03fc
+#define REG_PREULTRA_HALT5_EN				0x0400
+#define REG_PREULTRA_HALT6_EN				0x0404
+
+/* Status check */
+#define REG_CTL_EN					0x0000
+#define REG_CTL_EN2					0x0004
+
+/* DMA Enable Register, DMA_EN */
+#define REG_CTL_MOD5_EN					0x0010
+#define REG_CTL_MOD6_EN					0x0014
+/* RAW input trigger*/
+#define REG_CTL_RAWI_TRIG				0x00C0
+
+#define REG_CTL_MISC					0x0060
+#define CTL_DB_EN					BIT(4)
+
+#define REG_CTL_SW_CTL					0x00C4
+#define REG_CTL_START					0x00B0
+
+#define REG_CTL_RAW_INT_EN				0x0100
+#define REG_CTL_RAW_INT_STAT				0x0104
+#define REG_CTL_RAW_INT2_EN				0x0110
+#define REG_CTL_RAW_INT2_STAT				0x0114
+#define REG_CTL_RAW_INT3_STAT				0x0124
+#define REG_CTL_RAW_INT4_STAT				0x0134
+#define REG_CTL_RAW_INT5_STAT				0x0144
+#define REG_CTL_RAW_INT6_EN				0x0150
+#define REG_CTL_RAW_INT6_STAT				0x0154
+#define REG_CTL_RAW_INT7_EN				0x0160
+#define REG_CTL_RAW_INT7_STAT				0x0164
+
+#define REG_CTL_RAW_MOD_DCM_DIS				0x0300
+#define REG_CTL_RAW_MOD2_DCM_DIS			0x0304
+#define REG_CTL_RAW_MOD3_DCM_DIS			0x0308
+#define REG_CTL_RAW_MOD5_DCM_DIS			0x0310
+#define REG_CTL_RAW_MOD6_DCM_DIS			0x0314
+
+#define REG_CTL_DBG_SET					0x00F0
+#define REG_CTL_DBG_PORT				0x00F4
+#define REG_DMA_DBG_SEL					0x4070
+#define REG_DMA_DBG_PORT				0x4074
+#define REG_CTL_DBG_SET2				0x00F8
+
+#define REG_CTL_RAW_MOD_REQ_STAT			0x0340
+#define REG_CTL_RAW_MOD2_REQ_STAT			0x0344
+#define REG_CTL_RAW_MOD3_REQ_STAT			0x0348
+#define REG_CTL_RAW_MOD4_REQ_STAT			0x034c
+#define REG_CTL_RAW_MOD5_REQ_STAT			0x0350
+#define REG_CTL_RAW_MOD6_REQ_STAT			0x0354
+
+#define REG_CTL_RAW_MOD_RDY_STAT			0x0360
+#define REG_CTL_RAW_MOD2_RDY_STAT			0x0364
+#define REG_CTL_RAW_MOD3_RDY_STAT			0x0368
+#define REG_CTL_RAW_MOD4_RDY_STAT			0x036c
+#define REG_CTL_RAW_MOD5_RDY_STAT			0x0370
+#define REG_CTL_RAW_MOD6_RDY_STAT			0x0374
+
+#define REG_CQ_EN					0x0400
+#define REG_SCQ_START_PERIOD				0x0408
+#define REG_CQ_THR0_CTL					0x0410
+#define REG_CQ_SUB_CQ_EN				0x06B0
+#define REG_CQ_SUB_THR0_CTL				0x06C0
+
+#define REG_CTL_SW_PASS1_DONE				0x00c8
+#define SW_DONE_SAMPLE_EN				BIT(8)
+#define REG_CTL_SW_SUB_CTL				0x00cc
+
+#define REG_CQ_THR0_BASEADDR				0x0414
+#define REG_CQ_THR0_BASEADDR_MSB			0x0418
+#define REG_CQ_THR0_DESC_SIZE				0x041C
+#define REG_SCQ_CQ_TRIG_TIME				0x0410
+#define REG_CQ_SUB_THR0_BASEADDR_2			0x06CC
+#define REG_CQ_SUB_THR0_BASEADDR_MSB_2			0x06D0
+#define REG_CQ_SUB_THR0_DESC_SIZE_2			0x06D8
+#define REG_CQ_SUB_THR0_BASEADDR_1			0x06C4
+#define REG_CQ_SUB_THR0_BASEADDR_MSB_1			0x06C8
+#define REG_CQ_SUB_THR0_DESC_SIZE_1			0x06D4
+#define SCQ_EN						BIT(20)
+#define SCQ_STAGGER_MODE				BIT(12)
+#define SCQ_SUBSAMPLE_EN				BIT(21)
+#define CQ_DB_EN					BIT(4)
+#define CQ_THR0_MODE_IMMEDIATE				BIT(4)
+#define CQ_THR0_MODE_CONTINUOUS				BIT(5)
+#define CQ_THR0_EN					BIT(0)
+#define SCQ_SUB_RESET					BIT(16)
+
+#define REG_TG_SEN_MODE					0x0700
+#define TG_CMOS_RDY_SEL					BIT(14)
+#define TG_SEN_MODE_CMOS_EN				BIT(0)
+#define TG_VFDATA_EN					BIT(0)
+#define TG_TG_FULL_SEL					BIT(15)
+#define TG_STAGGER_EN					BIT(22)
+
+#define REG_TG_VF_CON					0x0704
+#define REG_TG_SEN_GRAB_PXL				0x0708
+#define REG_TG_SEN_GRAB_LIN				0x070C
+#define REG_TG_PATH_CFG					0x0710
+#define TG_DB_LOAD_DIS					BIT(8)
+#define TG_SUB_SOF_SRC_SEL_0				BIT(20)
+#define TG_SUB_SOF_SRC_SEL_1				BIT(21)
+
+#define REG_TG_INTER_ST					0x073C
+/* use this MASK to extract TG_CAM_CS from TG_INTER_ST */
+#define TG_CAM_CS_MASK					0x3f00
+#define TG_IDLE_ST					BIT(8)
+
+#define REG_TG_FRMSIZE_ST				0x0738
+#define REG_TG_DCIF_CTL					0x075C
+#define TG_DCIF_EN					BIT(16)
+
+#define REG_TG_FRMSIZE_ST_R				0x076C
+#define REG_TG_TIME_STAMP				0x0778
+#define REG_TG_TIME_STAMP_CNT				0x077C
+
+/* tg flash */
+#define	REG_TG_XENON_FLASH_CTL				0x0780
+#define REG_TG_XENON_FLASH_OFFSET			0x0784
+#define REG_TG_XENON_FLASH_HIGH_WIDTH			0x0788
+#define REG_TG_XENON_FLASH_LOW_WIDTH			0x078C
+#define	REG_TG_IR_FLASH_CTL				0x0798
+#define REG_TG_IR_FLASH_OFFSET				0x079C
+#define REG_TG_IR_FLASH_HIGH_WIDTH			0x07A0
+#define REG_TG_IR_FLASH_LOW_WIDTH			0x07A4
+
+/* for raw & yuv's dma top base */
+#define CAMDMATOP_BASE					0x4000
+
+#define REG_DMA_SOFT_RST_STAT				0x4068
+#define REG_DMA_SOFT_RST_STAT2				0x406C
+#define REG_DMA_DBG_CHASING_STATUS			0x4098
+#define REG_DMA_DBG_CHASING_STATUS2			0x409c
+
+#define RAWI_R2_SMI_REQ_ST				BIT(0)
+#define RAWI_R3_SMI_REQ_ST				BIT(16)
+#define RAWI_R5_SMI_REQ_ST				BIT(16)
+
+#define RST_STAT_RAWI_R2				BIT(0)
+#define RST_STAT_RAWI_R3				BIT(2)
+#define RST_STAT_RAWI_R5				BIT(5)
+/* use spare register FH_SPARE_5 */
+#define REG_FRAME_SEQ_NUM				0x4994
+
+#define REG_CAMCTL_FBC_SEL				0x00A0
+#define REG_CAMCTL_FBC_RCNT_INC				0x00A4
+
+#define CAMCTL_IMGO_R1_RCNT_INC				BIT(0)
+#define CAMCTL_CQ_THR0_DONE_ST				BIT(0)
+#define CAMCTL_CQ_THRSUB_DONE_EN			BIT(10)
+#define CTL_CQ_THR0_START				BIT(0)
+
+/* AE debug info */
+/* CAMSYS_RAW 0x1a03 */
+#define OFFSET_OBC_R1_R_SUM_L				0x1178
+#define OFFSET_OBC_R1_R_SUM_H				0x117c
+#define OFFSET_OBC_R1_B_SUM_L				0x1180
+#define OFFSET_OBC_R1_B_SUM_H				0x1184
+#define OFFSET_OBC_R1_GR_SUM_L				0x1188
+#define OFFSET_OBC_R1_GR_SUM_H				0x118c
+#define OFFSET_OBC_R1_GB_SUM_L				0x1190
+#define OFFSET_OBC_R1_GB_SUM_H				0x1194
+#define OFFSET_OBC_R1_ACT_WIN_Y				0x119c
+
+#define OFFSET_OBC_R2_R_SUM_L				0x1438
+#define OFFSET_OBC_R2_R_SUM_H				0x143c
+#define OFFSET_OBC_R2_B_SUM_L				0x1440
+#define OFFSET_OBC_R2_B_SUM_H				0x1444
+#define OFFSET_OBC_R2_GR_SUM_L				0x1448
+#define OFFSET_OBC_R2_GR_SUM_H				0x144c
+#define OFFSET_OBC_R2_GB_SUM_L				0x1450
+#define OFFSET_OBC_R2_GB_SUM_H				0x1454
+#define OFFSET_OBC_R2_ACT_WIN_X				0x1458
+#define OFFSET_OBC_R2_ACT_WIN_Y				0x145c
+
+#define OFFSET_OBC_R3_R_SUM_L				0x16f8
+#define OFFSET_OBC_R3_R_SUM_H				0x16fc
+#define OFFSET_OBC_R3_B_SUM_L				0x1700
+#define OFFSET_OBC_R3_B_SUM_H				0x1704
+#define OFFSET_OBC_R3_GR_SUM_L				0x1708
+#define OFFSET_OBC_R3_GR_SUM_H				0x170c
+#define OFFSET_OBC_R3_GB_SUM_L				0x1710
+#define OFFSET_OBC_R3_GB_SUM_H				0x1714
+#define OFFSET_OBC_R3_ACT_WIN_X				0x1718
+#define OFFSET_OBC_R3_ACT_WIN_Y				0x171c
+
+#define REG_LTM_AE_DEBUG_B_MSB				0x23f0
+#define REG_LTM_AE_DEBUG_B_LSB				0x23f4
+#define REG_LTM_AE_DEBUG_GB_MSB				0x23f8
+#define REG_LTM_AE_DEBUG_GB_LSB				0x23fc
+#define REG_LTM_AE_DEBUG_GR_MSB				0x2400
+#define REG_LTM_AE_DEBUG_GR_LSB				0x2404
+#define REG_LTM_AE_DEBUG_R_MSB				0x2408
+#define REG_LTM_AE_DEBUG_R_LSB				0x240c
+#define REG_LTMS_ACT_WIN_X				0x2578
+#define REG_LTMS_ACT_WIN_Y				0x257c
+
+#define REG_AA_R_SUM_L					0x2a1c
+#define REG_AA_R_SUM_H					0x2a20
+#define REG_AA_B_SUM_L					0x2a24
+#define REG_AA_B_SUM_H					0x2a28
+#define REG_AA_GR_SUM_L					0x2a2c
+#define REG_AA_GR_SUM_H					0x2a30
+#define REG_AA_GB_SUM_L					0x2a34
+#define REG_AA_GB_SUM_H					0x2a30
+#define REG_AA_ACT_WIN_X				0x2a3c
+#define REG_AA_ACT_WIN_Y				0x2a40
+
+#define DMA_OFFSET_CON0					0x020
+#define DMA_OFFSET_CON1					0x024
+#define DMA_OFFSET_CON2					0x028
+#define DMA_OFFSET_CON3					0x02c
+#define DMA_OFFSET_CON4					0x030
+#define DMA_OFFSET_ERR_STAT				0x034
+
+#define DMA_OFFSET_SPECIAL_DCIF				0x03c
+#define DC_CAMSV_STAGER_EN				BIT(16)
+
+#define FBC_R1A_BASE					0x2c00
+#define FBC_R2A_BASE					0x3780
+#define REG_FBC_CTL1(base, idx)				((base) + (idx) * 8)
+#define REG_FBC_CTL2(base, idx)				((base) + (idx) * 8 + 4)
+#define WCNT_BIT_MASK					0xFF00
+#define CNT_BIT_MASK					0xFF0000
+#define TG_FULLSEL_BIT_MASK				0x8000
+/* ORIDMA */
+/* CAMSYS_RAW 0x1a03 */
+#define REG_IMGO_R1_BASE				0x4880
+#define REG_FHO_R1_BASE					0x4930
+#define REG_AAHO_R1_BASE				0x49e0
+#define REG_PDO_R1_BASE					0x4a90
+#define REG_AAO_R1_BASE					0x4a40
+#define REG_AFO_R1_BASE					0x4bf0
+
+/* CAMSYS_YUV 0x1a05 */
+#define REG_YUVO_R1_BASE				0x4200
+#define REG_YUVBO_R1_BASE				0x42b0
+#define REG_YUVCO_R1_BASE				0x4360
+#define REG_YUVDO_R1_BASE				0x4410
+#define REG_YUVO_R3_BASE				0x44c0
+#define REG_YUVBO_R3_BASE				0x4570
+#define REG_YUVCO_R3_BASE				0x4620
+#define REG_YUVDO_R3_BASE				0x46D0
+
+/* ULCDMA */
+/* CAMSYS_RAW 0x1603 */
+#define REG_LTMSO_R1_BASE				0x4ce0
+#define REG_TSFSO_R1_BASE				0x4ca0
+#define REG_TSFSO_R2_BASE				0x4de0
+#define REG_FLKO_R1_BASE				0x4d20
+#define REG_UFEO_R1_BASE				0x4d60
+
+/* CAMSYS_YUV 0x1605 */
+#define REG_YUVO_R2_BASE				0x4780
+#define REG_YUVBO_R2_BASE				0x47c0
+#define REG_YUVO_R4_BASE				0x4800
+#define REG_YUVBO_R4_BASE				0x4840
+#define REG_YUVO_R5_BASE				0x4c00
+#define REG_YUVBO_R5_BASE				0x4c40
+#define REG_RZH1N2TO_R1_BASE				0x4880
+#define REG_RZH1N2TBO_R1_BASE				0x48c0
+#define REG_RZH1N2TO_R2_BASE				0x4900
+#define REG_RZH1N2TO_R3_BASE				0x4940
+#define REG_RZH1N2TBO_R3_BASE				0x4980
+#define REG_DRZS4NO_R1_BASE				0x49c0
+#define REG_DRZS4NO_R2_BASE				0x4a00
+#define REG_DRZS4NO_R3_BASE				0x4a40
+#define REG_ACTSO_R1_BASE				0x4ac0
+#define REG_TNCSO_R1_BASE				0x4b00
+#define REG_TNCSBO_R1_BASE				0x4b40
+#define REG_TNCSHO_R1_BASE				0x4b80
+#define REG_TNCSYO_R1_BASE				0x4bc0
+
+/* CAMSYS_RAW 0x1a03 */
+#define REG_RAWI_R2_BASE				0x4100
+#define REG_RAWI_R2_BASE_MSB				0x4104
+#define REG_UFDI_R2_BASE				0x4170
+#define REG_RAWI_R3_BASE				0x41e0
+#define REG_RAWI_R3_BASE_MSB				0x41e4
+#define REG_UFDI_R3_BASE				0x4250
+#define REG_CQI_R1_BASE					0x4410
+#define REG_CQI_R1_BASE_MSB				0x4414
+#define REG_CQI_R2_BASE					0x4480
+#define REG_CQI_R2_BASE_MSB				0x4484
+#define REG_CQI_R3_BASE					0x44f0
+#define REG_CQI_R3_BASE_MSB				0x44f4
+#define REG_CQI_R4_BASE					0x4560
+#define REG_CQI_R4_BASE_MSB				0x4564
+#define REG_LSCI_R1_BASE				0x45d0
+#define REG_BPCI_R1_BASE				0x4640
+#define REG_BPCI_R2_BASE				0x4680
+#define REG_BPCI_R3_BASE				0x46c0
+#define REG_PDI_R1_BASE					0x4700
+#define REG_AAI_R1_BASE					0x4780
+#define REG_CACI_R1_BASE				0x47c0
+#define REG_RAWI_R5_BASE				0x4330
+#define REG_RAWI_R6_BASE				0x4800
+
+#endif	/* _CAM_REGS_H */
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (8 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-08-01  5:45   ` CK Hu (胡俊光)
  2025-07-07  1:31 ` [PATCH v2 11/13] media: platform: mediatek: add isp_7x build config shangyao lin
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Introduce the V4L2 video interface and feature management for the MediaTek
ISP7.x CAMSYS. These interfaces provide functionalities such as video operation
initialization and registration. They also manage MediaTek-specific formats and
handle buffers for MediaTek camera video devices. This enables CAMSYS
functionalities to be compatible with the V4L2 framework.

Changes in v2:
- Removed mtk_cam-feature.c and mtk_cam-feature.h, along with related code
- Various fixes per review comments

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../isp/isp_7x/camsys/mtk_cam-video.c         | 1594 +++++++++++++++++
 .../isp/isp_7x/camsys/mtk_cam-video.h         |  223 +++
 2 files changed, 1817 insertions(+)
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
 create mode 100755 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-video.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
new file mode 100755
index 000000000000..8f071c259851
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c
@@ -0,0 +1,1594 @@
+// 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-video.h"
+#include "mtk_camera-v4l2-controls.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_ISP_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_ISP_META_STATS_0:
+	case MTKCAM_ISP_META_STATS_1:
+	case MTKCAM_ISP_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;
+			} 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;
+			} 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 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;
+
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
+	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;
+	/* fmt description is filled in v4l_fill_fmtdesc */
+
+	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;
+	/*fmt description is filled in v4l_fill_fmtdesc */
+
+	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_ISP_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_ISP_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 100755
index 000000000000..38b89cc2b81e
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h
@@ -0,0 +1,223 @@
+/* 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 11/13] media: platform: mediatek: add isp_7x build config
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (9 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-07  1:31 ` [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api shangyao lin
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Add Kconfig and Makefile to include MTK ISP CAMSYS, integrating the driver into
the kernel build and configuration process.

Question for CK:

Hi CK,

Thank you for your review and comments.

Just to confirm, do you mean that when I add mtk_cam-seninf-route.c and
mtk_cam-seninf-drv.c in patch [3/10], I should also create or update the
corresponding Makefile to ensure these two .c files are compiled as part of the
driver? Is my understanding correct?

Thank you for your clarification.

Best regards,
Shangyao

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 drivers/media/platform/mediatek/Kconfig       |  1 +
 drivers/media/platform/mediatek/Makefile      |  2 ++
 drivers/media/platform/mediatek/isp/Kconfig   | 21 +++++++++++++++++++
 .../platform/mediatek/isp/isp_7x/Makefile     |  7 +++++++
 .../mediatek/isp/isp_7x/camsys/Makefile       | 14 +++++++++++++
 5 files changed, 45 insertions(+)
 mode change 100644 => 100755 drivers/media/platform/mediatek/Kconfig
 mode change 100644 => 100755 drivers/media/platform/mediatek/Makefile
 create mode 100755 drivers/media/platform/mediatek/isp/Kconfig
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/Makefile
 create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile

diff --git a/drivers/media/platform/mediatek/Kconfig b/drivers/media/platform/mediatek/Kconfig
old mode 100644
new mode 100755
index 84104e2cd024..a405d5701329
--- a/drivers/media/platform/mediatek/Kconfig
+++ b/drivers/media/platform/mediatek/Kconfig
@@ -2,6 +2,7 @@
 
 comment "Mediatek media platform drivers"
 
+source "drivers/media/platform/mediatek/isp/Kconfig"
 source "drivers/media/platform/mediatek/jpeg/Kconfig"
 source "drivers/media/platform/mediatek/mdp/Kconfig"
 source "drivers/media/platform/mediatek/vcodec/Kconfig"
diff --git a/drivers/media/platform/mediatek/Makefile b/drivers/media/platform/mediatek/Makefile
old mode 100644
new mode 100755
index 38e6ba917fe5..74164df8c68d
--- a/drivers/media/platform/mediatek/Makefile
+++ b/drivers/media/platform/mediatek/Makefile
@@ -1,6 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
 obj-y += jpeg/
 obj-y += mdp/
 obj-y += vcodec/
 obj-y += vpu/
 obj-y += mdp3/
+obj-y += isp/isp_7x/
diff --git a/drivers/media/platform/mediatek/isp/Kconfig b/drivers/media/platform/mediatek/isp/Kconfig
new file mode 100755
index 000000000000..ce4dd21e3e79
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_MTK_ISP_71_CAMSYS
+	tristate "MediaTek ISP 7.1 camsys driver"
+	depends on ARCH_MEDIATEK
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	select VIDEOBUF2_DMA_CONTIG
+	select RPMSG_MTK_CCD
+	select MTKCCD_REMOTEPROC
+	select MTK_SCP
+
+	default n
+	help
+		Camsys driver controls 3A (auto-focus, exposure,
+		and white balance) with tuning feature and outputs
+		the captured image buffers in MediaTek's ISP7 system.
+
+		Choose y if you want to use MediaTek SoCs to create image
+		captured application such as video recording and still image
+		capturing.
\ No newline at end of file
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/Makefile
new file mode 100755
index 000000000000..be70346d224b
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+subdir-ccflags-y += -Werror
+
+subdir-ccflags-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += -DISP7_1
+
+obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += camsys/
\ No newline at end of file
diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile
new file mode 100755
index 000000000000..700ac2a85ac4
--- /dev/null
+++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022 MediaTek Inc.
+
+mtk-cam-isp-objs := mtk_cam.o mtk_cam-raw.o mtk_cam-pool.o \
+		    mtk_cam-video.o mtk_cam-ctrl.o \
+		    mtk_cam-seninf-route.o mtk_cam-seninf-drv.o \
+		    mtk_cam-timesync.o
+
+mtk-cam-plat-util-objs :=  mtk_cam-plat-util.o
+
+include $(src)/mtk_csi_phy_2_0/Makefile
+
+obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += mtk-cam-plat-util.o
+obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += mtk-cam-isp.o
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (10 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 11/13] media: platform: mediatek: add isp_7x build config shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-08  1:34   ` CK Hu (胡俊光)
  2025-07-07  1:31 ` [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls shangyao lin
  2025-07-07  5:55 ` [PATCH v2 00/13] Add MediaTek ISP7.x camera system support Krzysztof Kozlowski
  13 siblings, 1 reply; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

Add UAPI for the MediaTek ISP platform, providing user-space interfaces for the
new CAMSYS driver.

Changes in v2:
- Moved V4L2 pixel format definitions to include/uapi/linux/videodev2.h

Notes:

Hi Laurent Pinchart and CK,

Thank you very much for your detailed feedback and suggestions.

I would like to let you know that in the next patch, I have added an initial
version of an .rst document describing the MTK ISP CAMSYS controls. Most of
these ISP CAMSYS controls are intended for other advanced features. For normal
main-stream use cases, only controls such as V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC
are actually used.

Would you prefer that we remove the user space interfaces for these advanced
features for now, and only add them back in a future patch series dedicated to
advanced functionality? I am happy to follow your recommendation on this.

Additionally, I have also written an initial version of a brief .rst document
providing a high-level description of the hardware. If you think there is
anything else that should be added or clarified, please kindly let me know.

Thank you again for your valuable feedback!

Best regards,
Shangyao

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 include/uapi/linux/mtkisp_camsys.h | 132 +++++++++++++++++++++++++++++
 include/uapi/linux/videodev2.h     |  87 +++++++++++++++++++
 2 files changed, 219 insertions(+)
 create mode 100755 include/uapi/linux/mtkisp_camsys.h
 mode change 100644 => 100755 include/uapi/linux/videodev2.h

diff --git a/include/uapi/linux/mtkisp_camsys.h b/include/uapi/linux/mtkisp_camsys.h
new file mode 100755
index 000000000000..4d563c12077b
--- /dev/null
+++ b/include/uapi/linux/mtkisp_camsys.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * MediaTek ISP camsys User space API
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef _MTKISP_CAMSYS_USER_H
+#define _MTKISP_CAMSYS_USER_H
+
+#include <linux/videodev2.h>
+#include <linux/v4l2-controls.h>
+
+#define V4L2_BUF_FLAG_TIMESTAMP_COPY		0x00004000
+#define V4L2_BUF_FLAG_TIMESTAMP_BOOTIME		0x00008000
+
+/* MTK ISP camsys events */
+#define V4L2_EVENT_REQUEST_DRAINED              (V4L2_EVENT_PRIVATE_START + 1)
+#define V4L2_EVENT_REQUEST_DUMPED               (V4L2_EVENT_PRIVATE_START + 2)
+
+/* The base for the mediatek camsys driver controls */
+/* We reserve 48 controls for this driver. */
+#define V4L2_CID_USER_MTK_CAM_BASE		(V4L2_CID_USER_BASE + 0x10d0)
+
+/* MTK ISP camsys controls */
+#define V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT	(V4L2_CID_USER_MTK_CAM_BASE + 1)
+#define V4L2_CID_MTK_CAM_BIN_LIMIT		(V4L2_CID_USER_MTK_CAM_BASE + 2)
+#define V4L2_CID_MTK_CAM_FRZ_LIMIT		(V4L2_CID_USER_MTK_CAM_BASE + 3)
+#define V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY	(V4L2_CID_USER_MTK_CAM_BASE + 4)
+#define V4L2_CID_MTK_CAM_USED_ENGINE		(V4L2_CID_USER_MTK_CAM_BASE + 5)
+#define V4L2_CID_MTK_CAM_BIN			(V4L2_CID_USER_MTK_CAM_BASE + 6)
+#define V4L2_CID_MTK_CAM_FRZ			(V4L2_CID_USER_MTK_CAM_BASE + 7)
+#define V4L2_CID_MTK_CAM_USED_ENGINE_TRY	(V4L2_CID_USER_MTK_CAM_BASE + 8)
+#define V4L2_CID_MTK_CAM_BIN_TRY		(V4L2_CID_USER_MTK_CAM_BASE + 9)
+#define V4L2_CID_MTK_CAM_FRZ_TRY		(V4L2_CID_USER_MTK_CAM_BASE + 10)
+#define V4L2_CID_MTK_CAM_PIXEL_RATE		(V4L2_CID_USER_MTK_CAM_BASE + 11)
+#define V4L2_CID_MTK_CAM_FEATURE		(V4L2_CID_USER_MTK_CAM_BASE + 12)
+#define V4L2_CID_MTK_CAM_SYNC_ID		(V4L2_CID_USER_MTK_CAM_BASE + 13)
+#define V4L2_CID_MTK_CAM_RAW_PATH_SELECT	(V4L2_CID_USER_MTK_CAM_BASE + 14)
+#define V4L2_CID_MTK_CAM_HSF_EN			(V4L2_CID_USER_MTK_CAM_BASE + 15)
+#define V4L2_CID_MTK_CAM_PDE_INFO		(V4L2_CID_USER_MTK_CAM_BASE + 16)
+#define V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC	(V4L2_CID_USER_MTK_CAM_BASE + 18)
+#define V4L2_CID_MTK_CAM_TG_FLASH_CFG		(V4L2_CID_USER_MTK_CAM_BASE + 19)
+#define V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE	(V4L2_CID_USER_MTK_CAM_BASE + 20)
+#define V4L2_CID_MTK_CAM_CAMSYS_HW_MODE		(V4L2_CID_USER_MTK_CAM_BASE + 21)
+
+/*
+ * struct mtk_cam_resource_sensor - sensor resoruces for format negotiation
+ *
+ */
+struct mtk_cam_resource_sensor {
+	struct v4l2_fract interval;
+	__u32 hblank;
+	__u32 vblank;
+	__u64 pixel_rate;
+	__u64 cust_pixel_rate;
+};
+
+/*
+ * struct mtk_cam_resource_raw - MTK camsys raw resoruces for format negotiation
+ *
+ * @feature: value of V4L2_CID_MTK_CAM_FEATURE the user want to check the
+ *		  resource with. If it is used in set CTRL, we will apply the value
+ *		  to V4L2_CID_MTK_CAM_FEATURE ctrl directly.
+ * @strategy: indicate the order of multiple raws, binning or DVFS to be selected
+ *	      when doing format negotiation of raw's source pads (output pads).
+ *	      Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to
+ *	      determine it.
+ * @raw_max: indicate the max number of raw to be used for the raw pipeline.
+ *	     Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to
+ *	     determine it.
+ * @raw_min: indicate the max number of raw to be used for the raw pipeline.
+ *	     Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to
+ *	     determine it.
+ * @raw_used: The number of raw used. The used don't need to writ this failed,
+ *	      the driver always updates the field.
+ * @bin: indicate if the driver should enable the bining or not. The driver
+ *	 update the field depanding the hardware supporting status. Please pass
+ *	 MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to determine it.
+ * @path_sel: indicate the user selected raw path. The driver
+ *	      update the field depanding the hardware supporting status. Please
+ *	      pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to
+ *	      determine it.
+ * @pixel_mode: the pixel mode driver used in the raw pipeline. It is written by
+ *		driver only.
+ * @throughput: the throughput be used in the raw pipeline. It is written by
+ *		driver only.
+ *
+ */
+struct mtk_cam_resource_raw {
+	__s64	feature;
+	__u16	strategy;
+	__u8	raw_max;
+	__u8	raw_min;
+	__u8	raw_used;
+	__u8	bin;
+	__u8	path_sel;
+	__u8	pixel_mode;
+	__u64	throughput;
+};
+
+/*
+ * struct mtk_cam_resource - MTK camsys resoruces for format negotiation
+ *
+ * @sink_fmt: sink_fmt pad's format, it must be return by g_fmt or s_fmt
+ *		from driver.
+ * @sensor_res: senor information to calculate the required resource, it is
+ *		read-only and camsys driver will not change it.
+ * @raw_res: user hint and resource negotiation result.
+ * @status: resource negotiation status.
+ *
+ */
+struct mtk_cam_resource {
+	__u64 sink_fmt;
+	struct mtk_cam_resource_sensor sensor_res;
+	struct mtk_cam_resource_raw raw_res;
+	__u8 status;
+};
+
+/**
+ * struct mtk_cam_pde_info - PDE module information for raw
+ *
+ * @pdo_max_size: the max pdo size of pde sensor.
+ * @pdi_max_size: the max pdi size of pde sensor or max pd table size.
+ * @pd_table_offset: the offest of meta config for pd table content.
+ */
+struct mtk_cam_pde_info {
+	__u32 pdo_max_size;
+	__u32 pdi_max_size;
+	__u32 pd_table_offset;
+};
+#endif /* _MTKISP_CAMSYS_USER_H */
\ No newline at end of file
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
old mode 100644
new mode 100755
index 9e3b366d5fc7..abaee64bebd1
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -840,6 +840,93 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_PISP_COMP2_BGGR	v4l2_fourcc('P', 'C', '2', 'B') /* PiSP 8-bit mode 2 compressed BGGR bayer */
 #define V4L2_PIX_FMT_PISP_COMP2_MONO	v4l2_fourcc('P', 'C', '2', 'M') /* PiSP 8-bit mode 2 compressed monochrome */
 
+/* Luminance+Chrominance formats */
+#define V4L2_PIX_FMT_YUYV10  v4l2_fourcc('Y', 'U', 'Y', 'A') /* 16  YUV 4:2:2 10-bit */
+#define V4L2_PIX_FMT_YVYU10  v4l2_fourcc('Y', 'V', 'Y', 'A') /* 16  YUV 4:2:2 10-bit */
+#define V4L2_PIX_FMT_UYVY10  v4l2_fourcc('U', 'Y', 'V', 'A') /* 16  YUV 4:2:2 10-bit */
+#define V4L2_PIX_FMT_VYUY10  v4l2_fourcc('V', 'Y', 'U', 'A') /* 16  YUV 4:2:2 10-bit */
+#define V4L2_PIX_FMT_YUYV12  v4l2_fourcc('Y', 'U', 'Y', 'C') /* 16  YUV 4:2:2 12-bit */
+#define V4L2_PIX_FMT_YVYU12  v4l2_fourcc('Y', 'V', 'Y', 'C') /* 16  YUV 4:2:2 12-bit */
+#define V4L2_PIX_FMT_UYVY12  v4l2_fourcc('U', 'Y', 'V', 'C') /* 16  YUV 4:2:2 12-bit */
+#define V4L2_PIX_FMT_VYUY12  v4l2_fourcc('V', 'Y', 'U', 'C') /* 16  YUV 4:2:2 12-bit */
+
+/* two planes -- one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12_10 v4l2_fourcc('1', '2', 'A', 'U') /* 12  Y/CbCr 4:2:0 10 bits un-packed */
+#define V4L2_PIX_FMT_NV21_10 v4l2_fourcc('2', '1', 'A', 'U') /* 12  Y/CrCb 4:2:0 10 bits un-packed */
+#define V4L2_PIX_FMT_NV16_10 v4l2_fourcc('1', '6', 'A', 'U') /* 16  Y/CbCr 4:2:2 10 bits un-packed */
+#define V4L2_PIX_FMT_NV61_10 v4l2_fourcc('6', '1', 'A', 'U') /* 16  Y/CrCb 4:2:2 10 bits un-packed */
+#define V4L2_PIX_FMT_NV12_12 v4l2_fourcc('1', '2', 'C', 'U') /* 12  Y/CbCr 4:2:0 12 bits un-packed */
+#define V4L2_PIX_FMT_NV21_12 v4l2_fourcc('2', '1', 'C', 'U') /* 12  Y/CrCb 4:2:0 12 bits un-packed */
+#define V4L2_PIX_FMT_NV16_12 v4l2_fourcc('1', '6', 'C', 'U') /* 16  Y/CbCr 4:2:2 12 bits un-packed */
+#define V4L2_PIX_FMT_NV61_12 v4l2_fourcc('6', '1', 'C', 'U') /* 16  Y/CrCb 4:2:2 12 bits un-packed */
+
+/* Vendor specific - MediaTek ISP bayer formats */
+#define V4L2_PIX_FMT_MTISP_SBGGR8   v4l2_fourcc('M', 'B', 'B', '8') /*  Packed  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG8   v4l2_fourcc('M', 'B', 'G', '8') /*  Packed  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG8   v4l2_fourcc('M', 'B', 'g', '8') /*  Packed  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB8   v4l2_fourcc('M', 'B', 'R', '8') /*  Packed  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR10  v4l2_fourcc('M', 'B', 'B', 'A') /*  Packed 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG10  v4l2_fourcc('M', 'B', 'G', 'A') /*  Packed 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG10  v4l2_fourcc('M', 'B', 'g', 'A') /*  Packed 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB10  v4l2_fourcc('M', 'B', 'R', 'A') /*  Packed 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR12  v4l2_fourcc('M', 'B', 'B', 'C') /*  Packed 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG12  v4l2_fourcc('M', 'B', 'G', 'C') /*  Packed 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG12  v4l2_fourcc('M', 'B', 'g', 'C') /*  Packed 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB12  v4l2_fourcc('M', 'B', 'R', 'C') /*  Packed 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR14  v4l2_fourcc('M', 'B', 'B', 'E') /*  Packed 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG14  v4l2_fourcc('M', 'B', 'G', 'E') /*  Packed 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG14  v4l2_fourcc('M', 'B', 'g', 'E') /*  Packed 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB14  v4l2_fourcc('M', 'B', 'R', 'E') /*  Packed 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR8F  v4l2_fourcc('M', 'F', 'B', '8') /*  Full-G  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG8F  v4l2_fourcc('M', 'F', 'G', '8') /*  Full-G  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG8F  v4l2_fourcc('M', 'F', 'g', '8') /*  Full-G  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB8F  v4l2_fourcc('M', 'F', 'R', '8') /*  Full-G  8-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR10F  v4l2_fourcc('M', 'F', 'B', 'A') /*  Full-G 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG10F  v4l2_fourcc('M', 'F', 'G', 'A') /*  Full-G 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG10F  v4l2_fourcc('M', 'F', 'g', 'A') /*  Full-G 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB10F  v4l2_fourcc('M', 'F', 'R', 'A') /*  Full-G 10-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR12F  v4l2_fourcc('M', 'F', 'B', 'C') /*  Full-G 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG12F  v4l2_fourcc('M', 'F', 'G', 'C') /*  Full-G 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG12F  v4l2_fourcc('M', 'F', 'g', 'C') /*  Full-G 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB12F  v4l2_fourcc('M', 'F', 'R', 'C') /*  Full-G 12-bit  */
+#define V4L2_PIX_FMT_MTISP_SBGGR14F  v4l2_fourcc('M', 'F', 'B', 'E') /*  Full-G 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SGBRG14F  v4l2_fourcc('M', 'F', 'G', 'E') /*  Full-G 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRBG14F  v4l2_fourcc('M', 'F', 'g', 'E') /*  Full-G 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SRGGB14F  v4l2_fourcc('M', 'F', 'R', 'E') /*  Full-G 14-bit  */
+#define V4L2_PIX_FMT_MTISP_SGRB8F  v4l2_fourcc('M', 'F', '8', 'P') /* three planes Full-G 8-bit */
+#define V4L2_PIX_FMT_MTISP_SGRB10F  v4l2_fourcc('M', 'F', 'A', 'P') /* three planes Full-G 10-bit */
+#define V4L2_PIX_FMT_MTISP_SGRB12F  v4l2_fourcc('M', 'F', 'C', 'P') /* three planes Full-G 12-bit */
+
+/* Vendor specific - MediaTek Luminance+Chrominance formats */
+#define V4L2_PIX_FMT_MTISP_YUYV10P v4l2_fourcc('Y', 'U', 'A', 'P') /* YUV 4:2:2 10-bit packed */
+#define V4L2_PIX_FMT_MTISP_YVYU10P v4l2_fourcc('Y', 'V', 'A', 'P') /* YUV 4:2:2 10-bit packed */
+#define V4L2_PIX_FMT_MTISP_UYVY10P v4l2_fourcc('U', 'Y', 'A', 'P') /* YUV 4:2:2 10-bit packed */
+#define V4L2_PIX_FMT_MTISP_VYUY10P v4l2_fourcc('V', 'Y', 'A', 'P') /* YUV 4:2:2 10-bit packed */
+#define V4L2_PIX_FMT_MTISP_NV12_10P v4l2_fourcc('1', '2', 'A', 'P') /* Y/CbCr 4:2:0 10 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV21_10P v4l2_fourcc('2', '1', 'A', 'P') /* Y/CrCb 4:2:0 10 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV16_10P v4l2_fourcc('1', '6', 'A', 'P') /* Y/CbCr 4:2:2 10 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV61_10P v4l2_fourcc('6', '1', 'A', 'P') /* Y/CrCb 4:2:2 10 bits packed */
+#define V4L2_PIX_FMT_MTISP_YUYV12P v4l2_fourcc('Y', 'U', 'C', 'P') /* YUV 4:2:2 12-bit packed */
+#define V4L2_PIX_FMT_MTISP_YVYU12P v4l2_fourcc('Y', 'V', 'C', 'P') /* YUV 4:2:2 12-bit packed */
+#define V4L2_PIX_FMT_MTISP_UYVY12P v4l2_fourcc('U', 'Y', 'C', 'P') /* YUV 4:2:2 12-bit packed */
+#define V4L2_PIX_FMT_MTISP_VYUY12P v4l2_fourcc('V', 'Y', 'C', 'P') /* YUV 4:2:2 12-bit packed */
+#define V4L2_PIX_FMT_MTISP_NV12_12P v4l2_fourcc('1', '2', 'C', 'P') /* Y/CbCr 4:2:0 12 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV21_12P v4l2_fourcc('2', '1', 'C', 'P') /* Y/CrCb 4:2:0 12 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV16_12P v4l2_fourcc('1', '6', 'C', 'P') /* Y/CbCr 4:2:2 12 bits packed */
+#define V4L2_PIX_FMT_MTISP_NV61_12P v4l2_fourcc('6', '1', 'C', 'P') /* Y/CrCb 4:2:2 12 bits packed */
+
+/* Vendor specific - MediaTek specified compressed format */
+#define V4L2_PIX_FMT_MTISP_NV12_UFBC v4l2_fourcc('1', '2', '8', 'F') /* Y/CbCr 4:2:0 8 bits compressed */
+#define V4L2_PIX_FMT_MTISP_NV21_UFBC v4l2_fourcc('2', '1', '8', 'F') /* Y/CrCb 4:2:0 8 bits compressed */
+#define V4L2_PIX_FMT_MTISP_NV12_10_UFBC v4l2_fourcc('1', '2', 'A', 'F') /* Y/CbCr 4:2:0 10 bits compressed */
+#define V4L2_PIX_FMT_MTISP_NV21_10_UFBC v4l2_fourcc('2', '1', 'A', 'F') /* Y/CrCb 4:2:0 10 bits compressed */
+#define V4L2_PIX_FMT_MTISP_NV12_12_UFBC v4l2_fourcc('1', '2', 'C', 'F') /* Y/CbCr 4:2:0 12 bits compressed */
+#define V4L2_PIX_FMT_MTISP_NV21_12_UFBC v4l2_fourcc('2', '1', 'C', 'F') /* Y/CrCb 4:2:0 12 bits compressed */
+#define V4L2_PIX_FMT_MTISP_BAYER8_UFBC v4l2_fourcc('M', 'B', '8', 'U') /* Raw 8 bits compressed */
+#define V4L2_PIX_FMT_MTISP_BAYER10_UFBC v4l2_fourcc('M', 'B', 'A', 'U') /* Raw 10 bits compressed */
+#define V4L2_PIX_FMT_MTISP_BAYER12_UFBC v4l2_fourcc('M', 'B', 'C', 'U') /* Raw 12 bits compressed */
+#define V4L2_PIX_FMT_MTISP_BAYER14_UFBC v4l2_fourcc('M', 'B', 'E', 'U') /* Raw 14 bits compressed */
+
 /* SDR formats - used only for Software Defined Radio devices */
 #define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
 #define V4L2_SDR_FMT_CU16LE       v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (11 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api shangyao lin
@ 2025-07-07  1:31 ` shangyao lin
  2025-07-11  3:12   ` CK Hu (胡俊光)
  2025-07-07  5:55 ` [PATCH v2 00/13] Add MediaTek ISP7.x camera system support Krzysztof Kozlowski
  13 siblings, 1 reply; 41+ messages in thread
From: shangyao lin @ 2025-07-07  1:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: Shangyao Lin, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

From: "shangyao.lin" <shangyao.lin@mediatek.com>

This document covers:
- The hardware pipeline and firmware interface
- Integration with the V4L2 CAMSYS/media controller framework
- The list of custom V4L2 controls, their usage, valid ranges, and typical usage flow

Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
---
 .../media/v4l/mtk-isp7x-camsys.rst            |  94 +++++++++
 .../media/v4l/mtk-isp7x-controls.rst          | 199 ++++++++++++++++++
 2 files changed, 293 insertions(+)
 create mode 100755 Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
 create mode 100755 Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst

diff --git a/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst b/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
new file mode 100755
index 000000000000..04a1fe1c448d
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
@@ -0,0 +1,94 @@
+==========================
+MediaTek ISP7x Camera System
+==========================
+
+Overview
+========
+
+The MediaTek ISP7x camera system is designed to provide a flexible, high-performance image capture pipeline for SoCs, leveraging the Linux V4L2 framework. The system is composed of multiple hardware modules (Sensor, SENINF, RAW ISP, etc.) and a firmware backend, with a clear separation of control and data flow. This document describes the hardware architecture from the perspective of the interface exposed to the firmware (backend), and how it integrates with the V4L2 CAMSYS framework.
+
+V4L2 CAMSYS Framework Overview
+==============================
+
+The V4L2 CAMSYS framework models the camera pipeline as a set of interconnected devices and subdevices:
+
+- **Video Device**: Exposes buffer queue/dequeue (enque/deque) operations to user space, allowing applications to stream image data.
+- **Subdevice**: Represents a hardware block (e.g., sensor, SENINF, RAW ISP) and handles control/configuration operations.
+- **Pads and Links**: Each subdevice has pads (input/output endpoints). Media links connect pads, representing the physical and logical data flow between hardware blocks.
+
+The topology and link state are established at probe time and can be dynamically enabled/disabled by user space, depending on the desired pipeline configuration.
+
+Hardware Pipeline
+=================
+
+A typical pipeline consists of:
+
+.. code-block::
+
+    Sensor --> SENINF --> RAW ISP --> (optional: YUV ISP) --> Memory
+
+- **Sensor**: Provides MIPI CSI-2 data.
+- **SENINF**: Receives and demultiplexes sensor data, supports virtual channel (VC) and data type (DT) routing.
+- **RAW ISP**: Main image signal processor, handles demosaicing, noise reduction, and other image enhancements.
+- **YUV ISP** (optional): Further processing for YUV output.
+- **CAMSYS**: System controller, manages pipeline state, buffer flow, and synchronization.
+
+Firmware Interface
+==================
+
+The firmware (backend, e.g., CCD/SCP) is responsible for:
+
+- Calculating hardware settings (3A, tuning, DMA, FBC, Twin, etc.) for each frame.
+- Generating command queues (CQ) and descriptors to program the hardware.
+- Abstracting hardware-specific details from the kernel driver.
+
+The kernel driver communicates with the firmware via an inter-processor interface (IPI), typically using RPMSG. The main interactions are:
+
+1. **Session Management**: The kernel establishes a session with the firmware at stream-on, and destroys it at stream-off.
+2. **Per-frame Request Scheduling**: For each user request (frame), the kernel sends a request to the firmware, including sensor settings, buffer addresses, and control parameters.
+3. **CQ Generation**: The firmware generates the necessary command queues and returns them to the kernel.
+4. **Event Notification**: The firmware notifies the kernel of CQ completion, errors, or other events.
+
+Request Scheduling and Buffer Flow
+==================================
+
+The request scheduling flow is as follows:
+
+1. **User space** submits a request (with buffer and control settings) via V4L2.
+2. **PipeMgr** (user space) collects requests, groups them by file descriptor, and sends them to the kernel CAMSYS driver.
+3. **CAMSYS** schedules requests, manages buffer flow, and coordinates with the firmware for hardware programming.
+4. **Firmware** processes each request, generates CQ, and signals completion.
+5. **Kernel** dequeues the buffer and notifies user space.
+
+The system supports per-frame control, allowing sensor settings and ISP parameters to be updated on a frame-by-frame basis.
+
+Media Controller Topology
+=========================
+
+The media controller graph models the hardware pipeline as a set of entities (video devices, subdevices) connected by links. Each entity exposes pads, and links are established at probe time based on the hardware configuration and device tree.
+
+.. code-block::
+
+    +---------+     +--------+     +--------+     +------+
+    | Sensor  | --> | SENINF | --> | RAW ISP| --> | Video|
+    +---------+     +--------+     +--------+     +------+
+
+- Solid lines: active links (enabled)
+- Dashed lines: inactive links (disabled)
+
+User space can query and configure the topology using standard V4L2 and media controller APIs.
+
+Backend Abstraction
+===================
+
+The backend firmware abstracts hardware-specific programming, allowing the kernel driver to remain generic and maintainable. All hardware register programming, tuning, and advanced features are handled in the firmware, with the kernel acting as a control and data flow manager.
+
+This separation ensures that proprietary hardware details remain in the firmware, while the kernel driver exposes a standard V4L2 interface.
+
+Summary
+=======
+
+- The MediaTek ISP7x camera system is built on the V4L2 media controller framework, with a modular pipeline of video devices and subdevices.
+- The kernel driver manages pipeline state, buffer flow, and per-frame control, while delegating hardware programming to the backend firmware via IPI.
+- The firmware interface is session-based, supports per-frame CQ generation, and abstracts all hardware-specific details from the kernel.
+- The media controller graph models the hardware pipeline, allowing flexible configuration and dynamic topology management.
\ No newline at end of file
diff --git a/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst b/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst
new file mode 100755
index 000000000000..0e8d41d339e7
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst
@@ -0,0 +1,199 @@
+==========================================
+MediaTek ISP Camsys User Space Interface
+==========================================
+
+Overview
+--------
+
+The MediaTek ISP camsys driver provides a set of custom V4L2 controls for user space
+applications to configure and query the ISP hardware. These controls allow
+fine-grained management of resource allocation, feature enablement, and
+hardware-specific settings.
+
+Typical Usage Flow
+------------------
+
+1. Open the video device node (e.g., ``/dev/video0``).
+2. Set required V4L2 controls using ``VIDIOC_S_CTRL`` or ``VIDIOC_S_EXT_CTRLS``.
+3. Set up video format and buffers (``VIDIOC_S_FMT``, ``VIDIOC_REQBUFS``, etc.).
+4. Start streaming with ``VIDIOC_STREAMON``.
+5. Queue and dequeue buffers for image processing (``VIDIOC_QBUF``, ``VIDIOC_DQBUF``).
+6. Stop streaming with ``VIDIOC_STREAMOFF``.
+
+Control List and Documentation
+-----------------------------
+
+Below is a list of custom V4L2 controls provided by the camsys driver, with detailed descriptions.
+
+.. list-table::
+   :header-rows: 1
+
+   * - Control Name
+     - Type
+     - Description
+     - Valid Values / Range
+     - When to Set
+
+   * - ``V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT``
+     - Integer
+     - Limits the maximum number of RAW engines (hardware pipelines) that can be used for this stream.
+     - 1 ~ 2 (default: 2)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_BIN_LIMIT``
+     - Integer
+     - Sets the maximum binning ratio allowed for the stream.
+     - 0 ~ 0xFFF (default: 0)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_FRZ_LIMIT``
+     - Integer
+     - Sets the maximum resizer (FRZ) ratio allowed (as a percentage).
+     - 70 ~ 100 (default: 100)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY``
+     - Integer (Enum)
+     - Selects the resource planning policy for the stream.
+     - 0: Default, 1: Power-saving, 2: Performance, ... (0~10)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_USED_ENGINE``
+     - Integer
+     - Reports or sets the number of RAW engines actually used for this stream after negotiation.
+     - 1 ~ 2 (default: 2)
+     - After resource negotiation
+
+   * - ``V4L2_CID_MTK_CAM_BIN``
+     - Boolean
+     - Enables or disables binning for the stream.
+     - 0 (disable), 1 (enable, default)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_FRZ``
+     - Integer
+     - Sets the resizer (FRZ) ratio (as a percentage) for the stream.
+     - 70 ~ 100 (default: 100)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_USED_ENGINE_TRY``
+     - Integer
+     - Reports the number of RAW engines that would be used for the current "try" format negotiation.
+     - 1 ~ 2 (default: 2)
+     - After VIDIOC_TRY_FMT
+
+   * - ``V4L2_CID_MTK_CAM_BIN_TRY``
+     - Boolean
+     - Reports whether binning would be enabled for the current "try" format negotiation.
+     - 0, 1 (default: 1)
+     - After VIDIOC_TRY_FMT
+
+   * - ``V4L2_CID_MTK_CAM_FRZ_TRY``
+     - Integer
+     - Reports the resizer ratio that would be used for the current "try" format negotiation.
+     - 70 ~ 100 (default: 100)
+     - After VIDIOC_TRY_FMT
+
+   * - ``V4L2_CID_MTK_CAM_PIXEL_RATE``
+     - Integer64
+     - Sets the pixel rate (in pixels per second) of the sensor for resource calculation.
+     - 0 ~ 0xFFFFFFFF
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_FEATURE``
+     - Bitmask (Integer64)
+     - Bitmask of enabled features for the stream (e.g., HDR, 3A, etc.). See driver header for details.
+     - Bitmask (0 ~ RAW_FUNCTION_END)
+     - Before streaming or per-frame
+
+   * - ``V4L2_CID_MTK_CAM_SYNC_ID``
+     - Integer64
+     - Frame synchronization ID for multi-sensor or multi-pipeline synchronization.
+     - -1 ~ 0x7FFFFFFF (default: -1)
+     - Before streaming or per-frame
+
+   * - ``V4L2_CID_MTK_CAM_RAW_PATH_SELECT``
+     - Integer
+     - Selects the RAW path (e.g., main or secondary) for the stream.
+     - 0, 1 (default: 1)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_HSF_EN``
+     - Integer
+     - Enables or disables hardware secure flow (HSF) for the stream.
+     - 0 (disable), 1 (enable)
+     - Before streaming
+
+   * - ``V4L2_CID_MTK_CAM_PDE_INFO``
+     - Integer (struct mtk_cam_pde_info)
+     - Provides or sets phase detection (PDE) information for PDAF/AF features.
+     - See struct definition
+     - Before streaming or per-frame
+
+   * - ``V4L2_CID_MTK_CAM_MSTREAM_EXPOSURE``
+     - Integer/Integer64
+     - Controls multi-stream exposure settings for advanced HDR or multi-exposure modes.
+     - See driver header
+     - Before streaming or per-frame
+
+   * - ``V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC``
+     - Compound (struct mtk_cam_resource)
+     - Triggers resource calculation for the current format and settings.
+     - See struct definition
+     - During format negotiation
+
+   * - ``V4L2_CID_MTK_CAM_TG_FLASH_CFG``
+     - Integer/struct
+     - Configures timing generator (TG) and flash synchronization.
+     - See driver header
+     - Before streaming or per-frame
+
+   * - ``V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE``
+     - Integer
+     - Notifies the driver of a sensor mode update (e.g., seamless switch).
+     - 0 ~ 0xF (default: 0)
+     - When sensor mode changes
+
+   * - ``V4L2_CID_MTK_CAM_CAMSYS_HW_MODE``
+     - Integer64
+     - Selects the hardware mode for the CAMSYS pipeline (e.g., normal, secure, etc.).
+     - 0 ~ 0x7FFFFFFF
+     - Before streaming
+
+Control Usage Patterns
+---------------------
+
+- Controls with ``_TRY`` suffix are used to query the result of a "try" format negotiation (``VIDIOC_TRY_FMT``), without committing changes.
+- Controls without ``_TRY`` are used to set or get the actual configuration (``VIDIOC_S_FMT``, ``VIDIOC_G_CTRL``).
+- Use ``V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC`` to check if the requested format and settings are feasible, and to get recommended values.
+- Use ``V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE`` to notify the driver of a sensor mode change (e.g., seamless switch).
+- Use ``V4L2_CID_MTK_CAM_SYNC_ID`` to synchronize frames across multiple pipelines.
+- Use ``V4L2_CID_MTK_CAM_FEATURE`` to enable/disable advanced features (bitmask).
+- Use ``V4L2_CID_MTK_CAM_PDE_INFO`` to set/get phase detection information for PDAF/AF.
+- Use ``V4L2_CID_MTK_CAM_PIXEL_RATE`` to inform the driver of the sensor's pixel rate for bandwidth/resource calculation.
+
+Example: Setting a Control
+--------------------------
+
+.. code-block:: c
+
+   int fd = open("/dev/video0", O_RDWR);
+   struct v4l2_control ctrl = {
+       .id = V4L2_CID_MTK_CAM_BIN_LIMIT,
+       .value = 2,
+   };
+   if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
+       perror("Failed to set BIN_LIMIT");
+   }
+
+Notes
+-----
+
+- All controls should be set before starting the video stream unless otherwise specified.
+- Refer to the driver header file for detailed struct definitions and bitmask values.
+- The driver will reject invalid values or unsupported configurations with -EINVAL.
+
+References
+----------
+
+- V4L2 documentation: https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/v4l2.html
\ No newline at end of file
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
@ 2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:42   ` Krzysztof Kozlowski
  2025-07-15  8:25   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Rob Herring (Arm) @ 2025-07-07  2:46 UTC (permalink / raw)
  To: shangyao lin
  Cc: Matthias Brugger, Project_Global_Chrome_Upstream_Group,
	linaro-mm-sig, AngeloGioacchino Del Regno, linux-mediatek,
	Krzysztof Kozlowski, linux-kernel, linux-arm-kernel, devicetree,
	linux-media, dri-devel, Conor Dooley, Mauro Carvalho Chehab


On Mon, 07 Jul 2025 09:31:42 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-camisp.yaml
>   - Split bindings into four separate patches (one per YAML file)
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-camisp.yaml      | 68 +++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml:68:4: [error] no new line character at the end of file (new-line-at-end-of-file)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml: properties:reg-names: {'items': [{'const': 'base'}], 'minItems': 1, 'maxItems': 1, 'description': 'Name for the register region. Must be "base".'} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml: properties:reg-names: 'oneOf' conditional failed, one must be fixed:
	[{'const': 'base'}] is too short
	False schema does not allow 1
	hint: "minItems" is only needed if less than the "items" list length
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml: properties:reg: 'anyOf' conditional failed, one must be fixed:
	'minItems' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'minItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	1 is less than the minimum of 2
		hint: Arrays must be described with a combination of minItems/maxItems/items
	hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
	from schema $id: http://devicetree.org/meta-schemas/core.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml: properties:power-domains: 'anyOf' conditional failed, one must be fixed:
	'minItems' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'minItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	1 is less than the minimum of 2
		hint: Arrays must be described with a combination of minItems/maxItems/items
	hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
	from schema $id: http://devicetree.org/meta-schemas/power-domain.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename
 	 $id: http://devicetree.org/schemas/media/mediatek/mediatek,camisp.yaml
 	file: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dts:23.13-43: Warning (reg_format): /example-0/soc/isp@16000000:reg: property has invalid length (16 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dts:21.24-27.13: Warning (avoid_default_addr_size): /example-0/soc/isp@16000000: Relying on default #address-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dts:21.24-27.13: Warning (avoid_default_addr_size): /example-0/soc/isp@16000000: Relying on default #size-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: Warning (unique_unit_address_if_enabled): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.example.dtb: isp@16000000 (mediatek,mt8188-camisp): reg: [[0, 369098752], [0, 4096]] is too long
	from schema $id: http://devicetree.org/schemas/media/mediatek/mediatek,camisp.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250707013154.4055874-2-shangyao.lin@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding
  2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
@ 2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:44   ` Krzysztof Kozlowski
  2025-07-15  7:28   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Rob Herring (Arm) @ 2025-07-07  2:46 UTC (permalink / raw)
  To: shangyao lin
  Cc: Conor Dooley, Krzysztof Kozlowski, Mauro Carvalho Chehab,
	Matthias Brugger, AngeloGioacchino Del Regno, dri-devel,
	Project_Global_Chrome_Upstream_Group, devicetree,
	linux-arm-kernel, linaro-mm-sig, linux-mediatek, linux-media,
	linux-kernel


On Mon, 07 Jul 2025 09:31:43 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> 1. Add camera isp7x module device document
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-seninf-core.yaml
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Question for reviewer (CK):
> 
> Hi CK,
> 
> Thank you for your review and suggestions on this patch, especially for providing the reference patch (https://patchwork.kernel.org/project/linux-mediatek/list/?series=874617) and for mentioning in another patch ([V1,02/10] MEDIA: PLATFORM: MEDIATEK: ADD SENINF CONTROLLER) the suggestion to "Move the phy part to phy/mediatek/ folder. You could refer to phy/mediatek/phy-mtk-mipi-csi-0-5.c".
> 
> After reading your comments and the reference patches, my understanding is that only the seninf-core driver should manage all ports internally, and each port corresponds to a PHY. During probe, the driver will parse each port, obtain the corresponding PHY (e.g., devm_phy_get(dev, "csi0"), devm_phy_get(dev, "csi1"), etc.), and operate the PHY for each port individually during stream on/off or power on/off.
> 
> Could you please confirm if my understanding is correct?
> If you have any additional reference patches or examples, I would greatly appreciate it.
> 
> Thank you for your guidance!
> 
> Best regards,
> Shangyao
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-seninf-core.yaml | 121 ++++++++++++++++++
>  1 file changed, 121 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml:6:10: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml:121:4: [error] no new line character at the end of file (new-line-at-end-of-file)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: properties:clock-names: {'items': [{'const': 'clk_cam_seninf'}, {'const': 'clk_top_seninf'}, {'const': 'clk_top_seninf1'}, {'const': 'clk_top_camtm'}], 'minItems': 4, 'maxItems': 4} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: properties:clock-names: 'oneOf' conditional failed, one must be fixed:
	[{'const': 'clk_cam_seninf'}, {'const': 'clk_top_seninf'}, {'const': 'clk_top_seninf1'}, {'const': 'clk_top_camtm'}] is too long
	[{'const': 'clk_cam_seninf'}, {'const': 'clk_top_seninf'}, {'const': 'clk_top_seninf1'}, {'const': 'clk_top_camtm'}] is too short
	False schema does not allow 4
	1 was expected
	4 is greater than the maximum of 2
	4 is greater than the maximum of 3
	hint: "minItems" is only needed if less than the "items" list length
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: properties:reg-names: {'items': [{'const': 'base'}], 'minItems': 1, 'maxItems': 1} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: properties:reg-names: 'oneOf' conditional failed, one must be fixed:
	[{'const': 'base'}] is too short
	False schema does not allow 1
	hint: "minItems" is only needed if less than the "items" list length
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: properties:reg: 'anyOf' conditional failed, one must be fixed:
	'minItems' is not one of ['maxItems', 'description', 'deprecated']
		hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
	'minItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
	1 is less than the minimum of 2
		hint: Arrays must be described with a combination of minItems/maxItems/items
	hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
	from schema $id: http://devicetree.org/meta-schemas/core.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename
 	 $id: http://devicetree.org/schemas/media/mediatek,seninf-core.yaml
 	file: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-seninf-core.example.dtb: seninf@16010000 (mediatek,mt8188-seninf-core): reg: [[0, 369164288], [0, 32768]] is too long
	from schema $id: http://devicetree.org/schemas/media/mediatek,seninf-core.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250707013154.4055874-3-shangyao.lin@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding
  2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
@ 2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:48   ` Krzysztof Kozlowski
  2025-07-15  8:13   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Rob Herring (Arm) @ 2025-07-07  2:46 UTC (permalink / raw)
  To: shangyao lin
  Cc: dri-devel, linux-media, linux-mediatek, Matthias Brugger,
	devicetree, linaro-mm-sig, linux-kernel, Krzysztof Kozlowski,
	Conor Dooley, AngeloGioacchino Del Regno, Mauro Carvalho Chehab,
	Project_Global_Chrome_Upstream_Group, linux-arm-kernel


On Mon, 07 Jul 2025 09:31:44 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-cam-raw.yaml
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-cam-raw.yaml     | 156 ++++++++++++++++++
>  1 file changed, 156 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml:156:4: [error] no new line character at the end of file (new-line-at-end-of-file)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml: properties:clock-names: {'items': [{'const': 'camsys_cam2mm0_cgpdn'}, {'const': 'camsys_cam2mm1_cgpdn'}, {'const': 'camsys_cam2sys_cgpdn'}, {'const': 'camsys_cam_cgpdn'}, {'const': 'camsys_camtg_cgpdn'}, {'const': 'camsys_rawa_larbx_cgpdn'}, {'const': 'camsys_rawa_cam_cgpdn'}, {'const': 'camsys_rawa_camtg_cgpdn'}, {'const': 'topckgen_top_cam'}, {'const': 'topckgen_top_camtg'}, {'const': 'topckgen_top_camtm'}], 'minItems': 4, 'maxItems': 16, 'description': 'Names of the clocks, must match the order of the clocks property.'} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml: properties:reg-names: {'items': [{'const': 'base'}, {'const': 'inner_base'}], 'minItems': 1, 'maxItems': 2, 'description': 'Names for each register region. Must be "base" and optionally "inner_base".'} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename
 	 $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml
 	file: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.yaml
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dts:33.13-34.43: Warning (reg_format): /example-0/soc/raw@16030000:reg: property has invalid length (32 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dts:37.13-59: Warning (dma_ranges_format): /example-0/soc/raw@16030000:dma-ranges: "dma-ranges" property has invalid length (24 bytes) (parent #address-cells == 2, child #address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dts:31.24-78.13: Warning (avoid_default_addr_size): /example-0/soc/raw@16030000: Relying on default #address-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dts:31.24-78.13: Warning (avoid_default_addr_size): /example-0/soc/raw@16030000: Relying on default #size-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: Warning (unique_unit_address_if_enabled): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: raw@16030000 (mediatek,mt8188-cam-raw): dma-ranges: [[2], [0], [0], [1073741824], [1], [0]] is too long
	from schema $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-raw.example.dtb: raw@16030000 (mediatek,mt8188-cam-raw): reg: [[0, 369295360], [0, 32768], [0, 369328128], [0, 32768]] is too long
	from schema $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250707013154.4055874-4-shangyao.lin@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding
  2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
@ 2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:47   ` Krzysztof Kozlowski
  2025-07-15  7:41   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Rob Herring (Arm) @ 2025-07-07  2:46 UTC (permalink / raw)
  To: shangyao lin
  Cc: Conor Dooley, dri-devel, Matthias Brugger, linaro-mm-sig,
	Mauro Carvalho Chehab, linux-kernel, linux-media,
	Project_Global_Chrome_Upstream_Group, Krzysztof Kozlowski,
	devicetree, linux-mediatek, linux-arm-kernel,
	AngeloGioacchino Del Regno


On Mon, 07 Jul 2025 09:31:45 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-cam-yuv.yaml
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-cam-yuv.yaml     | 134 ++++++++++++++++++
>  1 file changed, 134 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml: properties:reg-names: {'items': [{'const': 'base'}, {'const': 'inner_base'}], 'minItems': 1, 'maxItems': 2, 'description': 'Names for each register region. Must be "base" and optionally "inner_base".'} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml: properties:clock-names: {'items': [{'const': 'camsys_cam2mm0_cgpdn'}, {'const': 'camsys_cam2mm1_cgpdn'}, {'const': 'camsys_cam2sys_cgpdn'}, {'const': 'camsys_yuva_larbx'}, {'const': 'camsys_yuva_cam_cgpdn'}, {'const': 'camsys_yuva_camtg_cgpdn'}, {'const': 'camsys_yuvb_larbx_cgpdn'}, {'const': 'camsys_yuvb_cam_cgpdn'}, {'const': 'camsys_yuvb_camtg_cgpdn'}], 'minItems': 4, 'maxItems': 16, 'description': 'Names of the clocks, must match the order of the clocks property.'} should not be valid under {'required': ['maxItems']}
	hint: "maxItems" is not needed with an "items" list
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename
 	 $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml
 	file: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dts:33.13-43: Warning (reg_format): /example-0/soc/yuv@16050000:reg: property has invalid length (16 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dts:37.13-59: Warning (dma_ranges_format): /example-0/soc/yuv@16050000:dma-ranges: "dma-ranges" property has invalid length (24 bytes) (parent #address-cells == 2, child #address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dts:31.24-58.13: Warning (avoid_default_addr_size): /example-0/soc/yuv@16050000: Relying on default #address-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dts:31.24-58.13: Warning (avoid_default_addr_size): /example-0/soc/yuv@16050000: Relying on default #size-cells value
Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: Warning (unique_unit_address_if_enabled): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: yuv@16050000 (mediatek,mt8188-cam-yuv): clock-names:3: 'camsys_yuva_larbx' was expected
	from schema $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.example.dtb: yuv@16050000 (mediatek,mt8188-cam-yuv): dma-ranges: [[2], [0], [0], [1073741824], [1], [0]] is too long
	from schema $id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250707013154.4055874-5-shangyao.lin@mediatek.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
@ 2025-07-07  5:42   ` Krzysztof Kozlowski
  2025-07-15  8:25   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:42 UTC (permalink / raw)
  To: shangyao lin
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On Mon, Jul 07, 2025 at 09:31:42AM +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.

Missing SoB, missing checkpatch.

> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-camisp.yaml
>   - Split bindings into four separate patches (one per YAML file)
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>

Apply this patch and see by yourself.

This wasn't tested either, so I will skip review.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding
  2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
@ 2025-07-07  5:44   ` Krzysztof Kozlowski
  2025-07-15  7:28   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:44 UTC (permalink / raw)
  To: shangyao lin
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On Mon, Jul 07, 2025 at 09:31:43AM +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> 1. Add camera isp7x module device document
> 

Still no SoB, still not tested, still no checkpatch...

and also:

...

> +
> +...
> \ No newline at end of file

Look, you have patch warnings. Review your patches before you post them.
You should reach internally to mediatek colleagues to explain you how
this process works. I really do not understand why mediatek has so poor
quality of work and cannot improve over last 1-2 years!

> -- 
> 2.18.0
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding
  2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
@ 2025-07-07  5:47   ` Krzysztof Kozlowski
  2025-07-15  7:41   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:47 UTC (permalink / raw)
  To: shangyao lin
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On Mon, Jul 07, 2025 at 09:31:45AM +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-cam-yuv.yaml
>   - Various fixes per review comments
>   - Update maintainers list

Where did you post v1?

Please use standard email subjects, so with the PATCH keyword in the
title. 'git format-patch -vX' helps here to create proper versioned patches.
Another useful tool is b4. Skipping the PATCH keyword makes filtering of
emails more difficult thus making the review process less convenient.

A nit, subject: drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

> +properties:
> +  compatible:
> +    const: mediatek,mt8188-cam-yuv
> +
> +  reg:
> +    minItems: 1

What, why?

Look at other bindings.

> +    maxItems: 2
> +    description:
> +      Base address and optional inner base address of the cam-yuv hardware block.

Why are you stating obvious? From where did you take it?

> +
> +  reg-names:
> +    items:
> +      - const: base
> +      - const: inner_base
> +    minItems: 1
> +    maxItems: 2

No, really no. You did not follow any existing patterns and this binding
does not look at all as anything else. Why making this things up? Just
use recently reviewed binding as starting point.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding
  2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
@ 2025-07-07  5:48   ` Krzysztof Kozlowski
  2025-07-15  8:13   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:48 UTC (permalink / raw)
  To: shangyao lin
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On Mon, Jul 07, 2025 at 09:31:44AM +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-cam-raw.yaml
>   - Various fixes per review comments

Which fixes? This is way too vague, considering how buggy and poor this
code is. Where was v1 of this?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit
  2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
@ 2025-07-07  5:50   ` Krzysztof Kozlowski
  2025-07-10  6:39   ` CK Hu (胡俊光)
  2025-07-16  4:06   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:50 UTC (permalink / raw)
  To: shangyao lin
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On Mon, Jul 07, 2025 at 09:31:46AM +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>

My most frequent comment last year to Mediatek. I even asked to come
with some internal procedure so you will not keep repating the same
mistake in author's name.

Any success?

> 
> Introduce support for the MediaTek sensor interface (seninf) in the SoC camera

...

> 
> ---
> 
> Note:
> The PHY operations have been refactored and separated from the seninf driver,
> but there are still some issues to confirm with reviewers in this v2 patch
> (dt-bindings: media: mediatek: add seninf-core binding). The PHY part will be
> moved to drivers/phy/mediatek/ in v3.
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>

and here the same.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 00/13] Add MediaTek ISP7.x camera system support
  2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
                   ` (12 preceding siblings ...)
  2025-07-07  1:31 ` [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls shangyao lin
@ 2025-07-07  5:55 ` Krzysztof Kozlowski
  13 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:55 UTC (permalink / raw)
  To: shangyao lin, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On 07/07/2025 03:31, shangyao lin wrote:
> Based on linux-next tag: next-20250630
> 
> This patch set adds the MediaTek ISP7.x camera system hardware driver.
> 
> The driver sets up ISP hardware, handles interrupts, and initializes
> V4L2 device nodes and functions. It also implements a V4L2 standard video
> driver utilizing the media framework APIs, connects sensors and the ISP
> via the seninf interface, and communicates with the SCP co-processor to
> compose ISP registers in firmware.
> 
Now I found v1. How did you address comment about compliance report?

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
@ 2025-07-07  5:58   ` Krzysztof Kozlowski
  2025-07-10  5:20   ` CK Hu (胡俊光)
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-07  5:58 UTC (permalink / raw)
  To: shangyao lin, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: linux-media, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, dri-devel, linaro-mm-sig,
	Project_Global_Chrome_Upstream_Group

On 07/07/2025 03:31, shangyao lin wrote:
> +static int mtk_cam_create_links(struct mtk_cam_device *cam)
> +{
> +	struct v4l2_subdev *sd;
> +	int ret = 0;
> +
> +	v4l2_device_for_each_subdev(sd, &cam->v4l2_dev) {
> +		if (sd->entity.function == MEDIA_ENT_F_VID_IF_BRIDGE)
> +			ret = config_bridge_pad_links(cam, sd);
> +	}
> +
> +	return ret;
> +}
> +
> +static int mtk_cam_master_register(struct device *dev)
> +{
> +	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
> +	struct media_device *media_dev = &cam_dev->media_dev;
> +	int ret;
> +
> +	dev_info(dev, "camsys | start %s\n", __func__);

NAK, nothing improved, you already got comments on that. Provide
detailed changelog next time. And respond to EACH comment acknowledging
that you understood it.

This code still has so many trivial issues and terrible coding style,
including wrong indentation, wrong alignment/wrapping.


> +
> +	media_dev->dev = cam_dev->dev;
> +	strscpy(media_dev->model, dev_driver_string(dev),
> +		sizeof(media_dev->model));
> +	snprintf(media_dev->bus_info, sizeof(media_dev->bus_info),
> +		 "platform:%s", dev_name(dev));
> +	media_dev->hw_revision = 0;
> +	media_dev->ops = &mtk_cam_dev_ops;
> +	media_device_init(media_dev);
> +
> +	cam_dev->v4l2_dev.mdev = media_dev;
> +	ret = v4l2_device_register(cam_dev->dev, &cam_dev->v4l2_dev);
> +	if (ret) {
> +		dev_dbg(dev, "Failed to register V4L2 device: %d\n", ret);
> +		goto fail_media_device_cleanup;
> +	}
> +
> +	ret = media_device_register(media_dev);
> +	if (ret) {
> +		dev_dbg(dev, "Failed to register media device: %d\n",
> +			ret);
> +		goto fail_v4l2_device_unreg;
> +	}
> +
> +	dev_info(dev, "%s success\n", __func__);
> +	return 0;
> +
> +fail_v4l2_device_unreg:
> +	v4l2_device_unregister(&cam_dev->v4l2_dev);
> +
> +fail_media_device_cleanup:
> +	media_device_cleanup(&cam_dev->media_dev);
> +
> +	return ret;
> +}
> +
> +static void mtk_cam_master_unregister(struct device *dev)
> +{
> +	struct mtk_cam_device *cam_dev = dev_get_drvdata(dev);
> +
> +	dev_info(dev, "camsys | start %s\n", __func__);

NAK

> +
> +	media_device_unregister(&cam_dev->media_dev);
> +	v4l2_device_unregister(&cam_dev->v4l2_dev);
> +	media_device_cleanup(&cam_dev->media_dev);
> +}
> +
> +static int mtk_cam_async_add_by_driver(struct device *dev,
> +				       struct platform_driver *drv,
> +				       struct v4l2_async_notifier *notifier)
> +{
> +	struct fwnode_handle *fwnode;
> +	struct device *p;
> +	struct v4l2_async_connection *asc;
> +	int dev_num = 0;
> +
> +	p = platform_find_device_by_driver(NULL, &drv->driver);
> +	while (p) {
> +		dev_info(dev, "camsys | %s add %s\n", __func__, p->kobj.name);
> +
> +		fwnode = dev_fwnode(p);
> +		asc = v4l2_async_nf_add_fwnode(notifier, fwnode,
> +					       struct v4l2_async_connection);
> +		put_device(p);
> +

...

> +
> +	cam_dev->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(cam_dev->base)) {
> +		dev_err(dev, "failed to map register base\n");
> +		return PTR_ERR(cam_dev->base);
> +	}
> +
> +	cam_dev->dev = dev;
> +	dev_set_drvdata(dev, cam_dev);
> +
> +	cam_dev->composer_cnt = 0;
> +	cam_dev->num_seninf_devices = 0;
> +
> +	cam_dev->max_stream_num = MTKCAM_SUBDEV_MAX;
> +	cam_dev->ctxs = devm_kcalloc(dev, cam_dev->max_stream_num,
> +				     sizeof(*cam_dev->ctxs), GFP_KERNEL);
> +	if (!cam_dev->ctxs)
> +		return -ENOMEM;
> +
> +	cam_dev->streaming_ctx = 0;
> +	for (i = 0; i < cam_dev->max_stream_num; i++)
> +		mtk_cam_ctx_init(cam_dev->ctxs + i, cam_dev, i);
> +
> +	cam_dev->running_job_count = 0;
> +	spin_lock_init(&cam_dev->pending_job_lock);
> +	spin_lock_init(&cam_dev->running_job_lock);
> +	INIT_LIST_HEAD(&cam_dev->pending_job_list);
> +	INIT_LIST_HEAD(&cam_dev->running_job_list);
> +
> +	cam_dev->dma_processing_count = 0;
> +	spin_lock_init(&cam_dev->dma_pending_lock);
> +	spin_lock_init(&cam_dev->dma_processing_lock);
> +	INIT_LIST_HEAD(&cam_dev->dma_pending);
> +	INIT_LIST_HEAD(&cam_dev->dma_processing);
> +
> +	mutex_init(&cam_dev->queue_lock);
> +
> +	pm_runtime_enable(dev);
> +
> +	ret = mtk_cam_of_rproc(cam_dev, pdev);
> +	if (ret)
> +		goto fail_destroy_mutex;
> +
> +	ret = register_sub_drivers(dev);
> +	if (ret) {
> +		dev_err(dev, "fail to register_sub_drivers\n");
> +		goto fail_destroy_mutex;
> +	}
> +
> +    cam_dev->clks_pdev = platform_device_register_data(
> +        dev, "clk-mt8188-cam", PLATFORM_DEVID_AUTO, NULL, 0);
> +    if (IS_ERR(cam_dev->clks_pdev)) {
> +        ret = PTR_ERR(cam_dev->clks_pdev);
> +        dev_err(dev, "Failed to register cam clk device: %d\n", ret);
> +        goto fail_unregister_sub_drivers;
> +    }
> +	
> +	/* register mtk_cam as all isp subdev async parent */
> +	cam_dev->notifier.ops = &mtk_cam_async_nf_ops;
> +	v4l2_async_nf_init(&cam_dev->notifier, &cam_dev->v4l2_dev);
> +	ret = mtk_cam_async_subdev_add(dev); /* wait all isp sub drivers */
> +	if (ret) {
> +		dev_err(dev, "%s failed mtk_cam_async_subdev_add\n", __func__);
> +		goto fail_unregister_clks;
> +	}
> +
> +	ret = v4l2_async_nf_register(&cam_dev->notifier);
> +	if (ret) {
> +		dev_err(dev, "%s async_nf_register ret:%d\n", __func__, ret);
> +		v4l2_async_nf_cleanup(&cam_dev->notifier);
> +		goto fail_unregister_clks;
> +	}
> +
> +	dev_info(dev, "camsys | [%s] success\n", __func__);

You already got comments. Nothing improved here.

> +
> +	return 0;
> +
> +fail_unregister_clks:
> +    if (cam_dev->clks_pdev)
> +        platform_device_unregister(cam_dev->clks_pdev);
> +

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api
  2025-07-07  1:31 ` [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api shangyao lin
@ 2025-07-08  1:34   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-08  1:34 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add UAPI for the MediaTek ISP platform, providing user-space interfaces for the
> new CAMSYS driver.
> 
> Changes in v2:
> - Moved V4L2 pixel format definitions to include/uapi/linux/videodev2.h
> 
> Notes:
> 
> Hi Laurent Pinchart and CK,
> 
> Thank you very much for your detailed feedback and suggestions.
> 
> I would like to let you know that in the next patch, I have added an initial
> version of an .rst document describing the MTK ISP CAMSYS controls. Most of
> these ISP CAMSYS controls are intended for other advanced features. For normal
> main-stream use cases, only controls such as V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC
> are actually used.
> 
> Would you prefer that we remove the user space interfaces for these advanced
> features for now, and only add them back in a future patch series dedicated to
> advanced functionality? I am happy to follow your recommendation on this.

I suggest that you send the basic function first.
For you and the reviewer, the process would be much easier.
Reviewer review fewer codes, and you get fewer comment.
Advanced function could be sent later at any time you want.

Regards,
CK

> 
> Additionally, I have also written an initial version of a brief .rst document
> providing a high-level description of the hardware. If you think there is
> anything else that should be added or clarified, please kindly let me know.
> 
> Thank you again for your valuable feedback!
> 
> Best regards,
> Shangyao
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
  2025-07-07  5:58   ` Krzysztof Kozlowski
@ 2025-07-10  5:20   ` CK Hu (胡俊光)
  2025-07-10  7:46   ` CK Hu (胡俊光)
  2025-07-24  8:36   ` CK Hu (胡俊光)
  3 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-10  5:20 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, MediaTek-specific features, pipeline management, streaming control, and error handling mechanisms. Additionally, it aggregates sub-drivers for the camera interface, raw, and yuv pipelines.
> 
> ---
> 
> Changes in v2:
> - Removed mtk_cam-ufbc-def.h along with related code
> - Various fixes per review comments
> 
> ---
> 
> [Question for CK]:
> 
> Hi CK,
> 
> Is your suggestion to simplify buffer management to a single buf_list with a buffer status (estate) state machine, so all buffers stay in one list and only the estate field changes (no more multiple lists)? The buffer life cycle would be: WAITING → SCP_GENERATE_CQ → CQ_READY → CQ_APPLY → DONE.
> 
> I have some concerns about concurrency and race conditions:
> 
> Multiple lists can use different locks to reduce contention.
> With a single list, all state changes need to lock the same list, which may require more careful lock design to avoid race conditions or deadlocks.
> When multiple threads (interrupts, workqueues, user requests) operate at the same time, synchronization becomes more difficult.
> Do you have any reference code or best practices for this kind of design?

Deadlock happen only when code hold two lock at the same time.
I think when you hold buf_list lock, it's not necessary to hold other lock, so it's not necessary to worry about deadlock.
The buffer management in this driver is simple.
All the buffer is processed step by step in order.
I have no sample code to provide to you.
You may point out the worry code in this patch and we could discuss on that point.

> 
> Thanks!
> 
> 
> 
> Reply regarding stream_id and pipe_id naming:
> 
> Hi CK,
> 
> Thank you for your suggestion. In our current design, stream_id and pipe_id are not always in a 1-to-1 relationship. In some cases, one stream may correspond to multiple pipes, or vice versa. That’s why we use both names in different contexts. If you have any suggestions on how to unify the naming while keeping this distinction clear, please let us know.
> 

So stream_id and pipe_id are different concept.
Below is the code in this patch.

+struct mtk_cam_request_stream_data*
+mtk_cam_get_req_s_data(struct mtk_cam_ctx *ctx, unsigned int pipe_id,
+                        unsigned int frame_seq_no)
 
+struct mtk_cam_request *mtk_cam_get_req(struct mtk_cam_ctx *ctx,
+                                              unsigned int frame_seq_no)
+{
+       struct mtk_cam_request_stream_data *req_stream_data;
+
+       req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, frame_seq_no);

The second parameter of mtk_cam_get_req_s_data() is pipe_id, but you pass stream_id into it.
Because stream_id and pipe_id are different concept, so you should not do this.
You should pass pipe_id into mtk_cam_get_req_s_data().

Regards,
CK

+       if (!req_stream_data)
+                 return NULL;
+
+       return req_stream_data->req;
+}


> Thanks!
> 
> Best regards,
> Shangyao
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit
  2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
  2025-07-07  5:50   ` Krzysztof Kozlowski
@ 2025-07-10  6:39   ` CK Hu (胡俊光)
  2025-07-16  4:06   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-10  6:39 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce support for the MediaTek sensor interface (seninf) in the SoC camera
> subsystem, focusing on CSI and stream control. The driver manages parameter
> control, metering, status tracking, and interrupt handling for the camera sensor
> interface hardware. It integrates with the MediaTek ISP CAMSYS, bridging camera
> sensors and the ISP system, and provides V4L2 framework support for dynamic
> stream configuration and virtual channel management.
> 
> ---

[snip]

> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
> new file mode 100755
> index 000000000000..a3c926cc3cee
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
> @@ -0,0 +1,1932 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2022 MediaTek Inc.
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>
> +
> +#include "../mtk_cam-seninf.h"
> +#include "../mtk_cam-seninf-hw.h"
> +#include "../mtk_cam-seninf-regs.h"
> +#include "mtk_cam-seninf-top-ctrl.h"
> +#include "mtk_cam-seninf-seninf1-mux.h"
> +#include "mtk_cam-seninf-seninf1.h"
> +#include "mtk_cam-seninf-seninf1-csi2.h"
> +#include "mtk_cam-seninf-tg1.h"
> +#include "mtk_cam-seninf-cammux.h"
> +#include "mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h"
> +#include "mtk_cam-seninf-csi0-cphy.h"
> +#include "mtk_cam-seninf-csi0-dphy.h"
> +#include "../kd_imgsensor_define_v4l2.h"
> +
> +static struct mtk_cam_seninf_cfg _seninf_cfg = {
> +	.mux_num = 8,
> +	.seninf_num = 4,
> +	.cam_mux_num = 11,
> +	.pref_mux_num = 11,
> +};
> +
> +struct mtk_cam_seninf_cfg *g_seninf_cfg = &_seninf_cfg;
> +
> +static inline u32 get_port_num(int port)
> +{
> +    if (port >= CSI_PORT_0A)
> +        return FIELD_GET(CSI_PORT_A_MASK, port - CSI_PORT_0A);
> +    else
> +        return port;
> +}
> +
> +static inline void mtk_cam_seninf_set_di_ch_ctrl(void __iomem *pseninf,
> +						 unsigned int stream_id,
> +						 struct seninf_vc *vc)
> +{
> +	if (stream_id > SENINF_MAX_STREAM)
> +		return;
> +
> +	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
> +		    RG_CSI2_DT_SEL, vc->dt);
> +	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
> +		    RG_CSI2_VC_SEL, 0);
> +	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
> +		    RG_CSI2_DT_INTERLEAVE_MODE, 1);
> +	SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2),
> +		    RG_CSI2_VC_INTERLEAVE_EN, 1);
> +
> +	switch (stream_id) {
> +	case 0:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S0_GRP_EN, 1);
> +		break;
> +	case 1:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S1_GRP_EN, 1);
> +		break;
> +	case 2:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S2_GRP_EN, 1);
> +		break;
> +	case 3:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S3_GRP_EN, 1);
> +		break;
> +	case 4:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S4_GRP_EN, 1);
> +		break;
> +	case 5:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S5_GRP_EN, 1);
> +		break;
> +	case 6:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S6_GRP_EN, 1);
> +		break;
> +	case 7:
> +		SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
> +			    RG_CSI2_S7_GRP_EN, 1);
> +		break;
> +	default:
> +		return;
> +	}

#define RG_CSI2_SX_GRP_EN(x)	BIT(x + 8)

and this switch case could be reduced as

	SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL,
		    RG_CSI2_SX_GRP_EN(stream_id), 1);


> +}
> +

[snip]

> +
> +int mtk_cam_seninf_set_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx,
> +				    int seninf_src)
> +{
> +	void __iomem *seninf = ctx->reg_if_top;
> +
> +	switch (mux_idx) {
> +	case SENINF_MUX1:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
> +			    RG_SENINF_MUX1_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX2:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
> +			    RG_SENINF_MUX2_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX3:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
> +			    RG_SENINF_MUX3_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX4:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0,
> +			    RG_SENINF_MUX4_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX5:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
> +			    RG_SENINF_MUX5_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX6:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
> +			    RG_SENINF_MUX6_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX7:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
> +			    RG_SENINF_MUX7_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX8:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1,
> +			    RG_SENINF_MUX8_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX9:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
> +			    RG_SENINF_MUX9_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX10:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
> +			    RG_SENINF_MUX10_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX11:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
> +			    RG_SENINF_MUX11_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX12:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2,
> +			    RG_SENINF_MUX12_SRC_SEL, seninf_src);
> +		break;
> +	case SENINF_MUX13:
> +		SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_3,
> +			    RG_SENINF_MUX13_SRC_SEL, seninf_src);
> +		break;
> +	default:
> +		dev_dbg(ctx->dev, "invalid mux_idx %d\n", mux_idx);
> +		return -EINVAL;
> +	}
> +

#define SENINF_TOP_MUX_CTRL(x)		(0x10 + 4 * x)
#define RG_SENINF_MUX_SRC_SEL(x)	GENMASK((x % 4) * 4 + 3, (x % 4) * 4)

And this switch case could be reduced as

	SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL(mux_idx / 4),
		    RG_SENINF_MUX_SRC_SEL(mux_idx), seninf_src);


Regards,
CK

> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
  2025-07-07  5:58   ` Krzysztof Kozlowski
  2025-07-10  5:20   ` CK Hu (胡俊光)
@ 2025-07-10  7:46   ` CK Hu (胡俊光)
  2025-07-24  8:36   ` CK Hu (胡俊光)
  3 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-10  7:46 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, MediaTek-specific features, pipeline management, streaming control, and error handling mechanisms. Additionally, it aggregates sub-drivers for the camera interface, raw, and yuv pipelines.
> 
> ---

[snip]

> +struct mtk_cam_ctx *mtk_cam_start_ctx(struct mtk_cam_device *cam,
> +				      struct mtk_cam_video_device *node)
> +{
> +	struct mtk_cam_ctx *ctx = node->ctx;
> +	struct device *dev;
> +	struct v4l2_subdev **target_sd;
> +	int ret, i, is_first_ctx;
> +	struct media_entity *entity = &node->vdev.entity;
> +	struct media_graph graph;
> +
> +	dev_info(cam->dev, "%s:ctx(%d): triggered by %s\n",
> +		 __func__, ctx->stream_id, entity->name);
> +
> +	atomic_set(&ctx->enqueued_frame_seq_no, 0);
> +	ctx->composed_frame_seq_no = 0;
> +	ctx->dequeued_frame_seq_no = 0;
> +	atomic_set(&ctx->running_s_data_cnt, 0);
> +	init_completion(&ctx->session_complete);
> +
> +	is_first_ctx = !cam->composer_cnt;
> +	if (is_first_ctx) {
> +		spin_lock(&cam->dma_processing_lock);
> +		cam->dma_processing_count = 0;
> +		spin_unlock(&cam->dma_processing_lock);
> +		spin_lock(&cam->running_job_lock);
> +		cam->running_job_count = 0;
> +		spin_unlock(&cam->running_job_lock);
> +
> +		dev_info(cam->dev, "%s: power on camsys\n", __func__);
> +		ret = pm_runtime_resume_and_get(cam->dev);
> +		if (ret < 0) {
> +			dev_info(cam->dev, "%s: power on camsys failed\n",
> +				 __func__);
> +			return NULL;
> +		}
> +
> +		ret = isp_composer_init(cam);
> +		if (ret)
> +			goto fail_shutdown;
> +	}
> +	cam->composer_cnt++;
> +	if (is_yuv_node(node->desc.id))
> +		dev = cam->raw.yuvs[0];
> +	else
> +		dev = cam->raw.devs[0];
> +
> +	ret = mtk_cam_working_buf_pool_init(ctx, dev);
> +	if (ret) {
> +		dev_info(cam->dev, "failed to reserve DMA memory:%d\n", ret);
> +		goto fail_uninit_composer;
> +	}
> +
> +	kthread_init_worker(&ctx->sensor_worker);

You does not do anything to sensor_worker, so it's usedless.
Drop it.

> +	ctx->sensor_worker_task = kthread_run(kthread_worker_fn,
> +					      &ctx->sensor_worker,
> +					      "sensor_worker-%d",
> +					      ctx->stream_id);
> +	if (IS_ERR(ctx->sensor_worker_task)) {
> +		dev_info(cam->dev,
> +			 "%s:ctx(%d): could not create sensor_worker_task\n",
> +			 __func__, ctx->stream_id);
> +		goto fail_release_buffer_pool;
> +	}
> +
> +	sched_set_fifo(ctx->sensor_worker_task);
> +
> +	ctx->composer_wq = alloc_ordered_workqueue(dev_name(cam->dev),
> +						   WQ_HIGHPRI | WQ_FREEZABLE);
> +	if (!ctx->composer_wq) {
> +		dev_info(cam->dev, "failed to alloc composer workqueue\n");
> +		goto fail_uninit_sensor_worker_task;
> +	}
> +
> +	ctx->frame_done_wq = alloc_ordered_workqueue(dev_name(cam->dev),
> +						     WQ_HIGHPRI | WQ_FREEZABLE);
> +	if (!ctx->frame_done_wq) {
> +		dev_info(cam->dev, "failed to alloc frame_done workqueue\n");
> +		goto fail_uninit_composer_wq;
> +	}
> +
> +	ret = media_pipeline_start(&entity->pads[0], &ctx->pipeline);
> +	if (ret) {
> +		dev_warn(cam->dev,
> +			 "%s:pipe(%d):failed in media_pipeline_start:%d\n",
> +			 __func__, node->uid.pipe_id, ret);
> +		goto fail_uninit_frame_done_wq;
> +	}
> +
> +	/* traverse to update used subdevs & number of nodes */
> +	i = 0;
> +	ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
> +	if (ret)
> +		goto fail_stop_pipeline;
> +
> +	media_graph_walk_start(&graph, entity);
> +	while ((entity = media_graph_walk_next(&graph))) {
> +		dev_dbg(cam->dev, "linked entity %s\n", entity->name);
> +
> +		target_sd = NULL;
> +
> +		switch (entity->function) {
> +		case MEDIA_ENT_F_IO_V4L:
> +			ctx->enabled_node_cnt++;
> +			break;
> +		case MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER: /* pipeline */
> +			if (i >= MAX_PIPES_PER_STREAM)
> +				goto fail_stop_pipeline;
> +			target_sd = ctx->pipe_subdevs + i;
> +			i++;
> +			break;
> +		case MEDIA_ENT_F_VID_IF_BRIDGE: /* seninf */
> +			target_sd = &ctx->seninf;
> +			break;
> +		case MEDIA_ENT_F_CAM_SENSOR:
> +			target_sd = &ctx->sensor;

In this series, no entity's function is MEDIA_ENT_F_CAM_SENSOR,
so ctx->sensor is always NULL.
Drop it.

Regards,
CK

> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (!target_sd)
> +			continue;
> +
> +		if (*target_sd) {
> +			dev_info(cam->dev, "duplicated subdevs!!!\n");
> +			goto fail_traverse_subdev;
> +		}
> +
> +		if (is_media_entity_v4l2_subdev(entity))
> +			*target_sd = media_entity_to_v4l2_subdev(entity);
> +	}
> +	media_graph_walk_cleanup(&graph);
> +
> +	return ctx;
> +
> +fail_traverse_subdev:
> +	media_graph_walk_cleanup(&graph);
> +fail_stop_pipeline:
> +	media_pipeline_stop(&entity->pads[0]);
> +fail_uninit_frame_done_wq:
> +	destroy_workqueue(ctx->frame_done_wq);
> +fail_uninit_composer_wq:
> +	destroy_workqueue(ctx->composer_wq);
> +fail_uninit_sensor_worker_task:
> +	kthread_stop(ctx->sensor_worker_task);
> +	ctx->sensor_worker_task = NULL;
> +fail_release_buffer_pool:
> +	mtk_cam_working_buf_pool_release(ctx, dev);
> +fail_uninit_composer:
> +	isp_composer_uninit(cam);
> +	cam->composer_cnt--;
> +fail_shutdown:
> +	if (is_first_ctx)
> +		rproc_shutdown(cam->rproc_handle);
> +
> +	return NULL;
> +}
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls
  2025-07-07  1:31 ` [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls shangyao lin
@ 2025-07-11  3:12   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-11  3:12 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> This document covers:
> - The hardware pipeline and firmware interface
> - Integration with the V4L2 CAMSYS/media controller framework
> - The list of custom V4L2 controls, their usage, valid ranges, and typical usage flow

You may drop some advanced function, but I don't know which are advanced function, so I would review all.

> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../media/v4l/mtk-isp7x-camsys.rst            |  94 +++++++++
>  .../media/v4l/mtk-isp7x-controls.rst          | 199 ++++++++++++++++++
>  2 files changed, 293 insertions(+)
>  create mode 100755 Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
>  create mode 100755 Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst
> 
> diff --git a/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst b/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
> new file mode 100755
> index 000000000000..04a1fe1c448d
> --- /dev/null
> +++ b/Documentation/userspace-api/media/v4l/mtk-isp7x-camsys.rst
> @@ -0,0 +1,94 @@
> +==========================
> +MediaTek ISP7x Camera System
> +==========================
> +
> +Overview
> +========
> +
> +The MediaTek ISP7x camera system is designed to provide a flexible, high-performance image capture pipeline for SoCs, leveraging the Linux V4L2 framework. The system is composed of multiple hardware modules (Sensor, SENINF, RAW ISP, etc.) and a firmware backend, with a clear separation of control and data flow. This document describes the hardware architecture from the perspective of the interface exposed to the firmware (backend), and how it integrates with the V4L2 CAMSYS framework.
> +
> +V4L2 CAMSYS Framework Overview
> +==============================
> +
> +The V4L2 CAMSYS framework models the camera pipeline as a set of interconnected devices and subdevices:
> +
> +- **Video Device**: Exposes buffer queue/dequeue (enque/deque) operations to user space, allowing applications to stream image data.
> +- **Subdevice**: Represents a hardware block (e.g., sensor, SENINF, RAW ISP) and handles control/configuration operations.
> +- **Pads and Links**: Each subdevice has pads (input/output endpoints). Media links connect pads, representing the physical and logical data flow between hardware blocks.
> +
> +The topology and link state are established at probe time and can be dynamically enabled/disabled by user space, depending on the desired pipeline configuration.
> +
> +Hardware Pipeline
> +=================
> +
> +A typical pipeline consists of:
> +
> +.. code-block::
> +
> +    Sensor --> SENINF --> RAW ISP --> (optional: YUV ISP) --> Memory
> +
> +- **Sensor**: Provides MIPI CSI-2 data.
> +- **SENINF**: Receives and demultiplexes sensor data, supports virtual channel (VC) and data type (DT) routing.
> +- **RAW ISP**: Main image signal processor, handles demosaicing, noise reduction, and other image enhancements.
> +- **YUV ISP** (optional): Further processing for YUV output.
> +- **CAMSYS**: System controller, manages pipeline state, buffer flow, and synchronization.
> +
> +Firmware Interface
> +==================
> +
> +The firmware (backend, e.g., CCD/SCP) is responsible for:
> +
> +- Calculating hardware settings (3A, tuning, DMA, FBC, Twin, etc.) for each frame.
> +- Generating command queues (CQ) and descriptors to program the hardware.
> +- Abstracting hardware-specific details from the kernel driver.
> +
> +The kernel driver communicates with the firmware via an inter-processor interface (IPI), typically using RPMSG. The main interactions are:
> +
> +1. **Session Management**: The kernel establishes a session with the firmware at stream-on, and destroys it at stream-off.
> +2. **Per-frame Request Scheduling**: For each user request (frame), the kernel sends a request to the firmware, including sensor settings, buffer addresses, and control parameters.
> +3. **CQ Generation**: The firmware generates the necessary command queues and returns them to the kernel.
> +4. **Event Notification**: The firmware notifies the kernel of CQ completion, errors, or other events.
> +
> +Request Scheduling and Buffer Flow
> +==================================
> +
> +The request scheduling flow is as follows:
> +
> +1. **User space** submits a request (with buffer and control settings) via V4L2.
> +2. **PipeMgr** (user space) collects requests, groups them by file descriptor, and sends them to the kernel CAMSYS driver.
> +3. **CAMSYS** schedules requests, manages buffer flow, and coordinates with the firmware for hardware programming.
> +4. **Firmware** processes each request, generates CQ, and signals completion.
> +5. **Kernel** dequeues the buffer and notifies user space.
> +
> +The system supports per-frame control, allowing sensor settings and ISP parameters to be updated on a frame-by-frame basis.
> +
> +Media Controller Topology
> +=========================
> +
> +The media controller graph models the hardware pipeline as a set of entities (video devices, subdevices) connected by links. Each entity exposes pads, and links are established at probe time based on the hardware configuration and device tree.
> +
> +.. code-block::
> +
> +    +---------+     +--------+     +--------+     +------+
> +    | Sensor  | --> | SENINF | --> | RAW ISP| --> | Video|
> +    +---------+     +--------+     +--------+     +------+
> +
> +- Solid lines: active links (enabled)
> +- Dashed lines: inactive links (disabled)
> +
> +User space can query and configure the topology using standard V4L2 and media controller APIs.
> +
> +Backend Abstraction
> +===================
> +
> +The backend firmware abstracts hardware-specific programming, allowing the kernel driver to remain generic and maintainable. All hardware register programming, tuning, and advanced features are handled in the firmware, with the kernel acting as a control and data flow manager.
> +
> +This separation ensures that proprietary hardware details remain in the firmware, while the kernel driver exposes a standard V4L2 interface.
> +
> +Summary
> +=======
> +
> +- The MediaTek ISP7x camera system is built on the V4L2 media controller framework, with a modular pipeline of video devices and subdevices.
> +- The kernel driver manages pipeline state, buffer flow, and per-frame control, while delegating hardware programming to the backend firmware via IPI.
> +- The firmware interface is session-based, supports per-frame CQ generation, and abstracts all hardware-specific details from the kernel.
> +- The media controller graph models the hardware pipeline, allowing flexible configuration and dynamic topology management.
> \ No newline at end of file
> diff --git a/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst b/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst
> new file mode 100755
> index 000000000000..0e8d41d339e7
> --- /dev/null
> +++ b/Documentation/userspace-api/media/v4l/mtk-isp7x-controls.rst
> @@ -0,0 +1,199 @@
> +==========================================
> +MediaTek ISP Camsys User Space Interface
> +==========================================
> +
> +Overview
> +--------
> +
> +The MediaTek ISP camsys driver provides a set of custom V4L2 controls for user space
> +applications to configure and query the ISP hardware. These controls allow
> +fine-grained management of resource allocation, feature enablement, and
> +hardware-specific settings.
> +
> +Typical Usage Flow
> +------------------
> +
> +1. Open the video device node (e.g., ``/dev/video0``).
> +2. Set required V4L2 controls using ``VIDIOC_S_CTRL`` or ``VIDIOC_S_EXT_CTRLS``.
> +3. Set up video format and buffers (``VIDIOC_S_FMT``, ``VIDIOC_REQBUFS``, etc.).
> +4. Start streaming with ``VIDIOC_STREAMON``.
> +5. Queue and dequeue buffers for image processing (``VIDIOC_QBUF``, ``VIDIOC_DQBUF``).
> +6. Stop streaming with ``VIDIOC_STREAMOFF``.
> +
> +Control List and Documentation
> +-----------------------------
> +
> +Below is a list of custom V4L2 controls provided by the camsys driver, with detailed descriptions.
> +
> +.. list-table::
> +   :header-rows: 1
> +
> +   * - Control Name
> +     - Type
> +     - Description
> +     - Valid Values / Range
> +     - When to Set
> +
> +   * - ``V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT``
> +     - Integer
> +     - Limits the maximum number of RAW engines (hardware pipelines) that can be used for this stream.
> +     - 1 ~ 2 (default: 2)

I don't know why you have this interface.
You have V4L2_CID_MTK_CAM_USED_ENGINE which would decide the engine number, why have this interface to limit it?
If I want 1 engine, I just use V4L2_CID_MTK_CAM_USED_ENGINE to set. V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT is redundant.
So drop this.

> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_BIN_LIMIT``
> +     - Integer
> +     - Sets the maximum binning ratio allowed for the stream.
> +     - 0 ~ 0xFFF (default: 0)

Is the binning equal to pixel binning [1]?
If it is, does 0 mean no binning effect?
What does the level mean?
I guess is:

The maximum is 16x16 binning, so 0xFFF means 16x16 binning, and 0x800 means 4x4 binning.

This is just my guess, please provide more information what the level mean.

[1] https://en.wikipedia.org/wiki/Pixel_binning

> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_FRZ_LIMIT``
> +     - Integer
> +     - Sets the maximum resizer (FRZ) ratio allowed (as a percentage).
> +     - 70 ~ 100 (default: 100)

I don't know why you have this interface.
You have V4L2_CID_MTK_CAM_FRZ which would decide the resize ratio, why have this interface to limit it?
If I want 0.8 ratio, I just use V4L2_CID_MTK_CAM_FRZ to set. V4L2_CID_MTK_CAM_FRZ_LIMIT is redundant.
So drop this.

> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY``
> +     - Integer (Enum)
> +     - Selects the resource planning policy for the stream.
> +     - 0: Default, 1: Power-saving, 2: Performance, ... (0~10)

You just list 0, 1, 2.
What about 3 ~ 10?
Add the rest information.

> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_USED_ENGINE``
> +     - Integer
> +     - Reports or sets the number of RAW engines actually used for this stream after negotiation.
> +     - 1 ~ 2 (default: 2)
> +     - After resource negotiation

What's the negotiation?
Is it V4L2_CID_MTK_CAM_USED_ENGINE_TRY?
or all XXX_TRY interface?
Please explicitly list all these interface.

> +
> +   * - ``V4L2_CID_MTK_CAM_BIN``
> +     - Boolean
> +     - Enables or disables binning for the stream.
> +     - 0 (disable), 1 (enable, default)
> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_FRZ``
> +     - Integer
> +     - Sets the resizer (FRZ) ratio (as a percentage) for the stream.
> +     - 70 ~ 100 (default: 100)
> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_USED_ENGINE_TRY``
> +     - Integer
> +     - Reports the number of RAW engines that would be used for the current "try" format negotiation.
> +     - 1 ~ 2 (default: 2)
> +     - After VIDIOC_TRY_FMT
> +
> +   * - ``V4L2_CID_MTK_CAM_BIN_TRY``
> +     - Boolean
> +     - Reports whether binning would be enabled for the current "try" format negotiation.
> +     - 0, 1 (default: 1)
> +     - After VIDIOC_TRY_FMT
> +
> +   * - ``V4L2_CID_MTK_CAM_FRZ_TRY``
> +     - Integer
> +     - Reports the resizer ratio that would be used for the current "try" format negotiation.
> +     - 70 ~ 100 (default: 100)
> +     - After VIDIOC_TRY_FMT
> +
> +   * - ``V4L2_CID_MTK_CAM_PIXEL_RATE``
> +     - Integer64
> +     - Sets the pixel rate (in pixels per second) of the sensor for resource calculation.
> +     - 0 ~ 0xFFFFFFFF
> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_FEATURE``
> +     - Bitmask (Integer64)
> +     - Bitmask of enabled features for the stream (e.g., HDR, 3A, etc.). See driver header for details.

In patch [12/13], I does not see any information about these feature.
Add these feature definition in patch [12/13].

> +     - Bitmask (0 ~ RAW_FUNCTION_END)
> +     - Before streaming or per-frame
> +
> +   * - ``V4L2_CID_MTK_CAM_SYNC_ID``
> +     - Integer64
> +     - Frame synchronization ID for multi-sensor or multi-pipeline synchronization.

Describe how to use this ID for multi-sensor or multi-pipeline.
I think every frame has a timestamp which could be used as ID.
Why not use timestamp instead of this ID?

> +     - -1 ~ 0x7FFFFFFF (default: -1)
> +     - Before streaming or per-frame
> +
> +   * - ``V4L2_CID_MTK_CAM_RAW_PATH_SELECT``
> +     - Integer
> +     - Selects the RAW path (e.g., main or secondary) for the stream.
> +     - 0, 1 (default: 1)

You have draw a graph like this, but it does not show two raw path.

    +---------+     +--------+     +--------+     +------+
    | Sensor  | --> | SENINF | --> | RAW ISP| --> | Video|
    +---------+     +--------+     +--------+     +------+

Does it mean this?

    +---------+     +--------+     +---------------+     +------+
    | Sensor  | --> | SENINF | +-> | MAIN RAW ISP  | --> | Video|
    +---------+     +--------+ |   +---------------+     +------+
                               |
                               |   +---------------+     +------+
                               +-> | SECOND RAW ISP| --> | Video|
                                   +---------------+     +------+

If so, change your graph.
How do we decide which should we select?
What's the difference of these two RAW?
When we configure camsys driver, both RAW has the same setting or each RAW has different setting?

> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_HSF_EN``
> +     - Integer
> +     - Enables or disables hardware secure flow (HSF) for the stream.

What is HSF?
Does it mean output video buffer is accessible only by trusted CPU or hardware?
Does it mean camsys hardware could be configured only by trusted CPU or firmware?
If so, add this information.

> +     - 0 (disable), 1 (enable)
> +     - Before streaming
> +
> +   * - ``V4L2_CID_MTK_CAM_PDE_INFO``
> +     - Integer (struct mtk_cam_pde_info)
> +     - Provides or sets phase detection (PDE) information for PDAF/AF features.
> +     - See struct definition

After seeing the structure, I still don't understand what it is.
What is pdo? What is pdi? What is pd table offset?
Try to add more information to let us know how to configure it.

> +     - Before streaming or per-frame
> +
> +   * - ``V4L2_CID_MTK_CAM_MSTREAM_EXPOSURE``
> +     - Integer/Integer64
> +     - Controls multi-stream exposure settings for advanced HDR or multi-exposure modes.
> +     - See driver header

I does not see this in driver header, so drop this.

> +     - Before streaming or per-frame
> +
> +   * - ``V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC``
> +     - Compound (struct mtk_cam_resource)
> +     - Triggers resource calculation for the current format and settings.
> +     - See struct definition
> +     - During format negotiation

Call this between some XXX_TRY interface?
The negotiation interface could be called in a random sequence?
If there are dependencies, explicitly describe it.

> +
> +   * - ``V4L2_CID_MTK_CAM_TG_FLASH_CFG``
> +     - Integer/struct
> +     - Configures timing generator (TG) and flash synchronization.
> +     - See driver header

I could not find this in driver, so drop it.

> +     - Before streaming or per-frame
> +
> +   * - ``V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE``
> +     - Integer
> +     - Notifies the driver of a sensor mode update (e.g., seamless switch).
> +     - 0 ~ 0xF (default: 0)

What is sensor mode?
I still don't understand to set value 3 or value 7?
Describe more about how to set these value.

> +     - When sensor mode changes
> +
> +   * - ``V4L2_CID_MTK_CAM_CAMSYS_HW_MODE``
> +     - Integer64
> +     - Selects the hardware mode for the CAMSYS pipeline (e.g., normal, secure, etc.).
> +     - 0 ~ 0x7FFFFFFF

What is hardware mode?
I still don't understand to set value 3 or value 7?
Describe more about how to set these value.

Do you understand the meaning of upstream?
Upstream is not a cloud server to store your code.
Upstream is to share your code so others could use your code to control this hardware.
Try to let us understand how to use this code to control hardware.

Regards,
CK

> +     - Before streaming
> +
> +Control Usage Patterns
> +---------------------
> +
> +- Controls with ``_TRY`` suffix are used to query the result of a "try" format negotiation (``VIDIOC_TRY_FMT``), without committing changes.
> +- Controls without ``_TRY`` are used to set or get the actual configuration (``VIDIOC_S_FMT``, ``VIDIOC_G_CTRL``).
> +- Use ``V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC`` to check if the requested format and settings are feasible, and to get recommended values.
> +- Use ``V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE`` to notify the driver of a sensor mode change (e.g., seamless switch).
> +- Use ``V4L2_CID_MTK_CAM_SYNC_ID`` to synchronize frames across multiple pipelines.
> +- Use ``V4L2_CID_MTK_CAM_FEATURE`` to enable/disable advanced features (bitmask).
> +- Use ``V4L2_CID_MTK_CAM_PDE_INFO`` to set/get phase detection information for PDAF/AF.
> +- Use ``V4L2_CID_MTK_CAM_PIXEL_RATE`` to inform the driver of the sensor's pixel rate for bandwidth/resource calculation.
> +
> +Example: Setting a Control
> +--------------------------
> +
> +.. code-block:: c
> +
> +   int fd = open("/dev/video0", O_RDWR);
> +   struct v4l2_control ctrl = {
> +       .id = V4L2_CID_MTK_CAM_BIN_LIMIT,
> +       .value = 2,
> +   };
> +   if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
> +       perror("Failed to set BIN_LIMIT");
> +   }
> +
> +Notes
> +-----
> +
> +- All controls should be set before starting the video stream unless otherwise specified.
> +- Refer to the driver header file for detailed struct definitions and bitmask values.
> +- The driver will reject invalid values or unsupported configurations with -EINVAL.
> +
> +References
> +----------
> +
> +- V4L2 documentation: https://urldefense.com/v3/__https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/v4l2.html__;!!CTRNKA9wMg0ARbw!koPmGRLtqjG7_WecTl2EBNDMmuZO-_VzYEAbKzsTJhueUGekgy_ky5-FeOERXvI6377LscGrivr2cMlRuXbU3pM$ 
> \ No newline at end of file


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl
  2025-07-07  1:31 ` [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl shangyao lin
@ 2025-07-11  8:56   ` CK Hu (胡俊光)
  2025-07-21  1:40   ` CK Hu (胡俊光)
  1 sibling, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-11  8:56 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce state management and debugging mechanisms for the MediaTek ISP7.x
> camsys platform. State management establishes control over ISP operations and
> events, defining distinct states for request handling, sensor control, and
> frame synchronization, ensuring proper event processing. The debugging
> mechanism ensures stable operation and timely data collection during anomalies.
> 
> ---
> 
> Changes in v2:
> - Removed mtk_cam-debug.c and mtk_cam-debug.h, along with related code
> - Various fixes per review comments
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---

[snip]

> +static bool mtk_cam_request_drained(struct mtk_camsys_sensor_ctrl *sensor_ctrl)
> +{
> +	struct mtk_cam_ctx *ctx = sensor_ctrl->ctx;

You use struct mtk_cam_ctx in this patch, but it's defined in patch [8/13].
You should define it first and then use it.
But here you use struct mtk_cam_ctx which is defined in later patch.
To prevent this, you could apply one patch and build code once.
For example,

After apply patch [5/13], build code.
After apply patch [6/13], build code.
After apply patch [7/13], build code.
...

The step would help you to prevent using symbol which has not defined.
In addition, this patch just add .c file but not add it in Makefile.
When you add .c, also add it in Makefile so you could check it could be built successfully.

Regards,
CK

> +	int sensor_seq_no_next =
> +		atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1;
> +	int res = 0;
> +
> +	if (sensor_seq_no_next <= atomic_read(&ctx->enqueued_frame_seq_no))
> +		res = 1;
> +	/* Send V4L2_EVENT_REQUEST_DRAINED event */
> +	if (res == 0) {
> +		mtk_cam_event_request_drained(ctx->pipe);
> +		dev_dbg(ctx->cam->dev, "request_drained:(%d)\n",
> +			sensor_seq_no_next);
> +	}
> +	return (res == 0);
> +}
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT
  2025-07-07  1:31 ` [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT shangyao lin
@ 2025-07-15  4:07   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-15  4:07 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduces the ISP pipeline driver for the MediaTek ISP raw and yuv
> modules. Key functionalities include data processing, V4L2 integration,
> resource management, debug support, and various control operations.
> Additionally, IRQ handling, platform device management, and MediaTek
> ISP DMA format support are also included.
> 
> Changes in v2:
> 
> - Removed mtk_cam-raw.c and mtk_cam-raw.h, along with related code
> - Removed M2M related code
> - Various fixes per review comments
> 
> Question for CK
> 
> Hi CK,
> 
> May I ask if it is acceptable to keep the id field for the following reason?
> When there is more than one RAW engine on the platform, having an id makes it
> much easier to manage and coordinate different RAW pipelines. It allows us to
> correctly associate events and interrupts with the corresponding RAW device
> context, which improves code maintainability and scalability.
> 
> Would you agree with keeping the id for this purpose, or do you have a preferred
> alternative?

You could keep it now. I would try to review where use this id.
If every where is not necessary, this id would finally be removed.

> 
> Explanation:
> 
> Reply to CK: "Remove resource calculation related code"
> 
> Thank you for your suggestion. The resource calculation code is retained even
> for the unprocessed IMGO path. All image streams, including IMGO unprocessed,
> pass through the raw pipeline and require proper ISP hardware configuration.

It's better to have a comment to explain the pipeline and function block in the pipeline.
When more information, I would give better advice.

> 
> Reply to CK: "It seems yuv is an independent function. If so, separate yuv
> function to an independent patch."
> 
> Thank you for your comment. The raw and yuv functions are not separated into
> independent patches because, in our hardware design, both are handled by the
> same hardware block and share the same register set. The yuv function is just a
> different mode of operation within the same unit, not an independent hardware
> module. Splitting them would not reflect the actual hardware architecture and
> could make the code harder to maintain.

I just want you to separate yuv function to another patch.
You could add it back in later patch.
Finally the code would be the same as now.
Finally it would show hardware architecture and you could maintain the same code.

> 
> Please let me know if you have any further suggestions. Thank you!
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---

[snip]

> +	{
> +		.id = MTK_RAW_RAWI_2_IN,
> +		.name = "rawi 2",
> +		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
> +		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,

For camera, capture device is basic function and output device is advanced function.
If this series just keep basic function, drop the output device code.

Regards,
CK

> +		.link_flags = MEDIA_LNK_FL_ENABLED |  MEDIA_LNK_FL_IMMUTABLE,
> +		.image = true,
> +		.smem_alloc = false,
> +		.dma_port = MTKCAM_ISP_RAWI_2,
> +		.fmts = stream_out_fmts,
> +		.num_fmts = ARRAY_SIZE(stream_out_fmts),
> +		.default_fmt_idx = 0,
> +		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
> +		.frmsizes = &(struct v4l2_frmsizeenum) {
> +			.index = 0,
> +			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
> +			.stepwise = {
> +				.max_width = IMG_MAX_WIDTH,
> +				.min_width = IMG_MIN_WIDTH,
> +				.max_height = IMG_MAX_HEIGHT,
> +				.min_height = IMG_MIN_HEIGHT,
> +				.step_height = 1,
> +				.step_width = 1,
> +			},
> +		},
> +	},
> +	{
> +		.id = MTK_RAW_RAWI_3_IN,
> +		.name = "rawi 3",
> +		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
> +		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
> +		.link_flags = 0,
> +		.image = true,
> +		.smem_alloc = false,
> +		.dma_port = MTKCAM_ISP_RAWI_3,
> +		.fmts = stream_out_fmts,
> +		.num_fmts = ARRAY_SIZE(stream_out_fmts),
> +		.default_fmt_idx = 0,
> +		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
> +		.frmsizes = &(struct v4l2_frmsizeenum) {
> +			.index = 0,
> +			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
> +			.stepwise = {
> +				.max_width = IMG_MAX_WIDTH,
> +				.min_width = IMG_MIN_WIDTH,
> +				.max_height = IMG_MAX_HEIGHT,
> +				.min_height = IMG_MIN_HEIGHT,
> +				.step_height = 1,
> +				.step_width = 1,
> +			},
> +		},
> +	},
> +	{
> +		.id = MTK_RAW_RAWI_4_IN,
> +		.name = "rawi 4",
> +		.cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
> +		.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
> +		.link_flags = 0,
> +		.image = true,
> +		.smem_alloc = false,
> +		.dma_port = MTKCAM_ISP_RAWI_3, /* align backend RAWI_3 */
> +		.fmts = stream_out_fmts,
> +		.num_fmts = ARRAY_SIZE(stream_out_fmts),
> +		.default_fmt_idx = 0,
> +		.ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops,
> +		.frmsizes = &(struct v4l2_frmsizeenum) {
> +			.index = 0,
> +			.type = V4L2_FRMSIZE_TYPE_CONTINUOUS,
> +			.stepwise = {
> +				.max_width = IMG_MAX_WIDTH,
> +				.min_width = IMG_MIN_WIDTH,
> +				.max_height = IMG_MAX_HEIGHT,
> +				.min_height = IMG_MIN_HEIGHT,
> +				.step_height = 1,
> +				.step_width = 1,
> +			},
> +		},
> +	}
> +};
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding
  2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:44   ` Krzysztof Kozlowski
@ 2025-07-15  7:28   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-15  7:28 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> 1. Add camera isp7x module device document
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-seninf-core.yaml
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Question for reviewer (CK):
> 
> Hi CK,
> 
> Thank you for your review and suggestions on this patch, especially for providing the reference patch (https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek/list/?series=874617__;!!CTRNKA9wMg0ARbw!lK62bVQ9-iOIdvsqy3Y0MZIGQl5Szp23K-rB_IB5uffV-tfbML9p144Cgt-4xTpgeYQWungRDBzhfuY1fYflBnk$ ) and for mentioning in another patch ([V1,02/10] MEDIA: PLATFORM: MEDIATEK: ADD SENINF CONTROLLER) the suggestion to "Move the phy part to phy/mediatek/ folder. You could refer to phy/mediatek/phy-mtk-mipi-csi-0-5.c".
> 
> After reading your comments and the reference patches, my understanding is that only the seninf-core driver should manage all ports internally, and each port corresponds to a PHY. During probe, the driver will parse each port, obtain the corresponding PHY (e.g., devm_phy_get(dev, "csi0"), devm_phy_get(dev, "csi1"), etc.), and operate the PHY for each port individually during stream on/off or power on/off.
> 
> Could you please confirm if my understanding is correct?
> If you have any additional reference patches or examples, I would greatly appreciate it.

I'm not expert on seninf and I find previous link [1] is invalid now.
I provide [2] here for your reference.
I don't know the relation of port and phy. You may find some hint in that link.

[1] https://patchwork.kernel.org/project/linux-mediatek/list/?series=874617
[2] https://patchwork.kernel.org/project/linux-mediatek/patch/20241121-add-mtk-isp-3-0-support-v7-3-b04dc9610619@baylibre.com/

> 
> Thank you for your guidance!
> 
> Best regards,
> Shangyao
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---

[snip]

> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/power/mediatek,mt8188-power.h>
> +    #include <dt-bindings/clock/mediatek,mt8188-clk.h>
> +
> +    seninf@16010000 {
> +      compatible = "mediatek,mt8188-seninf-core";
> +      reg = <0 0x16010000 0 0x8000>;
> +      reg-names = "base";
> +      mtk_csi_phy_ver = "mtk_csi_phy_2_0";

mtk_csi_phy_ver is not necessary. compatible imply this.
So drop this.

Regards,
CK

> +      interrupts = <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH 0>;
> +      power-domains = <&spm MT8188_POWER_DOMAIN_CSIRX_TOP>,
> +                      <&spm MT8188_POWER_DOMAIN_CAM_VCORE>,
> +                      <&spm MT8188_POWER_DOMAIN_CAM_MAIN>;
> +      clocks = <&camsys CLK_CAM_MAIN_SENINF>,
> +               <&topckgen CLK_TOP_SENINF>,
> +               <&topckgen CLK_TOP_SENINF1>,
> +               <&topckgen CLK_TOP_CAMTM>;
> +      clock-names = "clk_cam_seninf",
> +                    "clk_top_seninf",
> +                    "clk_top_seninf1",
> +                    "clk_top_camtm";
> +    };
> +
> +...
> \ No newline at end of file


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding
  2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:47   ` Krzysztof Kozlowski
@ 2025-07-15  7:41   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-15  7:41 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-cam-yuv.yaml
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-cam-yuv.yaml     | 134 ++++++++++++++++++
>  1 file changed, 134 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
> new file mode 100755
> index 000000000000..0de120d3c6e8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-cam-yuv.yaml
> @@ -0,0 +1,134 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (c) 2024 MediaTek Inc.
> +%YAML 1.2
> +---
> +$id: https://urldefense.com/v3/__http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml*__;Iw!!CTRNKA9wMg0ARbw!m5llIhxb52atfbJu7JZcPOjWHR2ypTsl8hAhZbX5kM91Vn1dPv9RPDCXHxNwMJDLf05csXuKqchuR_f0YjO6FS8$ 
> +$schema: https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!m5llIhxb52atfbJu7JZcPOjWHR2ypTsl8hAhZbX5kM91Vn1dPv9RPDCXHxNwMJDLf05csXuKqchuR_f0cW6r7vU$ 
> +
> +title: The cam-yuv unit of MediaTek ISP system
> +
> +maintainers:
> +  - Shangyao Lin <shangyao.lin@mediatek.com>
> +  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
> +  - Shun-yi Wang <shun-yi.wang@mediatek.com>
> +  - Teddy Chen <teddy.chen@mediatek.com>
> +
> +description:
> +  MediaTek cam-yuv is the camera YUV processing unit in MediaTek SoC.
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt8188-cam-yuv

In patch [7/13], you say yuv and raw use the same hardware with difference software configuration.
So you should not have different binding for yuv and raw.
Use one (maybe mediatek,mt8188-cam-raw) for both yuv and raw.
In your driver, try another way to decide it works as yuv or raw.

Regards,
CK

> +
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding
  2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:48   ` Krzysztof Kozlowski
@ 2025-07-15  8:13   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-15  8:13 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---

[snip]

> +$id: https://urldefense.com/v3/__http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml*__;Iw!!CTRNKA9wMg0ARbw!huoB5nm0-eewqNovfUlZpTbH1XdMjr0yWt3-_bNow3GppcMua0_ihDD4W1-due6CzcSdZJqTKs9hUNrWwljl0mM$ 
> +$schema: https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!huoB5nm0-eewqNovfUlZpTbH1XdMjr0yWt3-_bNow3GppcMua0_ihDD4W1-due6CzcSdZJqTKs9hUNrWTOQ4FiY$ 
> +
> +title: The cam-raw unit of MediaTek ISP system
> +
> +maintainers:
> +  - Shangyao Lin <shangyao.lin@mediatek.com>
> +  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
> +  - Shun-yi Wang <shun-yi.wang@mediatek.com>
> +  - Teddy Chen <teddy.chen@mediatek.com>
> +
> +description:
> +  MediaTek cam-raw is the camera RAW processing unit in MediaTek SoC.

After reading this description, I still don't understand what is cam-raw.
Describe more here.
What's the main function of it?
It has many iommu port, introduce the function of each port.

Regards,
CK

> +
> +properties:
> +  compatible:
> +    const: mediatek,mt8188-cam-raw
> +
> +  reg:
> +    minItems: 1
> +    maxItems: 2
> +    description:
> +      Base address and optional inner base address of the cam-raw hardware block.
> +
> +  reg-names:
> +    items:
> +      - const: base
> +      - const: inner_base
> +    minItems: 1
> +    maxItems: 2
> +    description:
> +      Names for each register region. Must be "base" and optionally "inner_base".
> +
> +  mediatek,larbs:
> +    description:
> +      List of phandles to the local arbiters in the current SoCs.
> +      Refer to bindings/memory-controllers/mediatek,smi-larb.yaml.
> +    $ref: /schemas/types.yaml#/definitions/phandle-array
> +    minItems: 1
> +    maxItems: 32
> +
> +  interrupts:
> +    minItems: 1
> +    description: Interrupts for the cam-raw block.
> +
> +  dma-ranges:
> +    minItems: 1
> +    description: Address information of IOMMU mapping to memory.
> +
> +  power-domains:
> +    minItems: 1
> +    description: Power domains for the cam-raw block.
> +
> +  clocks:
> +    minItems: 4
> +    maxItems: 16
> +    description: List of phandles to the clocks required by the cam-raw block.
> +
> +  clock-names:
> +    items:
> +      - const: camsys_cam2mm0_cgpdn
> +      - const: camsys_cam2mm1_cgpdn
> +      - const: camsys_cam2sys_cgpdn
> +      - const: camsys_cam_cgpdn
> +      - const: camsys_camtg_cgpdn
> +      - const: camsys_rawa_larbx_cgpdn
> +      - const: camsys_rawa_cam_cgpdn
> +      - const: camsys_rawa_camtg_cgpdn
> +      - const: topckgen_top_cam
> +      - const: topckgen_top_camtg
> +      - const: topckgen_top_camtm
> +    minItems: 4
> +    maxItems: 16
> +    description: Names of the clocks, must match the order of the clocks property.
> +
> +  iommus:
> +    minItems: 1
> +    maxItems: 32
> +    description: Points to the respective IOMMU block with master port as argument.
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - interrupts
> +  - power-domains
> +  - clocks
> +  - clock-names
> +  - iommus
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/power/mediatek,mt8188-power.h>
> +    #include <dt-bindings/clock/mediatek,mt8188-clk.h>
> +    #include <dt-bindings/memory/mediatek,mt8188-memory-port.h>
> +
> +    soc {
> +      raw@16030000 {
> +        compatible = "mediatek,mt8188-cam-raw";
> +        reg = <0 0x16030000 0 0x8000>,
> +              <0 0x16038000 0 0x8000>;
> +        reg-names = "base", "inner_base";
> +        interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH 0>;
> +        dma-ranges = <0x2 0x0 0x0 0x40000000 0x1 0x0>;
> +        power-domains = <&spm MT8188_POWER_DOMAIN_CAM_SUBA>;
> +        clocks = <&camsys CLK_CAM_MAIN_CAM2MM0_GALS>,
> +                 <&camsys CLK_CAM_MAIN_CAM2MM1_GALS>,
> +                 <&camsys CLK_CAM_MAIN_CAM2SYS_GALS>,
> +                 <&camsys CLK_CAM_MAIN_CAM>,
> +                 <&camsys CLK_CAM_MAIN_CAMTG>,
> +                 <&camsys_rawa CLK_CAM_RAWA_LARBX>,
> +                 <&camsys_rawa CLK_CAM_RAWA_CAM>,
> +                 <&camsys_rawa CLK_CAM_RAWA_CAMTG>,
> +                 <&topckgen CLK_TOP_CAM>,
> +                 <&topckgen CLK_TOP_CAMTG>,
> +                 <&topckgen CLK_TOP_CAMTM>;
> +        clock-names = "camsys_cam2mm0_cgpdn",
> +                      "camsys_cam2mm1_cgpdn",
> +                      "camsys_cam2sys_cgpdn",
> +                      "camsys_cam_cgpdn",
> +                      "camsys_camtg_cgpdn",
> +                      "camsys_rawa_larbx_cgpdn",
> +                      "camsys_rawa_cam_cgpdn",
> +                      "camsys_rawa_camtg_cgpdn",
> +                      "topckgen_top_cam",
> +                      "topckgen_top_camtg",
> +                      "topckgen_top_camtm";
> +        iommus = <&vpp_iommu M4U_PORT_L16A_IMGO_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_CQI_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_CQI_R2>,
> +                 <&vpp_iommu M4U_PORT_L16A_BPCI_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_LSCI_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_RAWI_R2>,
> +                 <&vpp_iommu M4U_PORT_L16A_RAWI_R3>,
> +                 <&vpp_iommu M4U_PORT_L16A_UFDI_R2>,
> +                 <&vpp_iommu M4U_PORT_L16A_UFDI_R3>,
> +                 <&vpp_iommu M4U_PORT_L16A_RAWI_R4>,
> +                 <&vpp_iommu M4U_PORT_L16A_RAWI_R5>,
> +                 <&vpp_iommu M4U_PORT_L16A_AAI_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_UFDI_R5>,
> +                 <&vpp_iommu M4U_PORT_L16A_FHO_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_AAO_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_TSFSO_R1>,
> +                 <&vpp_iommu M4U_PORT_L16A_FLKO_R1>;
> +      };
> +    };
> +
> +...
> \ No newline at end of file


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding
  2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
  2025-07-07  2:46   ` Rob Herring (Arm)
  2025-07-07  5:42   ` Krzysztof Kozlowski
@ 2025-07-15  8:25   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-15  8:25 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Add camera isp7x module device document.
> 
> ---
> 
> Changes in v2:
>   - Rename binding file to mediatek,mt8188-camisp.yaml
>   - Split bindings into four separate patches (one per YAML file)
>   - Various fixes per review comments
>   - Update maintainers list
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/mediatek,mt8188-camisp.yaml      | 68 +++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100755 Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
> new file mode 100755
> index 000000000000..53dbf5152e78
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,mt8188-camisp.yaml
> @@ -0,0 +1,68 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (c) 2024 MediaTek Inc.
> +%YAML 1.2
> +---
> +$id: https://urldefense.com/v3/__http://devicetree.org/schemas/media/mediatek/mediatek,camisp.yaml*__;Iw!!CTRNKA9wMg0ARbw!lF1heQiKVAbFIXXXQfR2iaCncLFFZQ6cRvhFJYGAj3MUbQkTc7AvH3yPBQjlsJy3RzRtOShBXxc4egYMq4Eka6A$ 
> +$schema: https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!lF1heQiKVAbFIXXXQfR2iaCncLFFZQ6cRvhFJYGAj3MUbQkTc7AvH3yPBQjlsJy3RzRtOShBXxc4egYMBse--Nk$ 
> +
> +title: The camisp unit of MediaTek ISP system
> +
> +maintainers:
> +  - Shangyao Lin <shangyao.lin@mediatek.com>
> +  - Shu-hsiang Yang <shu-hsiang.yang@mediatek.com>
> +  - Shun-yi Wang <shun-yi.wang@mediatek.com>
> +  - Teddy Chen <teddy.chen@mediatek.com>
> +
> +description:
> +  MediaTek camisp is the ISP auxiliary unit for camera system in MediaTek SoC.
> +
> +properties:
> +  compatible:
> +    const: mediatek,mt8188-camisp
> +
> +  reg:
> +    minItems: 1
> +    maxItems: 1
> +    description:
> +      Base address of the camisp hardware block.
> +
> +  reg-names:
> +    items:
> +      - const: base
> +    minItems: 1
> +    maxItems: 1
> +    description:
> +      Name for the register region. Must be "base".
> +
> +  power-domains:
> +    minItems: 1
> +    maxItems: 1
> +    description: Power domain for the camisp block.
> +
> +  mediatek,scp:
> +    description: MediaTek co-process unit for ISP system
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - power-domains
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/power/mediatek,mt8188-power.h>
> +
> +    soc {
> +      isp@16000000 {
> +        compatible = "mediatek,mt8188-camisp";

In [1], I has already says in the same address, it should not have more than one device with different compatible.
Follow [1] to modify.

[1] https://patchwork.kernel.org/project/linux-mediatek/patch/20241009111551.27052-2-Shu-hsiang.Yang@mediatek.com/#26114958

Regards,
CK

> +        reg = <0 0x16000000 0 0x1000>;
> +        reg-names = "base";
> +        mediatek,scp = <&scp_dual>;
> +        power-domains = <&spm MT8188_POWER_DOMAIN_CAM_MAIN>;
> +      };
> +    };
> +
> +...
> \ No newline at end of file


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit
  2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
  2025-07-07  5:50   ` Krzysztof Kozlowski
  2025-07-10  6:39   ` CK Hu (胡俊光)
@ 2025-07-16  4:06   ` CK Hu (胡俊光)
  2 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-16  4:06 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce support for the MediaTek sensor interface (seninf) in the SoC camera
> subsystem, focusing on CSI and stream control. The driver manages parameter
> control, metering, status tracking, and interrupt handling for the camera sensor
> interface hardware. It integrates with the MediaTek ISP CAMSYS, bridging camera
> sensors and the ISP system, and provides V4L2 framework support for dynamic
> stream configuration and virtual channel management.
> 
> ---

[snip]

>  .../isp_7x/camsys/kd_imgsensor_define_v4l2.h  |   86 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf-def.h    |  237 ++
>  .../isp/isp_7x/camsys/mtk_cam-seninf-drv.c    | 1441 ++++++++++++
>  .../isp/isp_7x/camsys/mtk_cam-seninf-drv.h    |   16 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf-hw.h     |  108 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf-if.h     |   24 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf-regs.h   |   44 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf-route.c  |  279 +++
>  .../isp/isp_7x/camsys/mtk_cam-seninf-route.h  |   20 +
>  .../isp/isp_7x/camsys/mtk_cam-seninf.h        |  161 ++

Add Makefile to build mtk-cam-seninfo-xxx.c in this patch.
Make this patch could be built.

>  .../isp_7x/camsys/mtk_csi_phy_2_0/Makefile    |    5 +
>  .../mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h   |  679 ++++++
>  .../mtk_cam-seninf-csi0-cphy.h                |   51 +
>  .../mtk_cam-seninf-csi0-dphy.h                |   98 +
>  .../mtk_cam-seninf-hw_phy_2_0.c               | 1932 +++++++++++++++++
>  .../mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h  |  165 ++
>  .../mtk_cam-seninf-seninf1-csi2.h             |  264 +++
>  .../mtk_cam-seninf-seninf1-mux.h              |  120 +
>  .../mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h  |   46 +
>  .../mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h      |   43 +
>  .../mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h |   76 +
>  21 files changed, 5895 insertions(+)
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h
> 
> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
> new file mode 100755
> index 000000000000..54c23afe64bd
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019 MediaTek Inc.
> + */
> +
> +#ifndef _KD_IMGSENSOR_DATA_V4L2_H
> +#define _KD_IMGSENSOR_DATA_V4L2_H
> +
> +enum VC_FEATURE {

Because mtk_cam_seninf_get_vc_feature() is useless, so VC_FEATURE is useless.
Drop these.

> +	VC_NONE = 0,
> +	VC_MIN_NUM,
> +	VC_RAW_DATA = VC_MIN_NUM,
> +	VC_RAW_DATA_MAX,
> +
> +	VC_PDAF_MIN_NUM = VC_RAW_DATA_MAX,
> +	VC_PDAF_STATS = VC_PDAF_MIN_NUM,
> +	VC_PDAF_STATS_NE,
> +	VC_PDAF_STATS_ME,
> +	VC_PDAF_STATS_SE,
> +	VC_PDAF_STATS_PIX_1,
> +	VC_PDAF_STATS_PIX_2,
> +	VC_PDAF_STATS_NE_PIX_1 = VC_PDAF_STATS_PIX_1,
> +	VC_PDAF_STATS_NE_PIX_2 = VC_PDAF_STATS_PIX_2,
> +	VC_PDAF_STATS_ME_PIX_1,
> +	VC_PDAF_STATS_ME_PIX_2,
> +	VC_PDAF_STATS_SE_PIX_2,
> +	VC_PDAF_MAX_NUM,
> +
> +	VC_HDR_MIN_NUM = VC_PDAF_MAX_NUM,
> +	VC_HDR_MVHDR = VC_HDR_MIN_NUM,
> +	VC_HDR_MAX_NUM,
> +
> +	VC_3HDR_MIN_NUM = VC_HDR_MAX_NUM,
> +	VC_3HDR_EMBEDDED = VC_3HDR_MIN_NUM,
> +	VC_3HDR_FLICKER,
> +	VC_3HDR_Y,
> +	VC_3HDR_AE,
> +	VC_3HDR_MAX_NUM,
> +
> +	VC_STAGGER_MIN_NUM = VC_3HDR_MAX_NUM,
> +	VC_STAGGER_EMBEDDED = VC_STAGGER_MIN_NUM,
> +	VC_STAGGER_NE,
> +	VC_STAGGER_ME,
> +	VC_STAGGER_SE,
> +	VC_STAGGER_MAX_NUM,
> +
> +	VC_YUV_MIN_NUM = VC_STAGGER_MAX_NUM,
> +	VC_YUV_Y = VC_YUV_MIN_NUM,
> +	VC_YUV_UV,
> +	VC_YUV_MAX_NUM,
> +
> +	VC_RAW_EXT_MIN_NUM = VC_YUV_MAX_NUM,
> +	VC_RAW_W_DATA = VC_RAW_EXT_MIN_NUM,
> +	VC_RAW_PROCESSED_DATA,
> +	VC_RAW_EXT_MAX_NUM,
> +
> +	VC_GENERAL_DATA_MIN_NUM = VC_RAW_EXT_MAX_NUM,
> +	VC_GENERAL_EMBEDDED = VC_GENERAL_DATA_MIN_NUM,
> +	VC_GENERAL_DATA_MAX_NUM,
> +
> +	VC_MAX_NUM = VC_GENERAL_DATA_MAX_NUM,
> +};
> +

[snip]

> +
> +#endif              /* _KD_IMGSENSOR_DATA_H */
> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
> new file mode 100755
> index 000000000000..39f6005c8227
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
> @@ -0,0 +1,237 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2022 MediaTek Inc.
> +
> +#ifndef __MTK_CAM_SENINF_DEF_H__
> +#define __MTK_CAM_SENINF_DEF_H__
> +
> +#include <linux/bitfield.h>
> +
> +#define SENINF_VC_MAXCNT 8
> +#define SENINF_DEF_PIXEL_MODE 2
> +
> +#define SENINF_CLK_MARGIN_IN_PERCENT 0
> +#define HW_BUF_EFFECT 10
> +
> +#define SENINF_HS_TRAIL_EN_CONDITION 1450000000

SENINF_HS_TRAIL_EN_CONDITION is useless. Drop it.

> +#define SENINF_TIMESTAMP_CLK 1000

SENINF_TIMESTAMP_CLK is useless. Drop it.

> +#define ISP_CLK_LOW 273000000
> +
> +#define SENINF_CPHY_SETTLE_DELAY_DT 0x10
> +#define SENINF_DPHY_SETTLE_DELAY_DT 0x10
> +#define SENINF_SETTLE_DELAY_CK 0x11
> +#define SENINF_HS_TRAIL_PARAMETER 0x34
> +
> +#define SENSOR_CLOCK_POLARITY_HIGH	0

SENSOR_CLOCK_POLARITY_HIGH is useless. Drop it.

> +#define SENSOR_CLOCK_POLARITY_LOW	1

SENSOR_CLOCK_POLARITY_LOW is useless. Drop it.

> +#define NUM_PORTS			2

NUM_PORTS is useless. Drop it.

> +#define DEFAULT_WIDTH			1600
> +#define DEFAULT_HEIGHT			1200
> +#define CSI_PORT_A_MASK GENMASK(3, 1)
> +#define SENINF_MAX_STREAM 7
> +

[snip]

> +
> +enum SENINF_PHY_VER_ENUM {
> +	SENINF_PHY_2_0,
> +	SENINF_PHY_VER_NUM,
> +};

SENINF_PHY_VER_ENUM, SENINF_PHY_2_0 and SENINF_PHY_VER_NUM are useless.
Drop them.

> +
> +#define MTK_CSI_PHY_VERSIONS "mtk_csi_phy_2_0"
> +

[snip]

> +
> +static const char * const csi_port_names[] = {
> +	SENINF_CSI_PORT_NAMES

Drop SENINF_CSI_PORT_NAMES and place string here.

> +};
> +
> +static const char * const clk_names[] = {
> +	SENINF_CLK_NAMES

Drop SENINF_CLK_NAMES and place string here.

> +};
> +
> +static const char * const set_reg_names[] = {
> +	SET_REG_KEYS_NAMES

Drop SET_REG_KEYS_NAMES and place string here.

> +};
> +
> +enum REG_OPS_CMD {
> +	REG_OPS_CMD_ID,
> +	REG_OPS_CMD_CSI,
> +	REG_OPS_CMD_RG,
> +	REG_OPS_CMD_VAL,
> +	REG_OPS_CMD_MAX_NUM,
> +};

REG_OPS_CMD_XXX is not defined. Drop all of them.

> +

[snip]

> +
> +static int seninf_core_probe(struct platform_device *pdev)
> +{
> +	int i, ret, irq;
> +	struct resource *res;
> +	struct seninf_core *core;
> +	struct device *dev = &pdev->dev;
> +
> +	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
> +	if (!core)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, core);
> +	core->dev = dev;
> +	mutex_init(&core->mutex);
> +	INIT_LIST_HEAD(&core->list);
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
> +	core->reg_if = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(core->reg_if))
> +		return PTR_ERR(core->reg_if);
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ana-rx");

"ana-rx" is not defined in binding document. Drop this.

> +	core->reg_ana = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(core->reg_ana))
> +		return PTR_ERR(core->reg_ana);
> +
> +	ret = get_seninf_cfg(dev, core);
> +	if (ret) {
> +		dev_err(dev, "failed to get seninf ops\n");
> +		return ret;
> +	}
> +	mtk_cam_seninf_init_res(core);
> +
> +	spin_lock_init(&core->spinlock_irq);
> +	irq = platform_get_irq(pdev, 0);
> +	if (!irq) {
> +		dev_err(dev, "failed to get irq\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = devm_request_irq(dev, irq, mtk_irq_seninf, 0,
> +			       dev_name(dev), core);
> +	if (ret) {
> +		dev_err(dev, "failed to request irq=%d\n", irq);
> +		return ret;
> +	}
> +
> +	/* default platform properties */
> +	core->cphy_settle_delay_dt = SENINF_CPHY_SETTLE_DELAY_DT;
> +	core->dphy_settle_delay_dt = SENINF_DPHY_SETTLE_DELAY_DT;
> +	core->settle_delay_ck = SENINF_SETTLE_DELAY_CK;
> +	core->hs_trail_parameter = SENINF_HS_TRAIL_PARAMETER;
> +
> +	/* read platform properties from device tree */
> +	of_property_read_u32(dev->of_node, "cphy_settle_delay_dt",
> +			     &core->cphy_settle_delay_dt);

"cphy_settle_delay_dt" is not defined in binding document. Drop this.

> +	of_property_read_u32(dev->of_node, "dphy_settle_delay_dt",
> +			     &core->dphy_settle_delay_dt);

"dphy_settle_delay_dt" is not defined in binding document. Drop this.

> +	of_property_read_u32(dev->of_node, "settle_delay_ck",
> +			     &core->settle_delay_ck);

"settle_delay_ck" is not defined in binding document. Drop this.

> +	of_property_read_u32(dev->of_node, "hs_trail_parameter",
> +			     &core->hs_trail_parameter);

"hs_trail_parameter" is not defined in binding document. Drop this.

> +
> +	core->dfs.cnt = 0;
> +	core->dfs.reg = NULL;
> +
> +	ret = seninf_core_pm_runtime_enable(core);
> +	if (ret) {
> +		dev_info(dev, "failed to enable seninf_core_pm_runtime\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < CLK_MAXCNT; i++) {
> +		core->clk[i] = devm_clk_get(dev, clk_names[i]);
> +		if (IS_ERR(core->clk[i])) {
> +			dev_info(dev, "failed to get %s\n", clk_names[i]);
> +			core->clk[i] = NULL;
> +			/* ignore not define seninf */
> +		}
> +	}
> +
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);

It seems "mediatek,mt8188-seninf-core" would probe "mediatek,mt8188-seninf",
but I does not find any relation between them.
How "mediatek,mt8188-seninf-core" proble "mediatek,mt8188-seninf"?

> +	if (ret) {
> +		dev_info(dev, "%s: failed to create sub devices\n", __func__);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +int update_isp_clk(struct seninf_ctx *ctx)
> +{
> +	int i, pixelmode;
> +	struct seninf_dfs *dfs = &ctx->core->dfs;
> +	s64 pixel_rate = -1;
> +	u64 dfs_freq;
> +	struct seninf_vc *vc;
> +	int ret = 0;
> +
> +	if (!dfs->cnt) {

dfs->cnt is always zero, so drop dfs and drop this function.

> +		dev_info(ctx->dev, "dfs not ready.\n");
> +		return ret;
> +	}
> +
> +	vc = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0);
> +	if (!vc) {
> +		dev_info(ctx->dev, "failed to get vc\n");
> +		return -1;
> +	}
> +	dev_info(ctx->dev,
> +		 "%s dfs->cnt %d pixel mode %d customized_pixel_rate %lld, buffered_pixel_rate %lld mipi_pixel_rate %lld\n",
> +		 __func__, dfs->cnt, vc->pixel_mode, ctx->customized_pixel_rate,
> +		 ctx->buffered_pixel_rate, ctx->mipi_pixel_rate);
> +
> +	/* Use SensorPixelrate */
> +	if (ctx->customized_pixel_rate) {
> +		pixel_rate = ctx->customized_pixel_rate;
> +	} else if (ctx->buffered_pixel_rate) {
> +		pixel_rate = ctx->buffered_pixel_rate;
> +	} else if (ctx->mipi_pixel_rate) {
> +		pixel_rate = ctx->mipi_pixel_rate;
> +	} else {
> +		dev_info(ctx->dev, "failed to get pixel_rate\n");
> +		return -EINVAL;
> +	}
> +
> +	pixelmode = vc->pixel_mode;
> +	for (i = 0; i < dfs->cnt; i++) {
> +		dfs_freq = dfs->freqs[i];
> +		dfs_freq = dfs_freq * (100 - SENINF_CLK_MARGIN_IN_PERCENT);
> +		do_div(dfs_freq, 100);
> +		if ((dfs_freq << pixelmode) >= pixel_rate)
> +			break;
> +	}
> +
> +	if (i == dfs->cnt) {
> +		dev_info(ctx->dev, "mux is overrun. please adjust pixelmode\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height,
> +				  s64 hblank, s64 vblank,
> +				  int fps_n, int fps_d,
> +				  s64 sensor_pixel_rate)
> +{
> +	int ret;
> +	s64 p_pixel_rate = sensor_pixel_rate;
> +
> +	ret = calc_buffered_pixel_rate(dev, width, height, hblank, vblank,
> +				       fps_n, fps_d, &p_pixel_rate);
> +	if (ret)
> +		return sensor_pixel_rate;
> +
> +	return p_pixel_rate;
> +}
> +
> +int mtk_cam_seninf_dump(struct v4l2_subdev *sd)

This function does nothing. Drop it.

> +{
> +	int ret = 0;
> +	//TODO debug patch
> +	return ret;
> +}
> +
> +void mtk_cam_seninf_set_secure(struct v4l2_subdev *sd,
> +			       int enable, unsigned int sec_info_addr)

This function is useless. Drop it.

> +{
> +	struct seninf_ctx *ctx = sd_to_ctx(sd);
> +
> +	ctx->sec_info_addr = sec_info_addr;
> +	dev_info(ctx->dev, "[%s]: %x, enable: %d\n",
> +		 __func__, sec_info_addr, enable);
> +	ctx->is_secure = enable ? 1 : 0;
> +}
> 

[snip]

> +
> +enum SET_REG_KEYS {
> +	REG_KEY_MIN = 0,
> +	REG_KEY_SETTLE_CK = REG_KEY_MIN,
> +	REG_KEY_SETTLE_DT,
> +	REG_KEY_HS_TRAIL_EN,
> +	REG_KEY_HS_TRAIL_PARAM,
> +	REG_KEY_CSI_IRQ_STAT,
> +	REG_KEY_CSI_RESYNC_CYCLE,
> +	REG_KEY_MUX_IRQ_STAT,
> +	REG_KEY_CAMMUX_IRQ_STAT,
> +	REG_KEY_CAMMUX_VSYNC_IRQ_EN,
> +	REG_KEY_CSI_IRQ_EN,
> +	REG_KEY_MAX_NUM

Because mtk_cam_seninf_set_reg() is useless and drop,
these enum is also useless. Drop these.

> +};
> +
> +#define SET_REG_KEYS_NAMES \
> +	"RG_SETTLE_CK", \
> +	"RG_SETTLE_DT", \
> +	"RG_HS_TRAIL_EN", \
> +	"RG_HS_TRAIL_PARAM", \
> +	"RG_CSI_IRQ_STAT", \
> +	"RG_CSI_RESYNC_CYCLE", \
> +	"RG_MUX_IRQ_STAT", \
> +	"RG_CAMMUX_IRQ_STAT", \
> +	"REG_VSYNC_IRQ_EN", \
> +	"RG_CSI_IRQ_EN", \
> +
> +struct mtk_cam_seninf_mux_meter {

mtk_cam_seninf_mux_meter is useless. Drop it.

> +	u32 width;
> +	u32 height;
> +	u32 h_valid;
> +	u32 h_blank;
> +	u32 v_valid;
> +	u32 v_blank;
> +	s64 mipi_pixel_rate;
> +	s64 vb_in_us;
> +	s64 hb_in_us;
> +	s64 line_time_in_us;
> +};
> +

[snip]

> +
> +#define to_std_fmt_code(code) \
> +	((code) & 0xFFFF)

to_std_fmt_code() is not necessary. Drop it.

> +
> +

[snip]

> +
> +void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux)
> +{
> +	struct seninf_core *core = ctx->core;
> +
> +	mutex_lock(&core->mutex);
> +	list_move_tail(&mux->list, &core->list_mux);
> +	mutex_unlock(&core->mutex);
> +}

I think using list to manage mux resource is a little over coding.
An array could be more simple.

struct sensor_core {
	...
	bool *mux_used;
	...
};

void mtk_cam_seninf_init_res(struct seninf_core *core)
{
	int i;

	core->mux_used = kzalloc(g_seninf_cfg->mux_num * sizeof(*core->mux_used));
}

int mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx,
					        int pref_cnt)
{
	int mux;

	mutex_lock(&core->mutex);

	if (!core->mux_used[pref_cnt]) {
		core->mux_used[pref_cnt] = true;
		mutex_unlock(&core->mutex);
		return pref_cnt;
	}

	for (mux = 0; mux < g_seninf_cfg->mux_num; mux++)
		if (!core->mux_used[mux]) {
			core->mux_used[mux] = true;
			mutex_unlock(&core->mutex);
			return mux
		}

	mutex_unlock(&core->mutex);

	return -1;
}

void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx)
{
	int mux;

	mutex_lock(&core->mutex);
	for (mux = 0; mux < g_seninf_cfg->mux_num; mux++)
		core->mux_used[mux] = false;
	mutex_unlock(&core->mutex);
}

> +
> +struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx)
> +{
> +	int i;
> +	struct seninf_vcinfo *vcinfo = &ctx->vcinfo;
> +
> +	for (i = 0; i < vcinfo->cnt; i++) {
> +		if (vcinfo->vc[i].out_pad == idx)
> +			return &vcinfo->vc[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd,
> +					   unsigned int pad)

This function is useless. Drop it.

> +{
> +	struct seninf_vc *pvc = NULL;
> +	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
> +
> +	pvc = mtk_cam_seninf_get_vc_by_pad(ctx, pad);
> +	if (pvc)
> +		return pvc->feature;
> +
> +	return VC_NONE;
> +}
> +

[snip]

> +
> +void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx)
> +{
> +	struct seninf_mux *ent, *tmp;
> +
> +	list_for_each_entry_safe(ent, tmp, &ctx->list_mux, list) {
> +		mtk_cam_seninf_mux_put(ctx, ent);
> +	}
> +}
> +
> +int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd,
> +				 int pad_id, int *pixel_mode)

This function is useless. Drop it.

> +{
> +	struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
> +	struct seninf_vc *vc;
> +
> +	vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id);
> +	if (!vc) {
> +		pr_info("%s: invalid pad=%d\n", __func__, pad_id);
> +		return -1;
> +	}
> +
> +	*pixel_mode = vc->pixel_mode;
> +
> +	return 0;
> +}
> +

[snip]

> +int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg)
> +{
> +	return _mtk_cam_seninf_set_camtg(sd, pad_id, camtg, true);

Squash _mtk_cam_seninf_set_camtg() into mtk_cam_seninf_set_camtg().

> +}
> 

[snip]

> +
> +struct seninf_vc {
> +	u8 dt;
> +	u8 feature;

Because mtk_cam_seninf_get_vc_feature() is useless, so feature is useless.
Drop it.

> +	u8 out_pad;
> +	u8 pixel_mode;
> +	u8 mux; /* allocated per group */
> +	u8 cam; /* assigned by cam driver */
> +	u8 enable;
> +};
> +

[snip]

> +
> +struct seninf_ctx {
> +	struct v4l2_subdev subdev;
> +	struct v4l2_async_notifier notifier;
> +	struct device *dev;
> +	struct v4l2_ctrl_handler ctrl_handler;
> +	struct media_pad pads[PAD_MAXCNT];
> +	struct v4l2_subdev_format fmt[PAD_MAXCNT];
> +	struct seninf_core *core;
> +	struct list_head list;
> +
> +	u32 port;
> +	u32 port_a;
> +	u32 port_b;
> +	u32 port_num;
> +	u32 num_data_lanes;
> +	s64 mipi_pixel_rate;

mipi_pixel_rate is never initialized. Drop it.

> +	s64 buffered_pixel_rate;

buffered_pixel_rate is used only in update_isp_clk().
update_isp_clk() is useless and drop, so buffered_pixel_rate is useless.
Drop it.

> +	s64 customized_pixel_rate;

customized_pixel_rate is useless. Drop it.

> +	unsigned int m_csi_efuse;
> +
> +	unsigned int is_4d1c:1;
> +	unsigned int is_cphy:1;
> +	unsigned int is_test_model:4;

is_test_model is useless. Drop it.

> +	unsigned int is_secure:1;
> +	unsigned int sec_info_addr;

Because mtk_cam_seninf_set_secure() is useless, so is_secure and sec_info_addr are useless.
Drop them.

> +	u32 seninf_idx;
> +	int pad2cam[PAD_MAXCNT];
> +
> +	/* remote sensor */
> +	struct v4l2_subdev *sensor_sd;
> +	u32 sensor_pad_idx;
> +
> +	/* provided by sensor */
> +	struct seninf_vcinfo vcinfo;
> +	int fps_n;
> +	int fps_d;
> +
> +	/* dfs */
> +	int isp_freq;

isp_freq is useless. Drop it.

> +
> +	void __iomem *reg_ana_csi_rx[CSI_PORT_MAX_NUM];
> +	void __iomem *reg_ana_dphy_top[CSI_PORT_MAX_NUM];
> +	void __iomem *reg_ana_cphy_top[CSI_PORT_MAX_NUM];
> +	void __iomem *reg_if_top;
> +	void __iomem *reg_if_ctrl[SENINF_NUM];
> +	void __iomem *reg_if_cam_mux;
> +	void __iomem *reg_if_cam_mux_gcsr;
> +	void __iomem *reg_if_cam_mux_pcsr[SENINF_CAM_MUX_NUM];
> +	void __iomem *reg_if_tg[SENINF_NUM];
> +	void __iomem *reg_if_csi2[SENINF_NUM];
> +	void __iomem *reg_if_mux[SENINF_MUX_NUM];
> +
> +	/* resources */
> +	struct list_head list_mux; /* work mux */
> +	struct list_head list_cam_mux;
> +
> +	/* flags */
> +	unsigned int streaming:1;
> +
> +	int cphy_settle_delay_dt;
> +	int dphy_settle_delay_dt;
> +	int settle_delay_ck;
> +	int hs_trail_parameter;
> +
> +	int open_refcnt;
> +	struct mutex mutex;  /* protect seninf context */
> +
> +	/* csi irq */
> +	unsigned int data_not_enough_cnt;
> +	unsigned int err_lane_resync_cnt;
> +	unsigned int crc_err_cnt;
> +	unsigned int ecc_err_double_cnt;
> +	unsigned int ecc_err_corrected_cnt;
> +	/* seninf_mux fifo overrun irq */
> +	unsigned int fifo_overrun_cnt;
> +	/* cam_mux h/v size irq */
> +	unsigned int size_err_cnt;
> +	/* error flag */
> +	unsigned int data_not_enough_flag;
> +	unsigned int err_lane_resync_flag;
> +	unsigned int crc_err_flag;
> +	unsigned int ecc_err_double_flag;
> +	unsigned int ecc_err_corrected_flag;
> +	unsigned int fifo_overrun_flag;
> +	unsigned int size_err_flag;
> +};
> +

[snip]

> +
> +int mtk_cam_seninf_set_cammux_vc(struct seninf_ctx *ctx, int cam_mux,
> +				 int vc_sel, int dt_sel, int vc_en,
> +				 int dt_en)

vc_sel is always zero, so just assign 0 in this function and drop vc_sel parameter.
vc_en and dt_en are always !!dt_sel, so it's not necessary to pass vc_en and dt_en as parameter.
Drop these two parameter and use !!dt_sel in this function.

> +{
> +	void __iomem *seninf_cam_mux_vc_addr = ctx->reg_if_cam_mux + (cam_mux << 0x2);
> +
> +	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> +		    RG_SENINF_CAM_MUX0_VC_SEL, vc_sel);
> +	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> +		    RG_SENINF_CAM_MUX0_DT_SEL, dt_sel);
> +	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> +		    RG_SENINF_CAM_MUX0_VC_EN, vc_en);
> +	SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> +		    RG_SENINF_CAM_MUX0_DT_EN, dt_en);
> +
> +	return 0;
> +}
> +

[snip]

> +int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx,
> +			  struct seninf_vcinfo *vcinfo)
> +{
> +	void __iomem *seninf_csi2 = ctx->reg_if_csi2[seninf_idx];
> +	int i;
> +	struct seninf_vc *vc;
> +
> +	if (WARN_ON(!vcinfo || !vcinfo->cnt))
> +		return -EINVAL;
> +
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S0_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S1_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S2_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S3_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S4_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S5_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S6_DI_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S7_DI_CTRL, 0);
> +
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH0_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH1_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH2_CTRL, 0);
> +	SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH3_CTRL, 0);
> +
> +	for (i = 0; i < vcinfo->cnt; i++) {
> +		vc = &vcinfo->vc[i];
> +
> +		/* General Long Packet Data Types: 0x10-0x17 */
> +		if (vc->dt >= 0x10 && vc->dt <= 0x17) {

vc->dt would only be 0, 0x2a, 0x2b, 0x2c, so this checking would always be false.
Drop this.

> +			SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT,
> +				    RG_CSI2_GENERIC_LONG_PACKET_EN, 1);
> +		}
> +
> +		mtk_cam_seninf_set_di_ch_ctrl(seninf_csi2, i, vc);
> +	}
> +
> +	dev_dbg(ctx->dev, "DI_CTRL 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
> +		readl(seninf_csi2 + SENINF_CSI2_S0_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S1_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S2_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S3_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S4_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S5_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S6_DI_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_S7_DI_CTRL));
> +
> +	dev_dbg(ctx->dev, "CH_CTRL 0x%x 0x%x 0x%x 0x%x\n",
> +		readl(seninf_csi2 + SENINF_CSI2_CH0_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_CH1_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_CH2_CTRL),
> +		readl(seninf_csi2 + SENINF_CSI2_CH3_CTRL));
> +
> +	return 0;
> +}
> +

[snip]

> +
> +int mtk_cam_seninf_irq_handler(int irq, void *data)
> +{
> +	struct seninf_core *core = (struct seninf_core *)data;
> +	unsigned long flags; /* for mipi err detection */
> +	struct seninf_ctx *ctx;
> +	struct seninf_vc *vc;
> +	void __iomem *csi2, *pmux, *seninf_cam_mux;
> +	int i;
> +	unsigned int csi_irq_ro;
> +	unsigned int mux_irq_ro;
> +	unsigned int cam_irq_exp_ro;
> +	unsigned int cam_irq_res_ro;
> +
> +	spin_lock_irqsave(&core->spinlock_irq, flags);
> +
> +	/* debug for set_reg case: REG_KEY_CSI_IRQ_EN */
> +	if (core->csi_irq_en_flag) {

Because mtk_cam_seninf_set_reg() is useless, so core->csi_irq_en_flag is always zero.
Drop these code.

> +		list_for_each_entry(ctx, &core->list, list) {
> +			csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
> +			csi_irq_ro =
> +				readl(csi2 + SENINF_CSI2_IRQ_STATUS);
> +
> +			if (csi_irq_ro) {
> +				SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
> +						 0xFFFFFFFF);
> +			}
> +
> +			if (csi_irq_ro & RO_CSI2_ECC_ERR_CORRECTED_IRQ)
> +				ctx->ecc_err_corrected_cnt++;
> +			if (csi_irq_ro & RO_CSI2_ECC_ERR_DOUBLE_IRQ)
> +				ctx->ecc_err_double_cnt++;
> +			if (csi_irq_ro & RO_CSI2_CRC_ERR_IRQ)
> +				ctx->crc_err_cnt++;
> +			if (csi_irq_ro & RO_CSI2_ERR_LANE_RESYNC_IRQ)
> +				ctx->err_lane_resync_cnt++;
> +			if (csi_irq_ro & RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ)
> +				ctx->data_not_enough_cnt++;
> +
> +			for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +				vc = &ctx->vcinfo.vc[i];
> +				pmux = ctx->reg_if_mux[vc->mux];
> +				seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +				mux_irq_ro = readl(pmux +
> +							     SENINF_MUX_IRQ_STATUS);
> +
> +				cam_irq_exp_ro = readl(seninf_cam_mux +
> +								 SENINF_CAM_MUX0_CHK_CTL_1 +
> +								 (0x10 * (vc->cam)));
> +
> +				cam_irq_res_ro = readl(seninf_cam_mux +
> +								 SENINF_CAM_MUX0_CHK_RES +
> +								 (0x10 * (vc->cam)));
> +
> +				if (mux_irq_ro)
> +					SENINF_WRITE_REG(pmux,
> +							 SENINF_MUX_IRQ_STATUS,
> +							 0xFFFFFFFF);
> +
> +				if (cam_irq_res_ro != cam_irq_exp_ro)
> +					SENINF_WRITE_REG(seninf_cam_mux,
> +							 SENINF_CAM_MUX0_CHK_RES +
> +							 (0x10 * (vc->cam)),
> +							 0xFFFFFFFF);
> +
> +				if (mux_irq_ro & (0x1 << 0))
> +					ctx->fifo_overrun_cnt++;
> +
> +				if (cam_irq_res_ro != cam_irq_exp_ro)
> +					ctx->size_err_cnt++;
> +			}
> +
> +			/* dump status counter: debug for electrical signal */
> +			if (ctx->data_not_enough_cnt >= core->detection_cnt ||
> +			    ctx->err_lane_resync_cnt >= core->detection_cnt ||
> +			    ctx->crc_err_cnt >= core->detection_cnt ||
> +			    ctx->ecc_err_double_cnt >= core->detection_cnt ||
> +			    ctx->ecc_err_corrected_cnt >= core->detection_cnt ||
> +			    ctx->fifo_overrun_cnt >= core->detection_cnt ||
> +			    ctx->size_err_cnt >= core->detection_cnt) {
> +				/* disable all interrupts */
> +				SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_EN, 0x80000000);
> +
> +				if (ctx->data_not_enough_cnt >= core->detection_cnt)
> +					ctx->data_not_enough_flag = 1;
> +				if (ctx->err_lane_resync_cnt >= core->detection_cnt)
> +					ctx->err_lane_resync_flag = 1;
> +				if (ctx->crc_err_cnt >= core->detection_cnt)
> +					ctx->crc_err_flag = 1;
> +				if (ctx->ecc_err_double_cnt >= core->detection_cnt)
> +					ctx->ecc_err_double_flag = 1;
> +				if (ctx->ecc_err_corrected_cnt >= core->detection_cnt)
> +					ctx->ecc_err_corrected_flag = 1;
> +				if (ctx->fifo_overrun_cnt >= core->detection_cnt)
> +					ctx->fifo_overrun_flag = 1;
> +				if (ctx->size_err_cnt >= core->detection_cnt)
> +					ctx->size_err_flag = 1;
> +			}
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&core->spinlock_irq, flags);
> +
> +	return 0;
> +}
> +
> +int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable, int index)

This function is useless, drop it.

> +{
> +    void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +    unsigned int mask;
> +
> +    mask = index ? RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1 : RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0;
> +
> +    SENINF_BITS_VAR(seninf_cam_mux, SENINF_CAM_MUX_DYN_CTRL, mask, enable);
> +
> +    return 0;
> +}
> +
> +int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index)

This function is useless, drop it.

> +{
> +	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +	if (index == 0)
> +		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
> +			    RG_SENINF_CAM_MUX_DYN_SWITCH_EN0, 0);
> +	else
> +		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
> +			    RG_SENINF_CAM_MUX_DYN_SWITCH_EN1, 0);
> +	return 0;
> +}
> +
> +int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable,
> +					  int index)

This function is useless, drop it.

> +{
> +	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +	if (index == 0)
> +		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
> +			    RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN, enable);
> +	else
> +		SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
> +			    RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN, enable);
> +	return 0;
> +}
> +
> +int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable,
> +					    int cam_mux)

This function is useless, drop it.

> +{
> +	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +	int tmp = 0;
> +
> +	tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> +			       RG_SENINF_CAM_MUX_VSYNC_IRQ_EN);
> +	if (enable)
> +		tmp |= (enable << cam_mux);
> +	else
> +		tmp &= ~(enable << cam_mux);
> +	SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> +		    RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, tmp);
> +	return 0;
> +}
> +
> +int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx)

This function is useless, drop it.

> +{
> +	void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +	SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> +		    RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, 0);
> +	return 0;
> +}
> +
> +int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val)

This function is useless, drop it.

Regards,
CK

> +{
> +	int i;
> +	void __iomem *base = ctx->reg_ana_dphy_top[ctx->port];
> +	void __iomem *csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
> +	void __iomem *pmux, *pcammux;
> +	struct seninf_vc *vc;
> +	struct seninf_core *core;
> +	struct seninf_ctx *ctx_;
> +	void __iomem *csi2_;
> +
> +	core = dev_get_drvdata(ctx->dev->parent);
> +
> +	if (!ctx->streaming)
> +		return 0;
> +
> +	dev_dbg(ctx->dev, "%s key = 0x%x, val = 0x%x\n", __func__, key, val);
> +
> +	switch (key) {
> +	case REG_KEY_SETTLE_CK:
> +		SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER,
> +			    RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER,
> +			    RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER, val);
> +		break;
> +	case REG_KEY_SETTLE_DT:
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> +			    RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> +			    RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> +			    RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> +			    RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER, val);
> +		break;
> +	case REG_KEY_HS_TRAIL_EN:
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> +			    RG_DPHY_RX_LD0_HS_TRAIL_EN, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> +			    RG_DPHY_RX_LD1_HS_TRAIL_EN, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> +			    RG_DPHY_RX_LD2_HS_TRAIL_EN, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> +			    RG_DPHY_RX_LD3_HS_TRAIL_EN, val);
> +		break;
> +	case REG_KEY_HS_TRAIL_PARAM:
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> +			    RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> +			    RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> +			    RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, val);
> +		SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> +			    RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, val);
> +		break;
> +	case REG_KEY_CSI_IRQ_STAT:
> +		SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
> +				 val & 0xFFFFFFFF);
> +		break;
> +	case REG_KEY_MUX_IRQ_STAT:
> +		for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +			vc = &ctx->vcinfo.vc[i];
> +			pmux = ctx->reg_if_mux[vc->mux];
> +			SENINF_WRITE_REG(pmux, SENINF_MUX_IRQ_STATUS,
> +					 val & 0xFFFFFFFF);
> +		}
> +		break;
> +	case REG_KEY_CAMMUX_IRQ_STAT:
> +		for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +			vc = &ctx->vcinfo.vc[i];
> +			pcammux = ctx->reg_if_cam_mux;
> +			SENINF_WRITE_REG(pcammux, SENINF_CAM_MUX_IRQ_STATUS,
> +					 val & 0xFFFFFFFF);
> +		}
> +		break;
> +	case REG_KEY_CSI_IRQ_EN:
> +		{
> +			if (!val) {
> +				core->csi_irq_en_flag = 0;
> +				return 0;
> +			}
> +
> +			core->csi_irq_en_flag = 1;
> +			core->detection_cnt = val;
> +			list_for_each_entry(ctx_, &core->list, list) {
> +				csi2_ = ctx_->reg_if_csi2[ctx_->seninf_idx];
> +				SENINF_WRITE_REG(csi2_, SENINF_CSI2_IRQ_EN,
> +						 0xA0002058);
> +			}
> +		}
> +		break;
> +	}
> +
> +	return 0;
> +}
> 


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl
  2025-07-07  1:31 ` [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl shangyao lin
  2025-07-11  8:56   ` CK Hu (胡俊光)
@ 2025-07-21  1:40   ` CK Hu (胡俊光)
  1 sibling, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-21  1:40 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce state management and debugging mechanisms for the MediaTek ISP7.x
> camsys platform. State management establishes control over ISP operations and
> events, defining distinct states for request handling, sensor control, and
> frame synchronization, ensuring proper event processing. The debugging
> mechanism ensures stable operation and timely data collection during anomalies.
> 
> ---
> 
> Changes in v2:
> - Removed mtk_cam-debug.c and mtk_cam-debug.h, along with related code
> - Various fixes per review comments
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---
>  .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c | 1409 +++++++++++++++++
>  .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h |  131 ++
>  2 files changed, 1540 insertions(+)
>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c

Why this file is executable?

>  create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h

Ditto.

> 
> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
> new file mode 100755
> index 000000000000..15af1eac5444
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c
> @@ -0,0 +1,1409 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2022 MediaTek Inc.

2025

> + */
> +
> +#include <linux/list.h>
> +#include <linux/math64.h>
> +#include <linux/of.h>
> +#include <linux/videodev2.h>
> +#include <linux/hrtimer.h>

Alphabetic order.

> +
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-ioctl.h>

Alphabetic order.

> +
> +#include "mtk_cam.h"
> +#include "mtk_cam-ctrl.h"
> +#include "mtk_cam-pool.h"
> +#include "mtk_cam-raw.h"
> +

Drop this blank line.

> +#include "mtk_cam-regs-mt8188.h"
> +

Drop this blank line.

> +#include "mtk_camera-v4l2-controls.h"
> +
> +#define SENSOR_SET_DEADLINE_MS  18
> +#define SENSOR_SET_RESERVED_MS  7
> +#define SENSOR_SET_DEADLINE_MS_60FPS  6
> +#define SENSOR_SET_RESERVED_MS_60FPS  6
> +#define STATE_NUM_AT_SOF 3
> +#define INITIAL_DROP_FRAME_CNT 1
> +
> +enum MTK_CAMSYS_STATE_RESULT {
> +	STATE_RESULT_TRIGGER_CQ = 0,
> +	STATE_RESULT_PASS_CQ_INIT,
> +	STATE_RESULT_PASS_CQ_SW_DELAY,
> +	STATE_RESULT_PASS_CQ_SCQ_DELAY,
> +	STATE_RESULT_PASS_CQ_HW_DELAY,

After call mtk_camsys_raw_state_handle(), just check STATE_RESULT_TRIGGER_CQ or not.
There result is just for print error log.
Direct print error in mtk_camsys_raw_state_handle() and drop these definition.

> +};
> +
> +void state_transition(struct mtk_camsys_ctrl_state *state_entry,

static void state_transition(struct mtk_camsys_ctrl_state *state_entry,

> +		      enum MTK_CAMSYS_STATE_IDX from,
> +		      enum MTK_CAMSYS_STATE_IDX to)
> +{
> +	if (state_entry->estate == from)
> +		state_entry->estate = to;
> +}
> +

[snip]

> +void mtk_cam_set_sensor_full(struct mtk_cam_request_stream_data *s_data,
> +			     struct mtk_camsys_sensor_ctrl *sensor_ctrl)
> +{
> +	struct mtk_cam_device *cam;
> +	struct mtk_cam_ctx *ctx;
> +	struct mtk_cam_request *req;
> +	struct mtk_raw_device *raw_dev;
> +	unsigned int time_after_sof = 0;
> +
> +	/* EnQ this request's state element to state_list (STATE:READY) */
> +	spin_lock(&sensor_ctrl->camsys_state_lock);
> +	list_add_tail(&s_data->state.state_element,
> +		      &sensor_ctrl->camsys_state_list);
> +	atomic_set(&sensor_ctrl->sensor_request_seq_no, s_data->frame_seq_no);
> +	spin_unlock(&sensor_ctrl->camsys_state_lock);
> +
> +	/* sensor_worker task */
> +	ctx = mtk_cam_s_data_get_ctx(s_data);
> +	cam = ctx->cam;
> +	req = mtk_cam_s_data_get_req(s_data);
> +
> +	dev_dbg(cam->dev, "%s:%s:ctx(%d) req(%d):sensor try set start\n",
> +		__func__, req->req.debug_str, ctx->stream_id, s_data->frame_seq_no);
> +
> +	if (ctx->used_raw_num && mtk_cam_req_frame_sync_start(req))
> +		dev_dbg(cam->dev,
> +			"%s:%s:ctx(%d): sensor ctrl with frame sync - start\n",
> +			__func__, req->req.debug_str, ctx->stream_id);
> +
> +	/*
> +	 * request setup
> +	 * 1st frame sensor setting is treated like normal frame
> +	 * and is set with other settings like max fps.
> +	 * 2nd is special, only exposure is set.
> +	 */
> +	if (s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN) {

In patch [8/13] I says ctx->sensor is always NULL, and MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN is set only when ctx->sensor is not NULL.
So drop MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN.

> +		v4l2_ctrl_request_setup(&req->req,
> +					s_data->sensor->ctrl_handler);
> +		time_after_sof =
> +			div_u64(ktime_get_boottime_ns(), 1000000) -
> +				ctx->sensor_ctrl.sof_time;
> +		dev_dbg(cam->dev,
> +			"[SOF+%dms] Sensor request:%d[ctx:%d] setup\n",
> +			time_after_sof, s_data->frame_seq_no,
> +			ctx->stream_id);
> +	}
> +
> +	state_transition(&s_data->state, E_STATE_READY, E_STATE_SENSOR);
> +
> +	if (ctx->used_raw_num && mtk_cam_req_frame_sync_end(req))
> +		dev_dbg(cam->dev,
> +			"%s:ctx(%d): sensor ctrl with frame sync - stop\n",
> +			__func__, ctx->stream_id);
> +
> +	if (ctx->used_raw_num) {
> +		raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe);
> +		if (raw_dev && atomic_read(&raw_dev->vf_en) == 0 &&
> +		    ctx->sensor_ctrl.initial_cq_done == 1 &&
> +		    s_data->frame_seq_no == 1)
> +			mtk_cam_stream_on(raw_dev, ctx);
> +	}
> +
> +	dev_dbg(cam->dev, "%s:%s:ctx(%d)req(%d):sensor done at SOF+%dms\n",
> +		__func__, req->req.debug_str, ctx->stream_id,
> +		s_data->frame_seq_no, time_after_sof);
> +
> +	mtk_cam_complete_sensor_hdl(s_data);
> +}
> +

[snip]

> +static int
> +mtk_camsys_raw_state_handle(struct mtk_raw_device *raw_dev,
> +			    struct mtk_camsys_sensor_ctrl *sensor_ctrl,
> +			    struct mtk_camsys_ctrl_state **current_state,
> +			    struct mtk_camsys_irq_info *irq_info)
> +{
> +	struct mtk_cam_ctx *ctx = sensor_ctrl->ctx;
> +	struct mtk_camsys_ctrl_state *state_temp, *state_outer = NULL;
> +	struct mtk_camsys_ctrl_state *state_inner = NULL;
> +	struct mtk_camsys_ctrl_state *state_rec[STATE_NUM_AT_SOF];
> +	struct mtk_cam_request_stream_data *req_stream_data;
> +	int frame_idx_inner = irq_info->frame_idx_inner;
> +	int stateidx;
> +	int que_cnt = 0;
> +	int write_cnt;
> +	u64 time_boot = ktime_get_boottime_ns();
> +	u64 time_mono = ktime_get_ns();
> +	int working_req_found = 0;
> +
> +	/* List state-queue status*/
> +	spin_lock(&sensor_ctrl->camsys_state_lock);
> +	list_for_each_entry(state_temp, &sensor_ctrl->camsys_state_list,
> +			    state_element) {
> +		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp);
> +		stateidx = atomic_read(&sensor_ctrl->sensor_request_seq_no) -
> +			   req_stream_data->frame_seq_no;
> +		if (stateidx < STATE_NUM_AT_SOF && stateidx > -1) {
> +			state_rec[stateidx] = state_temp;
> +			if (stateidx == 0)
> +				working_req_found = 1;
> +
> +			/* Find outer state element */
> +			if (state_temp->estate == E_STATE_OUTER ||
> +			    state_temp->estate == E_STATE_CAMMUX_OUTER ||
> +			    state_temp->estate == E_STATE_OUTER_HW_DELAY) {
> +				state_outer = state_temp;
> +				mtk_cam_set_timestamp(req_stream_data,
> +						      time_boot, time_mono);
> +			}
> +
> +			/* Find inner state element request */
> +			if (state_temp->estate == E_STATE_INNER ||
> +			    state_temp->estate == E_STATE_INNER_HW_DELAY)
> +				state_inner = state_temp;
> +
> +			dev_dbg(raw_dev->dev,
> +				"[SOF] STATE_CHECK [N-%d] Req:%d / State:%d\n",
> +				stateidx, req_stream_data->frame_seq_no,
> +				state_rec[stateidx]->estate);
> +		}
> +		/* counter for state queue*/
> +		que_cnt++;
> +	}
> +	spin_unlock(&sensor_ctrl->camsys_state_lock);
> +
> +	/* HW imcomplete case */
> +	if (state_inner) {
> +		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_inner);
> +		write_cnt = (atomic_read(&sensor_ctrl->isp_request_seq_no) / 256)
> +					* 256 + irq_info->write_cnt;
> +
> +		if (frame_idx_inner > atomic_read(&sensor_ctrl->isp_request_seq_no) ||
> +		    atomic_read(&req_stream_data->frame_done_work.is_queued) == 1) {
> +			dev_dbg_ratelimited(raw_dev->dev,
> +					    "[SOF] frame done work too late frames. req(%d),ts(%llu)\n",
> +					    req_stream_data->frame_seq_no,
> +					    irq_info->ts_ns);
> +		} else if (write_cnt >= req_stream_data->frame_seq_no) {
> +			dev_info_ratelimited(raw_dev->dev,
> +					     "[SOF] frame done reading lost %d frames. req(%d),ts(%llu)\n",
> +					     write_cnt - req_stream_data->frame_seq_no + 1,
> +					     req_stream_data->frame_seq_no,
> +					     irq_info->ts_ns);
> +			mtk_cam_set_timestamp(req_stream_data,
> +					      time_boot - 1000, time_mono - 1000);
> +			mtk_camsys_frame_done(ctx, write_cnt, ctx->stream_id);
> +		} else if ((write_cnt >= req_stream_data->frame_seq_no - 1) &&
> +			   irq_info->fbc_cnt == 0) {
> +			dev_info_ratelimited(raw_dev->dev,
> +					     "[SOF] frame done reading lost frames. req(%d),ts(%llu)\n",
> +					     req_stream_data->frame_seq_no, irq_info->ts_ns);
> +			mtk_cam_set_timestamp(req_stream_data,
> +					      time_boot - 1000, time_mono - 1000);
> +			mtk_camsys_frame_done(ctx, write_cnt + 1, ctx->stream_id);
> +		} else {
> +			state_transition(state_inner,
> +					 E_STATE_INNER, E_STATE_INNER_HW_DELAY);
> +			if (state_outer) {
> +				state_transition(state_outer,
> +						 E_STATE_OUTER,
> +						 E_STATE_OUTER_HW_DELAY);
> +				state_transition(state_outer,
> +						 E_STATE_CAMMUX_OUTER,
> +						 E_STATE_OUTER_HW_DELAY);
> +			}
> +			dev_info_ratelimited(raw_dev->dev,
> +					     "[SOF] HW_IMCOMPLETE state cnt(%d,%d),req(%d),ts(%llu)\n",
> +					     write_cnt, irq_info->write_cnt,
> +					     req_stream_data->frame_seq_no,
> +					     irq_info->ts_ns);
> +			return STATE_RESULT_PASS_CQ_HW_DELAY;
> +		}
> +	}
> +
> +	/* Transit outer state to inner state */
> +	if (state_outer && sensor_ctrl->sensorsetting_wq) {
> +		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_outer);
> +		if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 &&
> +		    req_stream_data->frame_seq_no > frame_idx_inner) {
> +			dev_info(raw_dev->dev,
> +				 "[SOF-noDBLOAD] HW delay outer_no:%d, inner_idx:%d <= processing_idx:%d,ts:%llu\n",
> +				 req_stream_data->frame_seq_no, frame_idx_inner,
> +				 atomic_read(&sensor_ctrl->isp_request_seq_no),
> +				 irq_info->ts_ns);
> +			return STATE_RESULT_PASS_CQ_HW_DELAY;
> +		}
> +
> +		if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 &&
> +		    req_stream_data->frame_seq_no == frame_idx_inner) {
> +			if (frame_idx_inner >
> +			    atomic_read(&sensor_ctrl->isp_request_seq_no)) {
> +				state_transition(state_outer,
> +						 E_STATE_OUTER_HW_DELAY,
> +						 E_STATE_INNER_HW_DELAY);
> +				state_transition(state_outer,
> +						 E_STATE_OUTER,
> +						 E_STATE_INNER);
> +				state_transition(state_outer,
> +						 E_STATE_CAMMUX_OUTER,
> +						 E_STATE_INNER);

State would change to E_STATE_INNER only in mtk_camsys_raw_state_handle().
mtk_camsys_raw_state_handle() is called only when ctx->sensor is not NULL.
In patch [8/13] I say ctx-sensor is always NULL,
so state would never change to E_STATE_INNER.
Drop it.

> +				atomic_set(&sensor_ctrl->isp_request_seq_no, frame_idx_inner);
> +				dev_dbg(raw_dev->dev,
> +					"[SOF-DBLOAD] frame_seq_no:%d, OUTER->INNER state:%d,ts:%llu\n",
> +					req_stream_data->frame_seq_no,
> +					state_outer->estate, irq_info->ts_ns);
> +			}
> +		}
> +	}
> +
> +	/* Trigger high resolution timer to try sensor setting */
> +	sensor_ctrl->sof_time = div_u64(irq_info->ts_ns, 1000000);
> +	mtk_cam_sof_timer_setup(ctx);
> +
> +	if (que_cnt > 1 && state_rec[1]) {
> +		state_temp = state_rec[1];
> +		req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp);
> +		if (req_stream_data->frame_seq_no == 1)
> +			state_transition(state_temp,
> +					 E_STATE_SENSOR, E_STATE_INNER);
> +	}
> +
> +	if (que_cnt > 0) {
> +		if (working_req_found && state_rec[0]) {
> +			if (state_rec[0]->estate == E_STATE_READY) {
> +				dev_info(raw_dev->dev, "[SOF] sensor delay ts:%llu\n",
> +					 irq_info->ts_ns);
> +				req_stream_data =
> +					mtk_cam_ctrl_state_to_req_s_data(state_rec[0]);
> +				req_stream_data->flags |=
> +					MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED;
> +			}
> +
> +			if (state_rec[0]->estate == E_STATE_SENINF)
> +				dev_info(raw_dev->dev, "[SOF] sensor switch delay\n");
> +
> +			/* CQ triggering judgment*/
> +			if (state_rec[0]->estate == E_STATE_SENSOR) {
> +				*current_state = state_rec[0];
> +				return STATE_RESULT_TRIGGER_CQ;
> +			}
> +			/* last SCQ triggering delay judgment*/
> +			if (state_rec[0]->estate == E_STATE_CQ_SCQ_DELAY) {
> +				state_transition(state_rec[0],
> +						 E_STATE_CQ_SCQ_DELAY,
> +						 E_STATE_OUTER);
> +				dev_info(raw_dev->dev, "[SOF] SCQ_DELAY state:%d ts:%llu\n",
> +					 state_rec[0]->estate, irq_info->ts_ns);
> +				return STATE_RESULT_PASS_CQ_SCQ_DELAY;
> +			}
> +		} else {
> +			dev_dbg(raw_dev->dev, "[SOF] working request not found\n");
> +		}
> +	}
> +	return STATE_RESULT_PASS_CQ_SW_DELAY;
> +}
> +
> +static void mtk_camsys_raw_frame_start(struct mtk_raw_device *raw_dev,
> +				       struct mtk_cam_ctx *ctx,
> +				       struct mtk_camsys_irq_info *irq_info)
> +{
> +	unsigned int dequeued_frame_seq_no = irq_info->frame_idx_inner;
> +	struct mtk_cam_request_stream_data *req_stream_data;
> +	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
> +	struct mtk_cam_working_buf_entry *buf_entry;
> +	struct mtk_camsys_ctrl_state *current_state;
> +	struct mtk_cam_buffer *buf;
> +
> +	dma_addr_t base_addr;
> +	enum MTK_CAMSYS_STATE_RESULT state_handle_ret;
> +
> +	/* touch watchdog*/
> +	if (watchdog_scenario(ctx))

In patch [8/13] I says ctx->sensor is always NULL.
watchdog_scenario() return true only when ctx->sensor is not NULL,
so watchdog_scenario() would always return false.
Drop all watchdog related code.

> +		mtk_ctx_watchdog_kick(ctx);
> +	/* inner register dequeue number */
> +	ctx->dequeued_frame_seq_no = dequeued_frame_seq_no;
> +	/* Send V4L2_EVENT_FRAME_SYNC event */
> +	mtk_cam_event_frame_sync(ctx->pipe, dequeued_frame_seq_no);
> +
> +	/* Handle directly enque buffers */
> +	spin_lock(&ctx->cam->dma_processing_lock);
> +	list_for_each_entry(buf, &ctx->cam->dma_processing, list) {
> +		if (buf->state.estate == E_BUF_STATE_COMPOSED) {
> +			spin_unlock(&ctx->cam->dma_processing_lock);
> +			goto apply_cq;
> +		}
> +	}
> +	spin_unlock(&ctx->cam->dma_processing_lock);
> +	buf = NULL;
> +	current_state = NULL;
> +
> +	/* Find request of this dequeued frame */
> +	req_stream_data =
> +		mtk_cam_get_req_s_data(ctx, ctx->stream_id, dequeued_frame_seq_no);
> +
> +	if (ctx->sensor) {

In patch [8/13] I says ctx->sensor is always NULL, so drop these code.

> +		state_handle_ret =
> +			mtk_camsys_raw_state_handle(raw_dev, sensor_ctrl,
> +						    &current_state, irq_info);

mtk_camsys_raw_state_handle() is called only here, but ctx->sensor is always NULL, so mtk_camsys_raw_state_handle() would never be called.
Drop mtk_camsys_raw_state_handle().

> +
> +		if (state_handle_ret != STATE_RESULT_TRIGGER_CQ) {
> +			dev_dbg(raw_dev->dev, "[SOF] CQ drop s:%d deq:%d\n",
> +				state_handle_ret, dequeued_frame_seq_no);
> +			return;
> +		}
> +	}
> +
> +apply_cq:
> +	/* Update CQ base address if needed */
> +	if (ctx->composed_frame_seq_no <= dequeued_frame_seq_no) {
> +		dev_info_ratelimited(raw_dev->dev,
> +				     "SOF[ctx:%d-#%d], CQ isn't updated [composed_frame_deq (%d) ts:%llu]\n",
> +				     ctx->stream_id, dequeued_frame_seq_no,
> +				     ctx->composed_frame_seq_no, irq_info->ts_ns);
> +		return;
> +	}
> +	/* apply next composed buffer */
> +	spin_lock(&ctx->composed_buffer_list.lock);
> +	if (list_empty(&ctx->composed_buffer_list.list)) {
> +		dev_info_ratelimited(raw_dev->dev,
> +				     "SOF_INT_ST, no buffer update, cq_num:%d, frame_seq:%d, ts:%llu\n",
> +				     ctx->composed_frame_seq_no, dequeued_frame_seq_no,
> +				     irq_info->ts_ns);
> +		spin_unlock(&ctx->composed_buffer_list.lock);
> +	} else {
> +		buf_entry = list_first_entry(&ctx->composed_buffer_list.list,
> +					     struct mtk_cam_working_buf_entry,
> +					     list_entry);
> +		list_del(&buf_entry->list_entry);
> +		ctx->composed_buffer_list.cnt--;
> +		spin_unlock(&ctx->composed_buffer_list.lock);
> +		spin_lock(&ctx->processing_buffer_list.lock);
> +		list_add_tail(&buf_entry->list_entry,
> +			      &ctx->processing_buffer_list.list);
> +		ctx->processing_buffer_list.cnt++;
> +		spin_unlock(&ctx->processing_buffer_list.lock);
> +		base_addr = buf_entry->buffer.iova;
> +		mtk_cam_raw_apply_cq(raw_dev, base_addr,
> +				     buf_entry->cq_desc_size,
> +				     buf_entry->cq_desc_offset,
> +				     buf_entry->sub_cq_desc_size,
> +				     buf_entry->sub_cq_desc_offset);
> +
> +		if (buf) {
> +			buf->state.estate = E_BUF_STATE_CQ;
> +			return;
> +		}
> +
> +		/* Transit state from Sensor -> CQ */
> +		if (ctx->sensor) {
> +			/* req_stream_data of req_cq*/
> +			req_stream_data = mtk_cam_ctrl_state_to_req_s_data(current_state);
> +			state_transition(current_state,
> +					 E_STATE_SENSOR, E_STATE_CQ);

In patch [8/13] I says ctx->sensor is always NULL, so these code would not execute.
This is the only code that change state to E_STATE_CQ but it never execute,
so E_STATE_CQ is useless. Drop it.

> +
> +			dev_dbg(raw_dev->dev,
> +				"SOF[ctx:%d-#%d], CQ-%d is update, composed:%d, cq_addr:0x%pad, time:%lld, monotime:%lld\n",
> +				ctx->stream_id, dequeued_frame_seq_no,
> +				req_stream_data->frame_seq_no,
> +				ctx->composed_frame_seq_no, &base_addr,
> +				req_stream_data->timestamp,
> +				req_stream_data->timestamp_mono);
> +		}
> +	}
> +}
> +

[snip]

> +void mtk_camsys_frame_done(struct mtk_cam_ctx *ctx,
> +			   unsigned int frame_seq_no,
> +			   unsigned int pipe_id)

static void mtk_camsys_frame_done(

> +{
> +	struct mtk_cam_req_work *frame_done_work;
> +	struct mtk_cam_request_stream_data *req_stream_data;
> +	struct mtk_cam_buffer *buf;
> +	struct mtk_cam_working_buf_entry *buf_entry = NULL;
> +	bool is_pending_buffer = false;
> +
> +	spin_lock(&ctx->cam->dma_processing_lock);
> +	if (!list_empty(&ctx->cam->dma_processing)) {
> +		buf = list_first_entry(&ctx->cam->dma_processing,
> +				       struct mtk_cam_buffer, list);
> +		list_del(&buf->list);
> +		ctx->cam->dma_processing_count--;
> +		vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_DONE);
> +		is_pending_buffer = true;
> +	}
> +	spin_unlock(&ctx->cam->dma_processing_lock);
> +	if (is_pending_buffer) {
> +		spin_lock(&ctx->processing_buffer_list.lock);
> +		if (!list_empty(&ctx->processing_buffer_list.list)) {
> +			buf_entry =
> +				list_first_entry(&ctx->processing_buffer_list.list,
> +						 struct mtk_cam_working_buf_entry,
> +						 list_entry);
> +			list_del(&buf_entry->list_entry);
> +			ctx->processing_buffer_list.cnt--;
> +		}
> +		spin_unlock(&ctx->processing_buffer_list.lock);
> +		if (buf_entry)
> +			mtk_cam_working_buf_put(buf_entry);
> +
> +		mtk_cam_buf_try_queue(ctx);
> +		return;
> +	}
> +
> +	req_stream_data = mtk_cam_get_req_s_data(ctx, pipe_id, frame_seq_no);
> +	if (!req_stream_data) {
> +		dev_err(ctx->cam->dev,
> +			 "%s:ctx-%d:pipe-%d:req(%d) not found!\n",
> +			 __func__, ctx->stream_id, pipe_id, frame_seq_no);
> +		return;
> +	}
> +
> +	if (atomic_read(&req_stream_data->frame_done_work.is_queued)) {
> +		dev_info(ctx->cam->dev,
> +			 "already queue done work req:%d seq:%d pipe_id:%d\n",
> +			 req_stream_data->frame_seq_no, frame_seq_no, pipe_id);
> +		return;
> +	}
> +
> +	atomic_set(&req_stream_data->frame_done_work.is_queued, 1);
> +	frame_done_work = &req_stream_data->frame_done_work;
> +	queue_work(ctx->frame_done_wq, &frame_done_work->work);
> +}
> +

[snip]

> +static bool mtk_camsys_is_all_cq_done(struct mtk_cam_ctx *ctx,
> +				      unsigned int pipe_id)
> +{
> +	unsigned int all_subdevs = 0;
> +	bool ret = false;
> +
> +	spin_lock(&ctx->first_cq_lock);
> +	if (ctx->is_first_cq_done) {
> +		ret = true;
> +		spin_unlock(&ctx->first_cq_lock);
> +		goto EXIT;
> +	}
> +
> +	// update cq done status

Run checkpatch.pl before you send out patch.
checkpatch would tell you not to use c++ style comment.

> +	ctx->cq_done_status |= (1 << pipe_id);
> +
> +	// check cq done status
> +	if (ctx->used_raw_num)
> +		all_subdevs |= (1 << ctx->pipe->id);
> +	if ((ctx->cq_done_status & all_subdevs) == all_subdevs) {
> +		ctx->is_first_cq_done = 1;
> +		ret = true;
> +	}
> +	spin_unlock(&ctx->first_cq_lock);
> +	dev_info(ctx->cam->dev,
> +		 "[1st-CQD] all done:%d, pipe_id:%d (using raw:%d)\n",
> +		 ctx->is_first_cq_done, pipe_id, ctx->used_raw_num);

Why print is_first_cq_done?
I think this is not necessary.

> +EXIT:
> +	return ret;
> +}
> +
> +static int mtk_camsys_event_handle_raw(struct mtk_cam_device *cam,
> +				       unsigned int engine_id,
> +				       struct mtk_camsys_irq_info *irq_info)
> +{
> +	struct mtk_raw_device *raw_dev;
> +	struct mtk_cam_ctx *ctx;
> +
> +	raw_dev = dev_get_drvdata(cam->raw.devs[engine_id]);
> +	ctx = mtk_cam_find_ctx(cam, &raw_dev->pipeline->subdev.entity);
> +	if (!ctx) {
> +		dev_err(raw_dev->dev, "cannot find ctx\n");
> +		return -EINVAL;
> +	}
> +
> +	/* raw's CQ done */
> +	if (irq_info->irq_type & 1 << CAMSYS_IRQ_SETTING_DONE) {
> +		if (mtk_camsys_is_all_cq_done(ctx, ctx->pipe->id))
> +				mtk_camsys_raw_cq_done(raw_dev, ctx,
> +						       irq_info->frame_idx);
> +	}
> +
> +	/* raw's DMA done, we only allow AFO done here */
> +	if (irq_info->irq_type & 1 << CAMSYS_IRQ_AFO_DONE)
> +		mtk_cam_meta1_done(ctx, ctx->dequeued_frame_seq_no, ctx->stream_id);
> +
> +	/* raw's SW done */
> +	if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_DONE) {
> +		mtk_camsys_frame_done(ctx, ctx->dequeued_frame_seq_no,
> +						ctx->stream_id);
> +	}
> +	/* raw's SOF */
> +	if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_START) {
> +		if (atomic_read(&raw_dev->vf_en) == 0) {
> +			dev_info(raw_dev->dev, "skip sof event when vf off\n");
> +			return 0;
> +		}
> +		mtk_camsys_raw_frame_start(raw_dev, ctx, irq_info);
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +struct mtk_camsys_irq_normal_data {
> +	/* with normal_status */

mtk_camsys_irq_normal_data is nothing. Drop it.

> +};
> +
> +struct mtk_camsys_irq_error_data {
> +	/* with error_status */
> +	int err_status;
> +};
> +
> +struct mtk_camsys_irq_info {
> +	enum MTK_CAMSYS_IRQ_EVENT irq_type;
> +	u64 ts_ns;
> +	int frame_idx;
> +	int frame_idx_inner;
> +	bool sub_engine;

sub_engine is useless. Drop it.

> +	int write_cnt;
> +	int fbc_cnt;
> +	union {
> +		struct mtk_camsys_irq_normal_data n;
> +		struct mtk_camsys_irq_error_data e;

e is never used. Drop it.

> +	};
> +};
> +
> +enum MTK_CAMSYS_STATE_IDX {
> +	/* For state analysis and controlling for request */
> +	E_STATE_READY = 0x0,
> +	E_STATE_SENINF,

state never change to E_STATE_SENINF. Drop it.

> +	E_STATE_SENSOR,
> +	E_STATE_CQ,
> +	E_STATE_OUTER,
> +	E_STATE_CAMMUX_OUTER_CFG,

state never change to E_STATE_CAMMUX_OUTER_CFG. Drop it.

> +	E_STATE_CAMMUX_OUTER,

state never change to E_STATE_CAMMUX_OUTER. Drop it.

> +	E_STATE_INNER,
> +	E_STATE_DONE_NORMAL,
> +	E_STATE_CQ_SCQ_DELAY,
> +	E_STATE_CAMMUX_OUTER_CFG_DELAY,

state never change to E_STATE_CAMMUX_OUTER_CFG_DELAY. Drop it.

> +	E_STATE_OUTER_HW_DELAY,
> +	E_STATE_INNER_HW_DELAY,
> +	E_STATE_DONE_MISMATCH,
> +};
> +
> +struct mtk_camsys_ctrl_state {
> +	enum MTK_CAMSYS_STATE_IDX estate;
> +	struct list_head state_element;
> +};
> +
> +struct mtk_camsys_link_ctrl {

mtk_camsys_link_ctrl is useless. Drop it.

> +	struct mtk_raw_pipeline *pipe;
> +	struct media_pad remote;
> +	struct mtk_cam_ctx *swapping_ctx;
> +	u8 active;
> +	u8 wait_exchange;
> +};
> +
> +/* per stream from sensor */
> +struct mtk_camsys_sensor_ctrl {
> +	struct mtk_cam_ctx *ctx;
> +	struct kthread_worker *sensorsetting_wq;
> +	struct kthread_work work;
> +	struct hrtimer sensor_deadline_timer;
> +	u64 sof_time;
> +	int timer_req_sensor;
> +	int timer_req_event;
> +	atomic_t sensor_enq_seq_no;
> +	atomic_t sensor_request_seq_no;
> +	atomic_t isp_request_seq_no;
> +	atomic_t isp_enq_seq_no;
> +	atomic_t last_drained_seq_no;
> +	int initial_cq_done;
> +	atomic_t initial_drop_frame_cnt;
> +	struct list_head camsys_state_list;
> +	spinlock_t camsys_state_lock; /* protect camsys_state_list */
> +	/* link change ctrl */
> +	struct mtk_camsys_link_ctrl link_ctrl;

link_ctrl is useless. Drop it.

> +	struct mtk_cam_request *link_change_req;

link_change_req is useless. Drop it.

Regards,
CK

> +};
> +



^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility
  2025-07-07  1:31 ` [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility shangyao lin
@ 2025-07-22  2:19   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-22  2:19 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce utility files for the MediaTek ISP7.x camsys driver. These utilities
> provide essential platform definitions, debugging tools, and management
> functions to support ISP operations and SCP communication.
> 
> Key functionalities include:
> - Hardware pipeline and register definitions for managing image processing
>   modules
> - Buffer management functions
> - Definitions of supported image formats for proper data handling
> - IPI and SCP communication structures for module state management and ISP
>   configuration
> - Metadata parameters for configuring image processing
> 
> Changes in v2:
> - Removed mtk_cam-dmadbg.h along with related code
> - Various fixes per review comments
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---

[snip]

> +/*
> + *  A U T O  F O C U S
> + */
> +
> +/*
> + * struct mtk_cam_uapi_af_param - af statistic parameters
> + *  @roi: AF roi rectangle (in pixel) for AF statistic covered, including
> + *    x, y, width, height
> + *  @th_sat_g:  green channel pixel value saturation threshold (0~255)
> + *  @th_h[3]: horizontal AF filters response threshold (0~50) for H0, H1,
> + *    and H2
> + *  @th_v:  vertical AF filter response threshold (0~50)
> + *  @blk_pixel_xnum: horizontal number of pixel per block
> + *  @blk_pixel_ynum: vertical number of pixel per block
> + *  @fir_type: to select FIR filter by AF target type (0,1,2,3)
> + *  @iir_type: to select IIR filter by AF target type (0,1,2,3)
> + *  @data_gain[7]: gamma curve gain for AF source data
> + */
> +struct mtk_cam_uapi_af_param {

Move all uapi definition to uapi folder.
But I does not see driver use mtk_cam_uapi_af_param.
If this is useless. Drop it.

> +	struct mtk_cam_uapi_meta_rect roi;
> +	u32 th_sat_g;
> +	u32 th_h[3];
> +	u32 th_v;
> +	u32 blk_pixel_xnum;
> +	u32 blk_pixel_ynum;
> +	u32 fir_type;
> +	u32 iir_type;
> +	u32 data_gain[7];
> +} __packed;
> +

[snip]

> +/*
> + * struct mtk_cam_uapi_pdp_stats - statistics of pd
> + *
> + * @stats_src:     source width and heitgh of the statistics.
> + * @stride:     stride value used by
> + * @pdo_buf:     The buffer for PD statistic hardware output.
> + *
> + * This is the PD statistic returned to user.
> + */
> +struct mtk_cam_uapi_pdp_stats {

I does not see driver use mtk_cam_uapi_pdp_stats.
If this is useless. Drop it.

> +	struct  mtk_cam_uapi_meta_size stats_src;
> +	u32   stride;
> +	struct  mtk_cam_uapi_meta_hw_buf pdo_buf;
> +} __packed;
> +

[snip]

> +/*
> + * struct mtk_cam_uapi_tnc_stats - Tone2 statistic data for
> + *                 Mediatek proprietary algorithm
> + *
> + * @tncso_buf: The buffer for tnc statistic hardware output. The buffer size
> + *           is defined in MTK_CAM_UAPI_TNCSO_SIZE (680*510*2)
> + */
> +struct mtk_cam_uapi_tnc_stats {
> +	struct mtk_cam_uapi_meta_hw_buf tncso_buf;

It's weird that define one structure including only one structure.
Drop mtk_cam_uapi_tnc_stats.

> +} __packed;
> +
> +/*
> + * struct mtk_cam_uapi_tnch_stats - Tone3 statistic data for Mediatek
> + *                                  proprietary algorithm
> + *
> + * @tncsho_buf: The buffer for tnch statistic hardware output. The buffer size
> + *           is defined in MTK_CAM_UAPI_TNCSHO_SIZE (1544)
> + */
> +struct mtk_cam_uapi_tnch_stats {
> +	struct mtk_cam_uapi_meta_hw_buf tncsho_buf;

It's weird that define one structure including only one structure.
Drop mtk_cam_uapi_tnch_stats.

> +} __packed;
> +
> +/*
> + * struct mtk_cam_uapi_tncb_stats - Tone4 statistic data for Mediatek
> + *                                  proprietary algorithm
> + *
> + * @tncsbo_buf: The buffer for tncb statistic hardware output. The buffer size
> + *           is defined in MTK_CAM_UAPI_TNCSBO_SIZE (3888)
> + */
> +struct mtk_cam_uapi_tncb_stats {
> +	struct mtk_cam_uapi_meta_hw_buf tncsbo_buf;

It's weird that define one structure including only one structure.
Drop mtk_cam_uapi_tncb_stats.

> +} __packed;
> +
> +/*
> + * struct mtk_cam_uapi_tncy_stats - Tone3 statistic data for Mediatek
> + *                                  proprietary algorithm
> + *
> + * @tncsyo_buf: The buffer for tncy statistic hardware output. The buffer size
> + *           is defined in MTK_CAM_UAPI_TNCSYO_SIZE (68)
> + */
> +struct mtk_cam_uapi_tncy_stats {
> +	struct mtk_cam_uapi_meta_hw_buf tncsyo_buf;

It's weird that define one structure including only one structure.
Drop mtk_cam_uapi_tncy_stats.

> +} __packed;
> +
> +/*
> + * struct mtk_cam_uapi_act_stats - act statistic data for Mediatek
> + *                                  proprietary algorithm
> + *
> + * @actso_buf: The buffer for tncy statistic hardware output. The buffer size
> + *           is defined in MTK_CAM_UAPI_ACTSO_SIZE (768)
> + */
> +#define MTK_CAM_UAPI_ACTSO_SIZE (768)
> +struct mtk_cam_uapi_act_stats {
> +	struct mtk_cam_uapi_meta_hw_buf actso_buf;

It's weird that define one structure including only one structure.
Drop mtk_cam_uapi_act_stats.

> +} __packed;
> +

[snip]

> +/*
> + * Usage example: To print value of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val"
> + * > printf("%x", GET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN));
> + */
> +#define GET_MTK_CAM(val, field) (((val) & field##_MASK) >> \
> +				 field##_SHIFT)
> +/*
> + * Usage example: To set "val_of_bpc_lut_bit_extend_en" to bits
> + * of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val"
> + * > val = SET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN,
> + * val_of_bpc_lut_bit_extend_en);
> + */
> +#define SET_MTK_CAM(val, field, set_val) (((val) & ~field##_MASK) | \
> +					  (((set_val) << field##_SHIFT) & field##_MASK))
> +
> +/*
> + * Bit Feild of BPC_FUNC_CON: BPC_EN
> + * MTK_CAM_BPC_FUNC_CON_BPC_EN: [31, 31]
> + * Enable/disable for BPC Correction
> + * 1'd1: enable the function
> + * 1'd0: disable the function
> + */
> +#define MTK_CAM_BPC_FUNC_CON_BPC_EN_MASK   0x80000000

I can not find anywhere to use this.
If it is useless, drop it.
If it is usable, it seams a structure could simplify these definition.

struct bpc_ctrl {
	u32 bpc_lut_bit_extend_en:1;
	u32 reserved:27;
	u32 bpc_lut_en:1;
	u32 bpc_pdc_en:1;
	u32 bpc_ct_en:1;
	u32 bpc_en:1;
};

> +#define MTK_CAM_BPC_FUNC_CON_BPC_EN_SHIFT  31
> +
> +/*
> + * Bit Feild of BPC_FUNC_CON: BPC_CT_EN
> + * MTK_CAM_BPC_FUNC_CON_BPC_CT_EN: [30, 30]
> + * Enable/disable for Cross-Talk compensation
> + * 1'd1: enable
> + * 1'd0: disable
> + */
> +#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_MASK   0x40000000
> +#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_SHIFT  30
> +
> +/*
> + * Bit Feild of BPC_FUNC_CON: BPC_PDC_EN
> + * MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN: [29, 29]
> + * Enable/disable for PDC correction
> + * 1'd1: enable
> + * 1'd0: disable
> + */
> +#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_MASK   0x20000000
> +#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_SHIFT  29
> +
> +/*
> + * Bit Feild of BPC_FUNC_CON: BPC_LUT_EN
> + * MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN: [28, 28]
> + * Enable table lookup
> + * 1'd1:  enable BPC with default table mode
> + * 1'd0:  disable BPC with default table mode
> + */
> +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_MASK   0x10000000
> +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_SHIFT  28
> +
> +/*
> + * Bit Feild of BPC_FUNC_CON: BPC_LUT_BIT_EXTEND_EN
> + * MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN: [0, 0]
> + * Enable table 24 bits mode
> + * 1'd1: Table format to be 24 bits
> + * 1'd0: @ the original format, tbale to be 16 bits mode
> + */
> +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_MASK   0x00000001
> +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_SHIFT  0
> +

[snip]

> +int mtk_cam_img_working_buf_pool_init(struct mtk_cam_ctx *ctx, int buf_num,
> +				      struct device *dev)

mtk_cam_img_working_buf_pool_init() is useless. Drop it.

> +{
> +	int i, ret;
> +	u32 working_buf_size;
> +	void *ptr;
> +	dma_addr_t addr;
> +	struct mtk_cam_device *cam = ctx->cam;
> +	struct mtk_cam_video_device *vdev;
> +
> +	if (buf_num > CAM_IMG_BUF_NUM) {
> +		dev_err(ctx->cam->dev,
> +			"%s: ctx(%d): image buffers number too large(%d)\n",
> +			__func__, ctx->stream_id, buf_num);
> +		WARN_ON(1);
> +		return 0;
> +	}
> +
> +	vdev = &ctx->pipe->vdev_nodes[MTK_RAW_MAIN_STREAM_OUT - MTK_RAW_SINK_NUM];
> +	working_buf_size = vdev->active_fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
> +	INIT_LIST_HEAD(&ctx->img_buf_pool.cam_freeimglist.list);
> +	spin_lock_init(&ctx->img_buf_pool.cam_freeimglist.lock);
> +	ctx->img_buf_pool.cam_freeimglist.cnt = 0;
> +	ctx->img_buf_pool.working_img_buf_size = buf_num * working_buf_size;
> +	ptr = dma_alloc_coherent(cam->smem_dev,
> +				 ctx->img_buf_pool.working_img_buf_size,
> +				 &addr, GFP_KERNEL);
> +	if (!ptr)
> +		return -ENOMEM;
> +	ctx->img_buf_pool.working_img_buf_scp_addr = addr;
> +	ctx->img_buf_pool.working_img_buf_va = ptr;
> +	addr = dma_map_resource(dev, addr, ctx->img_buf_pool.working_img_buf_size,
> +				DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
> +	if (dma_mapping_error(dev, addr)) {
> +		dev_err(dev, "failed to map scp iova\n");
> +		ret = -ENOMEM;
> +		goto fail_free_mem;
> +	}
> +	ctx->img_buf_pool.working_img_buf_iova = addr;
> +	dev_dbg(dev,
> +		"[%s] img working buf scp addr:%pad va:%pK iova: %pad size %d\n",
> +		__func__,
> +		&ctx->img_buf_pool.working_img_buf_scp_addr,
> +		ctx->img_buf_pool.working_img_buf_va,
> +		&ctx->img_buf_pool.working_img_buf_iova,
> +		ctx->img_buf_pool.working_img_buf_size);
> +
> +	for (i = 0; i < buf_num; i++) {
> +		struct mtk_cam_img_working_buf_entry *buf =
> +			&ctx->img_buf_pool.img_working_buf[i];
> +		int offset = i * working_buf_size;
> +
> +		buf->ctx = ctx;
> +		buf->img_buffer.va =
> +			ctx->img_buf_pool.working_img_buf_va + offset;
> +		buf->img_buffer.scp_addr =
> +			ctx->img_buf_pool.working_img_buf_scp_addr + offset;
> +		buf->img_buffer.iova =
> +			ctx->img_buf_pool.working_img_buf_iova + offset;
> +		buf->img_buffer.size = working_buf_size;
> +
> +		list_add_tail(&buf->list_entry,
> +			      &ctx->img_buf_pool.cam_freeimglist.list);
> +		ctx->img_buf_pool.cam_freeimglist.cnt++;
> +	}
> +
> +	dev_dbg(dev, "%s: ctx(%d): image buffers init, freebuf cnt(%d)\n",
> +		__func__, ctx->stream_id, ctx->img_buf_pool.cam_freeimglist.cnt);
> +	return 0;
> +
> +fail_free_mem:
> +	dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size,
> +			  ctx->img_buf_pool.working_img_buf_va,
> +			  ctx->img_buf_pool.working_img_buf_scp_addr);
> +	return ret;
> +}
> +
> +void mtk_cam_img_working_buf_pool_release(struct mtk_cam_ctx *ctx,
> +					  struct device *dev)

Becasue mtk_cam_img_working_buf_pool_init is useless,
so mtk_cam_img_working_buf_pool_release() is useless. Drop it.

> +{
> +	struct mtk_cam_device *cam = ctx->cam;
> +
> +	dma_unmap_page_attrs(dev, ctx->img_buf_pool.working_img_buf_iova,
> +			     ctx->img_buf_pool.working_img_buf_size,
> +			     DMA_BIDIRECTIONAL,
> +			     DMA_ATTR_SKIP_CPU_SYNC);
> +	dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size,
> +			  ctx->img_buf_pool.working_img_buf_va,
> +			  ctx->img_buf_pool.working_img_buf_scp_addr);
> +	dev_dbg(dev,
> +		"%s:ctx(%d):img working buf release, scp addr %pad va %pK iova %pad, sz %u\n",
> +		__func__, ctx->stream_id,
> +		&ctx->img_buf_pool.working_img_buf_scp_addr,
> +		ctx->img_buf_pool.working_img_buf_va,
> +		&ctx->img_buf_pool.working_img_buf_iova,
> +		ctx->img_buf_pool.working_img_buf_size);
> +}
> +
> +void mtk_cam_img_working_buf_put(struct mtk_cam_img_working_buf_entry *buf_entry)

mtk_cam_img_working_buf_put() is useless. Drop it.

> +{
> +	struct mtk_cam_ctx *ctx = buf_entry->ctx;
> +	int cnt;
> +
> +	spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock);
> +
> +	list_add_tail(&buf_entry->list_entry,
> +		      &ctx->img_buf_pool.cam_freeimglist.list);
> +	cnt = ++ctx->img_buf_pool.cam_freeimglist.cnt;
> +
> +	spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
> +
> +	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n",
> +		__func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt);
> +}
> +
> +struct mtk_cam_img_working_buf_entry *
> +mtk_cam_img_working_buf_get(struct mtk_cam_ctx *ctx)

mtk_cam_img_working_buf_get() is useless. Drop it.

> +{
> +	struct mtk_cam_img_working_buf_entry *buf_entry;
> +	int cnt;
> +
> +	/* get from free list */
> +	spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock);
> +	if (list_empty(&ctx->img_buf_pool.cam_freeimglist.list)) {
> +		spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
> +
> +		dev_info(ctx->cam->dev, "%s:ctx(%d):no free buf\n",
> +			 __func__, ctx->stream_id);
> +		return NULL;
> +	}
> +
> +	buf_entry = list_first_entry(&ctx->img_buf_pool.cam_freeimglist.list,
> +				     struct mtk_cam_img_working_buf_entry,
> +				     list_entry);
> +	list_del(&buf_entry->list_entry);
> +	cnt = --ctx->img_buf_pool.cam_freeimglist.cnt;
> +
> +	spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock);
> +
> +	dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n",
> +		__func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt);
> +
> +	return buf_entry;
> +}
> +

[snip]

> +/* IRQ signal mask */
> +#define INT_ST_MASK_CAM (VS_INT_ST	 |\
> +			 TG_INT1_ST	 |\
> +			 TG_INT2_ST	 |\
> +			 EXPDON_ST       |\
> +			 HW_PASS1_DON_ST |\
> +			 SOF_INT_ST      |\
> +			 SW_PASS1_DON_ST)
> +
> +/* IRQ Error Mask */
> +#define INT_ST_MASK_CAM_ERR	(TG_OVRUN_ST		|\
> +				 TG_GBERR_ST		|\
> +				 CQ_DB_LOAD_ERR_ST	|\
> +				 CQ_MAIN_CODE_ERR_ST	|\
> +				 CQ_MAIN_VS_ERR_ST	|\
> +				 DMA_ERR_ST)
> +
> +/* camsys */
> +#define REG_CAMSYS_CG_SET				0x0004

REG_CAMSYS_CG_SET is useless. Drop it.

> +#define REG_CAMSYS_CG_CLR				0x0008

REG_CAMSYS_CG_CLR is useless. Drop it.

> +
> +#define REG_HALT1_EN					0x0350
> +#define REG_HALT2_EN					0x0354
> +#define REG_HALT3_EN					0x0358
> +#define REG_HALT4_EN					0x035c
> +#define REG_HALT5_EN					0x0360
> +#define REG_HALT6_EN					0x0364
> +#define REG_FLASH					0x03A0

REG_FLASH is useless. Drop it.

> +#define REG_ULTRA_HALT1_EN				0x03c0
> +#define REG_ULTRA_HALT2_EN				0x03c4
> +#define REG_ULTRA_HALT3_EN				0x03c8
> +#define REG_ULTRA_HALT4_EN				0x03cc
> +#define REG_ULTRA_HALT5_EN				0x03d0
> +#define REG_ULTRA_HALT6_EN				0x03d4
> +#define REG_PREULTRA_HALT1_EN				0x03f0
> +#define REG_PREULTRA_HALT2_EN				0x03f4
> +#define REG_PREULTRA_HALT3_EN				0x03f8
> +#define REG_PREULTRA_HALT4_EN				0x03fc
> +#define REG_PREULTRA_HALT5_EN				0x0400
> +#define REG_PREULTRA_HALT6_EN				0x0404
> +
> +/* Status check */
> +#define REG_CTL_EN					0x0000
> +#define REG_CTL_EN2					0x0004

REG_CTL_EN2 is useless. Drop it.

> +
> +/* DMA Enable Register, DMA_EN */
> +#define REG_CTL_MOD5_EN					0x0010

REG_CTL_MOD5_EN is useless. Drop it.

> +#define REG_CTL_MOD6_EN					0x0014



> +/* RAW input trigger*/
> +#define REG_CTL_RAWI_TRIG				0x00C0
> +
> +#define REG_CTL_MISC					0x0060
> +#define CTL_DB_EN					BIT(4)
> +
> +#define REG_CTL_SW_CTL					0x00C4
> +#define REG_CTL_START					0x00B0
> +
> +#define REG_CTL_RAW_INT_EN				0x0100

REG_CTL_RAW_INT_EN is useless. Drop it.

> +#define REG_CTL_RAW_INT_STAT				0x0104
> +#define REG_CTL_RAW_INT2_EN				0x0110

REG_CTL_RAW_INT2_EN is useless. Drop it.

> +#define REG_CTL_RAW_INT2_STAT				0x0114
> +#define REG_CTL_RAW_INT3_STAT				0x0124
> +#define REG_CTL_RAW_INT4_STAT				0x0134
> +#define REG_CTL_RAW_INT5_STAT				0x0144
> +#define REG_CTL_RAW_INT6_EN				0x0150
> +#define REG_CTL_RAW_INT6_STAT				0x0154
> +#define REG_CTL_RAW_INT7_EN				0x0160
> +#define REG_CTL_RAW_INT7_STAT				0x0164
> +
> +#define REG_CTL_RAW_MOD_DCM_DIS				0x0300

REG_CTL_RAW_MOD_DCM_DIS is useless. Drop it.

> +#define REG_CTL_RAW_MOD2_DCM_DIS			0x0304

REG_CTL_RAW_MOD2_DCM_DIS is useless. Drop it.

> +#define REG_CTL_RAW_MOD3_DCM_DIS			0x0308

REG_CTL_RAW_MOD3_DCM_DIS is useless. Drop it.

> +#define REG_CTL_RAW_MOD5_DCM_DIS			0x0310
> +#define REG_CTL_RAW_MOD6_DCM_DIS			0x0314
> +
> +#define REG_CTL_DBG_SET					0x00F0

REG_CTL_DBG_SET is useless. Drop it.

> +#define REG_CTL_DBG_PORT				0x00F4

REG_CTL_DBG_PORT is useless. Drop it.

> +#define REG_DMA_DBG_SEL					0x4070

REG_DMA_DBG_SEL is useless. Drop it.

> +#define REG_DMA_DBG_PORT				0x4074
> +#define REG_CTL_DBG_SET2				0x00F8
> +
> +#define REG_CTL_RAW_MOD_REQ_STAT			0x0340

REG_CTL_RAW_MOD_REQ_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD2_REQ_STAT			0x0344

REG_CTL_RAW_MOD2_REQ_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD3_REQ_STAT			0x0348

REG_CTL_RAW_MOD3_REQ_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD4_REQ_STAT			0x034c

REG_CTL_RAW_MOD4_REQ_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD5_REQ_STAT			0x0350

REG_CTL_RAW_MOD5_REQ_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD6_REQ_STAT			0x0354

REG_CTL_RAW_MOD6_REQ_STAT is useless. Drop it.

> +
> +#define REG_CTL_RAW_MOD_RDY_STAT			0x0360

REG_CTL_RAW_MOD_RDY_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD2_RDY_STAT			0x0364

REG_CTL_RAW_MOD2_RDY_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD3_RDY_STAT			0x0368

REG_CTL_RAW_MOD3_RDY_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD4_RDY_STAT			0x036c

REG_CTL_RAW_MOD4_RDY_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD5_RDY_STAT			0x0370

REG_CTL_RAW_MOD5_RDY_STAT is useless. Drop it.

> +#define REG_CTL_RAW_MOD6_RDY_STAT			0x0374

REG_CTL_RAW_MOD6_RDY_STAT is useless. Drop it.

> +
> +#define REG_CQ_EN					0x0400
> +#define REG_SCQ_START_PERIOD				0x0408
> +#define REG_CQ_THR0_CTL					0x0410
> +#define REG_CQ_SUB_CQ_EN				0x06B0
> +#define REG_CQ_SUB_THR0_CTL				0x06C0
> +

[snip]

> +#define REG_TG_INTER_ST					0x073C
> +/* use this MASK to extract TG_CAM_CS from TG_INTER_ST */
> +#define TG_CAM_CS_MASK					0x3f00
> +#define TG_IDLE_ST					BIT(8)
> +
> +#define REG_TG_FRMSIZE_ST				0x0738

REG_TG_FRMSIZE_ST is useless. Drop it.

> +#define REG_TG_DCIF_CTL					0x075C
> +#define TG_DCIF_EN					BIT(16)
> +
> +#define REG_TG_FRMSIZE_ST_R				0x076C

REG_TG_FRMSIZE_ST_R is useless. Drop it.

> +#define REG_TG_TIME_STAMP				0x0778
> +#define REG_TG_TIME_STAMP_CNT				0x077C
> +
> +/* tg flash */
> +#define	REG_TG_XENON_FLASH_CTL				0x0780
> +#define REG_TG_XENON_FLASH_OFFSET			0x0784
> +#define REG_TG_XENON_FLASH_HIGH_WIDTH			0x0788
> +#define REG_TG_XENON_FLASH_LOW_WIDTH			0x078C
> +#define	REG_TG_IR_FLASH_CTL				0x0798
> +#define REG_TG_IR_FLASH_OFFSET				0x079C
> +#define REG_TG_IR_FLASH_HIGH_WIDTH			0x07A0
> +#define REG_TG_IR_FLASH_LOW_WIDTH			0x07A4
> +
> +/* for raw & yuv's dma top base */
> +#define CAMDMATOP_BASE					0x4000

CAMDMATOP_BASE is useless. Drop it.

Regards,
CK

> +
> +#define REG_DMA_SOFT_RST_STAT				0x4068
> +#define REG_DMA_SOFT_RST_STAT2				0x406C
> +#define REG_DMA_DBG_CHASING_STATUS			0x4098
> +#define REG_DMA_DBG_CHASING_STATUS2			0x409c
> +



^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit
  2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
                     ` (2 preceding siblings ...)
  2025-07-10  7:46   ` CK Hu (胡俊光)
@ 2025-07-24  8:36   ` CK Hu (胡俊光)
  3 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-07-24  8:36 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, MediaTek-specific features, pipeline management, streaming control, and error handling mechanisms. Additionally, it aggregates sub-drivers for the camera interface, raw, and yuv pipelines.
> 
> ---

[snip]

> +int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx,
> +			      unsigned int dequeued_frame_seq_no,
> +			      int pipe_id)
> +{
> +	struct mtk_cam_request *req, *req_prev;
> +	struct mtk_cam_request_stream_data *s_data, *s_data_pipe;
> +	struct mtk_cam_request_stream_data *deq_s_data[RUNNING_JOB_DEPTH];
> +	struct mtk_raw_pipeline *pipe = ctx->pipe;
> +	struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl;
> +	struct mtk_ae_debug_data ae_data;
> +	int buf_state;
> +	u32 dequeue_cnt, s_data_cnt, handled_cnt;
> +	bool del_job, del_req;
> +	bool unreliable = false;
> +	unsigned int done_status_latch;
> +
> +	memset(&ae_data, 0, sizeof(struct mtk_ae_debug_data));
> +	dequeue_cnt = 0;
> +	s_data_cnt = 0;
> +	spin_lock(&ctx->cam->running_job_lock);
> +	list_for_each_entry_safe(req, req_prev, &ctx->cam->running_job_list, list) {
> +		if (!(req->pipe_used & (1 << pipe_id)))
> +			continue;
> +
> +		s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0);
> +		if (!s_data) {
> +			dev_info(ctx->cam->dev,
> +				 "frame_seq:%d[ctx=%d,pipe=%d], de-queue request not found\n",
> +				 dequeued_frame_seq_no, ctx->stream_id, pipe_id);
> +			continue;
> +		}
> +
> +		if (s_data->frame_seq_no > dequeued_frame_seq_no)
> +			goto STOP_SCAN;
> +
> +		deq_s_data[s_data_cnt++] = s_data;
> +		if (s_data_cnt >= RUNNING_JOB_DEPTH) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:%s:ctx(%d):pipe(%d):seq(%d/%d) dequeue s_data over local buffer cnt(%d)\n",
> +				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no, dequeued_frame_seq_no,
> +				 s_data_cnt);
> +			goto STOP_SCAN;
> +		}
> +	}
> +
> +STOP_SCAN:
> +	spin_unlock(&ctx->cam->running_job_lock);
> +
> +	for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) {
> +		s_data = deq_s_data[handled_cnt];
> +		del_req = false;
> +		del_job = false;
> +		req = mtk_cam_s_data_get_req(s_data);
> +		if (!req) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:ctx(%d):pipe(%d):seq(%d) req not found\n",
> +				 __func__, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no);
> +			continue;
> +		}
> +
> +		spin_lock(&req->done_status_lock);
> +
> +		if (req->done_status & 1 << pipe_id) {
> +			/* already handled by another job done work */
> +			spin_unlock(&req->done_status_lock);
> +			continue;
> +		}
> +
> +		/* Check whether all pipelines of single ctx are done */
> +		req->done_status |= 1 << pipe_id;
> +		if ((req->done_status & ctx->streaming_pipe) ==
> +		    (req->pipe_used & ctx->streaming_pipe))
> +			del_job = true;
> +
> +		if ((req->done_status & ctx->cam->streaming_pipe) ==
> +		    (req->pipe_used & ctx->cam->streaming_pipe)) {
> +			if (MTK_CAM_REQ_STATE_RUNNING ==
> +			    atomic_cmpxchg(&req->state,
> +					   MTK_CAM_REQ_STATE_RUNNING,
> +					   MTK_CAM_REQ_STATE_DELETING))
> +				del_req = true;
> +		}
> +		done_status_latch = req->done_status;
> +		spin_unlock(&req->done_status_lock);
> +
> +		if (is_raw_subdev(pipe_id) && debug_ae) {
> +			mtk_cam_raw_dump_aa_info(ctx, &ae_data);
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d),metaout,size(%u,%u),AA(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)\n",
> +				__func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				dequeued_frame_seq_no, s_data->frame_seq_no,
> +				done_status_latch, req->pipe_used,
> +				ctx->streaming_pipe, ctx->cam->streaming_pipe,
> +				del_job, del_req,
> +				pipe->res_config.sink_fmt.width,
> +				pipe->res_config.sink_fmt.height,
> +				ae_data.obc_r1_sum[0], ae_data.obc_r1_sum[1],
> +				ae_data.obc_r1_sum[2], ae_data.obc_r1_sum[3],
> +				ae_data.obc_r2_sum[0], ae_data.obc_r2_sum[1],
> +				ae_data.obc_r2_sum[2], ae_data.obc_r2_sum[3],
> +				ae_data.obc_r3_sum[0], ae_data.obc_r3_sum[1],
> +				ae_data.obc_r3_sum[2], ae_data.obc_r3_sum[3],
> +				ae_data.aa_sum[0], ae_data.aa_sum[1],
> +				ae_data.aa_sum[2], ae_data.aa_sum[3],
> +				ae_data.ltm_sum[0], ae_data.ltm_sum[1],
> +				ae_data.ltm_sum[2], ae_data.ltm_sum[3]);

Add comment to describe what these information is and how to use these information to debug.

> +		} else {
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d)\n",
> +				dequeued_frame_seq_no, s_data->frame_seq_no,
> +				done_status_latch, req->pipe_used,
> +				ctx->streaming_pipe, ctx->cam->streaming_pipe,
> +				del_job, del_req);
> +		}
> +
> +		if (is_raw_subdev(pipe_id)) {
> +			mtk_cam_get_timestamp(ctx, s_data);
> +			mtk_cam_req_works_clean(s_data);
> +		}
> +
> +		if (del_job) {
> +			atomic_dec(&ctx->running_s_data_cnt);
> +			mtk_camsys_state_delete(ctx, sensor_ctrl, req);
> +
> +			/* release internal buffers */
> +			finish_cq_buf(s_data);
> +		}
> +
> +		if (del_req) {
> +			mtk_cam_del_req_from_running(ctx, req, pipe_id);
> +			dequeue_cnt++;
> +		}
> +
> +		/* release vb2 buffers of the pipe */
> +		s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0);
> +		if (!s_data_pipe) {
> +			dev_info(ctx->cam->dev,
> +				 "%s:%s:ctx(%d):pipe(%d):seq(%d) s_data_pipe not found\n",
> +				 __func__, req->req.debug_str, ctx->stream_id, pipe_id,
> +				 s_data->frame_seq_no);
> +			continue;
> +		}
> +
> +		if (s_data->frame_seq_no < dequeued_frame_seq_no) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, time:%lld drop, ctx:%d\n",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no, s_data->timestamp,
> +				ctx->stream_id);
> +		} else if (s_data->state.estate == E_STATE_DONE_MISMATCH) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, state done mismatch",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		} else if (unreliable) {
> +			buf_state = VB2_BUF_STATE_ERROR;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, done (unreliable)",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		} else {
> +			buf_state = VB2_BUF_STATE_DONE;
> +			dev_dbg(ctx->cam->dev,
> +				"%s:%s:pipe(%d) seq:%d, done success",
> +				__func__, req->req.debug_str, pipe_id,
> +				s_data->frame_seq_no);
> +		}
> +
> +		if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) {
> +			/* handle vb2_buffer_done */
> +			if (mtk_cam_req_put(req, pipe_id))
> +				dev_dbg(ctx->cam->dev,
> +					"%s:%s:pipe(%d) return request",
> +					__func__, req->req.debug_str, pipe_id);
> +		}
> +	}
> +
> +	return dequeue_cnt;
> +}
> +

[snip]

> +
> +void isp_composer_destroy_session(struct mtk_cam_ctx *ctx)

Only error case would call isp_composer_destroy_session().
In normal stop flow, it does not call isp_composer_destroy_session().
This would result in hang up in mtk_cam_stop_ctx().
It would wait compeletion but it would never complete because isp_composer_destroy_session() is not called.
Test your driver with stop flow and fix it.

> +{
> +	struct mtk_cam_device *cam = ctx->cam;
> +	struct mtkcam_ipi_event event;
> +	struct mtkcam_ipi_session_cookie *session = &event.cookie;
> +
> +	memset(&event, 0, sizeof(event));
> +	event.cmd_id = CAM_CMD_DESTROY_SESSION;
> +	session->session_id = ctx->stream_id;
> +	scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event,
> +		     sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT);
> +	dev_info(cam->dev, "IPI send id: %d\n", event.cmd_id);
> +}
> +

[snip]

> +void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data)

mtk_cam_apply_pending_dev_config() is useless. Drop it.

> +{
> +	struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data;
> +	struct mtk_cam_ctx *ctx;
> +	char *debug_str = mtk_cam_s_data_get_dbg_str(s_data);
> +
> +	s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data);
> +	if (!s_raw_pipe_data)
> +		return;
> +
> +	ctx = mtk_cam_s_data_get_ctx(s_data);
> +	if (!ctx)
> +		return;
> +	ctx->pipe->feature_active = ctx->pipe->user_res.raw_res.feature;
> +	ctx->pipe->enabled_raw = s_raw_pipe_data->enabled_raw;
> +	ctx->used_raw_dev = s_raw_pipe_data->enabled_raw;
> +
> +	dev_info(ctx->cam->dev,
> +		 "%s:%s:pipe(%d):seq(%d):feature_active(0x%llx), ctx->pipe->user_res.raw_res.feature(%lld), enabled_raw(0x%x)\n",
> +		 __func__, debug_str, ctx->stream_id, s_data->frame_seq_no,
> +		 ctx->pipe->feature_active,
> +		 ctx->pipe->user_res.raw_res.feature,
> +		 ctx->pipe->enabled_raw);
> +}
> +

[snip]

> +int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx,
> +				      struct v4l2_subdev *sd,
> +				      int pad_id, int pixel_mode)

static int mtk_cam_call_seninf_set_pixelmode(...

pad_idx is always PAD_SRC_RAW0, so use PAD_SRC_RAW0 to replace pad_id. Drop pad_id.

> +{
> +	int ret;
> +
> +	ret = mtk_cam_seninf_set_pixelmode(sd, pad_id, pixel_mode);

mtk_cam_seninf_set_pixelmode() would always get PAD_SRC_RAW0 as pad_id,
so drop pad_id parameter of mtk_cam_seninf_set_pixelmode().

> +	dev_dbg(ctx->cam->dev,
> +		"%s:ctx(%d): seninf(%s): pad(%d), pixel_mode(%d)\n, ret(%d)",
> +		__func__, ctx->stream_id, sd->name, pad_id, pixel_mode,
> +		ret);
> +
> +	return ret;
> +}
> +
> +int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node)
> +{
> +	struct mtk_cam_device *cam = ctx->cam;
> +	struct device *dev;
> +	struct mtk_raw_device *raw_dev;
> +	int i, ret;
> +	int tgo_pxl_mode;
> +	unsigned int streaming_ctx_latch;
> +
> +	dev_dbg(cam->dev, "ctx %d stream on, streaming_pipe:0x%x\n",
> +		ctx->stream_id, ctx->streaming_pipe);
> +
> +	if (ctx->streaming) {
> +		dev_dbg(cam->dev, "ctx-%d is already streaming on\n", ctx->stream_id);
> +		return 0;
> +	}
> +
> +	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) {
> +		ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 1);
> +		if (ret) {
> +			dev_info(cam->dev, "failed to stream on %s: %d\n",
> +				 ctx->pipe_subdevs[i]->name, ret);
> +			goto fail_pipe_off;
> +		}
> +	}
> +
> +	if (ctx->used_raw_num) {
> +		tgo_pxl_mode = ctx->pipe->res_config.tgo_pxl_mode;
> +
> +		ret = mtk_cam_dev_config(ctx);
> +		if (ret)
> +			goto fail_pipe_off;
> +		dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev);
> +		if (!dev) {
> +			dev_info(cam->dev, "streamon raw device not found\n");
> +			goto fail_pipe_off;
> +		}
> +		raw_dev = dev_get_drvdata(dev);
> +
> +		mtk_cam_call_seninf_set_pixelmode(ctx, ctx->seninf,
> +							PAD_SRC_RAW0,
> +							tgo_pxl_mode);
> +		mtk_cam_seninf_set_camtg(ctx->seninf, PAD_SRC_RAW0,
> +						pipeid_to_tgidx(raw_dev->id));

mtk_cam_seninf_set_camtg() parameter pad_id is always PAD_SRC_RAW0,
so use PAD_SRC_RAW0 to replace pad_id and drop pad_id parameter.

> +	}
> +
> +
> +	ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 1);
> +	if (ret) {
> +		dev_info(cam->dev, "failed to stream on seninf %s:%d\n",
> +				ctx->seninf->name, ret);
> +		goto fail_pipe_off;
> +	}
> +
> +	if (ctx->used_raw_num) {
> +		mtk_cam_raw_initialize(raw_dev, 0);
> +		/* Twin */
> +		if (ctx->pipe->res_config.raw_num_used != 1) {
> +			struct mtk_raw_device *raw_dev_sub =
> +			get_sub_raw_dev(cam, ctx->pipe);
> +			mtk_cam_raw_initialize(raw_dev_sub, 1);
> +			if (ctx->pipe->res_config.raw_num_used == 3) {
> +				struct mtk_raw_device *raw_dev_sub2 =
> +					get_sub2_raw_dev(cam, ctx->pipe);
> +				mtk_cam_raw_initialize(raw_dev_sub2, 1);
> +			}
> +		}
> +	}
> +
> +	spin_lock(&ctx->streaming_lock);
> +
> +	streaming_ctx_latch = cam->streaming_ctx;
> +	ctx->streaming = true;
> +	cam->streaming_ctx |= 1 << ctx->stream_id;
> +	spin_unlock(&ctx->streaming_lock);
> +
> +	ret = mtk_camsys_ctrl_start(ctx);
> +	if (ret)
> +		goto fail_streaming_off;
> +
> +	mutex_lock(&cam->queue_lock);
> +	mtk_cam_dev_req_try_queue(cam);  /* request moved into working list */
> +	mutex_unlock(&cam->queue_lock);
> +	if (watchdog_scenario(ctx))
> +		mtk_ctx_watchdog_start(ctx, 4);
> +
> +	dev_dbg(cam->dev, "streamed on camsys ctx:%d\n", ctx->stream_id);
> +
> +	return 0;
> +
> +fail_streaming_off:
> +	spin_lock(&ctx->streaming_lock);
> +	ctx->streaming = false;
> +	cam->streaming_ctx &= ~(1 << ctx->stream_id);
> +	spin_unlock(&ctx->streaming_lock);
> +	v4l2_subdev_call(ctx->seninf, video, s_stream, 0);
> +fail_pipe_off:
> +	for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++)
> +		v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0);
> +
> +	return ret;
> +}
> +

[snip]

> +static int mtk_cam_master_bound(struct v4l2_async_notifier *notifier,
> +				struct v4l2_subdev *subdev,
> +				struct v4l2_async_connection *asc)
> +{
> +	struct mtk_cam_device *cam_dev =
> +		container_of(notifier, struct mtk_cam_device, notifier);
> +	struct mtk_raw *raw = &cam_dev->raw;
> +	struct device *cam = cam_dev->dev;
> +	struct device *dev = subdev->dev;
> +
> +	dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__);
> +
> +	if (strcmp(dev_driver_string(dev), "seninf") == 0) {
> +		dev_dbg(cam, "%s@(seninf) done\n", __func__);
> +	} else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) {
> +		struct mtk_raw_device *raw_dev = dev_get_drvdata(dev);
> +
> +		raw_dev->cam = cam_dev;
> +		raw->devs[raw_dev->id] = dev;

raw_dev->id is never set, so raw_dev->id is always 0.
Does this driver support only one raw?
If this driver support only one raw, remove all code related to multiple raw.
One example is changing raw->devs[] to raw->dev, and

raw->dev = dev;

And pipeline number is equal to the raw number.
If raw number is one, imply there is only one pipeline.
If only one pipeline, it's not necessary to have pipe id to identify pipeline.

> +		raw->cam_dev = cam_dev->dev;
> +		dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__);
> +	} else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) {
> +		struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev);
> +
> +		raw->yuvs[yuv_dev->id] = dev;

yuv_dev->id is never set, so yuv_dev->id is always 0.
Does this driver support only one yuv?
If this driver support only one yuv, remove all code related to multiple yuv.
One example is changing raw->yuvs[] to raw->yuv, and

raw->yuv = dev;

> +		dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__);
> +	} else {
> +		dev_warn(cam, "%s got unrecongized device\n", __func__);
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +#define SENSOR_FMT_MASK			0xFFFF
> +
> +/* flags of mtk_cam_request */
> +#define MTK_CAM_REQ_FLAG_SENINF_IMMEDIATE_UPDATE	BIT(1)
> +
> +/* flags of mtk_cam_request_stream_data */
> +#define MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH		BIT(0)

MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH is useless. Drop it.

> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT	BIT(1)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE		BIT(2)
> +
> +/* Apply sensor mode and the timing is 1 vsync before */
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1	BIT(3)

MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1 is useless. Drop it.

> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN		BIT(4)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN		BIT(5)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE	BIT(6)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE	BIT(7)
> +
> +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED	BIT(8)

MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED is useless. Drop it.

> +
> +struct mtk_cam_working_buf {
> +	void *va;
> +	dma_addr_t iova;
> +	dma_addr_t scp_addr;
> +	unsigned int size;
> +};
> +

[snip]

> 
> +
> +struct mtk_cam_req_feature {
> +	int raw_feature;

raw_feature is useless. Drop it.

> +	bool switch_prev_frame_done;

switch_prev_frame_done is useless. Drop it.

> +	bool switch_curr_setting_done;

switch_curr_setting_done is useless. Drop it.

> +	bool switch_done;

switch_done is useless. Drop it.

> +};
> +
> +struct mtk_cam_sensor_work {
> +	struct kthread_work work;
> +	atomic_t is_queued;
> +};
> +
> +/*
> + * struct mtk_cam_request_stream_data - per stream members of a request
> + *
> + * @pad_fmt: pad format configurtion for sensor switch.
> + * @frame_params: The frame info. & address info. of enabled DMA nodes.
> + * @frame_work: work queue entry for frame transmission to SCP.
> + * @working_buf: command queue buffer associated to this request
> + * @deque_list_node: the entry node of s_data for deque
> + * @cleanup_list_node: the entry node of s_data for cleanup
> + *
> + */
> +struct mtk_cam_request_stream_data {
> +	u32 index;
> +	struct mtk_cam_request *req;
> +	struct mtk_cam_ctx *ctx;
> +	u32 pipe_id;
> +	u32 frame_seq_no;
> +	u32 flags;
> +	unsigned long raw_dmas;

raw_dmas is useless. Drop it.

> +	u64 timestamp;
> +	u64 timestamp_mono;
> +	atomic_t buf_state; /* default: -1 */
> +	struct mtk_cam_buffer *bufs[MTK_RAW_TOTAL_NODES];
> +	struct v4l2_subdev *sensor;
> +	struct media_request_object *sensor_hdl_obj;  /* for complete only */
> +	struct media_request_object *raw_hdl_obj;  /* for complete only */
> +	struct v4l2_subdev_format seninf_fmt;
> +	struct v4l2_subdev_format pad_fmt[MTK_RAW_PIPELINE_PADS_NUM];
> +	struct v4l2_rect pad_selection[MTK_RAW_PIPELINE_PADS_NUM];
> +	struct v4l2_format vdev_fmt[MTK_RAW_TOTAL_NODES];
> +	struct v4l2_selection vdev_selection[MTK_RAW_TOTAL_NODES];
> +	struct mtkcam_ipi_frame_param frame_params;
> +	struct mtk_cam_sensor_work sensor_work;
> +	struct mtk_cam_req_work seninf_s_fmt_work;

seninf_s_fmt_work is useless. Drop it.

> +	struct mtk_cam_req_work frame_work;

You queue this work from mtk_cam_dev_req_enqueue().
I think the frame work job could be done in mtk_cam_dev_req_enqueue().
So it's not necessary to queue the job to work queue.
Drop frame_work.

> +	struct mtk_cam_req_work meta1_done_work;

You queue this work from irq thread.
I think the meta1 done job could be done in irq thread.
So it's not necessary to queue the job to work queue.
Drop meta1_done_work.

> +	struct mtk_cam_req_work frame_done_work;

You queue this work from irq thread.
I think the frame done job could be done in irq thread.
So it's not necessary to queue the job to work queue.
Drop frame_done_work.

> +	struct mtk_camsys_ctrl_state state;
> +	struct mtk_cam_working_buf_entry *working_buf;
> +	unsigned int no_frame_done_cnt;

no_frame_done_cnt is useless. Drop it.

> +	atomic_t seninf_dump_state;

seninf_dump_state is useless. Drop it.

> +	struct mtk_cam_req_feature feature;

mtk_cam_req_feature is empty. Drop feature.

> +	struct list_head deque_list_node;
> +	struct list_head cleanup_list_node;
> +	atomic_t first_setting_check;
> +};
> +
> +struct mtk_cam_req_pipe {
> +	int s_data_num;

s_data_num is only set in mtk_cam_req_p_data_init().
mtk_cam_req_p_data_init() is only called in mtk_cam_req_get_pipe_used() with s_data_num = 1.
So s_data_num is always 1.
Use 1 to replace s_data_num and drop s_data_num.

> +	int req_seq;

req_seq is useless. Drop it.

> +	struct mtk_cam_request_stream_data s_data[MTK_CAM_REQ_MAX_S_DATA];

After previous drop. struct mtk_cam_req_pipe include only one structure. This is weird.
So drop struct mtk_cam_req_pipe and use struct mtk_cam_request_stream_data directly.

> +};
> +
> +enum mtk_cam_request_state {
> +	MTK_CAM_REQ_STATE_PENDING,
> +	MTK_CAM_REQ_STATE_RUNNING,
> +	MTK_CAM_REQ_STATE_DELETING,
> +	MTK_CAM_REQ_STATE_COMPLETE,
> +	MTK_CAM_REQ_STATE_CLEANUP,
> +	NR_OF_MTK_CAM_REQ_STATE,
> +};
> +

[snip]

> +
> +struct mtk_cam_img_working_buf_pool {

In patch [9/13], I says img working buf related things are useless.
Drop them.

> +	struct mtk_cam_ctx *ctx;
> +	struct dma_buf *working_img_buf_dmabuf;
> +	void *working_img_buf_va;
> +	dma_addr_t working_img_buf_iova;
> +	dma_addr_t working_img_buf_scp_addr;
> +	unsigned int working_img_buf_size;
> +	struct mtk_cam_img_working_buf_entry img_working_buf[CAM_IMG_BUF_NUM];
> +	struct mtk_cam_working_buf_list cam_freeimglist;
> +};
> +

[snip]

> +
> +struct mtk_cam_device {
> +	struct device *dev;
> +
> +	struct platform_device *clks_pdev;
> +	struct v4l2_device v4l2_dev;
> +	struct v4l2_async_notifier notifier;
> +	struct media_device media_dev;
> +	void __iomem *base;
> +
> +	struct mtk_scp *scp;
> +	struct device *smem_dev;
> +	struct rproc *rproc_handle;
> +
> +	unsigned int composer_cnt;
> +
> +	unsigned int num_seninf_devices;

num_seninf_devices is useless. Drop it.

> +	unsigned int num_raw_devices;
> +
> +	/* raw_pipe controller subdev */
> +	struct mtk_raw raw;
> +	struct mutex queue_lock; /* protect queue request */
> +
> +	unsigned int max_stream_num;
> +	unsigned int streaming_ctx;
> +	unsigned int streaming_pipe;
> +	struct mtk_cam_ctx *ctxs;
> +
> +	/* request related */
> +	struct list_head pending_job_list;
> +	spinlock_t pending_job_lock; /* protect pending_job_list */
> +	struct list_head running_job_list;
> +	unsigned int running_job_count;
> +	spinlock_t running_job_lock; /* protect running_job_list */
> +
> +	/* standard v4l2 buffer control */
> +	struct list_head dma_pending;
> +	spinlock_t dma_pending_lock; /* protect dma_pending_list */
> +	struct list_head dma_processing;

If you don't know how to merge all buffer list together,
you may try merge dma_pending and dma_processing first.
The merged name may be dma_buf_list.
And the buffer has a flag 'processing' to indicate it's processing or not.

> +	spinlock_t dma_processing_lock; /* protect dma_processing_list and dma_processing_count */
> +	unsigned int dma_processing_count;
> +
> +	struct workqueue_struct *debug_wq;

debug_wq is useless. Drop it.

> +	struct workqueue_struct *debug_exception_wq;

debug_exception_wq is useless. Drop it.

Regards,
CK

> +};
> +
> +static inline struct mtk_cam_request_stream_data*
> +mtk_cam_ctrl_state_to_req_s_data(struct mtk_camsys_ctrl_state *state)
> +{
> +	return container_of(state, struct mtk_cam_request_stream_data, state);
> +}
> +



^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops
  2025-07-07  1:31 ` [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops shangyao lin
@ 2025-08-01  5:45   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 41+ messages in thread
From: CK Hu (胡俊光) @ 2025-08-01  5:45 UTC (permalink / raw)
  To: robh@kernel.org, mchehab@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, matthias.bgg@gmail.com,
	Shangyao Lin (林上堯),
	AngeloGioacchino Del Regno
  Cc: linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org

On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
> 
> Introduce the V4L2 video interface and feature management for the MediaTek
> ISP7.x CAMSYS. These interfaces provide functionalities such as video operation
> initialization and registration. They also manage MediaTek-specific formats and
> handle buffers for MediaTek camera video devices. This enables CAMSYS
> functionalities to be compatible with the V4L2 framework.
> 
> Changes in v2:
> - Removed mtk_cam-feature.c and mtk_cam-feature.h, along with related code
> - Various fixes per review comments
> 
> Signed-off-by: shangyao.lin <shangyao.lin@mediatek.com>
> ---

[snip]

> +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;

I think all buffer should be no kernel mapping.
Which buffer you would access in kernel?

> +
> +	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;
> +}
> +

[snip]

> +
> +int is_mtk_format(u32 pixelformat)

Use mtk_cam_get_img_fmt() to replace is_mtk_format().
When mtk_cam_get_img_fmt() return MTK_CAM_IPI_IMG_FMT_UNKNOWN, it's not mtk image format.

> +{
> +	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;
> +	}
> +}
> +

[snip]

> +const struct mtk_format_info *mtk_format_info(u32 format)
> +{
> +	static const struct mtk_format_info formats[] = {

Move this array out of this function.

> +		/* YUV planar formats */
> +		{ .format = V4L2_PIX_FMT_NV12_10,
> +			.mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 },

mem_planes is always 1. Use 1 to replace mem_planes. Drop mem_planes.

> +			.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 },

bpp[3] is always 0. So shrink array size of bpp[] to 3.

> +			.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;
> +}
> +

[snip]

> +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);

mtk_cam_fill_pixfmt_mp() is called only by cal_image_pix_mp() and cal_image_pix_mp() already has ipi_fmt.
So pass ipi_fmt as parameter and do not call mtk_cam_get_img_fmt() again.

> +	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)) {

mtk_cam_fill_pixfmt_mp() is called only by cal_image_pix_mp(), so this checking is always true.
Drop this checking.

> +		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) {

mem_planes is always 1. Drop this checking.

> +			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;
> +			} 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;
> +			} 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");
> +		}
> +	}
> +}
> +

[snip]

> +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;

Why do you assign this?
You would calculate bytesperline in cal_image_pix_mp().
And you compare new cal_image_pix_mp and old cal_image_pix_mp to do something,
but I think it's not necessary.
Just calculate new bytesperline in cal_image_pix_mp() and don't care about old 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;
> +}
> +

[snip]

> +/**
> + * 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;

pending_fmt is useless. Drop it.

> +	/* 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;

mem_planes is always 1. Drop it.

Regards,
CK

> +	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 */
> +};
> +


^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2025-08-01  5:45 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-07  1:31 [PATCH v2 00/13] Add MediaTek ISP7.x camera system support shangyao lin
2025-07-07  1:31 ` [PATCH v2 01/13] dt-bindings: media: mediatek: add camisp binding shangyao lin
2025-07-07  2:46   ` Rob Herring (Arm)
2025-07-07  5:42   ` Krzysztof Kozlowski
2025-07-15  8:25   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 02/13] dt-bindings: media: mediatek: add seninf-core binding shangyao lin
2025-07-07  2:46   ` Rob Herring (Arm)
2025-07-07  5:44   ` Krzysztof Kozlowski
2025-07-15  7:28   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 03/13] dt-bindings: media: mediatek: add cam-raw binding shangyao lin
2025-07-07  2:46   ` Rob Herring (Arm)
2025-07-07  5:48   ` Krzysztof Kozlowski
2025-07-15  8:13   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 04/13] dt-bindings: media: mediatek: add cam-yuv binding shangyao lin
2025-07-07  2:46   ` Rob Herring (Arm)
2025-07-07  5:47   ` Krzysztof Kozlowski
2025-07-15  7:41   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 05/13] media: platform: mediatek: add isp_7x seninf unit shangyao lin
2025-07-07  5:50   ` Krzysztof Kozlowski
2025-07-10  6:39   ` CK Hu (胡俊光)
2025-07-16  4:06   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 06/13] media: platform: mediatek: add isp_7x state ctrl shangyao lin
2025-07-11  8:56   ` CK Hu (胡俊光)
2025-07-21  1:40   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 07/13] MEDIA: PLATFORM: MEDIATEK: ADD ISP_7X CAM-RAW UNIT shangyao lin
2025-07-15  4:07   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 08/13] media: platform: mediatek: add isp_7x camsys unit shangyao lin
2025-07-07  5:58   ` Krzysztof Kozlowski
2025-07-10  5:20   ` CK Hu (胡俊光)
2025-07-10  7:46   ` CK Hu (胡俊光)
2025-07-24  8:36   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 09/13] media: platform: mediatek: add isp_7x utility shangyao lin
2025-07-22  2:19   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 10/13] media: platform: mediatek: add isp_7x video ops shangyao lin
2025-08-01  5:45   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 11/13] media: platform: mediatek: add isp_7x build config shangyao lin
2025-07-07  1:31 ` [PATCH v2 12/13] uapi: linux: add mediatek isp_7x camsys user api shangyao lin
2025-07-08  1:34   ` CK Hu (胡俊光)
2025-07-07  1:31 ` [PATCH v2 13/13] media: uapi: mediatek: document ISP7x camera system and user controls shangyao lin
2025-07-11  3:12   ` CK Hu (胡俊光)
2025-07-07  5:55 ` [PATCH v2 00/13] Add MediaTek ISP7.x camera system support Krzysztof Kozlowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).