devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver
@ 2024-11-25  9:21 Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
                   ` (7 more replies)
  0 siblings, 8 replies; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

This series is the Video Input Interface driver
for Toshiba's ARM SoC, Visconti.
This provides DT binding documentation,
device driver, documentation and MAINTAINER files.

A visconti VIIF driver instance exposes
1 media control device file, 3 video device files for capture
and 2 video device files for controlling image signal processor.
Detailed HW/SW are described in documentation directory.
The VIIF hardware has CSI2 receiver,
image signal processor and video DMAC.

The device driver depends on two other drivers under development;
clock framework driver and IOMMU driver.
Corresponding features will be added later.

Best regards,
Yuji

Changelog v2:
- Resend v1 because a patch exceeds size limit.

Changelog v3:
- Add documentation to describe SW and HW
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters

Changelog v4:
- Split patches because a patch exceeds size limit
- fix dt-bindings document
- stop specifying ID numbers for driver instance explicitly at device tree
- use pm_runtime to trigger initialization of HW
  along with open/close of device files.
- add a entry for a header file at MAINTAINERS file

Changelog v5:
- Fix coding style problem in viif.c (patch 2/6)

Changelog v6:
- add register definition of BUS-IF and MPU in dt-bindings
- add CSI2RX subdevice (separated from ISP subdevice)
- change directory layout (moved to media/platform/toshiba/visconti)
- change source file layout (removed hwd_xxxx.c)
- pointer to userland memory is removed from uAPI parameters
- change register access (from struct style to macro style)
- remove unused macros

Changelog v7:
- remove redundant "bindings" from header and description text
- fix multiline text of "description"
- change "compatible" to "visconti5-viif"
- explicitly define allowed properties for port::endpoint
- remove unused variables
- update kerneldoc comments
- update references to headers

Changelog v8:
- rename bindings description file
- remove/simplify items in bindings
- update operations around v4l2_async_notifier
- use v4l2_async_connection instead of v4l2_async_subdev
- use dev_err_probe()
- better error handling at probe
- remove redundant mutex
- add V4L2_CTRL_TYPE_VISCONTI_ISP constant

Changelog v9:
- dictionary ordering of dt-bindings properties
- applied sparse checker
- call div64_u64 for 64bit division
- rebase to media_staging tree
- fix warning for cast between ptr and dma_addr_t

Changelog v10:
- add an independent entry in MAINTAINERS
- add paddings to uAPI structs
- use parameter buffer to control ISP (instead of vendor specific controls)

Changelog v11:
- stop merging sensor's controls and capture device's
- fix strange indents at initializations
- remove feature VB2_USERPTR from viif_params and viif_stats
- fix usage in the document

Changelog v12:
- Separated CSI2RX driver and made it independent driver
- Add a bindings for CSI2RX driver
- Add description of parameter/statistics interface to v4l2-ioctl.c
- use PM_RUNTIME_OPS macro for power management routines
- use v4l2_subdev_enable_streams() to start streaming
- implement callback enable_streams and disable_streams,
  instead of s_stream
- add spinlocks for variables shared among interrupt handlers
- use guard(spinlock)(locked_variable) macros
- call pm_runtime APIs at start/stop streaming,
  instead of file handle callbacks
- add new "resizer" subdevice between ISP and Capture devices.
- update capability of sub path capture: capture only RAW8 or RAW16
- document: add description of CSI2RX driver
- document: add description of resizer subdevice
- document: add block diagrams of VIIF and ISP
- document: update usage of the driver

Yuji Ishikawa (8):
  dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI
    CSI-2 Receiver
  dt-bindings: media: platform: visconti: Add Toshiba Visconti Video
    Input Interface
  media: uapi: add visconti viif meta buffer format
  media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  media: platform: visconti: Add Toshiba Visconti Video Input Interface
    driver
  media: platform: visconti: Add streaming interface for ISP parameters
    and status
  documentation: media: add documentation for Toshiba Visconti Video
    Input Interface driver
  MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface

 .../admin-guide/media/v4l-drivers.rst         |    1 +
 .../admin-guide/media/visconti-viif.dot       |   22 +
 .../admin-guide/media/visconti-viif.rst       |  435 ++++
 .../media/toshiba,visconti5-csi2rx.yaml       |  104 +
 .../media/toshiba,visconti5-viif.yaml         |   95 +
 .../userspace-api/media/v4l/meta-formats.rst  |    1 +
 .../media/v4l/metafmt-visconti-viif.rst       |   48 +
 MAINTAINERS                                   |   12 +
 drivers/media/platform/Kconfig                |    1 +
 drivers/media/platform/Makefile               |    1 +
 drivers/media/platform/toshiba/Kconfig        |    6 +
 drivers/media/platform/toshiba/Makefile       |    2 +
 .../media/platform/toshiba/visconti/Kconfig   |   34 +
 .../media/platform/toshiba/visconti/Makefile  |   10 +
 .../platform/toshiba/visconti/csi2rx_drv.c    |  791 +++++++
 .../media/platform/toshiba/visconti/viif.c    |  598 +++++
 .../media/platform/toshiba/visconti/viif.h    |  379 +++
 .../platform/toshiba/visconti/viif_capture.c  | 1285 +++++++++++
 .../platform/toshiba/visconti/viif_capture.h  |   21 +
 .../platform/toshiba/visconti/viif_common.c   |  239 ++
 .../platform/toshiba/visconti/viif_common.h   |   45 +
 .../platform/toshiba/visconti/viif_isp.c      |  911 ++++++++
 .../platform/toshiba/visconti/viif_isp.h      |   19 +
 .../platform/toshiba/visconti/viif_params.c   | 2034 +++++++++++++++++
 .../platform/toshiba/visconti/viif_params.h   |   24 +
 .../platform/toshiba/visconti/viif_regs.h     |  717 ++++++
 .../platform/toshiba/visconti/viif_resizer.c  |  491 ++++
 .../platform/toshiba/visconti/viif_resizer.h  |   18 +
 .../platform/toshiba/visconti/viif_stats.c    |  301 +++
 .../platform/toshiba/visconti/viif_stats.h    |   14 +
 drivers/media/v4l2-core/v4l2-ioctl.c          |    2 +
 include/uapi/linux/videodev2.h                |    4 +
 include/uapi/linux/visconti_viif.h            | 1921 ++++++++++++++++
 33 files changed, 10586 insertions(+)
 create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
 create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
 create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
 create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
 create mode 100644 Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
 create mode 100644 drivers/media/platform/toshiba/Kconfig
 create mode 100644 drivers/media/platform/toshiba/Makefile
 create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
 create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
 create mode 100644 drivers/media/platform/toshiba/visconti/csi2rx_drv.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_regs.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_resizer.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_resizer.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h
 create mode 100644 include/uapi/linux/visconti_viif.h

-- 
2.25.1



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

* [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2024-11-25 10:11   ` Krzysztof Kozlowski
  2025-01-02  9:29   ` Laurent Pinchart
  2024-11-25  9:21 ` [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Adds the Device Tree binding documentation that allows to describe
the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
---

Changelog v12:
- Newly add bindings for CSI2RX driver 

 .../media/toshiba,visconti5-csi2rx.yaml       | 104 ++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml

diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
new file mode 100644
index 000000000000..5488072bc82a
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
+
+maintainers:
+  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+
+description: |-
+  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI CSI-2 video
+  stream. Use with VIIF device. T.B.D
+
+properties:
+  compatible:
+    const: toshiba,visconti5-csi2rx
+
+  reg:
+    items:
+      - description: Registers for CSI2 receiver control
+
+  interrupts:
+    items:
+      - description: CSI2 Receiver Interrupt
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description:
+          Input port node, single endpoint describing the CSI-2 transmitter.
+
+        properties:
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes:
+                description: CSI2 receiver supports 1, 2, 3 or 4 data lanes
+                minItems: 1
+                items:
+                  - const: 1
+                  - const: 2
+                  - const: 3
+                  - const: 4
+            required:
+              - data-lanes
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Output port node, single endpoint describing the Visconti VIIF.
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        csi2rx@1c008000 {
+            compatible = "toshiba,visconti5-csi2rx";
+            reg = <0 0x1c008000 0 0x400>;
+            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                port@0 {
+                    reg = <0>;
+                    csi2rx_in0: endpoint {
+                        data-lanes = <1 2>;
+                        remote-endpoint = <&imx219_out0>;
+                    };
+                };
+                port@1 {
+                    reg = <1>;
+                    csi2rx_out0: endpoint {
+                        remote-endpoint = <&csi_in0>;
+                    };
+                };
+            };
+        };
+    };
-- 
2.25.1



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

* [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2024-11-25 10:07   ` Krzysztof Kozlowski
  2025-01-02  9:56   ` Laurent Pinchart
  2024-11-25  9:21 ` [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format Yuji Ishikawa
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Adds the Device Tree binding documentation that allows to describe
the Video Input Interface found in Toshiba Visconti SoCs.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
---
Changelog v2:
- no change

Changelog v3:
- no change

Changelog v4:
- fix style problems at the v3 patch
- remove "index" member
- update example

Changelog v5:
- no change

Changelog v6:
- add register definition of BUS-IF and MPU

Changelog v7:
- remove trailing "bindings" from commit header message
- remove trailing "Device Tree Bindings" from title
- fix text wrapping of description
- change compatible to visconti5-viif
- explicitly define allowed properties for port::endpoint

Changelog v8:
- Suggestion from Krzysztof Kozlowski
  - rename bindings description file
  - use block style array instead of inline style
  - remove clock-lane (as it is fixed at position 0)
  - update sample node's name
  - use lowercase hex for literals
- Suggestion from Laurent Pinchart
  - update description message port::description
  - remove port::endpoint::bus-type as it is fixed to <4>
  - remove port::endpoint::clock-lanes from example
  - add port::endpoint::data-lanes to required parameters list
  - fix sequence of data-lanes: <1 2 3 4> because current driver does not support data reordering
  - update port::endpoint::data-lanes::description
  - remove redundant type definition for port::endpoint::data-lanes

Changelog v9:
- place "required" after "properties"
- dictionary ordering of properties

Changelog v10:
- no change

Changelog v11:
- no change

Changelog v12:
- remove property "clock-noncontinuous" as VIIF switches both modes automatically
- remove property "link-frequencies" as VIIF does not use the information
- remove reg[2] and interrupts[3] which are used for CSI2RX driver
- update example to refer csi2rx for remote-endpoint

 .../media/toshiba,visconti5-viif.yaml         | 95 +++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml

diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
new file mode 100644
index 000000000000..ef0452a47e98
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/toshiba,visconti5-viif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba Visconti5 SoC Video Input Interface
+
+maintainers:
+  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+
+description: |-
+  Toshiba Visconti5 SoC Video Input Interface (VIIF) receives videostream
+  from MIPI CSI-2 receiver device, processes the stream with image signal
+  processors (L1ISP, L2ISP), then stores pictures to main memory.
+
+properties:
+  compatible:
+    const: toshiba,visconti5-viif
+
+  reg:
+    items:
+      - description: Registers for capture control
+      - description: Registers for bus interface unit control
+      - description: Registers for Memory Protection Unit
+
+  interrupts:
+    items:
+      - description: Sync Interrupt
+      - description: Status (Error) Interrupt
+      - description: L1ISP Interrupt
+
+  port:
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    unevaluatedProperties: false
+    description: CSI-2 input port, with a single endpoint connected to the CSI-2 transmitter.
+
+    properties:
+      endpoint:
+        $ref: video-interfaces.yaml#
+        additionalProperties: false
+
+        properties:
+          data-lanes:
+            description: VIIF supports 1, 2, 3 or 4 data lanes
+            minItems: 1
+            items:
+              - const: 1
+              - const: 2
+              - const: 3
+              - const: 4
+
+          remote-endpoint: true
+
+        required:
+          - data-lanes
+          - remote-endpoint
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        video@1c000000 {
+            compatible = "toshiba,visconti5-viif";
+            reg = <0 0x1c000000 0 0x6000>,
+                  <0 0x1c00e000 0 0x1000>,
+                  <0 0x2417a000 0 0x1000>;
+            interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+
+            port {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                csi_in0: endpoint {
+                    data-lanes = <1 2>;
+                    remote-endpoint = <&csi2rx_out0>;
+                };
+            };
+        };
+    };
-- 
2.25.1



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

* [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2025-01-02 13:10   ` Laurent Pinchart
  2024-11-25  9:21 ` [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Adds the Toshiba Visconti VIIF specific metadata format

- V4L2_META_FMT_VISCONTI_VIIF_PARAMS for ISP parameters
- V4L2_META_FMT_VISCONTI_VIIF_STATS for ISP statistics

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
---
Changelog v10:
- add entry for V4L2_META_FMT_VISCONTI_VIIF_PARAMS
- add entry for V4L2_META_FMT_VISCONTI_VIIF_STATS

Changelog v11:
- no change

Changelog v12:
- add description for meta formats at v4l2-ioctl.c

 drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
 include/uapi/linux/videodev2.h       | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 0304daa8471d..f7facb63b8ea 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1470,6 +1470,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 	case V4L2_META_FMT_RPI_BE_CFG:	descr = "RPi PiSP BE Config format"; break;
 	case V4L2_META_FMT_RPI_FE_CFG:  descr = "RPi PiSP FE Config format"; break;
 	case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics format"; break;
+	case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti ISP Parameters"; break;
+	case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP Statistics"; break;
 	case V4L2_META_FMT_GENERIC_8:	descr = "8-bit Generic Metadata"; break;
 	case V4L2_META_FMT_GENERIC_CSI2_10:	descr = "8-bit Generic Meta, 10b CSI-2"; break;
 	case V4L2_META_FMT_GENERIC_CSI2_12:	descr = "8-bit Generic Meta, 12b CSI-2"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index a5418759e2ba..9e1f66fdf038 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -863,6 +863,10 @@ struct v4l2_pix_format {
 #define V4L2_META_FMT_RPI_FE_CFG	v4l2_fourcc('R', 'P', 'F', 'C') /* PiSP FE configuration */
 #define V4L2_META_FMT_RPI_FE_STATS	v4l2_fourcc('R', 'P', 'F', 'S') /* PiSP FE stats */
 
+/* Vendor specific - used for Visconti VIIF sub-system */
+#define V4L2_META_FMT_VISCONTI_VIIF_PARAMS	v4l2_fourcc('V', 'I', 'F', 'P') /* ISP Params */
+#define V4L2_META_FMT_VISCONTI_VIIF_STATS	v4l2_fourcc('V', 'I', 'F', 'S') /* ISP Stats */
+
 #ifdef __KERNEL__
 /*
  * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when
-- 
2.25.1



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

* [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (2 preceding siblings ...)
  2024-11-25  9:21 ` [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2025-01-02 13:08   ` Laurent Pinchart
  2024-11-25  9:21 ` [PATCH v12 5/8] media: platform: visconti: Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Add support to MIPI CSI-2 Receiver on Toshiba Visconti ARM SoCs.
This driver is used with Visconti Video Input Interface driver.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
---
Changelog v12:
- Separate CSI2RX driver and made it independent driver
- viif_csi2rx subdevice driver (in v11 patch) was removed.
- dictionary order at Kconfig and Makefile

 drivers/media/platform/Kconfig                |   1 +
 drivers/media/platform/Makefile               |   1 +
 drivers/media/platform/toshiba/Kconfig        |   6 +
 drivers/media/platform/toshiba/Makefile       |   2 +
 .../media/platform/toshiba/visconti/Kconfig   |  16 +
 .../media/platform/toshiba/visconti/Makefile  |   8 +
 .../platform/toshiba/visconti/csi2rx_drv.c    | 791 ++++++++++++++++++
 7 files changed, 825 insertions(+)
 create mode 100644 drivers/media/platform/toshiba/Kconfig
 create mode 100644 drivers/media/platform/toshiba/Makefile
 create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
 create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
 create mode 100644 drivers/media/platform/toshiba/visconti/csi2rx_drv.c

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 85d2627776b6..761b15b07b90 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -86,6 +86,7 @@ source "drivers/media/platform/samsung/Kconfig"
 source "drivers/media/platform/st/Kconfig"
 source "drivers/media/platform/sunxi/Kconfig"
 source "drivers/media/platform/ti/Kconfig"
+source "drivers/media/platform/toshiba/Kconfig"
 source "drivers/media/platform/verisilicon/Kconfig"
 source "drivers/media/platform/via/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index ace4e34483dd..917145fe5171 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -29,6 +29,7 @@ obj-y += samsung/
 obj-y += st/
 obj-y += sunxi/
 obj-y += ti/
+obj-y += toshiba/
 obj-y += verisilicon/
 obj-y += via/
 obj-y += xilinx/
diff --git a/drivers/media/platform/toshiba/Kconfig b/drivers/media/platform/toshiba/Kconfig
new file mode 100644
index 000000000000..f02983f4fc97
--- /dev/null
+++ b/drivers/media/platform/toshiba/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Toshiba media platform drivers"
+
+source "drivers/media/platform/toshiba/visconti/Kconfig"
+
diff --git a/drivers/media/platform/toshiba/Makefile b/drivers/media/platform/toshiba/Makefile
new file mode 100644
index 000000000000..2bce85ef3b48
--- /dev/null
+++ b/drivers/media/platform/toshiba/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += visconti/
diff --git a/drivers/media/platform/toshiba/visconti/Kconfig b/drivers/media/platform/toshiba/visconti/Kconfig
new file mode 100644
index 000000000000..e5c92d598f8b
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_VISCONTI_CSI2RX
+	tristate "Visconti MIPI CSI-2 Receiver driver"
+	depends on V4L_PLATFORM_DRIVERS
+	depends on VIDEO_DEV && OF
+	depends on ARCH_VISCONTI || COMPILE_TEST
+	select MEDIA_CONTROLLER
+	select VIDEO_V4L2_SUBDEV_API
+	select V4L2_FWNODE
+	help
+	  Support for Toshiba Visconti MIPI CSI-2 receiver,
+	  which is used with Visconti Camera Interface driver.
+
+	  This driver yields 1 subdevice node for a hardware instance.
+	  To compile this driver as a module, choose M here: the
+	  module will be called visconti-csi2rx.
diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
new file mode 100644
index 000000000000..62a029376134
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Visconti video input device driver
+#
+
+visconti-csi2rx-objs = csi2rx_drv.o
+
+obj-$(CONFIG_VIDEO_VISCONTI_CSI2RX) += visconti-csi2rx.o
diff --git a/drivers/media/platform/toshiba/visconti/csi2rx_drv.c b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
new file mode 100644
index 000000000000..94567963872a
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
@@ -0,0 +1,791 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+/* CSI2HOST register space */
+#define REG_CSI2RX_NLANES	 0x4
+#define REG_CSI2RX_RESETN	 0x8
+#define REG_CSI2RX_INT_ST_MAIN	 0xc
+#define REG_CSI2RX_DATA_IDS_1	 0x10
+#define REG_CSI2RX_DATA_IDS_2	 0x14
+#define REG_CSI2RX_PHY_SHUTDOWNZ 0x40
+#define REG_CSI2RX_PHY_RSTZ	 0x44
+
+/* access to dphy external registers */
+#define REG_CSI2RX_PHY_TESTCTRL0 0x50
+#define BIT_TESTCTRL0_CLK_0	 0
+#define BIT_TESTCTRL0_CLK_1	 BIT(1)
+
+#define REG_CSI2RX_PHY_TESTCTRL1 0x54
+#define BIT_TESTCTRL1_ADDR	 BIT(16)
+#define MASK_TESTCTRL1_DIN	 0xff
+#define MASK_TESTCTRL1_DOUT	 0xff00
+
+#define REG_CSI2RX_INT_ST_PHY_FATAL  0xe0
+#define REG_CSI2RX_INT_MSK_PHY_FATAL 0xe4
+#define MASK_PHY_FATAL_ALL	     0x0000000f
+
+#define REG_CSI2RX_INT_ST_PKT_FATAL  0xf0
+#define REG_CSI2RX_INT_MSK_PKT_FATAL 0xf4
+#define MASK_PKT_FATAL_ALL	     0x0001000f
+
+#define REG_CSI2RX_INT_ST_FRAME_FATAL  0x100
+#define REG_CSI2RX_INT_MSK_FRAME_FATAL 0x104
+#define MASK_FRAME_FATAL_ALL	       0x000f0f0f
+
+#define REG_CSI2RX_INT_ST_PHY  0x110
+#define REG_CSI2RX_INT_MSK_PHY 0x114
+#define MASK_PHY_ERROR_ALL     0x000f000f
+
+#define REG_CSI2RX_INT_ST_PKT  0x120
+#define REG_CSI2RX_INT_MSK_PKT 0x124
+#define MASK_PKT_ERROR_ALL     0x000f000f
+
+#define REG_CSI2RX_INT_ST_LINE	0x130
+#define REG_CSI2RX_INT_MSK_LINE 0x134
+#define MASK_LINE_ERROR_ALL	0x00ff00ff
+
+/* DPHY register space */
+enum dphy_testcode {
+	DIG_TESTCODE_EXT = 0,
+	DIG_SYS_0 = 0x001,
+	DIG_SYS_1 = 0x002,
+	DIG_SYS_3 = 0x004,
+	DIG_SYS_7 = 0x008,
+	DIG_RX_STARTUP_OVR_2 = 0x0e2,
+	DIG_RX_STARTUP_OVR_3 = 0x0e3,
+	DIG_RX_STARTUP_OVR_4 = 0x0e4,
+	DIG_RX_STARTUP_OVR_5 = 0x0e5,
+	DIG_CB_2 = 0x1ac,
+	DIG_TERM_CAL_0 = 0x220,
+	DIG_TERM_CAL_1 = 0x221,
+	DIG_TERM_CAL_2 = 0x222,
+	DIG_CLKLANE_LANE_6 = 0x307,
+	DIG_CLKLANE_OFFSET_CAL_0 = 0x39d,
+	DIG_LANE0_OFFSET_CAL_0 = 0x59f,
+	DIG_LANE0_DDL_0 = 0x5e0,
+	DIG_LANE1_OFFSET_CAL_0 = 0x79f,
+	DIG_LANE1_DDL_0 = 0x7e0,
+	DIG_LANE2_OFFSET_CAL_0 = 0x99f,
+	DIG_LANE2_DDL_0 = 0x9e0,
+	DIG_LANE3_OFFSET_CAL_0 = 0xb9f,
+	DIG_LANE3_DDL_0 = 0xbe0,
+};
+
+#define SYS_0_HSFREQRANGE_OVR  BIT(5)
+#define SYS_3_NO_REXT	       BIT(4)
+#define SYS_7_RESERVED	       FIELD_PREP(0x1f, 0x0c)
+#define SYS_7_DESKEW_POL       BIT(5)
+#define STARTUP_OVR_4_CNTVAL   FIELD_PREP(0x70, 0x01)
+#define STARTUP_OVR_4_DDL_EN   BIT(0)
+#define STARTUP_OVR_5_BYPASS   BIT(0)
+#define CB_2_LPRX_BIAS	       BIT(6)
+#define CB_2_RESERVED	       FIELD_PREP(0x3f, 0x0b)
+#define CLKLANE_RXHS_PULL_LONG BIT(7)
+
+/* bit mask for calibration result registers */
+#define MASK_TERM_CAL_ERR  0
+#define MASK_TERM_CAL_DONE BIT(7)
+#define MASK_CLK_CAL_ERR   BIT(4)
+#define MASK_CLK_CAL_DONE  BIT(0)
+#define MASK_CAL_ERR	   BIT(2)
+#define MASK_CAL_DONE	   BIT(1)
+#define MASK_DDL_ERR	   BIT(1)
+#define MASK_DDL_DONE	   BIT(2)
+
+#define VISCONTI_CSI2RX_ERROR_MONITORS_NUM 8
+
+/**
+ * struct visconti_csi2rx_line_err_target
+ *
+ * Virtual Channel and Data Type pair for CSI2RX line error monitor
+ *
+ * When 0 is set to dt, line error detection is disabled.
+ *
+ * @vc: Virtual Channel to monitor; Range 0..3
+ * @dt: Data Type to monitor; Range 0, 0x10..0x3f
+ */
+struct visconti_csi2rx_line_err_target {
+	u32 vc[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
+	u32 dt[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
+};
+
+#define CSI2RX_MIN_DATA_RATE 80U
+#define CSI2RX_MAX_DATA_RATE 1500U
+
+#define VISCONTI_CSI2RX_PAD_SINK 0
+#define VISCONTI_CSI2RX_PAD_SRC	 1
+#define VISCONTI_CSI2RX_PAD_NUM	 2
+
+#define VISCONTI_CSI2RX_DEF_WIDTH  1920
+#define VISCONTI_CSI2RX_DEF_HEIGHT 1080
+#define VISCONTI_CSI2RX_MIN_WIDTH  640
+#define VISCONTI_CSI2RX_MAX_WIDTH  3840
+#define VISCONTI_CSI2RX_MIN_HEIGHT 480
+#define VISCONTI_CSI2RX_MAX_HEIGHT 2160
+
+struct visconti_csi2rx {
+	struct device *dev;
+	void __iomem *base;
+
+	struct v4l2_subdev subdev;
+	struct media_pad pads[VISCONTI_CSI2RX_PAD_NUM];
+	struct v4l2_async_notifier notifier;
+	struct v4l2_subdev *remote;
+	unsigned int remote_pad;
+
+	unsigned int lanes;
+
+	unsigned int irq;
+};
+
+static inline struct visconti_csi2rx *notifier_to_csi2(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct visconti_csi2rx, notifier);
+}
+
+static inline struct visconti_csi2rx *sd_to_csi2(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct visconti_csi2rx, subdev);
+}
+
+static inline void visconti_csi2rx_write(struct visconti_csi2rx *priv, u32 regid, u32 val)
+{
+	writel(val, priv->base + regid);
+}
+
+static inline u32 visconti_csi2rx_read(struct visconti_csi2rx *priv, u32 regid)
+{
+	return readl(priv->base + regid);
+}
+
+static inline void tick_testclk(struct visconti_csi2rx *priv)
+{
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
+}
+
+static inline void set_dphy_addr(struct visconti_csi2rx *priv, u32 test_mode)
+{
+	/* select testcode Ex space with top 4bits of test_mode */
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
+			      BIT_TESTCTRL1_ADDR | DIG_TESTCODE_EXT);
+	tick_testclk(priv);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, FIELD_GET(0xf00, test_mode));
+	tick_testclk(priv);
+
+	/* set bottom 8bit of test_mode */
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
+			      BIT_TESTCTRL1_ADDR | FIELD_GET(0xff, test_mode));
+	tick_testclk(priv);
+}
+
+static void write_dphy_param(struct visconti_csi2rx *priv, u32 test_mode, u8 test_in)
+{
+	set_dphy_addr(priv, test_mode);
+
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, (u32)test_in);
+	tick_testclk(priv);
+}
+
+struct csi2rx_dphy_hs_info {
+	u32 rate;
+	u32 hsfreqrange;
+	u32 osc_freq_target;
+};
+
+static const struct csi2rx_dphy_hs_info dphy_hs_info[] = {
+	{ 80, 0x0, 0x1cc },   { 85, 0x10, 0x1cc },   { 95, 0x20, 0x1cc },   { 105, 0x30, 0x1cc },
+	{ 115, 0x1, 0x1cc },  { 125, 0x11, 0x1cc },  { 135, 0x21, 0x1cc },  { 145, 0x31, 0x1cc },
+	{ 155, 0x2, 0x1cc },  { 165, 0x12, 0x1cc },  { 175, 0x22, 0x1cc },  { 185, 0x32, 0x1cc },
+	{ 198, 0x3, 0x1cc },  { 213, 0x13, 0x1cc },  { 228, 0x23, 0x1cc },  { 243, 0x33, 0x1cc },
+	{ 263, 0x4, 0x1cc },  { 288, 0x14, 0x1cc },  { 313, 0x25, 0x1cc },  { 338, 0x35, 0x1cc },
+	{ 375, 0x5, 0x1cc },  { 425, 0x16, 0x1cc },  { 475, 0x26, 0x1cc },  { 525, 0x37, 0x1cc },
+	{ 575, 0x7, 0x1cc },  { 625, 0x18, 0x1cc },  { 675, 0x28, 0x1cc },  { 725, 0x39, 0x1cc },
+	{ 775, 0x9, 0x1cc },  { 825, 0x19, 0x1cc },  { 875, 0x29, 0x1cc },  { 925, 0x3a, 0x1cc },
+	{ 975, 0xa, 0x1cc },  { 1025, 0x1a, 0x1cc }, { 1075, 0x2a, 0x1cc }, { 1125, 0x3b, 0x1cc },
+	{ 1175, 0xb, 0x1cc }, { 1225, 0x1b, 0x1cc }, { 1275, 0x2b, 0x1cc }, { 1325, 0x3c, 0x1cc },
+	{ 1375, 0xc, 0x1cc }, { 1425, 0x1c, 0x1cc }, { 1475, 0x2c, 0x1cc }
+};
+
+static void get_dphy_hs_transfer_info(u32 dphy_rate, u32 *hsfreqrange, u32 *osc_freq_target)
+{
+	unsigned int i;
+
+	for (i = 1; i < ARRAY_SIZE(dphy_hs_info); i++) {
+		if (dphy_rate < dphy_hs_info[i].rate) {
+			*hsfreqrange = dphy_hs_info[i - 1].hsfreqrange;
+			*osc_freq_target = dphy_hs_info[i - 1].osc_freq_target;
+			return;
+		}
+	}
+
+	/* not found; return the largest entry */
+	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].hsfreqrange;
+	*osc_freq_target = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].osc_freq_target;
+}
+
+static void visconti_csi2rx_set_dphy_rate(struct visconti_csi2rx *priv, u32 dphy_rate)
+{
+	u32 hsfreqrange, osc_freq_target;
+
+	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange, &osc_freq_target);
+
+	write_dphy_param(priv, DIG_SYS_1, (u8)hsfreqrange);
+	write_dphy_param(priv, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
+	write_dphy_param(priv, DIG_RX_STARTUP_OVR_5, STARTUP_OVR_5_BYPASS);
+	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL);
+	write_dphy_param(priv, DIG_CB_2, CB_2_LPRX_BIAS | CB_2_RESERVED);
+	write_dphy_param(priv, DIG_SYS_7, SYS_7_DESKEW_POL | SYS_7_RESERVED);
+	write_dphy_param(priv, DIG_CLKLANE_LANE_6, CLKLANE_RXHS_PULL_LONG);
+	write_dphy_param(priv, DIG_RX_STARTUP_OVR_2, FIELD_GET(0xff, osc_freq_target));
+	write_dphy_param(priv, DIG_RX_STARTUP_OVR_3, FIELD_GET(0xf00, osc_freq_target));
+	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL | STARTUP_OVR_4_DDL_EN);
+}
+
+static int visconti_csi2rx_initialize(struct visconti_csi2rx *priv, u32 num_lane, u32 dphy_rate,
+				      const struct visconti_csi2rx_line_err_target *err_target)
+{
+	u32 val;
+
+	if (dphy_rate < CSI2RX_MIN_DATA_RATE || dphy_rate > CSI2RX_MAX_DATA_RATE) {
+		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", dphy_rate);
+		return -ERANGE;
+	}
+
+	/* 1st phase of initialization */
+	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 1);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	ndelay(15U);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 0);
+
+	/* Configure D-PHY frequency range */
+	visconti_csi2rx_set_dphy_rate(priv, dphy_rate);
+
+	/* 2nd phase of initialization */
+	visconti_csi2rx_write(priv, REG_CSI2RX_NLANES, (num_lane - 1U));
+	ndelay(5U);
+
+	/* Release D-PHY from Reset */
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
+	ndelay(5U);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 1);
+
+	/* configuration of line error target */
+	val = (err_target->vc[3] << 30U) | (err_target->dt[3] << 24U) | (err_target->vc[2] << 22U) |
+	      (err_target->dt[2] << 16U) | (err_target->vc[1] << 14U) | (err_target->dt[1] << 8U) |
+	      (err_target->vc[0] << 6U) | (err_target->dt[0]);
+	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_1, val);
+	val = (err_target->vc[7] << 30U) | (err_target->dt[7] << 24U) | (err_target->vc[6] << 22U) |
+	      (err_target->dt[6] << 16U) | (err_target->vc[5] << 14U) | (err_target->dt[5] << 8U) |
+	      (err_target->vc[4] << 6U) | (err_target->dt[4]);
+	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_2, val);
+
+	/* configuration of mask */
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, MASK_PHY_FATAL_ALL);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, MASK_PKT_FATAL_ALL);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, MASK_FRAME_FATAL_ALL);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY, MASK_PHY_ERROR_ALL);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT, MASK_PKT_ERROR_ALL);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE, MASK_LINE_ERROR_ALL);
+
+	return 0;
+}
+
+struct visconti_csi2rx_format {
+	u32 code;
+	unsigned int bpp;
+};
+
+static const struct visconti_csi2rx_format visconti_csi2rx_formats[] = {
+	{ .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24 },
+	{ .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 },
+	{ .code = MEDIA_BUS_FMT_UYVY10_1X20, .bpp = 20 },
+	{ .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16 },
+	{ .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8 },
+	{ .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8 },
+	{ .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8 },
+	{ .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8 },
+	{ .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10 },
+	{ .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10 },
+	{ .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10 },
+	{ .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10 },
+	{ .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12 },
+	{ .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12 },
+	{ .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12 },
+	{ .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12 },
+	{ .code = MEDIA_BUS_FMT_SBGGR14_1X14, .bpp = 14 },
+	{ .code = MEDIA_BUS_FMT_SGBRG14_1X14, .bpp = 14 },
+	{ .code = MEDIA_BUS_FMT_SGRBG14_1X14, .bpp = 14 },
+	{ .code = MEDIA_BUS_FMT_SRGGB14_1X14, .bpp = 14 },
+};
+
+static const struct visconti_csi2rx_format *fmt_for_mbus_code(unsigned int mbus_code)
+{
+	int i;
+
+	for (i = 0; ARRAY_SIZE(visconti_csi2rx_formats); i++)
+		if (visconti_csi2rx_formats[i].code == mbus_code)
+			return &visconti_csi2rx_formats[i];
+}
+
+static unsigned int bpp_for_mbus_code(unsigned int mbus_code)
+{
+	const struct visconti_csi2rx_format *fmt = fmt_for_mbus_code(mbus_code);
+
+	return fmt ? fmt->bpp : 0;
+}
+
+static int64_t get_pixelclock(struct v4l2_subdev *sd)
+{
+	struct v4l2_ctrl *ctrl;
+
+	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	if (!ctrl)
+		return -EINVAL;
+
+	return v4l2_ctrl_g_ctrl_int64(ctrl);
+}
+
+static const struct visconti_csi2rx_line_err_target err_target_vc0_alldt = {
+	/* select VC=0 */
+	/* select all supported DataTypes */
+	.dt = {
+		MIPI_CSI2_DT_RGB565,
+		MIPI_CSI2_DT_YUV422_8B,
+		MIPI_CSI2_DT_YUV422_10B,
+		MIPI_CSI2_DT_RGB888,
+		MIPI_CSI2_DT_RAW8,
+		MIPI_CSI2_DT_RAW10,
+		MIPI_CSI2_DT_RAW12,
+		MIPI_CSI2_DT_RAW14,
+	}
+};
+
+static int visconti_csi2rx_start(struct visconti_csi2rx *priv, struct v4l2_subdev_state *state)
+{
+	struct v4l2_mbus_framefmt *sink_fmt;
+	int cur_bpp, dphy_rate;
+	s64 pixelclock;
+
+	/* get bpp for current format */
+	sink_fmt = v4l2_subdev_state_get_format(state, VISCONTI_CSI2RX_PAD_SINK);
+	cur_bpp = bpp_for_mbus_code(sink_fmt->code);
+
+	/* get pixel clock */
+	pixelclock = get_pixelclock(priv->remote);
+	if (pixelclock < 0)
+		return -EINVAL;
+
+	dphy_rate = div64_u64((u64)pixelclock * (u32)cur_bpp, priv->lanes * 1000000);
+
+	ndelay(15U);
+
+	return visconti_csi2rx_initialize(priv, priv->lanes, dphy_rate, &err_target_vc0_alldt);
+}
+
+static void visconti_csi2rx_stop(struct visconti_csi2rx *priv)
+{
+	/* disable interrupt -> make sure registers cleared -> wait for current handlers finish */
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE, 0);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY_FATAL);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT_FATAL);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT);
+	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_LINE);
+	synchronize_irq(priv->irq);
+
+	/* shutdown hardware */
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
+	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 0);
+}
+
+static int visconti_csi2rx_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+					  u32 pad, u64 streams_mask)
+{
+	struct visconti_csi2rx *priv = sd_to_csi2(sd);
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+	int ret;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* enabling: turn on CSI2RX -> turn on sensor */
+	ret = visconti_csi2rx_start(priv, state);
+	if (ret)
+		return ret;
+
+	/* currently CSI2RX supports only stream0 in source pad */
+	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, BIT(0));
+	if (ret) {
+		visconti_csi2rx_stop(priv);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int visconti_csi2rx_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+					   u32 pad, u64 streams_mask)
+{
+	struct visconti_csi2rx *priv = sd_to_csi2(sd);
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* disabling: turn off sensor -> turn off CSI2RX */
+	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, BIT(0));
+	visconti_csi2rx_stop(priv);
+
+	return 0;
+}
+
+static int visconti_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == VISCONTI_CSI2RX_PAD_SRC) {
+		const struct v4l2_mbus_framefmt *sink_fmt;
+
+		/* SRC pad supports exactly the same format as SINK pad */
+		if (code->index)
+			return -EINVAL;
+		sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
+		code->code = sink_fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(visconti_csi2rx_formats))
+		return -EINVAL;
+	code->code = visconti_csi2rx_formats[code->index].code;
+
+	return 0;
+}
+
+static int visconti_csi2rx_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SRC);
+
+	sink_fmt->width = VISCONTI_CSI2RX_DEF_WIDTH;
+	sink_fmt->height = VISCONTI_CSI2RX_DEF_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = visconti_csi2rx_formats[0].code;
+
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static int visconti_csi2rx_set_pad_format(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *sd_state,
+					  struct v4l2_subdev_format *fmt)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	/* SRC PAD has the same format as SINK PAD */
+	if (fmt->pad == 1)
+		return v4l2_subdev_get_fmt(sd, sd_state, fmt);
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
+
+	*sink_fmt = fmt->format;
+	sink_fmt->width = clamp_t(u32, fmt->format.width, VISCONTI_CSI2RX_MIN_WIDTH,
+				  VISCONTI_CSI2RX_MAX_WIDTH);
+	sink_fmt->height = clamp_t(u32, fmt->format.height, VISCONTI_CSI2RX_MIN_HEIGHT,
+				   VISCONTI_CSI2RX_MAX_HEIGHT);
+	if (!fmt_for_mbus_code(sink_fmt->code))
+		sink_fmt->code = visconti_csi2rx_formats[0].code;
+	fmt->format = *sink_fmt;
+
+	/* source pad should have the same format */
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SRC);
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static const struct media_entity_operations visconti_csi2rx_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops visconti_csi2rx_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops visconti_csi2rx_pad_ops = {
+	.enum_mbus_code = visconti_csi2rx_enum_mbus_code,
+	.disable_streams = visconti_csi2rx_disable_streams,
+	.enable_streams = visconti_csi2rx_enable_streams,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = visconti_csi2rx_set_pad_format,
+};
+
+static const struct v4l2_subdev_ops visconti_csi2rx_subdev_ops = {
+	.video = &visconti_csi2rx_video_ops,
+	.pad = &visconti_csi2rx_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops visconti_csi2rx_internal_ops = {
+	.init_state = visconti_csi2rx_init_state,
+};
+
+static int visconti_csi2rx_notify_bound(struct v4l2_async_notifier *notifier,
+					struct v4l2_subdev *subdev,
+					struct v4l2_async_connection *asc)
+{
+	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
+	int pad;
+
+	pad = media_entity_get_fwnode_pad(&subdev->entity, asc->match.fwnode, MEDIA_PAD_FL_SOURCE);
+	if (pad < 0) {
+		dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name);
+		return pad;
+	}
+
+	priv->remote = subdev;
+	priv->remote_pad = pad;
+
+	return media_create_pad_link(&subdev->entity, pad, &priv->subdev.entity, 0,
+				     MEDIA_LNK_FL_ENABLED);
+}
+
+static void visconti_csi2rx_notify_unbind(struct v4l2_async_notifier *notifier,
+					  struct v4l2_subdev *subdev,
+					  struct v4l2_async_connection *asc)
+{
+	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
+
+	priv->remote = NULL;
+}
+
+static const struct v4l2_async_notifier_operations visconti_csi2rx_notify_ops = {
+	.bound = visconti_csi2rx_notify_bound,
+	.unbind = visconti_csi2rx_notify_unbind,
+};
+
+static int visconti_csi2rx_parse_v4l2(struct visconti_csi2rx *priv,
+				      struct v4l2_fwnode_endpoint *vep)
+{
+	/* Only port 0 endpoint 0 is valid. */
+	if (vep->base.port || vep->base.id)
+		return -ENOTCONN;
+
+	priv->lanes = vep->bus.mipi_csi2.num_data_lanes;
+
+	/* got trouble */
+	if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
+		dev_err(priv->dev, "Specified bus type is not supported\n");
+		return -EINVAL;
+	}
+
+	if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) {
+		dev_err(priv->dev, "Unsupported number of data-lanes for D-PHY: %u\n", priv->lanes);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int visconti_csi2rx_parse_dt(struct visconti_csi2rx *priv)
+{
+	struct v4l2_async_connection *asc;
+	struct fwnode_handle *fwnode;
+	struct fwnode_handle *ep;
+	struct v4l2_fwnode_endpoint v4l2_ep = {
+		.bus_type = V4L2_MBUS_UNKNOWN,
+	};
+	int ret;
+
+	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0);
+	if (!ep) {
+		dev_err(priv->dev, "Not connected to subdevice\n");
+		return -EINVAL;
+	}
+
+	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
+	if (ret) {
+		dev_err(priv->dev, "Could not parse v4l2 endpoint\n");
+		fwnode_handle_put(ep);
+		return -EINVAL;
+	}
+
+	ret = visconti_csi2rx_parse_v4l2(priv, &v4l2_ep);
+	if (ret) {
+		fwnode_handle_put(ep);
+		return ret;
+	}
+
+	fwnode = fwnode_graph_get_remote_endpoint(ep);
+	fwnode_handle_put(ep);
+
+	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
+	priv->notifier.ops = &visconti_csi2rx_notify_ops;
+
+	asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, struct v4l2_async_connection);
+	fwnode_handle_put(fwnode);
+	if (IS_ERR(asc))
+		return PTR_ERR(asc);
+
+	ret = v4l2_async_nf_register(&priv->notifier);
+	if (ret)
+		v4l2_async_nf_cleanup(&priv->notifier);
+
+	return ret;
+}
+
+static irqreturn_t visconti_csi2rx_irq(int irq, void *dev_id)
+{
+	struct visconti_csi2rx *priv = dev_id;
+	u32 event;
+
+	event = visconti_csi2rx_read(priv, REG_CSI2RX_INT_ST_MAIN);
+	dev_err(priv->dev, "CSI2RX error 0x%x.\n", event);
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id visconti_csi2rx_of_table[] = {
+	{
+		.compatible = "toshiba,visconti5-csi2rx",
+	},
+	{},
+};
+
+static int visconti_csi2rx_probe(struct platform_device *pdev)
+{
+	struct visconti_csi2rx *priv;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base)) {
+		dev_err(priv->dev, "Failed to get registers\n");
+		return PTR_ERR(priv->base);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+	ret = devm_request_irq(&pdev->dev, irq, visconti_csi2rx_irq, 0, KBUILD_MODNAME, priv);
+	priv->irq = irq;
+	if (ret) {
+		dev_err(priv->dev, "request irq failed: %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	ret = visconti_csi2rx_parse_dt(priv); /*this function does v4l2_async_nf_register */
+	if (ret)
+		return ret;
+
+	priv->subdev.owner = THIS_MODULE;
+	priv->subdev.dev = &pdev->dev;
+	v4l2_subdev_init(&priv->subdev, &visconti_csi2rx_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+	snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", KBUILD_MODNAME,
+		 dev_name(&pdev->dev));
+
+	priv->subdev.internal_ops = &visconti_csi2rx_internal_ops;
+	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	priv->subdev.entity.ops = &visconti_csi2rx_entity_ops;
+
+	priv->pads[VISCONTI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	priv->pads[VISCONTI_CSI2RX_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&priv->subdev.entity, VISCONTI_CSI2RX_PAD_NUM, priv->pads);
+	if (ret)
+		goto err_cleanup_async;
+
+	ret = v4l2_subdev_init_finalize(&priv->subdev);
+	if (ret)
+		goto err_cleanup_media_entity;
+
+	ret = v4l2_async_register_subdev(&priv->subdev);
+	if (ret < 0)
+		goto err_cleanup_subdev_state;
+
+	return 0;
+
+err_cleanup_subdev_state:
+	v4l2_subdev_cleanup(&priv->subdev);
+
+err_cleanup_media_entity:
+	media_entity_cleanup(&priv->subdev.entity);
+
+err_cleanup_async:
+	v4l2_async_nf_unregister(&priv->notifier);
+	v4l2_async_nf_cleanup(&priv->notifier);
+
+	return ret;
+}
+
+static void visconti_csi2rx_remove(struct platform_device *pdev)
+{
+	struct visconti_csi2rx *priv = platform_get_drvdata(pdev);
+
+	v4l2_async_nf_unregister(&priv->notifier);
+	v4l2_async_nf_cleanup(&priv->notifier);
+	v4l2_async_unregister_subdev(&priv->subdev);
+
+	v4l2_subdev_cleanup(&priv->subdev);
+	media_entity_cleanup(&priv->subdev.entity);
+}
+
+static struct platform_driver visconti_csi2rx_driver = {
+	.probe = visconti_csi2rx_probe,
+	.remove = visconti_csi2rx_remove,
+	.driver = {
+		.name = "visconti_csi2rx_dev",
+		.of_match_table = visconti_csi2rx_of_table,
+	},
+};
+
+module_platform_driver(visconti_csi2rx_driver);
+
+MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
+MODULE_DESCRIPTION("Toshiba Visconti CSI-2 receiver driver");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
2.25.1



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

* [PATCH v12 5/8] media: platform: visconti: Add Toshiba Visconti Video Input Interface driver
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (3 preceding siblings ...)
  2024-11-25  9:21 ` [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 6/8] media: platform: visconti: Add streaming interface for ISP parameters and status Yuji Ishikawa
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Add support to Video Input Interface on Toshiba Visconti ARM SoCs.
The interface device includes frame grabber,
video DMAC and image signal processor.

A driver instance provides three /dev/videoX device files;
one for RGB image capture, another one for optional RGB capture
with different parameters and the last one for RAW capture.

Through the device files, the driver provides streaming interface.
Both DMABUF and MMAP operations are supported.
The buffer provided by a userland application should be DMA-contiguous.

The driver is based on media controller framework.
Its operations are roughly mapped to three subdrivers;
CSI2 receiver subdevice, ISP subdevice and capture devices.

The Video DMACs have 32bit address space
and currently corresponding IOMMU driver is not provided.
Therefore, memory-block address for captured image is 32bit IOVA
which is equal to 32bit-truncated physical address.
When the Visconti IOMMU driver (currently under development) is accepted,
the hardware layer will use 32bit IOVA mapped by the attached IOMMU.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
---
Changelog v2:
- Resend v1 because a patch exceeds size limit.

Changelog v3:
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters

Changelog v4:
- fix style problems at the v3 patch
- remove "index" member
- update example
- Split patches because the v3 patch exceeds size limit
- Stop using ID number to identify driver instance:
  - Use dynamically allocated structure to hold driver's context,
    instead of static one indexed by ID number.
  - internal functions accept context structure instead of ID number.
- Use pm_runtime to trigger initialization of HW
  along with open/close of device files.

Changelog v5:
- Fix coding style problems in viif.c

Changelog v6:
- update dependency description of Kconfig
- bugfix: usage of buffer pointed with dma_active
- remove unused macros
- add viif_common.c for commonly used register buffer control routine
- add initialization of Bus Controller (HWAIF) and Memory Protection Unit
- removed hwd_ and HWD_ prefix
- update source code documentation
- Suggestion from Hans Verkuil
  - pointer to userland memory is removed from uAPI arguments
    - style of structure is now "nested" instead of "chained by pointer";
  - use div64_u64 for 64bit division
  - define Visconti specific control IDs in v4l2-controls.h
  - set proper initial size to v4l2_ctrl_handler_init()
  - set all buffers to QUEUED state on an error at start_streaming
  - use vb2_is_busy() instead of vb2_is_streaming()
  - add parameter check for s->type and s->target in get_selection()
  - remove ioctls related to DV format and EDID
  - release v4l2 fh instance on and error at opening device file
  - support VB2_MMAP mode for streaming operation
  - add initial value to each vendor specific control
  - GET_LAST_CAPTURE_STATUS control is updated asynchronously from workqueue
  - applied v4l2-compliance
- Suggestion from Sakari Ailus
  - use div64_u64 for 64bit division
  - update copyright's year
  - use common definition of MIPI CSI2 DataTypes
  - remove redundant cast
  - use bool instead of HWD_VIIF_ENABLE/DISABLE
  - simplify comparison to 0
  - simplify statements with trigram operator
  - remove redundant local variables
  - simplify timeout loop
  - use general integer types instead of u32/s32
- Suggestion from Laurent Pinchart
  - moved VIIF driver to driver/platform/toshiba/visconti
  - add CSI2RX subdevice
  - change register access: struct-style to macro-style
  - use common definition of MIPI CSI2 DataTypes
  - Kconfig: add SPDX header, add V4L2_ASYNC
  - remove unused type definitions
  - define enums instead of successive macro constants
  - remove redundant parenthesis of macro constant
  - embed struct hwd_res into struct viif_device
  - turn switch-case into table lookup
  - use xxx_dma instead of xxx_paddr for variable names of IOVA
  - literal value: just 0 instead of 0x0
  - use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register access
  - use true or false instead of HWD_VIIF_ENABLE, DISABLE for function calls
  - remove ioctl request handlers which refers subdevices

Changelog v7:
- change compatible string to visconti5-viif
- remove unused variables
- set static to internal functions
- Suggestion from kernel test robot <lkp@intel.com>
  - update references to headers

Changelog v8:
- bugfix: handling return value of visconti_viif_parse_dt()
- add visconti_viif_subdev_notifier_register() to gather
  all operations around v4l2_async_notifier
- update for v6.6-rc2
  - use v4l2_async_connection instead of v4l2_async_subdev
  - aid for devices using subdev active state
- add __maybe_unused for runtime_pm callbacks
- Suggestion from Krzysztof Kozlowski
  - use static initialization of local variable
  - use dev_err_probe()
  - remove error message for DMA memory allocation failure
  - remove unused comment messages
  - add error handling at fail of workqueue_create()
  - remove redundant mutex for pm_runtime callback routines
- Suggestion from Hans Verkuil
  - remove pr_info() calls
  - build check with media_stage.git
  - some lacks for kerneldoc description

Changelog v9:
- applied sparse checker
  - add static qualifier to a file scoped local variable
  - expand functions for acquiring/releasing locks
- bugfix: use NULL (instead of 0) for pad::get_fmt subdevice API
- fix warnings for cast between ptr and dma_addr_t
- call div64_u64 for 64bit division
- rebase to media_staging tree; update Visconti specific control IDs

Changelog v10:
- remove vendor specific compound controls
- remove "rawpack mode" flag
  - RAW16, RAW18, RAW20 (to be implemented and tested) should be used instead
- catch up to v6.9-rc4

Changelog v11:
- stop merging sensor's controls to capture device's
- remove redundant parameter checkings
- update routines handling crop/compose rects of the ISP subdevice
- update kerneldoc comments
- update copyright year

Changelog v12:
- expand functions used only once
- separate IRQ handlers one for VSync and the other for error.
- remove redundant NULL check at visconti_viif_create_sensor_link()
- return error at "missing CSI-2 properties in endpoint"
- detailed error message at return of platform_get_irq()
- improve cast operations for viif_dev->tables_dma
- use RUNTIME_PM_OPS instead of SET_RUNTIME_PM_OPS
- improve identifiers for include guards
- remove unused v4l2-m2m.h
- add comment to VIIF_SYS_CLK macro
- use struct v4l2_rect instead of viif_img_area to hold crop rectangle
- name capture devices cap_{post0, post1, sub} for better understanding
- remove viif_csi2rx subdevice and made it independent driver
- limit vbp size; there might be a sensor with too large vbp; tested with IMX335
- newly add viif_resizer subdevice between ISP and Capture devices.
  - they are available on the capture paths for cap_dev_post0 and cap_dev_post1
  - Resizer offer resize and crop feature; ISP's feature is dropped
- use v4l2_subdev_enable_streams() to start streaming
- implement callback enable_streams and disable_streams, instead of s_steram
- applied rules for setting parameters of downstream pads
- use lowercase hexadecimal literals
- hardware limitation: cap_sub can capture only RAW8 or RAW16
  - for RAW10, 12, 14 input, pixel values are shifted to MSB
- add spinlocks to status_err, reported_err_main, reported_err_sub
- call pm_runtime API at start/stop streaming, instead of file handle callback
- use guard(spinlock)(locked_variable) macros
  - also use custom guard macros for viif_isp_guard
- migration to v6.12: signature of platform_driver::remove is changed

 .../media/platform/toshiba/visconti/Kconfig   |   18 +
 .../media/platform/toshiba/visconti/Makefile  |    2 +
 .../media/platform/toshiba/visconti/viif.c    |  576 +++++
 .../media/platform/toshiba/visconti/viif.h    |  379 ++++
 .../platform/toshiba/visconti/viif_capture.c  | 1285 +++++++++++
 .../platform/toshiba/visconti/viif_capture.h  |   21 +
 .../platform/toshiba/visconti/viif_common.c   |  239 ++
 .../platform/toshiba/visconti/viif_common.h   |   45 +
 .../platform/toshiba/visconti/viif_isp.c      |  909 ++++++++
 .../platform/toshiba/visconti/viif_isp.h      |   19 +
 .../platform/toshiba/visconti/viif_regs.h     |  717 ++++++
 .../platform/toshiba/visconti/viif_resizer.c  |  461 ++++
 .../platform/toshiba/visconti/viif_resizer.h  |   18 +
 include/uapi/linux/visconti_viif.h            | 1921 +++++++++++++++++
 14 files changed, 6610 insertions(+)
 create mode 100644 drivers/media/platform/toshiba/visconti/viif.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_regs.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_resizer.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_resizer.h
 create mode 100644 include/uapi/linux/visconti_viif.h

diff --git a/drivers/media/platform/toshiba/visconti/Kconfig b/drivers/media/platform/toshiba/visconti/Kconfig
index e5c92d598f8b..8fcab00a0c29 100644
--- a/drivers/media/platform/toshiba/visconti/Kconfig
+++ b/drivers/media/platform/toshiba/visconti/Kconfig
@@ -14,3 +14,21 @@ config VIDEO_VISCONTI_CSI2RX
 	  This driver yields 1 subdevice node for a hardware instance.
 	  To compile this driver as a module, choose M here: the
 	  module will be called visconti-csi2rx.
+
+config VIDEO_VISCONTI_VIIF
+	tristate "Visconti Camera Interface driver"
+	depends on V4L_PLATFORM_DRIVERS
+	depends on VIDEO_DEV && OF
+	depends on ARCH_VISCONTI || COMPILE_TEST
+	select MEDIA_CONTROLLER
+	select VIDEO_V4L2_SUBDEV_API
+	select VIDEOBUF2_DMA_CONTIG
+	select VIDEOBUF2_VMALLOC
+	select V4L2_FWNODE
+	help
+	  This is V4L2 driver for Toshiba Visconti Camera Interface hardware
+
+	  This driver yields 3 video device nodes
+	  and 1 media device node for a hardware instance.
+	  To compile this driver as a module, choose M here: the
+	  module will be called visconti-viif.
diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
index 62a029376134..4c7433744b64 100644
--- a/drivers/media/platform/toshiba/visconti/Makefile
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -4,5 +4,7 @@
 #
 
 visconti-csi2rx-objs = csi2rx_drv.o
+visconti-viif-objs = viif.o viif_capture.o viif_common.o viif_isp.o viif_resizer.o
 
 obj-$(CONFIG_VIDEO_VISCONTI_CSI2RX) += visconti-csi2rx.o
+obj-$(CONFIG_VIDEO_VISCONTI_VIIF) += visconti-viif.o
diff --git a/drivers/media/platform/toshiba/visconti/viif.c b/drivers/media/platform/toshiba/visconti/viif.c
new file mode 100644
index 000000000000..d2521718abe5
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-fwnode.h>
+
+#include "viif.h"
+#include "viif_capture.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+#include "viif_resizer.h"
+
+/*=============================================*/
+/* Register Access */
+/*=============================================*/
+static inline void viif_hwaif_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->hwaif_reg + regid);
+}
+
+static inline void viif_mpu_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->mpu_reg + regid);
+}
+
+/*=============================================*/
+/* Low Layer hardware setup */
+/*=============================================*/
+static void viif_mpu_disable(struct viif_device *viif_dev)
+{
+	viif_mpu_write(viif_dev, REG_MPU_MP_EN, 0);
+	viif_mpu_write(viif_dev, REG_MPU_MF_EN, 1);
+}
+
+static void viif_hwaif_enable(struct viif_device *viif_dev)
+{
+	/* pass through; disable all entries */
+	viif_hwaif_write(viif_dev, REG_HWAIF_REGION_ENTRY_EN, 0);
+
+	/* no limit for outstanding requests */
+	viif_hwaif_write(viif_dev, REG_HWAIF_OSTD_RLEN, 0);
+	viif_hwaif_write(viif_dev, REG_HWAIF_OSTD_WREQ, 0);
+
+	/* no data-pack/outstanding */
+	viif_hwaif_write(viif_dev, REG_HWAIF_HWAIF_CONF, 0);
+
+	/* enable bus access */
+	viif_hwaif_write(viif_dev, REG_HWAIF_HWAIF_EN, 1);
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+static irqreturn_t viif_vsync_irq_handler(int irq, void *dev_id)
+{
+	u32 event_main = 0, event_sub = 0, status_err, l2_transfer_status, mask, val;
+	struct viif_device *viif_dev = dev_id;
+	u64 ts;
+
+	if (!viif_dev->irq_enabled)
+		return IRQ_HANDLED;
+
+	ts = ktime_get_ns();
+
+	/* Delayed Vsync of MAIN unit */
+	mask = viif_capture_read(viif_dev, REG_INT_M_SYNC_MASK);
+	event_main = viif_capture_read(viif_dev, REG_INT_M_SYNC) & ~mask;
+	if (event_main)
+		viif_capture_write(viif_dev, REG_INT_M_SYNC, event_main);
+
+	if (event_main & MASK_INT_M_SYNC_LINES_DELAY_INT2) {
+		/* unmask timeout error of gamma table */
+		viif_capture_write(viif_dev, REG_INT_M_MASK, MASK_INT_M_DELAY_INT_ERROR);
+		viif_dev->masked_gamma_path = 0;
+
+		/* Get abort status of L2ISP */
+		{
+			guard(spinlock)(&viif_dev->regbuf_lock);
+			guard(viif_isp)(viif_dev);
+
+			val = viif_capture_read(viif_dev, REG_L2_CRGBF_ISP_INT);
+			viif_capture_write(viif_dev, REG_L2_CRGBF_ISP_INT, val);
+			l2_transfer_status = val & MASK_L2_STATUS_ERR_ALL;
+		}
+		{
+			guard(spinlock)(&viif_dev->errflag_lock);
+
+			status_err = viif_dev->status_err;
+			viif_dev->status_err = 0;
+		}
+
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_post0, status_err,
+						    l2_transfer_status, ts);
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_post1, status_err,
+						    l2_transfer_status, ts);
+	}
+
+	/* Delayed Vsync of SUB unit */
+	mask = viif_capture_read(viif_dev, REG_INT_S_SYNC_MASK);
+	event_sub = viif_capture_read(viif_dev, REG_INT_S_SYNC) & ~mask;
+	if (event_sub)
+		viif_capture_write(viif_dev, REG_INT_S_SYNC, event_sub);
+
+	if (event_sub & MASK_INT_S_SYNC_LINES_DELAY_INT1)
+		visconti_viif_capture_switch_buffer(&viif_dev->cap_sub, 0, 0, ts);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t viif_status_err_irq_handler(int irq, void *dev_id)
+{
+	u32 event_main = 0, event_sub = 0, val, mask;
+	struct viif_device *viif_dev = dev_id;
+
+	if (!viif_dev->irq_enabled)
+		return IRQ_HANDLED;
+
+	mask = viif_capture_read(viif_dev, REG_INT_M_MASK);
+	event_main = viif_capture_read(viif_dev, REG_INT_M_STATUS) & ~mask;
+	if (event_main) {
+		viif_capture_write(viif_dev, REG_INT_M_STATUS, event_main);
+
+		/* mask for gamma table time out error which will be unmasked in the next Vsync */
+		val = FIELD_GET(MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT, event_main);
+		if (val) {
+			viif_dev->masked_gamma_path |= val;
+			mask = MASK_INT_M_DELAY_INT_ERROR |
+			       FIELD_PREP(MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT,
+					  viif_dev->masked_gamma_path);
+			viif_capture_write(viif_dev, REG_INT_M_MASK, mask);
+		}
+		{
+			guard(spinlock)(&viif_dev->errflag_lock);
+			viif_dev->status_err = event_main;
+		}
+	}
+
+	mask = viif_capture_read(viif_dev, REG_INT_S_MASK);
+	event_sub = viif_capture_read(viif_dev, REG_INT_S_STATUS) & ~mask;
+	if (event_sub)
+		viif_capture_write(viif_dev, REG_INT_S_STATUS, event_sub);
+
+	{
+		guard(spinlock)(&viif_dev->repflag_lock);
+
+		viif_dev->reported_err_main |= event_main;
+		viif_dev->reported_err_sub |= event_sub;
+	}
+	dev_err(viif_dev->dev, "MAIN/SUB error 0x%x 0x%x.\n", event_main, event_sub);
+
+	return IRQ_HANDLED;
+}
+
+/* ----- Async Notifier Operations----- */
+static int visconti_viif_create_sensor_link(struct viif_device *viif_dev)
+{
+	struct v4l2_subdev *remote_sd = viif_dev->remote_sd;
+	int source_pad;
+	int ret;
+
+	/* camera subdev pad0 -> isp suddev pad0 */
+	source_pad = media_entity_get_fwnode_pad(&remote_sd->entity, remote_sd->fwnode,
+						 MEDIA_PAD_FL_SOURCE);
+	if (source_pad < 0) {
+		dev_err(viif_dev->dev, "failed to find source pad\n");
+		return source_pad;
+	}
+
+	ret = media_create_pad_link(&remote_sd->entity, source_pad, &viif_dev->isp_subdev.sd.entity,
+				    VIIF_ISP_PAD_SINK_VIDEO, MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (sensor:src -> isp:sink)\n");
+
+	return ret;
+}
+
+/**
+ * struct viif_remote_async -  remote subdevice information handled by v4l2_async APIs
+ * @asc:      async_connection
+ * @v4l2_sd:  v4l2_subdev for the subdevice
+ * @num_lane: number of lanes for the connection
+ * @index:    index of the subdevice
+ */
+struct viif_remote_async {
+	struct v4l2_async_connection asc;
+	struct v4l2_subdev *v4l2_sd;
+	unsigned int num_lane;
+	unsigned int index;
+};
+
+static int visconti_viif_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *v4l2_sd,
+				      struct v4l2_async_connection *asc)
+{
+	struct viif_device *viif_dev = container_of(notifier, struct viif_device, notifier);
+	struct viif_remote_async *s_as = container_of(asc, struct viif_remote_async, asc);
+
+	s_as->v4l2_sd = v4l2_sd;
+	if (!s_as->index) {
+		viif_dev->remote_sd = v4l2_sd;
+		viif_dev->remote_num_lane = s_as->num_lane;
+		return visconti_viif_create_sensor_link(viif_dev);
+	}
+
+	return 0;
+}
+
+static void visconti_viif_notify_unbind(struct v4l2_async_notifier *notifier,
+					struct v4l2_subdev *subdev,
+					struct v4l2_async_connection *asc)
+{
+	struct viif_device *viif_dev = container_of(notifier, struct viif_device, notifier);
+
+	if (viif_dev->remote_sd == subdev)
+		viif_dev->remote_sd = NULL;
+}
+
+static int visconti_viif_notify_complete(struct v4l2_async_notifier *notifier)
+{
+	return v4l2_device_register_subdev_nodes(notifier->v4l2_dev);
+}
+
+static const struct v4l2_async_notifier_operations viif_notify_ops = {
+	.bound = visconti_viif_notify_bound,
+	.unbind = visconti_viif_notify_unbind,
+	.complete = visconti_viif_notify_complete,
+};
+
+/* ----- Probe and Remove ----- */
+static int visconti_viif_subdev_notifier_register(struct viif_device *viif_dev)
+{
+	struct fwnode_handle *fwnode = dev_fwnode(viif_dev->dev);
+	struct v4l2_async_notifier *ntf = &viif_dev->notifier;
+	struct fwnode_handle *ep;
+	unsigned int index = 0;
+	int ret = 0;
+
+	v4l2_async_nf_init(ntf, &viif_dev->v4l2_dev);
+	ntf->ops = &viif_notify_ops;
+
+	fwnode_graph_for_each_endpoint(fwnode, ep) {
+		struct v4l2_fwnode_endpoint vep = {};
+		struct viif_remote_async *viif_asd;
+
+		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+		if (ret) {
+			dev_err(viif_dev->dev, "failed to parse endpoint %pfw\n", ep);
+			break;
+		}
+
+		if (vep.bus_type != V4L2_MBUS_CSI2_DPHY || vep.bus.mipi_csi2.num_data_lanes == 0) {
+			dev_err(viif_dev->dev, "missing CSI-2 properties in endpoint %pfw\n", ep);
+			ret = -EINVAL;
+			break;
+		}
+
+		viif_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, struct viif_remote_async);
+		viif_asd->index = index++;
+		viif_asd->num_lane = vep.bus.mipi_csi2.num_data_lanes;
+	}
+
+	if (ret) {
+		fwnode_handle_put(ep);
+		v4l2_async_nf_cleanup(ntf);
+		return ret;
+	}
+
+	if (!index)
+		dev_dbg(viif_dev->dev, "No remote subdevice found\n");
+
+	ret = v4l2_async_nf_register(ntf);
+	if (ret) {
+		v4l2_async_nf_cleanup(ntf);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int visconti_viif_create_links(struct viif_device *viif_dev)
+{
+	int ret;
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH0,
+				    &viif_dev->resizer_post0.sd.entity, VIIF_RESIZER_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:path0 -> resizer0:sink)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->resizer_post0.sd.entity, VIIF_RESIZER_PAD_SRC,
+				    &viif_dev->cap_post0.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (resizer0:src -> capture0:sink)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH1,
+				    &viif_dev->resizer_post1.sd.entity, VIIF_RESIZER_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:path1 -> resizer1:sink)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->resizer_post1.sd.entity, VIIF_RESIZER_PAD_SRC,
+				    &viif_dev->cap_post1.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (resizer1:src -> capture1:sink)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_PATH2,
+				    &viif_dev->cap_sub.vdev.entity, VIIF_CAPTURE_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:path2 -> capture2:sink)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->params_dev.vdev.entity, VIIF_PARAMS_PAD_SRC,
+				    &viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SINK_PARAMS,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed create_pad_link (params:src -> isp:params)\n");
+		return ret;
+	}
+
+	ret = media_create_pad_link(&viif_dev->isp_subdev.sd.entity, VIIF_ISP_PAD_SRC_STATS,
+				    &viif_dev->stats_dev.vdev.entity, VIIF_STATS_PAD_SINK,
+				    MEDIA_LNK_FL_ENABLED);
+	if (ret)
+		dev_err(viif_dev->dev, "failed create_pad_link (isp:stats -> stat:sink)\n");
+
+	return ret;
+}
+
+static const struct of_device_id visconti_viif_of_table[] = {
+	{
+		.compatible = "toshiba,visconti5-viif",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, visconti_viif_of_table);
+
+static irqreturn_t (*viif_irq_handlers[VIIF_NUM_IRQS])(int, void *) = {
+	viif_vsync_irq_handler,
+	viif_status_err_irq_handler,
+};
+
+static int visconti_viif_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct viif_device *viif_dev;
+	dma_addr_t tables_dma;
+	int ret, i;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+	if (ret)
+		return ret;
+
+	viif_dev = devm_kzalloc(dev, sizeof(*viif_dev), GFP_KERNEL);
+	if (!viif_dev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, viif_dev);
+	viif_dev->dev = dev;
+
+	spin_lock_init(&viif_dev->regbuf_lock);
+	spin_lock_init(&viif_dev->errflag_lock);
+	spin_lock_init(&viif_dev->repflag_lock);
+	mutex_init(&viif_dev->stream_lock);
+
+	viif_dev->capture_reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(viif_dev->capture_reg))
+		return PTR_ERR(viif_dev->capture_reg);
+
+	viif_dev->hwaif_reg = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(viif_dev->hwaif_reg))
+		return PTR_ERR(viif_dev->hwaif_reg);
+
+	viif_dev->mpu_reg = devm_platform_ioremap_resource(pdev, 2);
+	if (IS_ERR(viif_dev->mpu_reg))
+		return PTR_ERR(viif_dev->mpu_reg);
+
+	viif_dev->run_flag_main = false;
+
+	for (i = 0; i < ARRAY_SIZE(viif_irq_handlers); i++) {
+		int irq;
+
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0)
+			return dev_err_probe(dev, irq, "failed to acquire irq resource %d\n", i);
+		ret = devm_request_irq(dev, irq, viif_irq_handlers[i], 0, "viif", viif_dev);
+		if (ret)
+			return dev_err_probe(dev, ret, "irq request failed: resource %d\n", i);
+		viif_dev->irq[i] = irq;
+	}
+
+	viif_dev->tables =
+		dma_alloc_wc(dev, sizeof(struct viif_table_area), &tables_dma, GFP_KERNEL);
+	if (!viif_dev->tables)
+		return -ENOMEM;
+	viif_dev->tables_dma = tables_dma;
+
+	pm_runtime_enable(dev);
+
+	/* build media_dev */
+	viif_dev->media_dev.hw_revision = 0;
+	strscpy(viif_dev->media_dev.model, VIIF_DRIVER_NAME, sizeof(viif_dev->media_dev.model));
+	viif_dev->media_dev.dev = dev;
+	media_device_init(&viif_dev->media_dev);
+
+	/* build v4l2_dev */
+	viif_dev->v4l2_dev.mdev = &viif_dev->media_dev;
+	ret = v4l2_device_register(dev, &viif_dev->v4l2_dev);
+	if (ret)
+		goto error_dma_free;
+
+	ret = media_device_register(&viif_dev->media_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register media device\n");
+		goto error_v4l2_unregister;
+	}
+
+	ret = visconti_viif_isp_register(viif_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to register isp sub node\n");
+		goto error_media_unregister;
+	}
+
+	ret = visconti_viif_resizer_register(viif_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to register resizer sub node\n");
+		goto error_isp_unregister;
+	}
+
+	ret = visconti_viif_capture_register(viif_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to register capture node\n");
+		goto error_resizer_unregister;
+	}
+
+	ret = visconti_viif_create_links(viif_dev);
+	if (ret)
+		goto error_capture_unregister;
+
+	visconti_viif_subdev_notifier_register(viif_dev);
+	if (ret)
+		goto error_capture_unregister;
+
+	return 0;
+
+error_capture_unregister:
+	visconti_viif_capture_unregister(viif_dev);
+error_resizer_unregister:
+	visconti_viif_resizer_unregister(viif_dev);
+error_isp_unregister:
+	visconti_viif_isp_unregister(viif_dev);
+error_media_unregister:
+	media_device_unregister(&viif_dev->media_dev);
+error_v4l2_unregister:
+	v4l2_device_unregister(&viif_dev->v4l2_dev);
+error_dma_free:
+	pm_runtime_disable(dev);
+	dma_free_wc(&pdev->dev, sizeof(struct viif_table_area), viif_dev->tables,
+		    (dma_addr_t)(uintptr_t)viif_dev->tables_dma);
+	return ret;
+}
+
+static void visconti_viif_remove(struct platform_device *pdev)
+{
+	struct viif_device *viif_dev = platform_get_drvdata(pdev);
+
+	v4l2_async_nf_unregister(&viif_dev->notifier);
+	v4l2_async_nf_cleanup(&viif_dev->notifier);
+	visconti_viif_capture_unregister(viif_dev);
+	visconti_viif_resizer_unregister(viif_dev);
+	visconti_viif_isp_unregister(viif_dev);
+	media_device_unregister(&viif_dev->media_dev);
+	v4l2_device_unregister(&viif_dev->v4l2_dev);
+
+	pm_runtime_disable(&pdev->dev);
+	dma_free_wc(&pdev->dev, sizeof(struct viif_table_area), viif_dev->tables,
+		    (dma_addr_t)(uintptr_t)viif_dev->tables_dma);
+}
+
+static int visconti_viif_runtime_suspend(struct device *dev)
+{
+	struct viif_device *viif_dev = dev_get_drvdata(dev);
+	int i;
+
+	viif_dev->irq_enabled = false;
+	/* Make sure the IRQ handler will see the flag change */
+	mb();
+
+	/* mask all IRQs */
+	viif_capture_write(viif_dev, REG_INT_M_SYNC_MASK, 0);
+	viif_capture_write(viif_dev, REG_INT_M_MASK, 0);
+	viif_capture_write(viif_dev, REG_INT_S_SYNC_MASK, 0);
+	viif_capture_write(viif_dev, REG_INT_S_MASK, 0);
+	viif_capture_read(viif_dev, REG_INT_M_SYNC_MASK);
+	viif_capture_read(viif_dev, REG_INT_M_MASK);
+	viif_capture_read(viif_dev, REG_INT_S_SYNC_MASK);
+	viif_capture_read(viif_dev, REG_INT_S_MASK);
+	for (i = 0; i < VIIF_NUM_IRQS; i++)
+		synchronize_irq(viif_dev->irq[i]);
+
+	return 0;
+}
+
+static int visconti_viif_runtime_resume(struct device *dev)
+{
+	struct viif_device *viif_dev = dev_get_drvdata(dev);
+
+	/* Disable MPU */
+	viif_mpu_disable(viif_dev);
+	/* Enable HWAIF */
+	viif_hwaif_enable(viif_dev);
+
+	viif_dev->irq_enabled = true;
+	/* Make sure the IRQ handler will see the flag change */
+	mb();
+
+	/* VSYNC mask setting of MAIN unit */
+	viif_capture_write(viif_dev, REG_INT_M_SYNC_MASK, MASK_INT_M_SYNC_MASK_SET);
+
+	/* STATUS error mask setting of MAIN unit */
+	viif_capture_write(viif_dev, REG_INT_M_MASK, MASK_INT_M_DELAY_INT_ERROR);
+
+	/* VSYNC mask settings of SUB unit */
+	viif_capture_write(viif_dev, REG_INT_S_SYNC_MASK, MASK_INT_S_SYNC_MASK_SET);
+
+	/* STATUS error mask setting(unmask) of SUB unit */
+	viif_capture_write(viif_dev, REG_INT_S_MASK,
+			   MASK_INT_S_RESERVED_SET | MASK_INT_S_DELAY_INT_ERROR);
+
+	return 0;
+}
+
+static const struct dev_pm_ops visconti_viif_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+	RUNTIME_PM_OPS(visconti_viif_runtime_suspend, visconti_viif_runtime_resume, NULL)
+};
+
+static struct platform_driver visconti_viif_driver = {
+	.probe = visconti_viif_probe,
+	.remove = visconti_viif_remove,
+	.driver = {
+		.name = "visconti_viif",
+		.of_match_table = visconti_viif_of_table,
+		.pm = pm_ptr(&visconti_viif_pm_ops),
+	},
+};
+
+module_platform_driver(visconti_viif_driver);
+
+MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
+MODULE_DESCRIPTION("Toshiba Visconti Video Input driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/toshiba/visconti/viif.h b/drivers/media/platform/toshiba/visconti/viif.h
new file mode 100644
index 000000000000..d720ea8bd8d9
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif.h
@@ -0,0 +1,379 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_H__
+#define __VIIF_H__
+
+#include <linux/visconti_viif.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define VIIF_DRIVER_NAME "visconti-viif"
+
+#define VIIF_ISP_REGBUF_0 0
+#define VIIF_L2ISP_POST_0 0
+#define VIIF_L2ISP_POST_1 1
+#define VIIF_MAX_POST_NUM 2U
+
+#define VIIF_CAPTURE_PAD_SINK 0
+
+#define VIIF_RESIZER_PAD_SINK 0
+#define VIIF_RESIZER_PAD_SRC  1
+#define VIIF_RESIZER_PAD_NUM  2
+
+#define VIIF_ISP_PAD_SINK_VIDEO	 0
+#define VIIF_ISP_PAD_SRC_PATH0	 1
+#define VIIF_ISP_PAD_SRC_PATH1	 2
+#define VIIF_ISP_PAD_SRC_PATH2	 3
+#define VIIF_ISP_PAD_SINK_PARAMS 4
+#define VIIF_ISP_PAD_SRC_STATS	 5
+#define VIIF_ISP_PAD_NUM	 6
+
+#define VIIF_PARAMS_PAD_SRC 0
+#define VIIF_PARAMS_PAD_NUM 1
+
+#define VIIF_STATS_PAD_SINK 0
+#define VIIF_STATS_PAD_NUM  1
+
+#define CAPTURE_PATH_MAIN_POST0 0
+#define CAPTURE_PATH_MAIN_POST1 1
+#define CAPTURE_PATH_SUB	2
+
+#define RESIZER_PATH_MAIN_POST0 0
+#define RESIZER_PATH_MAIN_POST1 1
+
+#define VIIF_DPC_TABLE_BYTES	   8192
+#define VIIF_LSC_TABLE_BYTES	   1536
+#define VIIF_UNDIST_TABLE_BYTES	   8192
+#define VIIF_L2_GAMMA_TABLE_BYTES  512
+#define VIIF_L2_GAMMA_TABLE_CH_NUM 6
+
+#define VIIF_NUM_IRQS 2
+
+/* The system clock (500MHz fixed) */
+/* this should be retrieved dynamically when the clock driver is implemented */
+#define VIIF_SYS_CLK 500000UL
+
+enum viif_output_color_mode {
+	VIIF_COLOR_Y_G = 0,
+	VIIF_COLOR_U_B = 1U,
+	VIIF_COLOR_V_R = 2U,
+	VIIF_COLOR_YUV_RGB = 4U
+};
+
+/**
+ * struct viif_out_process - configuration of output process of MAIN unit and L2ISP
+ * @half_scale: true to enable half scaling
+ * @select_color: viif_output_color_mode "select output color"
+ * @alpha: alpha value used in case of ARGB8888 output. Range: [0..255]
+ */
+struct viif_out_process {
+	bool half_scale;
+	enum viif_output_color_mode select_color;
+	u8 alpha;
+};
+
+/**
+ * struct viif_fmt - description of supported output image format
+ * @fourcc: V4L2 fourcc format ID
+ * @bpp: bits per pixel for each plane
+ * @num_planes: number of planes in a image
+ * @colorspace: colorspace ID
+ * @pitch_align: alignment constraint of pitch
+ */
+struct viif_fmt {
+	u32 fourcc;
+	u8 bpp[3];
+	u8 num_planes;
+	u32 colorspace;
+	u32 pitch_align;
+};
+
+/*
+ * struct viif_table_area - table for ISP features.
+ *
+ * The memory block for this structure must be allocated with dma_alloc_wc()
+ * so that the allocated block will be physically continuous.
+ */
+struct viif_table_area {
+	/* L1ISP DPC */
+	u32 dpc_table_h[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	u32 dpc_table_m[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	u32 dpc_table_l[VIIF_DPC_TABLE_BYTES / sizeof(u32)];
+	/* L1ISP LSC */
+	u16 lsc_table_gr[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_r[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_b[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	u16 lsc_table_gb[VIIF_LSC_TABLE_BYTES / sizeof(u16)];
+	/* L2ISP UNDIST */
+	u32 undist_write_g[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_b[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_g[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	u32 undist_read_r[VIIF_UNDIST_TABLE_BYTES / sizeof(u32)];
+	/* L2ISP GAMMA */
+	u16 l2_gamma_table[VIIF_MAX_POST_NUM][VIIF_L2_GAMMA_TABLE_CH_NUM]
+			  [VIIF_L2_GAMMA_TABLE_BYTES / sizeof(u16)];
+};
+
+/**
+ * struct cap_dev - device node for capture device
+ * @pathid: 0 for MAIN POST0, 1 for MAIN POST1, 2 for SUB
+ * @vdev: video node
+ * @capture_pad: media pad
+ * @vlock: serialize ioctl to vb2_queue and video_device
+ * @vb2_vq: queue of buffers
+ * @buf_queue: list of available buffers
+ * @active: VDMAC will start writing to this buffer at the next VSYNC
+ * @dma_active: VDMAC will complete writing to this buffer at the next VSYNC
+ * @buf_cnt: number of queued buffers
+ * @sequence: total count of processed frames
+ * @buf_lock: serialize queue access (including ISR's)
+ * @v4l2_pix: current picture format (set by S_FMT)
+ * @out_format: output format for VDMAC
+ * @img_area: crop of output picture
+ * @out_process: output configuration
+ * @fmts: format supported by this capture device
+ * @fmt_size: sizeof fmts
+ * @viif_dev: reference to viif device
+ */
+struct cap_dev {
+	u32 pathid;
+	struct video_device vdev;
+	struct media_pad capture_pad;
+	struct mutex vlock; /*serialize ioctl to vb2_queue and video_device*/
+
+	/* vb2 queue, capture buffer list and active buffer pointer */
+	struct vb2_queue vb2_vq;
+	struct list_head buf_queue;
+	struct vb2_v4l2_buffer *active;
+	struct vb2_v4l2_buffer *dma_active;
+	int buf_cnt;
+	unsigned int sequence;
+	spinlock_t buf_lock; /* serialize queue access (including ISR's) */
+
+	/* current configuration of frame and pixel format */
+	struct v4l2_pix_format_mplane v4l2_pix;
+	unsigned int out_format;
+	struct v4l2_rect img_area;
+	struct viif_out_process out_process;
+
+	/* format supported by this cap device */
+	const struct viif_fmt *fmts;
+	int fmt_size;
+
+	struct viif_device *viif_dev;
+};
+
+/**
+ * struct params_dev - device node for ISP parameters
+ * @vdev: video node
+ * @params_pad: media pad
+ * @vlock: serialize ioctl to vb2_queue and video_device
+ * @vb2_vq: queue of buffers
+ * @params_queue: list of available buffers
+ * @params_lock: serialize params_queue
+ */
+struct params_dev {
+	struct video_device vdev;
+	struct media_pad params_pad;
+	struct mutex vlock; /*serialize ioctl to vb2_queue and video_device*/
+
+	struct vb2_queue vb2_vq;
+	struct list_head params_queue;
+	spinlock_t params_lock; /* serialize params_queue */
+};
+
+/**
+ * struct stats_dev - device node for ISP status
+ * @vdev: video node
+ * @stats_pad: media pad
+ * @vlock: serialize ioctl to vb2_queue and video_device
+ * @vb2_vq: queue of buffers
+ * @stats_queue: list of available buffers
+ * @stats_lock: serialize stats_queue
+ */
+struct stats_dev {
+	struct video_device vdev;
+	struct media_pad stats_pad;
+	struct mutex vlock; /*serialize ioctl to vb2_queue and video_device*/
+
+	struct vb2_queue vb2_vq;
+	struct list_head stats_queue;
+	spinlock_t stats_lock; /* serialize stats_queue */
+};
+
+/**
+ * struct resizer_subdev - device node for Resizer subdevice
+ * @pathid: 0 for MAIN POST0, 1 for MAIN POST1
+ * @sd: v4l2 subdevice
+ * @pads: media pad
+ * @viif_dev: reference to viif device
+ */
+struct resizer_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[VIIF_RESIZER_PAD_NUM];
+	struct viif_device *viif_dev;
+	u32 pathid;
+};
+
+/**
+ * struct isp_subdev - device node for ISP subdevice
+ * @sd: v4l2 subdevice
+ * @pads: media pad
+ * @viif_dev: reference to viif device
+ */
+struct isp_subdev {
+	struct v4l2_subdev sd;
+	struct media_pad pads[VIIF_ISP_PAD_NUM];
+	struct viif_device *viif_dev;
+};
+
+/**
+ * struct viif_l2_roi_path_info - crop information of main paths
+ * @roi_num:
+ *
+ * - 1: crops of MAIN POST0 and POST1 share the same ROI
+ * - 2: crops of MAIN POST0 and POST1 have independent ROIs
+ *
+ * @post_enable_flag: flag to enable corresponding main path
+ * @post_crop_x: left of crop rect for a POST
+ * @post_crop_y: top of crop rect for a POST
+ * @post_crop_w: width of crop rect for a POST
+ * @post_crop_h: height of crop rect for a POST
+ */
+struct viif_l2_roi_path_info {
+	u32 roi_num;
+	bool post_enable_flag[VIIF_MAX_POST_NUM];
+	u32 post_crop_x[VIIF_MAX_POST_NUM];
+	u32 post_crop_y[VIIF_MAX_POST_NUM];
+	u32 post_crop_w[VIIF_MAX_POST_NUM];
+	u32 post_crop_h[VIIF_MAX_POST_NUM];
+};
+
+/**
+ * struct viif_img_clk - relation between realtime duration and number of lines
+ * @pixel_clock: picture transfer clock frequency
+ * @htotal_size: width of picture including blanking period
+ *
+ * These values are used to convert realtime duration (such as HW specific setup time)
+ * into number of lines in a picture.
+ * See sysclk_to_numlines() called at the reconfiguration of L1ISP HDRC feature.
+ */
+struct viif_img_clk {
+	unsigned int pixel_clock;
+	unsigned int htotal_size;
+};
+
+/**
+ * struct viif_device - driver information of Visconti VIIF
+ * @dev: device
+ * @v4l2_dev: v4l2 device
+ * @media_dev: media device
+ * @pipe: media pipeline
+ * @masked_gamma_path: flag to ignore L2_GAMMA error just after capture error
+ * @notifier: async subdev notification helper
+ * @cap_post0: capture device for MAIN PATH 0
+ * @cap_post1: capture device for MAIN PATH 1
+ * @cap_sub: capture device for MAIN PATH 2
+ * @resizer_post0: resizer subdevice for PATH 0
+ * @resizer_post1: resizer subdevice for PATH 1
+ * @isp_subdev: ISP subdevice
+ * @params_dev: streaming device for ISP parameter
+ * @stats_dev: streaming device for ISP status
+ * @remote_sd: currently active remote (possibly sensor) subdevice
+ * @remote_num_lane: number of lanes for the currently active remote subdevice
+ * @stream_lock: serialize stream ON/OFF sequence
+ * @regbuf_lock: Serialize VIIF Register Buffer Access
+ * @l2_roi_path_info: crop information of main paths
+ * @img_clk: relation between realtime duration and number of lines
+ * @run_flag_main: flag to check if the stream is ON
+ * @capture_reg: HW capture registers
+ * @hwaif_reg: HW bus interface registers
+ * @mpu_reg: HW memory protection unit registers
+ * @irq: IRQ number
+ * @irq_enabled: true when interrupts can be handled correctly
+ * @tables: table for ISP features (virtual address)
+ * @tables_dma: table for ISP features (IOVA)
+ * @errflag_lock: serialize access to status_err
+ * @repflag_lock: serialize access to reported_err_main, reported_err_sub
+ * @status_err: error of Main path in a frame
+ * @reported_err_main: accumulated error flags for MAIN path
+ * @reported_err_sub: accumulated error flags for SUB path
+ */
+struct viif_device {
+	struct device *dev;
+	struct v4l2_device v4l2_dev;
+	struct media_device media_dev;
+	struct media_pipeline pipe;
+	u32 masked_gamma_path;
+
+	struct v4l2_async_notifier notifier;
+
+	struct cap_dev cap_post0;
+	struct cap_dev cap_post1;
+	struct cap_dev cap_sub;
+	struct resizer_subdev resizer_post0;
+	struct resizer_subdev resizer_post1;
+	struct isp_subdev isp_subdev;
+	struct params_dev params_dev;
+	struct stats_dev stats_dev;
+	struct v4l2_subdev *remote_sd;
+	unsigned int remote_num_lane;
+
+	/* stream_lock - Serialize stream ON/OFF sequence */
+	struct mutex stream_lock;
+
+	/* regbuf_lock - Serialize VIIF Register Buffer Access */
+	spinlock_t regbuf_lock;
+
+	struct viif_l2_roi_path_info l2_roi_path_info;
+	struct viif_img_clk img_clk;
+	bool run_flag_main;
+
+	void __iomem *capture_reg;
+	void __iomem *hwaif_reg;
+	void __iomem *mpu_reg;
+	unsigned int irq[VIIF_NUM_IRQS];
+
+	bool irq_enabled;
+
+	/* Memory region for tables referred by the HW */
+	struct viif_table_area *tables;
+	dma_addr_t tables_dma;
+
+	/* errflag_lock - serialize access to status_err */
+	spinlock_t errflag_lock;
+
+	/* repflag_lock - serialize access to reported_err_main, reported_err_sub */
+	spinlock_t repflag_lock;
+
+	/* Error flag checked at delayed vsync handler  */
+	u32 status_err;
+
+	/* Error flag checked at stats streaming interface */
+	u32 reported_err_main;
+	u32 reported_err_sub;
+};
+
+static inline void viif_capture_write(struct viif_device *viif_dev, unsigned int regid, u32 val)
+{
+	writel(val, viif_dev->capture_reg + regid);
+}
+
+static inline u32 viif_capture_read(struct viif_device *viif_dev, unsigned int regid)
+{
+	return readl(viif_dev->capture_reg + regid);
+}
+
+#endif /* __VIIF_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_capture.c b/drivers/media/platform/toshiba/visconti/viif_capture.c
new file mode 100644
index 000000000000..a7e51214f653
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_capture.c
@@ -0,0 +1,1285 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_capture.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+#include "viif_resizer.h"
+
+/* single plane for RGB/Grayscale types, 3 planes for YUV types */
+#define VIIF_MAX_PLANE_NUM 3
+
+/* maximum horizontal/vertical position/dimension of CROP with ISP */
+#define VIIF_CROP_MAX_X_ISP 8062U
+#define VIIF_CROP_MAX_Y_ISP 3966U
+#define VIIF_CROP_MAX_W_ISP 8190U
+#define VIIF_CROP_MAX_H_ISP 4094U
+
+/* minimum horizontal/vertical dimension of CROP */
+#define VIIF_CROP_MIN_W 128U
+#define VIIF_CROP_MIN_H 128U
+
+/* maximum output size with ISP */
+#define VIIF_MAX_OUTPUT_IMG_WIDTH_ISP  5760U
+#define VIIF_MAX_OUTPUT_IMG_HEIGHT_ISP 3240U
+#define VIIF_MAX_PITCH_ISP	       32704U
+
+/* minimum output size */
+#define VIIF_MIN_OUTPUT_IMG_WIDTH  128U
+#define VIIF_MIN_OUTPUT_IMG_HEIGHT 128U
+
+/* DMA settings for SUB path */
+#define VDMAC_SRAM_BASE_ADDR_W03 0x440U
+#define SRAM_SIZE_W_PORT	 0x200
+
+enum viif_color_format {
+	VIIF_YCBCR422_8_PACKED = 0,
+	VIIF_RGB888_PACKED = 1U,
+	VIIF_ARGB8888_PACKED = 3U,
+	VIIF_YCBCR422_8_PLANAR = 8U,
+	VIIF_RGB888_YCBCR444_8_PLANAR = 9U,
+	VIIF_ONE_COLOR_8 = 11U,
+	VIIF_YCBCR422_16_PLANAR = 12U,
+	VIIF_RGB161616_YCBCR444_16_PLANAR = 13U,
+	VIIF_ONE_COLOR_16 = 15U
+};
+
+/**
+ * struct viif_csc_param - color conversion information
+ * @r_cr_in_offset: input offset of R/Cr
+ * @g_y_in_offset: input offset of G/Y
+ * @b_cb_in_offset: input offset of B/Cb
+ * @coef: coefficient of matrix.
+ * @r_cr_out_offset: output offset of R/Cr
+ * @g_y_out_offset: output offset of G/Y
+ * @b_cb_out_offset: output offset of B/Cb
+ *
+ * Range of parameters is:
+ *
+ * - {r_cr,g_y,b_cb}_{in,out}_offset
+ *
+ *   - Range: [0x0..0x1ffff]
+ *
+ * - coef
+ *
+ *   - Range: [0x0..0xffff]
+ *   - [0] : c00(YG_YG), [1] : c01(UB_YG), [2] : c02(VR_YG),
+ *   - [3] : c10(YG_UB), [4] : c11(UB_UB), [5] : c12(VR_UB),
+ *   - [6] : c20(YG_VR), [7] : c21(UB_VR), [8] : c22(VR_VR)
+ */
+struct viif_csc_param {
+	u32 r_cr_in_offset;
+	u32 g_y_in_offset;
+	u32 b_cb_in_offset;
+	u32 coef[9];
+	u32 r_cr_out_offset;
+	u32 g_y_out_offset;
+	u32 b_cb_out_offset;
+};
+
+/**
+ * struct viif_pixelmap - pixelmap information
+ * @pmap_dma: start address of pixel data(DMA address). 4byte alignment.
+ * @pitch: pitch size of pixel map [unit: byte]
+ *
+ * Condition of pitch in case of L2ISP output is as below.
+ *
+ * * max: 32704
+ * * min: max (active width of image * k / r, 128)
+ * * alignment: 64
+ *
+ * Condition of pitch in the other cases is as below.
+ *
+ * * max: 65536
+ * * min: active width of image * k / r
+ * * alignment: 4
+ *
+ * k is the size of 1 pixel and the value is as below.
+ *
+ * * VIIF_YCBCR422_8_PACKED: 2
+ * * VIIF_RGB888_PACKED: 3
+ * * VIIF_ARGB8888_PACKED: 4
+ * * VIIF_YCBCR422_8_PLANAR: 1
+ * * VIIF_RGB888_YCBCR444_8_PLANAR: 1
+ * * VIIF_ONE_COLOR_8: 1
+ * * VIIF_YCBCR422_16_PLANAR: 2
+ * * VIIF_RGB161616_YCBCR444_16_PLANAR: 2
+ * * VIIF_ONE_COLOR_16: 2
+ *
+ * r is the correction factor for Cb or Cr of YCbCr422 planar and the value is as below.
+ *
+ * * YCbCr422 Cb-planar: 2
+ * * YCbCr422 Cr-planar: 2
+ * * others: 1
+ */
+struct viif_pixelmap {
+	dma_addr_t pmap_dma;
+	u32 pitch;
+};
+
+/**
+ * struct viif_img - image information
+ * @width: active width of image [unit: pixel]
+ * * Range: [128..5760](output from L2ISP)
+ * * Range: [128..4096](output from SUB unit)
+ * * The value should be even.
+ *
+ * @height: active height of image[line]
+ * * Range: [128..3240](output from L2ISP)
+ * * Range: [128..2160](output from SUB unit)
+ * * The value should be even.
+ *
+ * @num_planes: number of image planes for this image
+ *
+ * @format: viif_color_format "color format"
+ * * Below color formats are supported for input and output of MAIN unit
+ * * VIIF_YCBCR422_8_PACKED
+ * * VIIF_RGB888_PACKED
+ * * VIIF_ARGB8888_PACKED
+ * * VIIF_YCBCR422_8_PLANAR
+ * * VIIF_RGB888_YCBCR444_8_PLANAR
+ * * VIIF_ONE_COLOR_8
+ * * VIIF_YCBCR422_16_PLANAR
+ * * VIIF_RGB161616_YCBCR444_16_PLANAR
+ * * VIIF_ONE_COLOR_16
+ * * Below color formats are supported for output of SUB unit
+ * * VIIF_ONE_COLOR_8
+ * * VIIF_ONE_COLOR_16
+ *
+ * @pixelmap: pixelmap information
+ * * [0]: Y/G-planar, packed/Y/RAW
+ * * [1]: Cb/B-planar
+ * * [2]: Cr/R-planar
+ */
+struct viif_img {
+	u32 width;
+	u32 height;
+	u32 num_planes;
+	enum viif_color_format format;
+	struct viif_pixelmap pixelmap[VIIF_MAX_PLANE_NUM];
+};
+
+/*=============================================*/
+/* Low Layer Implementation */
+/*=============================================*/
+/**
+ * viif_l2_set_output_csc() - Set output color space conversion parameters of L2ISP
+ *
+ * @viif_dev: the VIIF device
+ * @post_id: POST ID. Range: [0..1]
+ * @param: Pointer to output color space conversion parameters of L2ISP
+ */
+static void viif_l2_set_output_csc(struct viif_device *viif_dev, u32 post_id,
+				   const struct viif_csc_param *param)
+{
+	/* disable csc matrix when param is NULL */
+	if (!param) {
+		viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB(post_id), 0);
+		return;
+	}
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG_OFFSETI(post_id),
+			   param->g_y_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[0]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[1]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[2]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_YG_OFFSETO(post_id),
+			   param->g_y_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB_OFFSETI(post_id),
+			   param->b_cb_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[3]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[4]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[5]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CB_OFFSETO(post_id),
+			   param->b_cb_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR_OFFSETI(post_id),
+			   param->r_cr_in_offset);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR1(post_id),
+			   FIELD_CSC_MTB_LOWER(param->coef[6]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR2(post_id),
+			   FIELD_CSC_MTB_UPPER(param->coef[7]) |
+				   FIELD_CSC_MTB_LOWER(param->coef[8]));
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB_CR_OFFSETO(post_id),
+			   param->r_cr_out_offset);
+
+	viif_capture_write(viif_dev, REG_L2_POST_X_CSC_MTB(post_id), 1);
+}
+
+/**
+ * viif_l2_set_img_transmission() - Set image transfer condition of L2ISP
+ *
+ * @viif_dev: the VIIF device
+ * @post_id: POST ID. Range: [0..1]
+ * @enable: set True to enable image transfer of MAIN unit.
+ * @src: Pointer to crop area information
+ * @out_process: Pointer to output process information
+ * @img: Pointer to output image information
+ *
+ * see also: #viif_l2_set_roi_path
+ */
+static void viif_l2_set_img_transmission(struct viif_device *viif_dev, u32 post_id, bool enable,
+					 const struct v4l2_rect *src,
+					 const struct viif_out_process *out_process,
+					 const struct viif_img *img)
+{
+	const struct viif_pixelmap *pm;
+
+	/* DISABLE: no DMA transmission setup, set minimum crop rectangle */
+	if (!enable) {
+		viif_dev->l2_roi_path_info.post_enable_flag[post_id] = false;
+		viif_dev->l2_roi_path_info.post_crop_x[post_id] = 0U;
+		viif_dev->l2_roi_path_info.post_crop_y[post_id] = 0U;
+		viif_dev->l2_roi_path_info.post_crop_w[post_id] = VIIF_CROP_MIN_W;
+		viif_dev->l2_roi_path_info.post_crop_h[post_id] = VIIF_CROP_MIN_H;
+		visconti_viif_l2_set_roi_path(viif_dev);
+
+		return;
+	}
+
+	pm = &img->pixelmap[0];
+	viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_G(post_id), (u32)pm->pmap_dma);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_G(post_id), pm->pitch);
+	if (img->num_planes == 3) {
+		pm = &img->pixelmap[1];
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_B(post_id), (u32)pm->pmap_dma);
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_B(post_id), pm->pitch);
+		pm = &img->pixelmap[2];
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_STADR_R(post_id), (u32)pm->pmap_dma);
+		viif_capture_write(viif_dev, REG_L2_POST_X_OUT_PITCH_R(post_id), pm->pitch);
+	}
+
+	/* Set CROP */
+	viif_capture_write(viif_dev, REG_L2_POST_X_CAP_OFFSET(post_id),
+			   (src->top << 16U) | src->left);
+	viif_capture_write(viif_dev, REG_L2_POST_X_CAP_SIZE(post_id),
+			   (src->height << 16U) | src->width);
+
+	/* Set output process */
+	viif_capture_write(viif_dev, REG_L2_POST_X_HALF_SCALE_EN(post_id),
+			   out_process->half_scale ? 1 : 0);
+	viif_capture_write(viif_dev, REG_L2_POST_X_C_SELECT(post_id), out_process->select_color);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OPORTALP(post_id), (u32)out_process->alpha);
+	viif_capture_write(viif_dev, REG_L2_POST_X_OPORTFMT(post_id), img->format);
+
+	/* Update ROI area and input to each POST */
+	viif_dev->l2_roi_path_info.post_enable_flag[post_id] = true;
+	viif_dev->l2_roi_path_info.post_crop_x[post_id] = src->left;
+	viif_dev->l2_roi_path_info.post_crop_y[post_id] = src->top;
+	viif_dev->l2_roi_path_info.post_crop_w[post_id] = src->width;
+	viif_dev->l2_roi_path_info.post_crop_h[post_id] = src->height;
+	visconti_viif_l2_set_roi_path(viif_dev);
+}
+
+/**
+ * viif_sub_set_img_transmission() - Set image transfer condition of SUB unit
+ *
+ * @viif_dev: the VIIF device
+ * @img: Pointer to output image information
+ */
+static void viif_sub_set_img_transmission(struct viif_device *viif_dev, const struct viif_img *img)
+{
+	dma_addr_t img_start_addr, img_end_addr;
+	u32 data_width, pitch, height;
+	u32 port_control;
+
+	/* disable VDMAC when img is NULL */
+	if (!img) {
+		viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 0);
+		port_control = ~((u32)1U << 3U) & viif_capture_read(viif_dev, REG_VDM_W_ENABLE);
+		viif_capture_write(viif_dev, REG_VDM_W_ENABLE, port_control);
+		return;
+	}
+
+	img_start_addr = (u32)img->pixelmap[0].pmap_dma;
+	pitch = img->pixelmap[0].pitch;
+	height = img->height;
+
+	if (img->format == VIIF_ONE_COLOR_8) {
+		data_width = 0U;
+		img_end_addr = img_start_addr + img->width - 1U;
+	} else {
+		/* VIIF_ONE_COLOR_16 */
+		data_width = 1U;
+		img_end_addr = img_start_addr + (img->width * 2U) - 1U;
+	}
+
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_SRAM_BASE(IDX_WPORT_SUB_IMG),
+			   VDMAC_SRAM_BASE_ADDR_W03);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_SRAM_SIZE(IDX_WPORT_SUB_IMG),
+			   SRAM_SIZE_W_PORT);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_STADR(IDX_WPORT_SUB_IMG),
+			   (u32)img_start_addr);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_ENDADR(IDX_WPORT_SUB_IMG),
+			   (u32)img_end_addr);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_HEIGHT(IDX_WPORT_SUB_IMG), height);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_PITCH(IDX_WPORT_SUB_IMG), pitch);
+	viif_capture_write(viif_dev, REG_VDM_WPORT_X_W_CFG0(IDX_WPORT_SUB_IMG), data_width << 8U);
+	port_control = BIT(3) | viif_capture_read(viif_dev, REG_VDM_W_ENABLE);
+	viif_capture_write(viif_dev, REG_VDM_W_ENABLE, port_control);
+	viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 1);
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+struct viif_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+};
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+	return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct cap_dev *video_drvdata_to_capdev(struct file *file)
+{
+	return (struct cap_dev *)video_drvdata(file);
+}
+
+static inline struct cap_dev *vb2queue_to_capdev(struct vb2_queue *vq)
+{
+	return (struct cap_dev *)vb2_get_drv_priv(vq);
+}
+
+/* ----- ISRs and VB2 Operations ----- */
+static void viif_set_img(struct cap_dev *cap_dev, struct vb2_buffer *vb)
+{
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct viif_img next_out_img;
+	int i;
+
+	next_out_img.width = pix->width;
+	next_out_img.height = pix->height;
+	next_out_img.format = cap_dev->out_format;
+	next_out_img.num_planes = pix->num_planes;
+
+	for (i = 0; i < pix->num_planes; i++) {
+		next_out_img.pixelmap[i].pitch = pix->plane_fmt[i].bytesperline;
+		next_out_img.pixelmap[i].pmap_dma = vb2_dma_contig_plane_dma_addr(vb, i);
+	}
+
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		guard(spinlock)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+		viif_l2_set_img_transmission(viif_dev, VIIF_L2ISP_POST_0, true, &cap_dev->img_area,
+					     &cap_dev->out_process, &next_out_img);
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		guard(spinlock)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+		viif_l2_set_img_transmission(viif_dev, VIIF_L2ISP_POST_1, true, &cap_dev->img_area,
+					     &cap_dev->out_process, &next_out_img);
+	} else if (cap_dev->pathid == CAPTURE_PATH_SUB) {
+		guard(spinlock)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+		viif_sub_set_img_transmission(viif_dev, &next_out_img);
+	}
+}
+
+/*
+ * viif_capture_switch_buffer() is called from interrupt service routine
+ * triggered by VSync with some fixed delay.
+ * The function may switch DMA target buffer by calling viif_set_img().
+ * The VIIF DMA HW captures the destination address at next VSync
+ * and completes transfer at one more after.
+ * Therefore, filled buffer is available at the one after next ISR.
+ *
+ * To avoid DMA HW getting stuck, we always need to set valid destination address.
+ * If a prepared buffer is not available, we reuse the buffer currently being transferred to.
+ *
+ * The cap_dev structure has two pointers and a queue to handle video buffers;
+ + Description of each item at the entry of this function:
+ * * buf_queue:  holds prepared buffers, set by vb2_queue()
+ * * active:     pointing at address captured (and to be filled) by DMA HW
+ * * dma_active: pointing at buffer filled by DMA HW
+ *
+ * Rules to update items:
+ * * when buf_queue is not empty, "active" buffer goes "dma_active"
+ * * when buf_queue is empty:
+ *   * "active" buffer stays the same (DMA HW fills the same buffer for coming two frames)
+ *   * "dma_active" gets NULL (filled buffer will be reused; should not go "DONE" at next ISR)
+ *
+ * Simulation:
+ * | buf_queue   | active  | dma_active | note |
+ * | X           | NULL    | NULL       |      |
+ * <QBUF BUF0>
+ * | X           | BUF0    | NULL       | BUF0 stays |
+ * | X           | BUF0    | NULL       | BUF0 stays |
+ * <QBUF BUF1>
+ * <QBUF BUF2>
+ * | BUF2 BUF1   | BUF0    | NULL       |      |
+ * | BUF2        | BUF1    | BUF0       | BUF0 goes DONE |
+ * | X           | BUF2    | BUF1       | BUF1 goes DONE, BUF2 stays |
+ * | X           | BUF2    | NULL       | BUF2 stays |
+ */
+void visconti_viif_capture_switch_buffer(struct cap_dev *cap_dev, u32 status_err,
+					 u32 l2_transfer_status, u64 timestamp)
+{
+	guard(spinlock)(&cap_dev->buf_lock);
+
+	if (cap_dev->dma_active) {
+		/* DMA has completed and another framebuffer instance is set */
+		struct vb2_v4l2_buffer *vbuf = cap_dev->dma_active;
+		enum vb2_buffer_state state;
+
+		cap_dev->buf_cnt--;
+		vbuf->vb2_buf.timestamp = timestamp;
+		vbuf->sequence = cap_dev->sequence++;
+		vbuf->field = V4L2_FIELD_NONE;
+		if (status_err || l2_transfer_status)
+			state = VB2_BUF_STATE_ERROR;
+		else
+			state = VB2_BUF_STATE_DONE;
+
+		vb2_buffer_done(&vbuf->vb2_buf, state);
+	}
+
+	/* QUEUE pop to register an instance as next DMA target; if empty, reuse current instance */
+	if (!list_empty(&cap_dev->buf_queue)) {
+		struct viif_buffer *buf =
+			list_entry(cap_dev->buf_queue.next, struct viif_buffer, queue);
+		list_del_init(&buf->queue);
+		viif_set_img(cap_dev, &buf->vb.vb2_buf);
+		cap_dev->dma_active = cap_dev->active;
+		cap_dev->active = &buf->vb;
+	} else {
+		cap_dev->dma_active = NULL;
+	}
+}
+
+/* --- Capture buffer control --- */
+static int viif_vb2_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes,
+			  unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	unsigned int i;
+
+	/* num_planes is set: just check plane sizes. */
+	if (*num_planes) {
+		for (i = 0; i < pix->num_planes; i++)
+			if (sizes[i] < pix->plane_fmt[i].sizeimage)
+				return -EINVAL;
+
+		return 0;
+	}
+
+	/* num_planes not set: called from REQBUFS, just set plane sizes. */
+	*num_planes = pix->num_planes;
+	for (i = 0; i < pix->num_planes; i++)
+		sizes[i] = pix->plane_fmt[i].sizeimage;
+
+	cap_dev->buf_cnt = 0;
+
+	return 0;
+}
+
+static void viif_vb2_queue(struct vb2_buffer *vb)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct viif_buffer *buf = vb2_to_viif(vbuf);
+
+	guard(spinlock_irqsave)(&cap_dev->buf_lock);
+
+	list_add_tail(&buf->queue, &cap_dev->buf_queue);
+	cap_dev->buf_cnt++;
+}
+
+static int viif_vb2_prepare(struct vb2_buffer *vb)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vb->vb2_queue);
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	unsigned int i;
+
+	for (i = 0; i < pix->num_planes; i++) {
+		if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) {
+			dev_info(viif_dev->dev, "Plane size too small (%lu < %u)\n",
+				 vb2_plane_size(vb, i), pix->plane_fmt[i].sizeimage);
+			return -EINVAL;
+		}
+
+		vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage);
+	}
+	return 0;
+}
+
+static void viif_return_all_buffers(struct cap_dev *cap_dev, enum vb2_buffer_state state)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct viif_buffer *buf;
+
+	guard(spinlock_irqsave)(&cap_dev->buf_lock);
+
+	/* buffer control */
+	if (cap_dev->active) {
+		vb2_buffer_done(&cap_dev->active->vb2_buf, state);
+		cap_dev->buf_cnt--;
+		cap_dev->active = NULL;
+	}
+	if (cap_dev->dma_active) {
+		vb2_buffer_done(&cap_dev->dma_active->vb2_buf, state);
+		cap_dev->buf_cnt--;
+		cap_dev->dma_active = NULL;
+	}
+
+	/* Release all queued buffers. */
+	list_for_each_entry(buf, &cap_dev->buf_queue, queue) {
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+		cap_dev->buf_cnt--;
+	}
+	INIT_LIST_HEAD(&cap_dev->buf_queue);
+	if (cap_dev->buf_cnt)
+		dev_err(viif_dev->dev, "Buffer count error %d\n", cap_dev->buf_cnt);
+}
+
+static int viif_l2_set_format(struct cap_dev *cap_dev);
+static const struct viif_fmt *get_viif_fmt_from_fourcc(struct cap_dev *cap_dev,
+						       unsigned int fourcc);
+
+static int viif_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+	int ret = 0;
+
+	guard(mutex)(&viif_dev->stream_lock);
+
+	/* note that pipe is shared among paths; see pipe.streaming_count member variable */
+	ret = video_device_pipeline_start(&cap_dev->vdev, &viif_dev->pipe);
+	if (ret) {
+		dev_err(viif_dev->dev, "start pipeline failed %d\n", ret);
+		return ret;
+	}
+
+	ret = pm_runtime_resume_and_get(viif_dev->dev);
+	if (ret) {
+		dev_err(viif_dev->dev, "failed to power on %d\n", ret);
+		goto release_pipe;
+	}
+
+	/* buffer control */
+	cap_dev->sequence = 0;
+
+	/* Currently, we assume that path0 (MAIN POST0) is enabled first and disabled last */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		ret = visconti_viif_isp_main_set_unit(viif_dev);
+		if (ret) {
+			dev_err(viif_dev->dev, "Setting up main path0 L1ISP failed %d\n", ret);
+			goto config_path_end;
+		}
+		ret = viif_l2_set_format(cap_dev);
+		if (ret) {
+			dev_err(viif_dev->dev, "Setting up main path0 L2VDM failed %d\n", ret);
+			goto config_path_end;
+		}
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		ret = viif_l2_set_format(cap_dev);
+		if (ret) {
+			dev_err(viif_dev->dev, "Setting up main path1 L2VDM failed %d\n", ret);
+			goto config_path_end;
+		}
+	} else {
+		cap_dev->out_format =
+			get_viif_fmt_from_fourcc(cap_dev, cap_dev->v4l2_pix.pixelformat)->bpp[0] >
+					8 ?
+				VIIF_ONE_COLOR_16 :
+				VIIF_ONE_COLOR_8;
+		ret = visconti_viif_isp_sub_set_unit(viif_dev);
+		if (ret) {
+			dev_err(viif_dev->dev, "Setting up sub path failed %d\n", ret);
+			goto config_path_end;
+		}
+	}
+
+	remote_pad = media_pad_remote_pad_first(&cap_dev->vdev.entity.pads[0]);
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, BIT(0));
+	if (ret)
+		dev_err(viif_dev->dev, "Start resizer/isp subdevice stream failed. %d\n", ret);
+
+config_path_end:
+	if (ret) {
+		viif_return_all_buffers(cap_dev, VB2_BUF_STATE_QUEUED);
+		pm_runtime_put(viif_dev->dev);
+		ret = -EPIPE;
+	}
+release_pipe:
+	if (ret)
+		video_device_pipeline_stop(&cap_dev->vdev);
+	return ret;
+}
+
+static void viif_stop_streaming(struct vb2_queue *vq)
+{
+	struct cap_dev *cap_dev = vb2queue_to_capdev(vq);
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+	int ret;
+
+	guard(mutex)(&viif_dev->stream_lock);
+
+	remote_pad = media_pad_remote_pad_first(&cap_dev->vdev.entity.pads[0]);
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, BIT(0));
+	if (ret)
+		dev_err(viif_dev->dev, "Stop isp subdevice stream failed %d\n", ret);
+
+	ret = pm_runtime_put(viif_dev->dev);
+	if (ret)
+		dev_err(viif_dev->dev, "power down failed %d\n", ret);
+
+	viif_return_all_buffers(cap_dev, VB2_BUF_STATE_ERROR);
+	video_device_pipeline_stop(&cap_dev->vdev);
+}
+
+static const struct vb2_ops viif_vb2_ops = {
+	.queue_setup = viif_vb2_setup,
+	.buf_queue = viif_vb2_queue,
+	.buf_prepare = viif_vb2_prepare,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = viif_start_streaming,
+	.stop_streaming = viif_stop_streaming,
+};
+
+/* --- VIIF hardware settings --- */
+/* L2ISP output csc setting for YUV to RGB(ITU-R BT.709) */
+static const struct viif_csc_param viif_csc_yuv2rgb = {
+	.r_cr_in_offset = 0x18000,
+	.g_y_in_offset = 0x1f000,
+	.b_cb_in_offset = 0x18000,
+	.coef = {
+			[0] = 0x1000,
+			[1] = 0xfd12,
+			[2] = 0xf8ad,
+			[3] = 0x1000,
+			[4] = 0x1d07,
+			[5] = 0x0000,
+			[6] = 0x1000,
+			[7] = 0x0000,
+			[8] = 0x18a2,
+		},
+	.r_cr_out_offset = 0x1000,
+	.g_y_out_offset = 0x1000,
+	.b_cb_out_offset = 0x1000,
+};
+
+/* L2ISP output csc setting for RGB to YUV(ITU-R BT.709) */
+static const struct viif_csc_param viif_csc_rgb2yuv = {
+	.r_cr_in_offset = 0x1f000,
+	.g_y_in_offset = 0x1f000,
+	.b_cb_in_offset = 0x1f000,
+	.coef = {
+			[0] = 0x0b71,
+			[1] = 0x0128,
+			[2] = 0x0367,
+			[3] = 0xf9b1,
+			[4] = 0x082f,
+			[5] = 0xfe20,
+			[6] = 0xf891,
+			[7] = 0xff40,
+			[8] = 0x082f,
+		},
+	.r_cr_out_offset = 0x8000,
+	.g_y_out_offset = 0x1000,
+	.b_cb_out_offset = 0x8000,
+};
+
+static int viif_l2_set_format(struct cap_dev *cap_dev)
+{
+	struct v4l2_pix_format_mplane *pix = &cap_dev->v4l2_pix;
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	const struct viif_csc_param *csc_param = NULL;
+	struct v4l2_subdev_selection sel = {
+		.target = V4L2_SEL_TGT_CROP,
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = VIIF_RESIZER_PAD_SRC,
+	};
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = VIIF_RESIZER_PAD_SRC,
+	};
+	bool inp_is_rgb = false;
+	bool out_is_rgb = false;
+	struct v4l2_subdev *sd;
+	u32 postid;
+	int ret;
+
+	/* check path id */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		sd = &viif_dev->resizer_post0.sd;
+		postid = VIIF_L2ISP_POST_0;
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		sd = &viif_dev->resizer_post1.sd;
+		postid = VIIF_L2ISP_POST_1;
+	} else {
+		return -EINVAL;
+	}
+
+	cap_dev->out_process.half_scale = false;
+	cap_dev->out_process.select_color = VIIF_COLOR_YUV_RGB;
+	cap_dev->out_process.alpha = 0;
+
+	ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sel);
+	if (ret) {
+		cap_dev->img_area.left = 0;
+		cap_dev->img_area.top = 0;
+		cap_dev->img_area.width = pix->width;
+		cap_dev->img_area.height = pix->height;
+	} else {
+		cap_dev->img_area.left = sel.r.left;
+		cap_dev->img_area.top = sel.r.top;
+		cap_dev->img_area.width = sel.r.width;
+		cap_dev->img_area.height = sel.r.height;
+	}
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+	if (!ret)
+		inp_is_rgb = (fmt.format.code == MEDIA_BUS_FMT_RGB888_1X24);
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_RGB24:
+		cap_dev->out_format = VIIF_RGB888_PACKED;
+		out_is_rgb = true;
+		break;
+	case V4L2_PIX_FMT_ABGR32:
+		cap_dev->out_format = VIIF_ARGB8888_PACKED;
+		cap_dev->out_process.alpha = 0xff;
+		out_is_rgb = true;
+		break;
+	case V4L2_PIX_FMT_YUV422M:
+		cap_dev->out_format = VIIF_YCBCR422_8_PLANAR;
+		break;
+	case V4L2_PIX_FMT_YUV444M:
+		cap_dev->out_format = VIIF_RGB888_YCBCR444_8_PLANAR;
+		break;
+	case V4L2_PIX_FMT_Y16:
+		cap_dev->out_format = VIIF_ONE_COLOR_16;
+		cap_dev->out_process.select_color = VIIF_COLOR_Y_G;
+		break;
+	}
+
+	if (!inp_is_rgb && out_is_rgb)
+		csc_param = &viif_csc_yuv2rgb; /* YUV -> RGB */
+	else if (inp_is_rgb && !out_is_rgb)
+		csc_param = &viif_csc_rgb2yuv; /* RGB -> YUV */
+
+	viif_l2_set_output_csc(viif_dev, postid, csc_param);
+
+	return 0;
+}
+
+/* --- IOCTL Operations --- */
+static const struct viif_fmt viif_capture_fmt_list_mainpath[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.bpp = { 24, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 384,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.bpp = { 32, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 512,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422M,
+		.bpp = { 8, 4, 4 },
+		.num_planes = 3,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV444M,
+		.bpp = { 8, 8, 8 },
+		.num_planes = 3,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_Y16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_REC709,
+		.pitch_align = 128,
+	},
+};
+
+static const struct viif_fmt viif_capture_fmt_list_subpath[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB8,
+		.bpp = { 8, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SGRBG8,
+		.bpp = { 8, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SGBRG8,
+		.bpp = { 8, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SBGGR8,
+		.bpp = { 8, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SRGGB16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SGRBG16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SGBRG16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_SBGGR16,
+		.bpp = { 16, 0, 0 },
+		.num_planes = 1,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.pitch_align = 256,
+	},
+};
+
+static const struct viif_fmt *get_viif_fmt_from_fourcc(struct cap_dev *cap_dev, unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < cap_dev->fmt_size; i++) {
+		const struct viif_fmt *fmt = &cap_dev->fmts[i];
+
+		if (fmt->fourcc == fourcc)
+			return fmt;
+	}
+	return NULL;
+}
+
+static u32 get_pixelformat_from_fourcc(struct cap_dev *cap_dev, unsigned int fourcc)
+{
+	const struct viif_fmt *fmt = get_viif_fmt_from_fourcc(cap_dev, fourcc);
+
+	return fmt ? fmt->fourcc : cap_dev->fmts[0].fourcc;
+}
+
+static u32 get_pixelformat_from_mbus_code(struct cap_dev *cap_dev, unsigned int mbus_code)
+{
+	unsigned int fourcc;
+
+	switch (mbus_code) {
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		fourcc = V4L2_PIX_FMT_SRGGB8;
+		break;
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		fourcc = V4L2_PIX_FMT_SRGGB16;
+		break;
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+		fourcc = V4L2_PIX_FMT_SGRBG8;
+		break;
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+		fourcc = V4L2_PIX_FMT_SGRBG16;
+		break;
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+		fourcc = V4L2_PIX_FMT_SGBRG8;
+		break;
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+		fourcc = V4L2_PIX_FMT_SGBRG16;
+		break;
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+		fourcc = V4L2_PIX_FMT_SBGGR8;
+		break;
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		fourcc = V4L2_PIX_FMT_SBGGR16;
+		break;
+	default:
+		return cap_dev->fmts[0].fourcc;
+	}
+
+	return get_pixelformat_from_fourcc(cap_dev, fourcc);
+}
+
+static void viif_calc_plane_sizes(struct cap_dev *cap_dev, struct v4l2_pix_format_mplane *pix)
+{
+	const struct viif_fmt *viif_fmt = get_viif_fmt_from_fourcc(cap_dev, pix->pixelformat);
+	unsigned int i;
+
+	for (i = 0; i < viif_fmt->num_planes; i++) {
+		struct v4l2_plane_pix_format *plane_i = &pix->plane_fmt[i];
+		unsigned int bpl;
+
+		memset(plane_i, 0, sizeof(*plane_i));
+		bpl = roundup(pix->width * viif_fmt->bpp[i] / 8, viif_fmt->pitch_align);
+
+		plane_i->bytesperline = bpl;
+		plane_i->sizeimage = pix->height * bpl;
+	}
+	pix->num_planes = viif_fmt->num_planes;
+}
+
+static int viif_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+	strscpy(cap->card, cap_dev->vdev.name, sizeof(cap->card));
+
+	return 0;
+}
+
+static int viif_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	if (f->index >= cap_dev->fmt_size)
+		return -EINVAL;
+
+	f->pixelformat = cap_dev->fmts[f->index].fourcc;
+	return 0;
+}
+
+static void viif_try_fmt(struct cap_dev *cap_dev, struct v4l2_pix_format_mplane *pix)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_subdev_format format = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_subdev *sd;
+	int ret;
+
+	/* check path id */
+	if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST0) {
+		sd = &viif_dev->resizer_post0.sd;
+		format.pad = VIIF_RESIZER_PAD_SRC;
+	} else if (cap_dev->pathid == CAPTURE_PATH_MAIN_POST1) {
+		sd = &viif_dev->resizer_post1.sd;
+		format.pad = VIIF_RESIZER_PAD_SRC;
+	} else {
+		sd = &viif_dev->isp_subdev.sd;
+		format.pad = VIIF_ISP_PAD_SRC_PATH2;
+	}
+
+	pix->field = V4L2_FIELD_NONE;
+	pix->colorspace = V4L2_COLORSPACE_DEFAULT;
+	pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	pix->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
+	if (ret) {
+		/* minimal default format */
+		pix->width = VIIF_MIN_OUTPUT_IMG_WIDTH;
+		pix->height = VIIF_MIN_OUTPUT_IMG_HEIGHT;
+		pix->pixelformat = (cap_dev->pathid == CAPTURE_PATH_SUB) ? V4L2_PIX_FMT_SRGGB8 :
+									   V4L2_PIX_FMT_RGB24;
+		viif_calc_plane_sizes(cap_dev, pix);
+		return;
+	}
+
+	pix->width = format.format.width;
+	pix->height = format.format.height;
+
+	/* check output format */
+	if (cap_dev->pathid == CAPTURE_PATH_SUB)
+		pix->pixelformat = get_pixelformat_from_mbus_code(cap_dev, format.format.code);
+	else
+		pix->pixelformat = get_pixelformat_from_fourcc(cap_dev, pix->pixelformat);
+
+	/* update derived parameters, such as bpp */
+	viif_calc_plane_sizes(cap_dev, pix);
+}
+
+static int viif_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	viif_try_fmt(cap_dev, &f->fmt.pix_mp);
+	return 0;
+}
+
+static int viif_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	if (vb2_is_busy(&cap_dev->vb2_vq))
+		return -EBUSY;
+
+	viif_try_fmt(cap_dev, &f->fmt.pix_mp);
+	cap_dev->v4l2_pix = f->fmt.pix_mp;
+
+	return 0;
+}
+
+static int viif_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	f->fmt.pix_mp = cap_dev->v4l2_pix;
+
+	return 0;
+}
+
+static int viif_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+	struct cap_dev *cap_dev = video_drvdata_to_capdev(file);
+
+	if (fsize->index)
+		return -EINVAL;
+
+	if (!get_viif_fmt_from_fourcc(cap_dev, fsize->pixel_format))
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+	fsize->stepwise.min_width = VIIF_MIN_OUTPUT_IMG_WIDTH;
+	fsize->stepwise.max_width = VIIF_MAX_OUTPUT_IMG_WIDTH_ISP;
+	fsize->stepwise.min_height = VIIF_MIN_OUTPUT_IMG_HEIGHT;
+	fsize->stepwise.max_height = VIIF_MAX_OUTPUT_IMG_HEIGHT_ISP;
+	fsize->stepwise.step_width = 1;
+	fsize->stepwise.step_height = 1;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_ioctl_ops = {
+	.vidioc_querycap = viif_querycap,
+
+	.vidioc_enum_fmt_vid_cap = viif_enum_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane = viif_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane = viif_s_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane = viif_g_fmt_vid_cap,
+
+	.vidioc_enum_framesizes = viif_enum_framesizes,
+
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+
+	.vidioc_log_status = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* --- File Operations --- */
+static const struct v4l2_pix_format_mplane pixm_default[3] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_RGB24,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	},
+	{
+		.pixelformat = V4L2_PIX_FMT_SRGGB8,
+		.width = 1920,
+		.height = 1080,
+		.field = V4L2_FIELD_NONE,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+	}
+};
+
+static const struct v4l2_file_operations viif_fops = {
+	.owner = THIS_MODULE,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vb2_fop_mmap,
+	.poll = vb2_fop_poll,
+};
+
+/* ----- media control callbacks ----- */
+static int viif_capture_link_validate(struct media_link *link)
+{
+	/* link validation at start-stream */
+	return 0;
+}
+
+static const struct media_entity_operations viif_media_ops = {
+	.link_validate = viif_capture_link_validate,
+};
+
+/* ----- register/remove capture device node ----- */
+static int visconti_viif_capture_register_node(struct cap_dev *cap_dev)
+{
+	struct viif_device *viif_dev = cap_dev->viif_dev;
+	struct v4l2_device *v4l2_dev = &viif_dev->v4l2_dev;
+	struct video_device *vdev = &cap_dev->vdev;
+	struct vb2_queue *q = &cap_dev->vb2_vq;
+	static const char *const node_name[] = {
+		"viif_capture_post0",
+		"viif_capture_post1",
+		"viif_capture_sub",
+	};
+	struct v4l2_pix_format_mplane pixm;
+	int ret;
+
+	INIT_LIST_HEAD(&cap_dev->buf_queue);
+
+	mutex_init(&cap_dev->vlock);
+	spin_lock_init(&cap_dev->buf_lock);
+
+	/* Initialize image format */
+	pixm = pixm_default[cap_dev->pathid];
+	viif_try_fmt(cap_dev, &pixm);
+	cap_dev->v4l2_pix = pixm;
+
+	/* Initialize vb2 queue. */
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->min_queued_buffers = 3;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->ops = &viif_vb2_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->drv_priv = cap_dev;
+	q->buf_struct_size = sizeof(struct viif_buffer);
+	q->lock = &cap_dev->vlock;
+	q->dev = viif_dev->v4l2_dev.dev;
+
+	ret = vb2_queue_init(q);
+	if (ret)
+		return ret;
+
+	/* Register the video device. */
+	strscpy(vdev->name, node_name[cap_dev->pathid], sizeof(vdev->name));
+	vdev->v4l2_dev = v4l2_dev;
+	vdev->lock = &cap_dev->vlock;
+	vdev->queue = &cap_dev->vb2_vq;
+	vdev->fops = &viif_fops;
+	vdev->ioctl_ops = &viif_ioctl_ops;
+	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
+	vdev->device_caps |= V4L2_CAP_IO_MC;
+	vdev->entity.ops = &viif_media_ops;
+	vdev->release = video_device_release_empty;
+	video_set_drvdata(vdev, cap_dev);
+	vdev->vfl_dir = VFL_DIR_RX;
+	cap_dev->capture_pad.flags = MEDIA_PAD_FL_SINK;
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret < 0) {
+		dev_err(v4l2_dev->dev, "video_register_device failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = media_entity_pads_init(&vdev->entity, 1, &cap_dev->capture_pad);
+	if (ret) {
+		video_unregister_device(vdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+int visconti_viif_capture_register(struct viif_device *viif_dev)
+{
+	int ret;
+
+	/* register MAIN POST0 (primary RGB)*/
+	viif_dev->cap_post0.pathid = CAPTURE_PATH_MAIN_POST0;
+	viif_dev->cap_post0.viif_dev = viif_dev;
+	viif_dev->cap_post0.fmts = viif_capture_fmt_list_mainpath;
+	viif_dev->cap_post0.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_mainpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_post0);
+	if (ret)
+		return ret;
+
+	/* register MAIN POST1 (additional RGB)*/
+	viif_dev->cap_post1.pathid = CAPTURE_PATH_MAIN_POST1;
+	viif_dev->cap_post1.viif_dev = viif_dev;
+	viif_dev->cap_post1.fmts = viif_capture_fmt_list_mainpath;
+	viif_dev->cap_post1.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_mainpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_post1);
+	if (ret)
+		return ret;
+
+	/* register SUB (RAW) */
+	viif_dev->cap_sub.pathid = CAPTURE_PATH_SUB;
+	viif_dev->cap_sub.viif_dev = viif_dev;
+	viif_dev->cap_sub.fmts = viif_capture_fmt_list_subpath;
+	viif_dev->cap_sub.fmt_size = ARRAY_SIZE(viif_capture_fmt_list_subpath);
+	ret = visconti_viif_capture_register_node(&viif_dev->cap_sub);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void visconti_viif_capture_unregister_node(struct cap_dev *cap_dev)
+{
+	media_entity_cleanup(&cap_dev->vdev.entity);
+	vb2_video_unregister_device(&cap_dev->vdev);
+	mutex_destroy(&cap_dev->vlock);
+}
+
+void visconti_viif_capture_unregister(struct viif_device *viif_dev)
+{
+	visconti_viif_capture_unregister_node(&viif_dev->cap_post0);
+	visconti_viif_capture_unregister_node(&viif_dev->cap_post1);
+	visconti_viif_capture_unregister_node(&viif_dev->cap_sub);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_capture.h b/drivers/media/platform/toshiba/visconti/viif_capture.h
new file mode 100644
index 000000000000..8587b1575278
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_capture.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_CAPTURE_H__
+#define __VIIF_CAPTURE_H__
+
+struct cap_dev;
+struct viif_device;
+struct viif_l2_roi_config;
+
+void visconti_viif_capture_switch_buffer(struct cap_dev *cap_dev, u32 status_err,
+					 u32 l2_transfer_status, u64 timestamp);
+
+int visconti_viif_capture_register(struct viif_device *viif_dev);
+void visconti_viif_capture_unregister(struct viif_device *viif_dev);
+
+#endif /* __VIIF_CAPTURE_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_common.c b/drivers/media/platform/toshiba/visconti/viif_common.c
new file mode 100644
index 000000000000..efee40e15cd4
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_common.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+
+/*=============================================*/
+/* Low level guards for registers */
+/*=============================================*/
+
+#define VIIF_L1_CRGBF_R_START_ADDR_LIMIT 0x0200U
+#define VIIF_L1_CRGBF_R_END_ADDR_LIMIT	 0x10bfU
+#define VIIF_L2_CRGBF_R_START_ADDR_LIMIT 0x1cU
+#define VIIF_L2_CRGBF_R_END_ADDR_LIMIT	 0x1fU
+
+/**
+ * hwd_viif_main_mask_vlatch() - Control Vlatch mask of MAIN unit
+ *
+ * @viif_dev: the VIIF device
+ * @enable: true to enable Vlatch mask of MAIN unit, false to disable
+ */
+static void hwd_viif_main_mask_vlatch(struct viif_device *viif_dev, bool enable)
+{
+	u32 val = enable ? MASK_IPORTM_VLATCH : 0;
+
+	viif_capture_write(viif_dev, REG_IPORTM0_LD, val);
+	viif_capture_write(viif_dev, REG_IPORTM1_LD, val);
+}
+
+/**
+ * hwd_viif_isp_set_regbuf_auto_transmission() - Set register buffer auto transmission
+ *
+ * @viif_dev: the VIIF device
+ */
+void hwd_viif_isp_set_regbuf_auto_transmission(struct viif_device *viif_dev)
+{
+	/* Set parameters for auto read transmission of register buffer */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_RBADDR, VIIF_L1_CRGBF_R_START_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_READDR, VIIF_L1_CRGBF_R_END_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_RBADDR, VIIF_L2_CRGBF_R_START_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_READDR, VIIF_L2_CRGBF_R_END_ADDR_LIMIT);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, VAL_L2_CRGBF_TRN_AUTO_READ_BANK0);
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, VAL_L1_CRGBF_TRN_AUTO_READ_BANK0);
+}
+
+/**
+ * hwd_viif_isp_disable_regbuf_auto_transmission() - Disable register buffer auto transmission
+ *
+ * @viif_dev: the VIIF device
+ */
+void hwd_viif_isp_disable_regbuf_auto_transmission(struct viif_device *viif_dev)
+{
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+}
+
+/**
+ * hwd_viif_isp_guard_start() - stop register auto update
+ *
+ * @viif_dev: the VIIF device
+ *
+ * This function call stops update of some hardware registers
+ * while the manual setup of VIIF, L1ISP registers is in progress.
+ *
+ * * regbuf control: load/store HW register (settings, status) values to backup SRAM.
+ * * vlatch control: copy timer-counter register value to status register.
+ */
+void hwd_viif_isp_guard_start(struct viif_device *viif_dev)
+{
+	hwd_viif_isp_disable_regbuf_auto_transmission(viif_dev);
+	ndelay(500);
+	hwd_viif_main_mask_vlatch(viif_dev, true);
+}
+
+/**
+ * hwd_viif_isp_guard_end() - restart register auto update
+ *
+ * @viif_dev: the VIIF device
+ *
+ * see also hwd_viif_isp_guard_start().
+ */
+void hwd_viif_isp_guard_end(struct viif_device *viif_dev)
+{
+	hwd_viif_main_mask_vlatch(viif_dev, false);
+	hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);
+}
+
+/*=============================================*/
+/* supported Visual formats */
+/*=============================================*/
+static const struct viif_mbus_format mbus_formats[] = {
+	{ .code = MEDIA_BUS_FMT_RGB888_1X24,
+	  .bpp = 24,
+	  .is_bayer = false,
+	  .rgb_out = true,
+	  .mipi_dt = MIPI_CSI2_DT_RGB888 },
+	{ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+	  .bpp = 16,
+	  .is_bayer = false,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_YUV422_8B },
+	{ .code = MEDIA_BUS_FMT_UYVY10_1X20,
+	  .bpp = 20,
+	  .is_bayer = false,
+	  .rgb_out = false,
+	  .mipi_dt = MIPI_CSI2_DT_YUV422_10B },
+	{ .code = MEDIA_BUS_FMT_RGB565_1X16,
+	  .bpp = 16,
+	  .is_bayer = false,
+	  .rgb_out = true,
+	  .mipi_dt = MIPI_CSI2_DT_RGB565 },
+
+	{ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+	  .bpp = 8,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_BGGR,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+	  .bpp = 8,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GBRG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+	  .bpp = 8,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GRBG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+	{ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+	  .bpp = 8,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_RGGB,
+	  .mipi_dt = MIPI_CSI2_DT_RAW8 },
+
+	{ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+	  .bpp = 10,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_BGGR,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+	  .bpp = 10,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GBRG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+	  .bpp = 10,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GRBG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+	{ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+	  .bpp = 10,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_RGGB,
+	  .mipi_dt = MIPI_CSI2_DT_RAW10 },
+
+	{ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+	  .bpp = 12,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_BGGR,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+	  .bpp = 12,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GBRG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+	  .bpp = 12,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GRBG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+	{ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+	  .bpp = 12,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_RGGB,
+	  .mipi_dt = MIPI_CSI2_DT_RAW12 },
+
+	{ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
+	  .bpp = 14,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_BGGR,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
+	  .bpp = 14,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GBRG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
+	  .bpp = 14,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_GRBG,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+	{ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
+	  .bpp = 14,
+	  .is_bayer = true,
+	  .rgb_out = false,
+	  .bayer_pattern = VAL_L1_SYSM_START_COLOR_RGGB,
+	  .mipi_dt = MIPI_CSI2_DT_RAW14 },
+};
+
+const struct viif_mbus_format *viif_mbus_format_from_code(unsigned int mbus_code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mbus_formats); i++)
+		if (mbus_formats[i].code == mbus_code)
+			return &mbus_formats[i];
+
+	return NULL;
+}
+
+const struct viif_mbus_format *viif_mbus_format_nth(unsigned int n)
+{
+	return (n < ARRAY_SIZE(mbus_formats)) ? &mbus_formats[n] : NULL;
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_common.h b/drivers/media/platform/toshiba/visconti/viif_common.h
new file mode 100644
index 000000000000..075361085011
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_COMMON_H__
+#define __VIIF_COMMON_H__
+
+#include "viif.h"
+
+/**
+ * struct viif_mbus_format - description of supported input format
+ *
+ * @code: V4L2 media bus format (coming from image sensor)
+ * @bpp: bits per pixel
+ * @mipi_dt: MIPI Datatype corresponding to code
+ * @bayer_pattern: ordering of bayer color filter
+ * @is_bayer: true when the format is bayer, false otherwise
+ * @rgb_out:
+ * * True: L1ISP output is RGB format
+ * * False: L1ISP output is YUV format
+ */
+struct viif_mbus_format {
+	unsigned int code;
+	unsigned int bpp;
+	unsigned int mipi_dt;
+	unsigned int bayer_pattern;
+	bool is_bayer;
+	bool rgb_out;
+};
+
+void hwd_viif_isp_set_regbuf_auto_transmission(struct viif_device *viif_dev);
+void hwd_viif_isp_disable_regbuf_auto_transmission(struct viif_device *viif_dev);
+void hwd_viif_isp_guard_start(struct viif_device *viif_dev);
+void hwd_viif_isp_guard_end(struct viif_device *viif_dev);
+
+DEFINE_GUARD(viif_isp, struct viif_device *, hwd_viif_isp_guard_start(_T),
+	     hwd_viif_isp_guard_end(_T))
+
+const struct viif_mbus_format *viif_mbus_format_from_code(unsigned int mbus_code);
+const struct viif_mbus_format *viif_mbus_format_nth(unsigned int n);
+
+#endif /* __VIIF_COMMON_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
new file mode 100644
index 000000000000..0bcc6bba9bf1
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -0,0 +1,909 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-rect.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+
+/* disable CSI2 capture at viif_mux_start() */
+#define VIIF_CSI2_NOT_CAPTURE -1
+
+/* validation at main_set_unit() and sub_set_unit() */
+/* picture size: [unit: pixel] */
+#define VIIF_MIN_HTOTAL_PIXEL 143U
+#define VIIF_MAX_HTOTAL_PIXEL 65535U
+
+/* pixel clock: [unit: kHz] */
+#define VIIF_MIN_PIXEL_CLOCK 3375U
+#define VIIF_MAX_PIXEL_CLOCK 600000U
+
+/* horizontal back porch size: [unit: system clock ticks] */
+#define VIIF_HBP_SYSCLK 10U
+
+/* num of pictures accepted by the ISP */
+#define VIIF_L1_INPUT_NUM_MIN 1U
+#define VIIF_L1_INPUT_NUM_MAX 3U
+
+/* active picture size: [unit: pixel] */
+#define VIIF_MIN_HACTIVE_PIXEL_W_L1ISP	640U
+#define VIIF_MAX_HACTIVE_PIXEL_W_L1ISP	3840U
+#define VIIF_MIN_HACTIVE_PIXEL_WO_L1ISP 128U
+#define VIIF_MAX_HACTIVE_PIXEL_WO_L1ISP 4096U
+
+/* picture vertical size: [unit: line] */
+#define VIIF_MIN_VTOTAL_LINE	       144U
+#define VIIF_MAX_VTOTAL_LINE	       16383U
+#define VIIF_MIN_VBP_LINE	       5U
+#define VIIF_MAX_VBP_LINE	       4095U
+#define VIIF_MIN_VACTIVE_LINE_WO_L1ISP 128U
+#define VIIF_MAX_VACTIVE_LINE_WO_L1ISP 2160U
+#define VIIF_MIN_VACTIVE_LINE_W_L1ISP  480U
+#define VIIF_MAX_VACTIVE_LINE_W_L1ISP  2160U
+
+/* internal operation latencies: [unit: system clock ticks]*/
+#define VIIF_TABLE_LOAD_TIME	24000UL
+#define VIIF_REGBUF_ACCESS_TIME 15360UL
+
+/* offset of Vsync delay: [unit: line] */
+#define VIIF_L1_DELAY_W_HDRC  31U
+#define VIIF_L1_DELAY_WO_HDRC 11U
+
+/* timeout definitions for viif_stop_mux() */
+/*
+ * wait time for force abort to complete (max 1line time = 1228.8 us)
+ * when width = 4096, RAW24, 80Mbps
+ */
+#define VIIF_WAIT_ABORT_COMPLETE_TIME 1229U
+
+/*
+ * complete time of register buffer transfer.
+ * actual time is about 30us in case of L1ISP
+ */
+#define VIIF_WAIT_ISP_REGBF_TRNS_COMPLETE_TIME 39U
+
+/* default parameters for V4L2 subdevice node */
+#define VISCONTI_VIIF_ISP_DEFAULT_WIDTH	  1920
+#define VISCONTI_VIIF_ISP_DEFAULT_HEIGHT  1080
+#define VISCONTI_VIIF_MAX_COMPOSED_WIDTH  8190
+#define VISCONTI_VIIF_MAX_COMPOSED_HEIGHT 4094
+
+/* CSI2RX DPHY settings: corresponding registers reside in ISP register region */
+enum viif_csi2rx_dphy_lane {
+	VIIF_CSI2RX_DPHY_L0L1L2L3 = 0U,
+	VIIF_CSI2RX_DPHY_L0L3L1L2 = 1U,
+	VIIF_CSI2RX_DPHY_L0L2L3L1 = 2U,
+	VIIF_CSI2RX_DPHY_L0L1L3L2 = 4U,
+	VIIF_CSI2RX_DPHY_L0L3L2L1 = 5U,
+	VIIF_CSI2RX_DPHY_L0L2L1L3 = 6U
+};
+
+#define VIIF_DPHY_CFG_CLK_25M 32U
+
+/**
+ * struct viif_input_img - input image information
+ * @pixel_clock: pixel clock [unit: kHz]. Range: [3375..600000]
+ * @htotal_size: horizontal total size [unit: pixel]. Range: [143..65535]
+ * @hactive_size: horizontal active size [unit: pixel]
+ * * Range (w/o L1ISP): [128..4096] (multiple of 2)
+ * * Range (with L1ISP): [640..3840] (multiple of 8)
+ * * Range (SUB path): 0
+ * @vtotal_size: vertical total size [unit: line].
+ * * Range: [144..16383]
+ * @vbp_size: vertical back porch size.
+ * * Range: [5..4095]
+ * @vactive_size: vertical active size [unit: line].
+ * * Range (w/o L1ISP) [128..2160] (multiple of 2)
+ * * Range (with L1ISP) [480..2160] (multiple of 2)
+ * @hobc_width: the number of horizontal optical black pixels.
+ * * Range (w/o L1ISP): 0
+ * * Range (with L1ISP):  [0,16,32,64 or 128]
+ *   * should be 0 when hobc_margin = 0
+ * * Range (SUB path): 0
+ * @hobc_margin: the number of horizontal optical black margin.
+ * * Range (w/o L1ISP): 0
+ * * Range (with L1ISP): [0..30] (even number)
+ +   * should be 0 when hobc_width = 0
+ * * Range (SUB path): 0
+ *
+ * Constraints between parameters:
+ *
+ * * (htotal_size > (hactive_size + hobc_width + hobc_margin))
+ * * (vtotal_size > (vbp_size + vactive_size))
+ * * w/o L1ISP:
+ *   * vbp_size >= (39360[cycle] / 500000[kHz]) * (pixel_clock / htotal_size) + 16 + ISST time
+ * * with L1ISP:
+ *   * vbp_size >= (54720[cycle] / 500000[kHz]) * (pixel_clock / htotal_size) + 38 + ISST time
+ *
+ * Note: L1ISP is used when RAW data is input to MAIN unit
+ */
+struct viif_input_img {
+	u32 pixel_clock;
+	u32 htotal_size;
+	u32 hactive_size;
+	u32 vtotal_size;
+	u32 vbp_size;
+	u32 vactive_size;
+	u32 hobc_width;
+	u32 hobc_margin;
+};
+
+/*=============================================*/
+/* Low Layer Implementation */
+/*=============================================*/
+/* Convert the unit of time-period (from sysclk, to num lines in the image) */
+static u32 sysclk_to_numlines(u32 time_in_sysclk, const struct viif_input_img *img)
+{
+	u64 v1 = (u64)time_in_sysclk * img->pixel_clock;
+	u64 v2 = (u64)img->htotal_size * VIIF_SYS_CLK;
+
+	return div64_u64(v1, v2);
+}
+
+static u32 lineperiod_in_sysclk(u32 hsize, u32 pixel_clock)
+{
+	return div64_u64((u64)hsize * VIIF_SYS_CLK, pixel_clock);
+}
+
+/**
+ * viif_main_set_unit() - Set static configuration of MAIN unit(CH0 or CH1)
+ *
+ * @viif_dev: the VIIF device
+ * @data_type: DT of image; either of
+ *     YUV422_8B, YUV422_10B, RGB565, RGB888, RAW8, RAW10, RAW12, RAW14
+ * @in_img: Pointer to input image information
+ * @yuv_interp: true to use interpolation for YUV422 to YUV444 conversion.
+ */
+static void viif_main_set_unit(struct viif_device *viif_dev, u32 data_type,
+			       const struct viif_input_img *in_img, bool yuv_interp)
+{
+	u32 total_hact_size;
+	u32 sw_delay0, sw_delay1, hw_delay;
+	u32 val, color, sysclk_num;
+
+	if (data_type == MIPI_CSI2_DT_RAW8 || data_type == MIPI_CSI2_DT_RAW10 ||
+	    data_type == MIPI_CSI2_DT_RAW12 || data_type == MIPI_CSI2_DT_RAW14) {
+		total_hact_size = in_img->hactive_size + in_img->hobc_width + in_img->hobc_margin;
+	} else {
+		total_hact_size = in_img->hactive_size;
+	}
+
+	/* Set DT and color type of image data */
+	viif_capture_write(viif_dev, REG_IPORTM_MAIN_DT, (data_type << 8U) | data_type);
+	viif_capture_write(viif_dev, REG_IPORTM_OTHER, 0x00);
+
+	/* Set back porch*/
+	viif_capture_write(viif_dev, REG_BACK_PORCH_M, (in_img->vbp_size << 16U) | VIIF_HBP_SYSCLK);
+
+	/* single pulse of vsync is input to DPGM */
+	viif_capture_write(viif_dev, REG_DPGM_VSYNC_SOURCE, VAL_DPGM_VSYNC_PULSE);
+
+	/* set preprocess type before L2ISP based on color_type. */
+	if (data_type == MIPI_CSI2_DT_YUV422_8B || data_type == MIPI_CSI2_DT_YUV422_10B) {
+		color = VAL_PREPROCESS_FMT_YUV422;
+	} else if (data_type == MIPI_CSI2_DT_RGB565 || data_type == MIPI_CSI2_DT_RGB888) {
+		color = VAL_PREPROCESS_FMT_RGB;
+	} else {
+		/* RGB or YUV444 from L1ISP */
+		color = VAL_PREPROCESS_FMT_YUV444;
+	}
+	viif_capture_write(viif_dev, REG_PREPROCESS_FMTM, color);
+
+	/* set Total size and valid size information of image data */
+	sysclk_num = lineperiod_in_sysclk(in_img->htotal_size, in_img->pixel_clock);
+	sysclk_num &= GENMASK(15, 0);
+	viif_capture_write(viif_dev, REG_TOTALSIZE_M, (in_img->vtotal_size << 16U) | sysclk_num);
+	viif_capture_write(viif_dev, REG_VALSIZE_M,
+			   (in_img->vactive_size << 16U) | total_hact_size);
+
+	/* set image size information to L2ISP */
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_VSIZE, in_img->vactive_size);
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_HSIZE, in_img->hactive_size);
+
+	/* RAW input case */
+	if (data_type >= MIPI_CSI2_DT_RAW8) {
+		/* interpolation mode = by LINE */
+		viif_capture_write(viif_dev, REG_L1_IBUF_INPUT_ORDER, 1U);
+		viif_capture_write(viif_dev, REG_L1_SYSM_HEIGHT, in_img->vactive_size);
+		viif_capture_write(viif_dev, REG_L1_SYSM_WIDTH, in_img->hactive_size);
+		val = (in_img->hobc_margin << 8U) | in_img->hobc_width;
+		viif_capture_write(viif_dev, REG_L1_HOBC_MARGIN, val);
+	}
+
+	/* disable rawpack */
+	viif_capture_write(viif_dev, REG_IPORTM_MAIN_RAW, 0);
+
+	/* Set yuv_conv; only for VAL_PREPROCESS_FMT_YUV422 */
+	viif_capture_write(viif_dev, REG_PREPROCESS_C24M, yuv_interp ? 1 : 0);
+
+	/* Set vsync delay */
+	hw_delay = in_img->vbp_size - sysclk_to_numlines(VIIF_TABLE_LOAD_TIME, in_img) + 4U;
+	hw_delay = min(hw_delay, 255U);
+
+	sw_delay0 = hw_delay - sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, in_img) + 2U;
+
+	if (data_type == MIPI_CSI2_DT_RAW8 || data_type == MIPI_CSI2_DT_RAW10 ||
+	    data_type == MIPI_CSI2_DT_RAW12 || data_type == MIPI_CSI2_DT_RAW14) {
+		sw_delay1 = sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, in_img) +
+			    VIIF_L1_DELAY_WO_HDRC + 1U;
+	} else {
+		sw_delay1 = 10U;
+	}
+	viif_capture_write(viif_dev, REG_INT_M0_LINE, sw_delay0 << 16U);
+	viif_capture_write(viif_dev, REG_INT_M1_LINE, (sw_delay1 << 16U) | hw_delay);
+
+	/* M2_LINE is the same condition as M1_LINE */
+	viif_capture_write(viif_dev, REG_INT_M2_LINE, (sw_delay1 << 16U) | hw_delay);
+
+	/* hold pixel_clock, htotal_size for future use */
+	viif_dev->img_clk.pixel_clock = in_img->pixel_clock;
+	viif_dev->img_clk.htotal_size = in_img->htotal_size;
+}
+
+/**
+ * viif_sub_set_unit() - Set static configuration of SUB unit
+ *
+ * @viif_dev: the VIIF device
+ * @dt_image: DT of image. Range: [0x1e, 0x1f, 0x22, 0x24, 0x2a-0x2d]
+ * @in_img: Pointer to input image information
+ */
+static void viif_sub_set_unit(struct viif_device *viif_dev, u32 dt_image,
+			      const struct viif_input_img *in_img)
+{
+	u32 sysclk_num, temp_delay;
+
+	viif_capture_write(viif_dev, REG_IPORTS_MAIN_DT, dt_image);
+	viif_capture_write(viif_dev, REG_IPORTS_OTHER, 0x00);
+
+	/* Set line size and delay value of delayed Vsync */
+	sysclk_num = lineperiod_in_sysclk(in_img->htotal_size, in_img->pixel_clock);
+	viif_capture_write(viif_dev, REG_INT_SA0_LINE, sysclk_num & GENMASK(15, 0));
+	temp_delay = in_img->vbp_size - 4U;
+	if (temp_delay > 255U) {
+		/* Replace the value with HW max spec */
+		temp_delay = 255U;
+	}
+	viif_capture_write(viif_dev, REG_INT_SA1_LINE, temp_delay);
+}
+
+/**
+ * viif_mux_start() - Setup CSI-2 input path
+ *
+ * @viif_dev: the VIIF device
+ * @vc_main: VCID (0, 1, 2, 3) to capture with Main unit; VIIF_CSI2_NOT_CAPTURE to disable.
+ * @vc_sub:  VCID (0, 1, 2, 3) to capture with Sub unit; VIIF_CSI2_NOT_CAPTURE to disable.
+ */
+static void viif_mux_start(struct viif_device *viif_dev, s32 vc_main, s32 vc_sub)
+{
+	bool en_vc0 = false, en_vc1 = false;
+
+	viif_capture_write(viif_dev, REG_IPORTM, VAL_IPORTM_INPUT_CSI2);
+
+	if (vc_main != VIIF_CSI2_NOT_CAPTURE) {
+		viif_capture_write(viif_dev, REG_VCID0SELECT, (u32)vc_main);
+		en_vc0 = true;
+	}
+	if (vc_sub != VIIF_CSI2_NOT_CAPTURE) {
+		viif_capture_write(viif_dev, REG_VCID1SELECT, (u32)vc_sub);
+		en_vc1 = true;
+	}
+
+	/* Control VC port enable */
+	viif_capture_write(viif_dev, REG_VCPORTEN,
+			   (en_vc0 ? MASK_VCPORTEN_EN_VC0 : 0) |
+				   (en_vc1 ? MASK_VCPORTEN_EN_VC1 : 0));
+
+	if (en_vc0) {
+		/* Update flag information for run status of MAIN unit */
+		viif_dev->run_flag_main = true;
+	}
+}
+
+/**
+ * viif_mux_stop() - Teardown CSI-2 input path
+ *
+ * @viif_dev: the VIIF device
+ * Return: 0 for success, -ETIMEDOUT for timeout error
+ */
+static int viif_mux_stop(struct viif_device *viif_dev)
+{
+	u64 timeout_ns, cur_ns;
+
+	/* Disable auto transmission of register buffer */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_TRN_A_CONF, 0);
+	viif_capture_write(viif_dev, REG_L2_CRGBF_TRN_A_CONF, 0);
+
+	/* Wait for completion of register buffer transmission */
+	udelay(VIIF_WAIT_ISP_REGBF_TRNS_COMPLETE_TIME);
+
+	/* Stop all VCs, long packet input and emb data input of MAIN unit */
+	viif_capture_write(viif_dev, REG_VCPORTEN, 0);
+	viif_capture_write(viif_dev, REG_IPORTM_OTHEREN, 0);
+	viif_capture_write(viif_dev, REG_IPORTM_EMBEN, 0);
+
+	/* Stop image data input, long packet input and emb data input of SUB unit */
+	viif_capture_write(viif_dev, REG_IPORTS_OTHEREN, 0);
+	viif_capture_write(viif_dev, REG_IPORTS_EMBEN, 0);
+	viif_capture_write(viif_dev, REG_IPORTS_IMGEN, 0);
+
+	/* Stop VDMAC for all table ports, input ports and write ports */
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, 0);
+	viif_capture_write(viif_dev, REG_VDM_R_ENABLE, 0);
+	viif_capture_write(viif_dev, REG_VDM_W_ENABLE, 0);
+
+	/* Stop all groups(g00, g01 and g02) of VDMAC */
+	viif_capture_write(viif_dev, REG_VDM_ABORTSET, 0x7);
+
+	timeout_ns = ktime_get_ns() + VIIF_WAIT_ABORT_COMPLETE_TIME * 1000;
+
+	do {
+		u32 status_r, status_w, status_t, l2_status;
+
+		/* Get VDMAC transfer status  */
+		status_r = viif_capture_read(viif_dev, REG_VDM_R_RUN);
+		status_w = viif_capture_read(viif_dev, REG_VDM_W_RUN);
+		status_t = viif_capture_read(viif_dev, REG_VDM_T_RUN);
+		l2_status = viif_capture_read(viif_dev, REG_L2_BUS_L2_STATUS);
+
+		if (!status_r && !status_w && !status_t && !l2_status) {
+			viif_dev->run_flag_main = false;
+			return 0;
+		}
+
+		cur_ns = ktime_get_ns();
+	} while (timeout_ns > cur_ns);
+
+	return -ETIMEDOUT;
+}
+
+/*=============================================*/
+/* handling V4L2 framework */
+/*=============================================*/
+/* ----- supported MBUS formats ----- */
+static bool viif_get_mbus_rgb_out(unsigned int mbus_code)
+{
+	const struct viif_mbus_format *fmt;
+
+	fmt = viif_mbus_format_from_code(mbus_code);
+
+	return fmt ? fmt->rgb_out : false; /* YUV as default */
+}
+
+/* ----- handling main processing path ----- */
+/* find a linked media entity which represents a sensor */
+static struct media_entity *viif_find_sensor(struct media_entity *entity)
+{
+	struct media_pad *pad;
+
+	while (1) {
+		pad = &entity->pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			return NULL;
+
+		pad = media_pad_remote_pad_first(pad);
+		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+			return NULL;
+
+		entity = pad->entity;
+		if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
+			return entity;
+	}
+}
+
+static int viif_get_dv_timings(struct viif_device *viif_dev, struct v4l2_dv_timings *timings,
+			       unsigned int *mbus_code)
+{
+	struct v4l2_subdev_format format = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = 0,
+	};
+	struct media_entity *sensor_entity;
+	struct v4l2_subdev_state *state;
+	struct v4l2_subdev *sensor_sd;
+	struct v4l2_ctrl *ctrl;
+	int ret;
+
+	sensor_entity = viif_find_sensor(&viif_dev->isp_subdev.sd.entity);
+	if (!sensor_entity)
+		return -EINVAL;
+
+	sensor_sd = media_entity_to_v4l2_subdev(sensor_entity);
+	if (!sensor_sd)
+		return -EINVAL;
+
+	state = v4l2_subdev_lock_and_get_active_state(sensor_sd);
+	if (state) {
+		ret = v4l2_subdev_call(sensor_sd, pad, get_fmt, state, &format);
+		v4l2_subdev_unlock_state(state);
+	} else {
+		struct v4l2_subdev_pad_config pad_cfg;
+		struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
+
+		ret = v4l2_subdev_call(sensor_sd, pad, get_fmt, &pad_state, &format);
+	}
+	if (ret)
+		return ret;
+
+	/* some video I/F support dv_timings query */
+	ret = v4l2_subdev_call(sensor_sd, pad, g_dv_timings, 0, timings);
+	if (!ret) {
+		*mbus_code = format.format.code;
+		return 0;
+	}
+
+	/* others: call some discrete APIs */
+	timings->bt.width = format.format.width;
+	timings->bt.height = format.format.height;
+	*mbus_code = format.format.code;
+
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_HBLANK);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_VBLANK error.\n");
+		return -EINVAL;
+	}
+	timings->bt.hsync = v4l2_ctrl_g_ctrl(ctrl);
+
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_VBLANK);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_VBLANK error.\n");
+		return -EINVAL;
+	}
+	timings->bt.vsync = v4l2_ctrl_g_ctrl(ctrl);
+
+	ctrl = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
+	if (!ctrl) {
+		dev_err(viif_dev->dev, "subdev: V4L2_CID_PIXEL_RATE error.\n");
+		return -EINVAL;
+	}
+	timings->bt.pixelclock = v4l2_ctrl_g_ctrl_int64(ctrl);
+
+	return 0;
+}
+
+static unsigned int dt_image_from_mbus_code(unsigned int mbus_code)
+{
+	const struct viif_mbus_format *fmt;
+
+	fmt = viif_mbus_format_from_code(mbus_code);
+
+	return fmt ? fmt->mipi_dt : MIPI_CSI2_DT_RGB888;
+}
+
+static void set_isp_input_depth_and_bayer_pattern(struct viif_device *viif_dev,
+						  unsigned int mbus_code)
+{
+	const struct viif_mbus_format *format;
+
+	format = viif_mbus_format_from_code(mbus_code);
+	if (format && format->is_bayer) {
+		viif_capture_write(viif_dev, REG_L1_IBUF_DEPTH, format->bpp);
+		viif_capture_write(viif_dev, REG_L1_SYSM_START_COLOR, format->bayer_pattern);
+	}
+}
+
+int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev)
+{
+	struct viif_input_img in_img_main = {};
+	struct v4l2_dv_timings timings = {};
+	bool yuv_interp = false;
+	unsigned int data_type;
+	unsigned int mbus_code;
+	int ret = 0;
+
+	ret = viif_get_dv_timings(viif_dev, &timings, &mbus_code);
+	if (ret) {
+		dev_err(viif_dev->dev, "could not get timing information of subdev");
+		return -EINVAL;
+	}
+
+	data_type = dt_image_from_mbus_code(mbus_code);
+
+	set_isp_input_depth_and_bayer_pattern(viif_dev, mbus_code);
+
+	yuv_interp = (data_type == MIPI_CSI2_DT_YUV422_8B || data_type == MIPI_CSI2_DT_YUV422_10B);
+
+	in_img_main.hactive_size = timings.bt.width;
+	in_img_main.vactive_size = timings.bt.height;
+	in_img_main.htotal_size = timings.bt.width + timings.bt.hsync;
+	in_img_main.vtotal_size = timings.bt.height + timings.bt.vsync;
+	in_img_main.pixel_clock = div64_u64(timings.bt.pixelclock, 1000);
+	/* ISP can issue a frame error when too large VBP value is set */
+	in_img_main.vbp_size = min(100, timings.bt.vsync - 5);
+	in_img_main.hobc_width = 0;
+	in_img_main.hobc_margin = 0;
+
+	/* TODO: might need to check Sink pad's {width, height} matches to active_size */
+
+	/* configuration of MAIN unit */
+	viif_main_set_unit(viif_dev, data_type, &in_img_main, yuv_interp);
+
+	/* Enable regbuf */
+	hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);
+
+	return 0;
+}
+
+int visconti_viif_isp_sub_set_unit(struct viif_device *viif_dev)
+{
+	struct viif_input_img in_img_sub;
+	struct v4l2_dv_timings timings;
+	unsigned int mbus_code;
+	unsigned int dt_image;
+	int ret;
+
+	ret = viif_get_dv_timings(viif_dev, &timings, &mbus_code);
+	if (ret)
+		return -EINVAL;
+
+	dt_image = dt_image_from_mbus_code(mbus_code);
+
+	in_img_sub.hactive_size = 0;
+	in_img_sub.vactive_size = timings.bt.height;
+	in_img_sub.htotal_size = timings.bt.width + timings.bt.hsync;
+	in_img_sub.vtotal_size = timings.bt.height + timings.bt.vsync;
+	in_img_sub.pixel_clock = div64_u64(timings.bt.pixelclock, 1000);
+	in_img_sub.vbp_size = timings.bt.vsync - 5;
+	in_img_sub.hobc_width = 0;
+	in_img_sub.hobc_margin = 0;
+
+	/* TODO: might need to check Sink pad's {width, height} matches to active_size */
+
+	viif_sub_set_unit(viif_dev, dt_image, &in_img_sub);
+
+	return 0;
+};
+
+/* ----- subdevice video operations ----- */
+static int visconti_viif_isp_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+					    u32 pad, u64 streams_mask)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+	int ret;
+
+	/* Currently, we assume PATH0 is enabled first */
+	/* Currently, further configuration is only for PATH0 */
+	if (pad != VIIF_ISP_PAD_SRC_PATH0)
+		return 0;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VIIF_ISP_PAD_SINK_VIDEO]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* enabling: start ISP, MUX -> start CSI2RX, sensor */
+	viif_dev->masked_gamma_path = 0;
+	viif_mux_start(viif_dev, 0, 0);
+
+	/* CSI2RX control registers which reside in the ISP register region */
+	/* FIXED 25MHz clock for CSI2RX DPHY configuration clock */
+	viif_capture_write(viif_dev, REG_DPHY_FREQRANGE, VIIF_DPHY_CFG_CLK_25M);
+	/* CSI2 data lane swapping; controlled by a vendor specific register */
+	viif_capture_write(viif_dev, REG_DPHY_LANE, VIIF_CSI2RX_DPHY_L0L1L2L3);
+
+	/* currently ISP.sink_video supports only stream0 */
+	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, BIT(0));
+	if (ret)
+		viif_mux_stop(viif_dev);
+
+	return ret;
+}
+
+static int visconti_viif_isp_disable_streams(struct v4l2_subdev *sd,
+					     struct v4l2_subdev_state *state, u32 pad,
+					     u64 streams_mask)
+{
+	struct viif_device *viif_dev = ((struct isp_subdev *)sd)->viif_dev;
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+
+	/* Currently, we assume PATH0 is disabled last */
+	/* Currently, further configuration is only for PATH0 */
+	if (pad != VIIF_ISP_PAD_SRC_PATH0)
+		return 0;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VIIF_ISP_PAD_SINK_VIDEO]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* disabling: stop sensor, CSI2RX -> stop MUX, ISP */
+	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, BIT(0));
+	viif_mux_stop(viif_dev);
+
+	return 0;
+}
+
+/* ----- subdevice pad operations ----- */
+static int visconti_viif_isp_enum_mbus_code(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *sd_state,
+					    struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == VIIF_ISP_PAD_SINK_VIDEO) {
+		const struct viif_mbus_format *fmt;
+
+		fmt = viif_mbus_format_nth(code->index);
+		if (!fmt)
+			return -EINVAL;
+
+		code->code = fmt->code;
+		return 0;
+	} else if (code->pad == VIIF_ISP_PAD_SRC_PATH0 || code->pad == VIIF_ISP_PAD_SRC_PATH1) {
+		struct v4l2_mbus_framefmt *sink_fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+		if (viif_get_mbus_rgb_out(sink_fmt->code))
+			code->code = MEDIA_BUS_FMT_RGB888_1X24;
+		else
+			code->code = MEDIA_BUS_FMT_YUV8_1X24;
+		return 0;
+	} else if (code->pad == VIIF_ISP_PAD_SRC_PATH2) {
+		struct v4l2_mbus_framefmt *sink_fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+		code->code = sink_fmt->code;
+		return 0;
+	} else if (code->pad == VIIF_ISP_PAD_SINK_PARAMS || code->pad == VIIF_ISP_PAD_SRC_STATS) {
+		if (code->index > 0)
+			return -EINVAL;
+
+		code->code = MEDIA_BUS_FMT_METADATA_FIXED;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static void visconti_viif_isp_set_sink_fmt(struct v4l2_subdev_state *sd_state,
+					   struct v4l2_mbus_framefmt *format)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src0_fmt, *src1_fmt, *src2_fmt;
+	const struct viif_mbus_format *mb_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+	src0_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH0);
+	src1_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH1);
+	src2_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH2);
+
+	/* sink format */
+	mb_fmt = viif_mbus_format_from_code(format->code);
+	if (!mb_fmt)
+		mb_fmt = viif_mbus_format_nth(0);
+
+	sink_fmt->code = mb_fmt->code;
+
+	if (mb_fmt->is_bayer) {
+		u32 tmp_width = round_down(format->width, 8);
+		u32 tmp_height = round_down(format->height, 2);
+
+		sink_fmt->width = clamp(tmp_width, VIIF_MIN_HACTIVE_PIXEL_W_L1ISP,
+					VIIF_MAX_HACTIVE_PIXEL_W_L1ISP);
+		sink_fmt->height = clamp(tmp_height, VIIF_MIN_VACTIVE_LINE_W_L1ISP,
+					 VIIF_MAX_VACTIVE_LINE_W_L1ISP);
+	} else {
+		u32 tmp_width = round_down(format->width, 2);
+		u32 tmp_height = round_down(format->height, 2);
+
+		sink_fmt->width = clamp(tmp_width, VIIF_MIN_HACTIVE_PIXEL_WO_L1ISP,
+					VIIF_MAX_HACTIVE_PIXEL_WO_L1ISP);
+		sink_fmt->height = clamp(tmp_height, VIIF_MIN_VACTIVE_LINE_WO_L1ISP,
+					 VIIF_MAX_VACTIVE_LINE_WO_L1ISP);
+	}
+
+	/* source format */
+	if (viif_get_mbus_rgb_out(sink_fmt->code)) {
+		src0_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+		src1_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+	} else {
+		src0_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+		src1_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+	}
+	src0_fmt->width = sink_fmt->width;
+	src0_fmt->height = sink_fmt->height;
+	src1_fmt->width = sink_fmt->width;
+	src1_fmt->height = sink_fmt->height;
+
+	/* SRC2 (RAW output) follows SINK format */
+	src2_fmt->code = mb_fmt->is_bayer ? sink_fmt->code : MEDIA_BUS_FMT_SRGGB10_1X10;
+	src2_fmt->width = sink_fmt->width;
+	src2_fmt->height = sink_fmt->height;
+
+	*format = *sink_fmt;
+}
+
+static void visconti_viif_isp_set_src_fmt(struct v4l2_subdev_state *sd_state,
+					  struct v4l2_mbus_framefmt *format, unsigned int pad)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, pad);
+
+	if (viif_get_mbus_rgb_out(sink_fmt->code))
+		src_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+	else
+		src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	src_fmt->width = sink_fmt->width;
+	src_fmt->height = sink_fmt->height;
+
+	*format = *src_fmt;
+}
+
+static void visconti_viif_isp_set_src_fmt_rawpath(struct v4l2_subdev_state *sd_state,
+						  struct v4l2_mbus_framefmt *format,
+						  unsigned int pad)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	const struct viif_mbus_format *mb_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, pad);
+	mb_fmt = viif_mbus_format_from_code(sink_fmt->code);
+
+	src_fmt->code = mb_fmt->is_bayer ? sink_fmt->code : MEDIA_BUS_FMT_SRGGB10_1X10;
+	src_fmt->width = sink_fmt->width;
+	src_fmt->height = sink_fmt->height;
+
+	*format = *src_fmt;
+}
+
+static int visconti_viif_isp_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+				     struct v4l2_subdev_format *fmt)
+{
+	if (fmt->pad == VIIF_ISP_PAD_SINK_VIDEO)
+		visconti_viif_isp_set_sink_fmt(sd_state, &fmt->format);
+	else if (fmt->pad == VIIF_ISP_PAD_SRC_PATH2)
+		visconti_viif_isp_set_src_fmt_rawpath(sd_state, &fmt->format, fmt->pad);
+	else if (fmt->pad == VIIF_ISP_PAD_SRC_PATH0 || fmt->pad == VIIF_ISP_PAD_SRC_PATH1)
+		visconti_viif_isp_set_src_fmt(sd_state, &fmt->format, fmt->pad);
+	else
+		fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad);
+
+	return 0;
+}
+
+static int visconti_viif_isp_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_VIDEO);
+	sink_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	sink_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH0);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH1);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_YUV8_1X24;
+
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_PATH2);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SINK_PARAMS);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_ISP_PAD_SRC_STATS);
+	sink_fmt->width = 0;
+	sink_fmt->height = 0;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED;
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static int visconti_viif_isp_subdev_link_validate(struct media_link *link)
+{
+	if (link->sink->index == VIIF_ISP_PAD_SINK_PARAMS)
+		return 0;
+
+	return v4l2_subdev_link_validate(link);
+}
+
+static const struct media_entity_operations visconti_viif_isp_media_ops = {
+	.link_validate = visconti_viif_isp_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_pad_ops visconti_viif_isp_pad_ops = {
+	.disable_streams = visconti_viif_isp_disable_streams,
+	.enable_streams = visconti_viif_isp_enable_streams,
+	.enum_mbus_code = visconti_viif_isp_enum_mbus_code,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = visconti_viif_isp_set_fmt,
+	.link_validate = v4l2_subdev_link_validate_default,
+};
+
+static const struct v4l2_subdev_video_ops visconti_viif_isp_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_ops visconti_viif_isp_ops = {
+	.video = &visconti_viif_isp_video_ops,
+	.pad = &visconti_viif_isp_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops visconti_viif_isp_internal_ops = {
+	.init_state = visconti_viif_isp_init_state,
+};
+
+/* ----- register/remove isp subdevice node ----- */
+int visconti_viif_isp_register(struct viif_device *viif_dev)
+{
+	struct media_pad *pads = viif_dev->isp_subdev.pads;
+	struct v4l2_subdev *sd = &viif_dev->isp_subdev.sd;
+	int ret;
+
+	viif_dev->isp_subdev.viif_dev = viif_dev;
+
+	v4l2_subdev_init(sd, &visconti_viif_isp_ops);
+	sd->internal_ops = &visconti_viif_isp_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->entity.ops = &visconti_viif_isp_media_ops;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+	sd->owner = THIS_MODULE;
+	strscpy(sd->name, "visconti-viif:isp", sizeof(sd->name));
+
+	pads[VIIF_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_ISP_PAD_SRC_PATH0].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_ISP_PAD_SRC_PATH1].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_ISP_PAD_SRC_PATH2].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
+	pads[VIIF_ISP_PAD_SRC_STATS].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&sd->entity, VIIF_ISP_PAD_NUM, pads);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed on media_entity_pads_init\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		goto err_cleanup_media_entity;
+
+	ret = v4l2_device_register_subdev(&viif_dev->v4l2_dev, sd);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to register ISP subdev\n");
+		goto err_cleanup_subdev;
+	}
+
+	return 0;
+
+err_cleanup_subdev:
+	v4l2_subdev_cleanup(sd);
+err_cleanup_media_entity:
+	media_entity_cleanup(&sd->entity);
+	return ret;
+}
+
+void visconti_viif_isp_unregister(struct viif_device *viif_dev)
+{
+	v4l2_device_unregister_subdev(&viif_dev->isp_subdev.sd);
+	media_entity_cleanup(&viif_dev->isp_subdev.sd.entity);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.h b/drivers/media/platform/toshiba/visconti/viif_isp.h
new file mode 100644
index 000000000000..633d53acc84a
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_ISP_H__
+#define __VIIF_ISP_H__
+
+struct viif_device;
+
+int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev);
+int visconti_viif_isp_sub_set_unit(struct viif_device *viif_dev);
+
+int visconti_viif_isp_register(struct viif_device *viif_dev);
+void visconti_viif_isp_unregister(struct viif_device *viif_dev);
+
+#endif /* __VIIF_ISP_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_regs.h b/drivers/media/platform/toshiba/visconti/viif_regs.h
new file mode 100644
index 000000000000..a6518364227b
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_regs.h
@@ -0,0 +1,717 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture register definitions
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_REGS_H__
+#define __VIIF_REGS_H__
+
+#include <linux/bitfield.h>
+
+/*=============================================*/
+/* Capture registers */
+/*=============================================*/
+#define REG_IPORTM0_LD	   0
+#define REG_IPORTM1_LD	   0x4
+#define MASK_IPORTM_VLATCH 0x3
+
+#define REG_VCID0SELECT	      0x30
+#define REG_VCID1SELECT	      0x34
+#define REG_VCPORTEN	      0x3c
+#define MASK_VCPORTEN_EN_VC0  BIT(0)
+#define MASK_VCPORTEN_EN_VC1  BIT(4)
+#define REG_IPORTM	      0x54
+#define VAL_IPORTM_INPUT_CSI2 0
+
+#define REG_IPORTM_MAIN_DT		 0x58
+#define REG_IPORTM_MAIN_RAW		 0x5c
+#define REG_IPORTM_OTHER		 0x60
+#define REG_IPORTM_OTHEREN		 0x64
+#define REG_IPORTM_EMBEN		 0x68
+#define REG_IPORTS_MAIN_DT		 0x78
+#define REG_IPORTS_OTHER		 0x80
+#define REG_IPORTS_OTHEREN		 0x84
+#define REG_IPORTS_EMBEN		 0x88
+#define REG_IPORTS_IMGEN		 0x8c
+#define REG_TOTALSIZE_M			 0xc0
+#define REG_VALSIZE_M			 0xc4
+#define REG_BACK_PORCH_M		 0xc8
+#define REG_INT_M_SYNC			 0x130
+#define REG_INT_M_SYNC_MASK		 0x134
+#define MASK_INT_M_SYNC_VSYNC_INT	 BIT(0)
+#define MASK_INT_M_SYNC_LINES_DELAY_INT1 BIT(1)
+#define MASK_INT_M_SYNC_LINES_DELAY_INT2 BIT(2)
+#define MASK_INT_M_SYNC_SW_DELAY_INT0	 BIT(16)
+#define MASK_INT_M_SYNC_SW_DELAY_INT1	 BIT(17)
+#define MASK_INT_M_SYNC_SW_DELAY_INT2	 BIT(18)
+/* we only care for LINES_DELAY_INT2, SW_DELAY_INT2 */
+#define MASK_INT_M_SYNC_MASK_SET                                        \
+	(MASK_INT_M_SYNC_VSYNC_INT | MASK_INT_M_SYNC_LINES_DELAY_INT1 | \
+	 MASK_INT_M_SYNC_SW_DELAY_INT0 | MASK_INT_M_SYNC_SW_DELAY_INT1)
+
+#define REG_INT_S_SYNC			 0x138
+#define REG_INT_S_SYNC_MASK		 0x13c
+#define MASK_INT_S_SYNC_VSYNC_INT	 BIT(0)
+#define MASK_INT_S_SYNC_LINES_DELAY_INT1 BIT(1)
+#define MASK_INT_S_SYNC_SW_DELAY_INT0	 BIT(16)
+#define MASK_INT_S_SYNC_SW_DELAY_INT1	 BIT(17)
+/* we only care for LINES_DELAY_INT1 */
+#define MASK_INT_S_SYNC_MASK_SET \
+	(MASK_INT_S_SYNC_VSYNC_INT | MASK_INT_S_SYNC_SW_DELAY_INT0 | MASK_INT_S_SYNC_SW_DELAY_INT1)
+
+#define REG_INT_M0_LINE			     0x140
+#define REG_INT_M1_LINE			     0x144
+#define REG_INT_M2_LINE			     0x148
+#define REG_INT_SA0_LINE		     0x160
+#define REG_INT_SA1_LINE		     0x164
+#define REG_INT_M_STATUS		     0x180
+#define REG_INT_M_MASK			     0x184
+#define MASK_INT_M_L2ISP_SIZE_ERROR	     BIT(0)
+#define MASK_INT_M_CRGBF_INTCRGERR_WRSTART   BIT(1)
+#define MASK_INT_M_CRGBF_INTCRGERR_RDSTART   BIT(2)
+#define MASK_INT_M_EMBED_ERROR		     BIT(3)
+#define MASK_INT_M_USERDATA_ERROR	     BIT(4)
+#define MASK_INT_M_L2ISP_GAMMA_TABLE_TIMEOUT (BIT(8) | BIT(9) | BIT(10))
+#define MASK_INT_M_L2ISP_GRID_TABLE_TIMEOUT  BIT(11)
+#define MASK_INT_M_L1ISP_SIZE_ERROR0	     BIT(16)
+#define MASK_INT_M_L1ISP_SIZE_ERROR1	     BIT(17)
+#define MASK_INT_M_L1ISP_SIZE_ERROR2	     BIT(18)
+#define MASK_INT_M_L1ISP_SIZE_ERROR3	     BIT(19)
+#define MASK_INT_M_L1ISP_SIZE_ERROR4	     BIT(20)
+#define MASK_INT_M_L1ISP_INT_ERR_CRGWRSTART  BIT(21)
+#define MASK_INT_M_L1ISP_INT_ERR_CRGRDSTART  BIT(22)
+#define MASK_INT_M_DELAY_INT_ERROR	     BIT(24)
+
+#define REG_INT_S_STATUS	   0x188
+#define REG_INT_S_MASK		   0x18c
+#define MASK_INT_S_SIZE_ERROR	   BIT(0)
+#define MASK_INT_S_EMBED_ERROR	   BIT(1)
+#define MASK_INT_S_USERDATA_ERROR  BIT(2)
+#define MASK_INT_S_DELAY_INT_ERROR BIT(24)
+#define MASK_INT_S_RESERVED_SET	   (BIT(16) | BIT(28))
+
+#define REG_PREPROCESS_FMTM	  0x210
+#define VAL_PREPROCESS_FMT_RGB	  (0x0 << 4)
+#define VAL_PREPROCESS_FMT_YUV444 (0x1 << 4)
+#define VAL_PREPROCESS_FMT_YUV422 (0x3 << 4)
+
+#define REG_PREPROCESS_C24M		   0x214
+#define REG_L2ISP_INPUT_CSC_MTB		   0x220
+#define REG_L2ISP_INPUT_CSC_MTB_YG_OFFSETI 0x230
+#define REG_L2ISP_INPUT_CSC_MTB_YG1	   0x234
+#define REG_L2ISP_INPUT_CSC_MTB_YG2	   0x238
+#define REG_L2ISP_INPUT_CSC_MTB_YG_OFFSETO 0x23c
+#define REG_L2ISP_INPUT_CSC_MTB_CB_OFFSETI 0x240
+#define REG_L2ISP_INPUT_CSC_MTB_CB1	   0x244
+#define REG_L2ISP_INPUT_CSC_MTB_CB2	   0x248
+#define REG_L2ISP_INPUT_CSC_MTB_CB_OFFSETO 0x24c
+#define REG_L2ISP_INPUT_CSC_MTB_CR_OFFSETI 0x250
+#define REG_L2ISP_INPUT_CSC_MTB_CR1	   0x254
+#define REG_L2ISP_INPUT_CSC_MTB_CR2	   0x258
+#define REG_L2ISP_INPUT_CSC_MTB_CR_OFFSETO 0x25c
+#define REG_DPHY_FREQRANGE		   0x700
+#define REG_DPHY_LANE			   0x710
+#define REG_DPGM_VSYNC_SOURCE		   0x804
+#define VAL_DPGM_VSYNC_PULSE		   1
+
+#define REG_VDM_R_ENABLE		 0x1030
+#define REG_VDM_W_ENABLE		 0x1034
+#define REG_VDM_T_ENABLE		 0x1038
+#define MASK_VDM_T_ENABLE_L1_DPC_H	 BIT(0)
+#define MASK_VDM_T_ENABLE_L1_DPC_M	 BIT(1)
+#define MASK_VDM_T_ENABLE_L1_DPC_L	 BIT(2)
+#define MASK_VDM_T_ENABLE_L1_DPC	 0x07
+#define MASK_VDM_T_ENABLE_L1_LSSC_GR	 BIT(4)
+#define MASK_VDM_T_ENABLE_L1_LSSC_R	 BIT(5)
+#define MASK_VDM_T_ENABLE_L1_LSSC_B	 BIT(6)
+#define MASK_VDM_T_ENABLE_L1_LSSC_GB	 BIT(7)
+#define MASK_VDM_T_ENABLE_L1_LSSC	 0x00f0
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_B BIT(8)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_G BIT(9)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_RD_R BIT(10)
+#define MASK_VDM_T_ENABLE_L2_UNDIST_WR_G BIT(11)
+#define MASK_VDM_T_ENABLE_L2_UNDIST	 0x0f00
+/* val: 12-23; postid: 0-1, ch: 0-5 */
+#define MASK_VDM_T_ENABLE_L2_GAMMA(postid, ch) BIT(12 + ((postid) * 6) + (ch))
+#define MASK_VDM_T_ENABLE_L2_GAMMA_ALL(postid) (0x3fu << (12 + ((postid) * 6)))
+
+#define REG_VDM_ABORTSET 0x103c
+
+/* x: 0-3 */
+#define REG_VDM_TGROUP_X_BASE(x)	 (0x1040 + 16 * (x))
+#define REG_VDM_TGROUP_X_CFG(x)		 (REG_VDM_TGROUP_X_BASE(x) + 0)
+#define REG_VDM_TGROUP_X_SRAM_BASE(x)	 (REG_VDM_TGROUP_X_BASE(x) + 4)
+#define REG_VDM_TGROUP_X_SRAM_SIZE(x)	 (REG_VDM_TGROUP_X_BASE(x) + 8)
+#define IDX_TGROUP_L1_ISP		 0
+#define IDX_TGROUP_L2_UNDIST		 1
+#define IDX_TGROUP_L2_GAMMA_LUT(post_id) (2 + (post_id))
+#define VAL_TGROUP_CFG_64BIT_RD		 0x0310U
+#define VAL_TGROUP_CFG_32BIT_RD		 0x0210U
+
+/* x: 0-23*/
+#define REG_VDM_TPORT_X_BASE(x)	 (0x1100 + 8 * (x))
+#define REG_VDM_TPORT_X_SIZE(x)	 (REG_VDM_TPORT_X_BASE(x) + 4)
+#define REG_VDM_TPORT_X_STADR(x) (REG_VDM_TPORT_X_BASE(x) + 0)
+/* idx: 0-2; x: 0-2 */
+#define IDX_TPORT_L1_DPC(x)	 (x)
+#define IDX_TPORT_L1_DPC_H	 0
+#define IDX_TPORT_L1_DPC_M	 1
+#define IDX_TPORT_L1_DPC_L	 2
+#define IDX_TPORT_L1_LSSC_GR	 4
+#define IDX_TPORT_L1_LSSC_R	 5
+#define IDX_TPORT_L1_LSSC_B	 6
+#define IDX_TPORT_L1_LSSC_GB	 7
+#define IDX_TPORT_L2_UNDIST_RD_B 8
+#define IDX_TPORT_L2_UNDIST_RD_G 9
+#define IDX_TPORT_L2_UNDIST_RD_R 10
+#define IDX_TPORT_L2_UNDIST_WR_G 11
+/* idx: 12-23; post_id: 0-1, col: 0-5 */
+#define IDX_TPORT_L2_GAMMA_LUT(post_id, col) (12 + (col) + (post_id) * 6)
+
+/* x: 0-5 */
+#define REG_VDM_WPORT_X_BASE(x)	       (0x1300 + 64 * (x))
+#define REG_VDM_WPORT_X_W_CFG0(x)      (REG_VDM_WPORT_X_BASE(x) + 16)
+#define REG_VDM_WPORT_X_W_ENDADR(x)    (REG_VDM_WPORT_X_BASE(x) + 4)
+#define REG_VDM_WPORT_X_W_HEIGHT(x)    (REG_VDM_WPORT_X_BASE(x) + 8)
+#define REG_VDM_WPORT_X_W_PITCH(x)     (REG_VDM_WPORT_X_BASE(x) + 12)
+#define REG_VDM_WPORT_X_W_SRAM_BASE(x) (REG_VDM_WPORT_X_BASE(x) + 24)
+#define REG_VDM_WPORT_X_W_SRAM_SIZE(x) (REG_VDM_WPORT_X_BASE(x) + 28)
+#define REG_VDM_WPORT_X_W_STADR(x)     (REG_VDM_WPORT_X_BASE(x) + 0)
+#define IDX_WPORT_MAIN_LNG	       0
+#define IDX_WPORT_MAIN_EMB	       1
+#define IDX_WPORT_SUB_IMG	       3
+#define IDX_WPORT_SUB_LNG	       4
+#define IDX_WPORT_SUB_EMB	       5
+
+#define REG_VDM_R_RUN		     0x1e18
+#define REG_VDM_W_RUN		     0x1e1c
+#define REG_VDM_T_RUN		     0x1e20
+#define REG_L1_SYSM_WIDTH	     0x2000
+#define REG_L1_SYSM_HEIGHT	     0x2004
+#define REG_L1_SYSM_START_COLOR	     0x2008
+#define VAL_L1_SYSM_START_COLOR_GRBG 0
+#define VAL_L1_SYSM_START_COLOR_RGGB 1
+#define VAL_L1_SYSM_START_COLOR_BGGR 2
+#define VAL_L1_SYSM_START_COLOR_GBRG 3
+
+#define REG_L1_SYSM_INPUT_MODE 0x200c
+#define REG_L1_SYSM_YCOEF_R    0x2014
+#define REG_L1_SYSM_YCOEF_G    0x2018
+#define REG_L1_SYSM_YCOEF_B    0x201c
+#define REG_L1_SYSM_AG_H       0x2040
+#define REG_L1_SYSM_AG_M       0x2044
+#define REG_L1_SYSM_AG_L       0x2048
+#define REG_L1_SYSM_AG_PARAM_A 0x204c
+#define REG_L1_SYSM_AG_PARAM_B 0x2050
+#define REG_L1_SYSM_AG_PARAM_C 0x2054
+#define REG_L1_SYSM_AG_PARAM_D 0x2058
+#define PACK_L1_SYSM_AG_PARAM(grad, ofst) \
+	(FIELD_PREP(0x00ff0000, (grad)) | FIELD_PREP(0x00ffff, (ofst)))
+
+#define REG_L1_SYSM_AG_SEL_HOBC 0x205c
+#define REG_L1_SYSM_AG_SEL_ABPC 0x2060
+#define REG_L1_SYSM_AG_SEL_RCNR 0x2064
+#define PACK_L1_SYSM_AG_SEL_HML(high, mid, low) \
+	(FIELD_PREP(0x00c0, (high)) | FIELD_PREP(0x0030, (mid)) | FIELD_PREP(0x0c, (low)))
+
+#define REG_L1_SYSM_AG_SEL_LSSC		   0x2068
+#define REG_L1_SYSM_AG_SEL_MPRO		   0x206c
+#define REG_L1_SYSM_AG_SEL_VPRO		   0x2070
+#define PACK_L1_SYSM_AG_SEL_SP(ssel, psel) (FIELD_PREP(0x00c0, (ssel)) | (FIELD_PREP(0x03, (psel))))
+
+#define REG_L1_SYSM_AG_CONT_HOBC01_EN 0x2074
+#define REG_L1_SYSM_AG_CONT_HOBC2_EN  0x2078
+#define REG_L1_SYSM_AG_CONT_ABPC01_EN 0x207c
+#define REG_L1_SYSM_AG_CONT_ABPC2_EN  0x2080
+#define REG_L1_SYSM_AG_CONT_RCNR01_EN 0x2084
+#define REG_L1_SYSM_AG_CONT_RCNR2_EN  0x2088
+#define MASK_L1_SYSM_AG_CONT_M_EN     BIT(24)
+#define MASK_L1_SYSM_AG_CONT_H_EN     BIT(8)
+#define MASK_L1_SYSM_AG_CONT_M_VAL    0x00ff0000
+#define MASK_L1_SYSM_AG_CONT_H_VAL    0x00ff
+#define MASK_L1_SYSM_AG_CONT_L_EN     BIT(8)
+#define MASK_L1_SYSM_AG_CONT_L_VAL    0x00ff
+
+#define REG_L1_SYSM_AG_CONT_LSSC_EN 0x208c
+#define REG_L1_SYSM_AG_CONT_MPRO_EN 0x2090
+#define REG_L1_SYSM_AG_CONT_VPRO_EN 0x2094
+#define MASK_L1_SYSM_AG_CONT_EN	    BIT(8)
+#define MASK_L1_SYSM_AG_CONT_VAL    0x00ff
+
+#define LEN_L1_HDRE_SRCPOINT	16
+#define REG_L1_HDRE_SRCPOINT(x) (0x20c4 + 4 * (x))
+
+#define LEN_L1_HDRE_SRCBASE    17
+#define REG_L1_HDRE_SRCBASE(x) (0x2104 + 4 * (x))
+
+#define LEN_L1_HDRE_RATIO    17
+#define REG_L1_HDRE_RATIO(x) (0x2148 + 4 * (x))
+
+#define LEN_L1_HDRE_DSTBASE    17
+#define REG_L1_HDRE_DSTBASE(x) (0x218c + 4 * (x))
+
+#define REG_L1_HDRE_DSTMAXVAL	 0x21d0
+#define REG_L1_AEXP_ON		 0x2200
+#define REG_L1_AEXP_RESULT_AVE	 0x2204
+#define REG_L1_AEXP_START_X	 0x2210
+#define REG_L1_AEXP_START_Y	 0x2214
+#define REG_L1_AEXP_BLOCK_WIDTH	 0x2218
+#define REG_L1_AEXP_BLOCK_HEIGHT 0x221c
+#define REG_L1_AEXP_WEIGHT_0	 0x2220
+#define REG_L1_AEXP_WEIGHT_1	 0x2224
+#define REG_L1_AEXP_WEIGHT_2	 0x2228
+#define REG_L1_AEXP_WEIGHT_3	 0x222c
+#define REG_L1_AEXP_WEIGHT_4	 0x2230
+#define REG_L1_AEXP_WEIGHT_5	 0x2234
+#define REG_L1_AEXP_WEIGHT_6	 0x2238
+#define REG_L1_AEXP_WEIGHT_7	 0x223c
+#define REG_L1_AEXP_SATUR_RATIO	 0x2240
+#define REG_L1_AEXP_BLACK_RATIO	 0x2244
+#define REG_L1_AEXP_SATUR_LEVEL	 0x2248
+/* 8 x 8 elements */
+#define REG_L1_AEXP_AVE(y, x)	       (0x2250 + 32 * (y) + 4 * (x))
+#define REG_L1_AEXP_SATUR_BLACK_PIXNUM 0x2350
+#define REG_L1_AEXP_AVE4LINESY0	       0x2354
+#define REG_L1_AEXP_AVE4LINESY1	       0x2358
+#define REG_L1_AEXP_AVE4LINESY2	       0x235c
+#define REG_L1_AEXP_AVE4LINESY3	       0x2360
+#define REG_L1_AEXP_AVE4LINES0	       0x2364
+#define REG_L1_AEXP_AVE4LINES1	       0x2368
+#define REG_L1_AEXP_AVE4LINES2	       0x236c
+#define REG_L1_AEXP_AVE4LINES3	       0x2370
+#define REG_L1_IBUF_DEPTH	       0x2380
+#define REG_L1_IBUF_INPUT_ORDER	       0x2384
+#define REG_L1_SLIC_SRCBLACKLEVEL_GR   0x2390
+#define REG_L1_SLIC_SRCBLACKLEVEL_R    0x2394
+#define REG_L1_SLIC_SRCBLACKLEVEL_B    0x2398
+#define REG_L1_SLIC_SRCBLACKLEVEL_GB   0x239c
+#define REG_L1_ABPC012_STA_EN	       0x240c
+#define REG_L1_ABPC012_DYN_EN	       0x2410
+#define MASK_L1_ABPC_ENABLE_H	       BIT(24)
+#define MASK_L1_ABPC_ENABLE_M	       BIT(16)
+#define MASK_L1_ABPC_ENABLE_L	       BIT(8)
+
+#define REG_L1_ABPC012_DYN_MODE	       0x2414
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_H BIT(24)
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_M BIT(16)
+#define MASK_L1_ABPC_DYN_MODE_2PIXEL_L BIT(8)
+
+#define REG_L1_ABPC0_RATIO_LIMIT      0x2424
+#define REG_L1_ABPC0_DARK_LIMIT	      0x242c
+#define REG_L1_ABPC0_SN_COEF_W_AG_MIN 0x2430
+#define REG_L1_ABPC0_SN_COEF_W_AG_MID 0x2434
+#define REG_L1_ABPC0_SN_COEF_W_AG_MAX 0x2438
+#define REG_L1_ABPC0_SN_COEF_W_TH_MIN 0x243c
+#define REG_L1_ABPC0_SN_COEF_W_TH_MAX 0x2440
+#define REG_L1_ABPC0_SN_COEF_B_AG_MIN 0x2444
+#define REG_L1_ABPC0_SN_COEF_B_AG_MID 0x2448
+#define REG_L1_ABPC0_SN_COEF_B_AG_MAX 0x244c
+#define REG_L1_ABPC0_SN_COEF_B_TH_MIN 0x2450
+#define REG_L1_ABPC0_SN_COEF_B_TH_MAX 0x2454
+#define REG_L1_ABPC1_RATIO_LIMIT      0x2460
+#define REG_L1_ABPC1_DARK_LIMIT	      0x2468
+#define REG_L1_ABPC1_SN_COEF_W_AG_MIN 0x246c
+#define REG_L1_ABPC1_SN_COEF_W_AG_MID 0x2470
+#define REG_L1_ABPC1_SN_COEF_W_AG_MAX 0x2474
+#define REG_L1_ABPC1_SN_COEF_W_TH_MIN 0x2478
+#define REG_L1_ABPC1_SN_COEF_W_TH_MAX 0x247c
+#define REG_L1_ABPC1_SN_COEF_B_AG_MIN 0x2480
+#define REG_L1_ABPC1_SN_COEF_B_AG_MID 0x2484
+#define REG_L1_ABPC1_SN_COEF_B_AG_MAX 0x2488
+#define REG_L1_ABPC1_SN_COEF_B_TH_MIN 0x248c
+#define REG_L1_ABPC1_SN_COEF_B_TH_MAX 0x2490
+#define REG_L1_ABPC2_RATIO_LIMIT      0x249c
+#define REG_L1_ABPC2_DARK_LIMIT	      0x24a4
+#define REG_L1_ABPC2_SN_COEF_W_AG_MIN 0x24a8
+#define REG_L1_ABPC2_SN_COEF_W_AG_MID 0x24ac
+#define REG_L1_ABPC2_SN_COEF_W_AG_MAX 0x24b0
+#define REG_L1_ABPC2_SN_COEF_W_TH_MIN 0x24b4
+#define REG_L1_ABPC2_SN_COEF_W_TH_MAX 0x24b8
+#define REG_L1_ABPC2_SN_COEF_B_AG_MIN 0x24bc
+#define REG_L1_ABPC2_SN_COEF_B_AG_MID 0x24c0
+#define REG_L1_ABPC2_SN_COEF_B_AG_MAX 0x24c4
+#define REG_L1_ABPC2_SN_COEF_B_TH_MIN 0x24c8
+#define REG_L1_ABPC2_SN_COEF_B_TH_MAX 0x24cc
+#define REG_L1_PWHB_H_GR	      0x2584
+#define REG_L1_PWHB_HR		      0x2588
+#define REG_L1_PWHB_HB		      0x258c
+#define REG_L1_PWHB_H_GB	      0x2590
+#define REG_L1_PWHB_M_GR	      0x2594
+#define REG_L1_PWHB_MR		      0x2598
+#define REG_L1_PWHB_MB		      0x259c
+#define REG_L1_PWHB_M_GB	      0x25a0
+#define REG_L1_PWHB_L_GR	      0x25a4
+#define REG_L1_PWHB_LR		      0x25a8
+#define REG_L1_PWHB_LB		      0x25ac
+#define REG_L1_PWHB_L_GB	      0x25b0
+#define REG_L1_PWHB_DSTMAXVAL	      0x25b4
+
+/* 0 for high, 1 for middle, 2 for low sensitivity image */
+#define REG_L1_RCNR_X_SW(x)		   (0x2608 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG0(x)	   (0x260c + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG1(x)	   (0x2610 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_DARK_AG2(x)	   (0x2614 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG0(x)	   (0x2618 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG1(x)	   (0x261c + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_RATIO_AG2(x)	   (0x2620 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_R(x)   (0x2624 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_G(x)   (0x2628 + 0x94 * (x))
+#define REG_L1_RCNR_X_CNF_CLIP_GAIN_B(x)   (0x262c + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG0(x)	   (0x2630 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG1(x)	   (0x2634 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_DARK_AG2(x)	   (0x2638 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG0(x)	   (0x263c + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG1(x)	   (0x2640 + 0x94 * (x))
+#define REG_L1_RCNR_X_A1L_RATIO_AG2(x)	   (0x2644 + 0x94 * (x))
+#define REG_L1_RCNR_X_INF_ZERO_CLIP(x)	   (0x2648 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG0(x) (0x2650 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG1(x) (0x2654 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_D2BLEND_AG2(x) (0x2658 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_BLACK(x)	   (0x265c + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_MINDIV(x)	   (0x2660 + 0x94 * (x))
+#define REG_L1_RCNR_X_HRY_TYPE(x)	   (0x2664 + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG0(x)	   (0x2668 + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG1(x)	   (0x266c + 0x94 * (x))
+#define REG_L1_RCNR_X_ANF_BLEND_AG2(x)	   (0x2670 + 0x94 * (x))
+#define REG_L1_RCNR_X_LPF_THRESHOLD(x)	   (0x2678 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG0(x) (0x267c + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG1(x) (0x2680 + 0x94 * (x))
+#define REG_L1_RCNR_X_MERGE_HLBLEND_AG2(x) (0x2684 + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_SW(x)		   (0x2688 + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_RATIO(x)	   (0x268c + 0x94 * (x))
+#define REG_L1_RCNR_X_GNR_WIDE_EN(x)	   (0x2690 + 0x94 * (x))
+
+#define REG_L1_HDRS_HDRRATIO_M	     0x2884
+#define REG_L1_HDRS_HDRRATIO_L	     0x2888
+#define REG_L1_HDRS_HDRRATIO_E	     0x288c
+#define REG_L1_HDRS_BLENDEND_H	     0x2898
+#define REG_L1_HDRS_BLENDEND_M	     0x289c
+#define REG_L1_HDRS_BLENDEND_E	     0x28a0
+#define REG_L1_HDRS_BLENDBEG_H	     0x28a4
+#define REG_L1_HDRS_BLENDBEG_M	     0x28a8
+#define REG_L1_HDRS_BLENDBEG_E	     0x28ac
+#define REG_L1_HDRS_DG_H	     0x28c8
+#define REG_L1_HDRS_DG_M	     0x28cc
+#define REG_L1_HDRS_DG_L	     0x28d0
+#define REG_L1_HDRS_DG_E	     0x28d4
+#define REG_L1_HDRS_LEDMODE_ON	     0x28d8
+#define REG_L1_HDRS_HDRMODE	     0x28dc
+#define REG_L1_HDRS_DSTMAXVAL	     0x28ec
+#define REG_L1_BLVC_SRCBLACKLEVEL_GR 0x2900
+#define REG_L1_BLVC_SRCBLACKLEVEL_R  0x2904
+#define REG_L1_BLVC_SRCBLACKLEVEL_B  0x2908
+#define REG_L1_BLVC_SRCBLACKLEVELGB  0x290c
+#define REG_L1_BLVC_MULTVAL_GR	     0x2910
+#define REG_L1_BLVC_MULTVAL_R	     0x2914
+#define REG_L1_BLVC_MULTVAL_B	     0x2918
+#define REG_L1_BLVC_MULTVAL_GB	     0x291c
+#define REG_L1_BLVC_DSTMAXVAL	     0x2920
+#define REG_L1_LSSC_EN		     0x2980
+#define REG_L1_LSSC_PWHB_R_GAIN	     0x2990
+#define REG_L1_LSSC_PWHB_GR_GAIN     0x2994
+#define REG_L1_LSSC_PWHB_GB_GAIN     0x2998
+#define REG_L1_LSSC_PWHB_B_GAIN	     0x299c
+#define REG_L1_LSSC_PARA_EN	     0x29a0
+#define REG_L1_LSSC_PARA_H_CENTER    0x29a4
+#define REG_L1_LSSC_PARA_V_CENTER    0x29a8
+#define REG_L1_LSSC_PARA_H_GAIN	     0x29ac
+#define REG_L1_LSSC_PARA_V_GAIN	     0x29b0
+#define REG_L1_LSSC_PARA_MGSEL2	     0x29b4
+#define REG_L1_LSSC_PARA_MGSEL4	     0x29b8
+
+/*0: R/2D, 1: R/4D, 2: GR/2D, 3: GR/4D, 4: GB/2D, 5: GB/4D, 6: B/2D, 7: B/4D*/
+#define REG_L1_LSSC_PARA_COEF_X_H_L(x)	 (0x29bc + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_H_R(x)	 (0x29c0 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_V_U(x)	 (0x29c4 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_V_D(x)	 (0x29c8 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_LU(x) (0x29cc + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_RU(x) (0x29d0 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_LD(x) (0x29d4 + 0x20 * (x))
+#define REG_L1_LSSC_PARA_COEF_X_HV_RD(x) (0x29d8 + 0x20 * (x))
+
+#define REG_L1_LSSC_GRID_EN	   0x2abc
+#define REG_L1_LSSC_GRID_H_CENTER  0x2ac0
+#define REG_L1_LSSC_GRID_V_CENTER  0x2ac4
+#define REG_L1_LSSC_GRID_H_SIZE	   0x2ac8
+#define REG_L1_LSSC_GRID_V_SIZE	   0x2acc
+#define REG_L1_LSSC_GRID_MGSEL	   0x2ad0
+#define REG_L1_MPRO_SW		   0x2b00
+#define REG_L1_MPRO_CONF	   0x2b04
+#define REG_L1_MPRO_DST_MINVAL	   0x2b0c
+#define REG_L1_MPRO_DST_MAXVAL	   0x2b10
+#define REG_L1_MPRO_LM0_RMG_MIN	   0x2b20
+#define REG_L1_MPRO_LM0_RMB_MIN	   0x2b24
+#define REG_L1_MPRO_LM0_GMR_MIN	   0x2b28
+#define REG_L1_MPRO_LM0_GMB_MIN	   0x2b2c
+#define REG_L1_MPRO_LM0_BMR_MIN	   0x2b30
+#define REG_L1_MPRO_LM0_BMG_MIN	   0x2b34
+#define REG_L1_MPRO_LM0_RMG_MAX	   0x2b38
+#define REG_L1_MPRO_LM0_RMB_MAX	   0x2b3c
+#define REG_L1_MPRO_LM0_GMR_MAX	   0x2b40
+#define REG_L1_MPRO_LM0_GMB_MAX	   0x2b44
+#define REG_L1_MPRO_LM0_BMR_MAX	   0x2b48
+#define REG_L1_MPRO_LM0_BMG_MAX	   0x2b4c
+#define REG_L1_MPRO_LCS_MODE	   0x2bf0
+#define REG_L1_VPRO_PGC_SW	   0x2d80
+#define REG_L1_VPRO_YUVC_SW	   0x2d88
+#define REG_L1_VPRO_YNR_SW	   0x2d8c
+#define REG_L1_VPRO_ETE_SW	   0x2d90
+#define REG_L1_VPRO_CSUP_UVSUP_SW  0x2d94
+#define REG_L1_VPRO_CSUP_CORING_SW 0x2d98
+#define REG_L1_VPRO_BRIGHT_SW	   0x2d9c
+#define REG_L1_VPRO_LCNT_SW	   0x2da0
+#define REG_L1_VPRO_NLCNT_SW	   0x2da4
+#define REG_L1_VPRO_EDGE_SUP_SW	   0x2dac
+#define REG_L1_VPRO_CNR_SW	   0x2db0
+#define REG_L1_VPRO_BLKADJ	   0x2db8
+/* (GAM00P is fixed 0) GAM01P-GAM44P: x:0-43 */
+#define REG_L1_VPRO_GAMxP(x)		 (0x2dbc + 4 * (x))
+#define REG_L1_VPRO_CB_MAT		 0x2e6c
+#define REG_L1_VPRO_CR_MAT		 0x2e70
+#define REG_L1_VPRO_BRIGHT		 0x2e74
+#define REG_L1_VPRO_LCONT_LEV		 0x2e78
+#define REG_L1_VPRO_BLK_KNEE		 0x2e7c
+#define REG_L1_VPRO_WHT_KNEE		 0x2e80
+#define REG_L1_VPRO_BLK_CONT0		 0x2e84
+#define REG_L1_VPRO_BLK_CONT1		 0x2e88
+#define REG_L1_VPRO_BLK_CONT2		 0x2e8c
+#define REG_L1_VPRO_WHT_CONT0		 0x2e90
+#define REG_L1_VPRO_WHT_CONT1		 0x2e94
+#define REG_L1_VPRO_WHT_CONT2		 0x2e98
+#define REG_L1_VPRO_YNR_GAIN_MIN	 0x2eb4
+#define REG_L1_VPRO_YNR_GAIN_MAX	 0x2eb8
+#define REG_L1_VPRO_YNR_LIM_MIN		 0x2ebc
+#define REG_L1_VPRO_YNR_LIM_MAX		 0x2ec0
+#define REG_L1_VPRO_ETE_GAIN_MIN	 0x2ec4
+#define REG_L1_VPRO_ETE_GAIN_MAX	 0x2ec8
+#define REG_L1_VPRO_ETE_LIM_MIN		 0x2ecc
+#define REG_L1_VPRO_ETE_LIM_MAX		 0x2ed0
+#define REG_L1_VPRO_ETE_CORING_MIN	 0x2ed4
+#define REG_L1_VPRO_ETE_CORING_MAX	 0x2ed8
+#define REG_L1_VPRO_CB_GAIN		 0x2edc
+#define REG_L1_VPRO_CR_GAIN		 0x2ee0
+#define REG_L1_VPRO_CBR_MGAIN_MIN	 0x2ee4
+#define REG_L1_VPRO_CB_P_GAIN_MAX	 0x2ee8
+#define REG_L1_VPRO_CB_M_GAIN_MAX	 0x2eec
+#define REG_L1_VPRO_CR_P_GAIN_MAX	 0x2ef0
+#define REG_L1_VPRO_CR_M_GAIN_MAX	 0x2ef4
+#define REG_L1_VPRO_CSUP_CORING_LV_MIN	 0x2ef8
+#define REG_L1_VPRO_CSUP_CORING_LV_MAX	 0x2efc
+#define REG_L1_VPRO_CSUP_CORING_GAIN_MIN 0x2f00
+#define REG_L1_VPRO_CSUP_CORING_GAIN_MAX 0x2f04
+#define REG_L1_VPRO_CSUP_BK_SLV		 0x2f08
+#define REG_L1_VPRO_CSUP_BK_MP		 0x2f0c
+#define REG_L1_VPRO_CSUP_BLACK		 0x2f10
+#define REG_L1_VPRO_CSUP_WH_SLV		 0x2f14
+#define REG_L1_VPRO_CSUP_WH_MP		 0x2f18
+#define REG_L1_VPRO_CSUP_WHITE		 0x2f1c
+#define REG_L1_VPRO_EDGE_SUP_GAIN	 0x2f20
+#define REG_L1_VPRO_EDGE_SUP_LIM	 0x2f24
+#define REG_L1_AWHB_SW			 0x2f80
+#define MASK_L1_AWHB_SW_EN		 BIT(7)
+#define MASK_L1_AWHB_SW_LOCK		 BIT(5)
+
+#define REG_L1_AWHB_WBMRG	     0x2f88
+#define REG_L1_AWHB_WBMGG	     0x2f8c
+#define REG_L1_AWHB_WBMBG	     0x2f90
+#define REG_L1_AWHB_GATE_CONF0	     0x2f94
+#define MASK_L1_AWHB_GATE_YGATE_SEL  BIT(7)
+#define MASK_L1_AWHB_GATE_YGATE_DATA 0x0060
+#define MASK_L1_AWHB_GATE_CGRANGE    0x0003
+
+#define REG_L1_AWHB_GATE_CONF1	   0x2f98
+#define MASK_L1_AWHB_GATE_YGATESW  BIT(5)
+#define MASK_L1_AWHB_GATE_HEXSW	   BIT(4)
+#define MASK_L1_AWHB_GATE_AREAMODE 0x0003
+
+#define REG_L1_AWHB_AREA_HSIZE	    0x2f9c
+#define REG_L1_AWHB_AREA_VSIZE	    0x2fa0
+#define REG_L1_AWHB_AREA_HOFS	    0x2fa4
+#define REG_L1_AWHB_AREA_VOFS	    0x2fa8
+#define REG_L1_AWHB_AREA_MASKH	    0x2fac
+#define REG_L1_AWHB_AREA_MASKL	    0x2fb0
+#define REG_L1_AWHB_SQ_CONF	    0x2fb4
+#define MASK_L1_AWHB_SQ_CONF_SQ3POL BIT(2)
+#define MASK_L1_AWHB_SQ_CONF_SQ3SW  BIT(3)
+#define MASK_L1_AWHB_SQ_CONF_SQ2POL BIT(4)
+#define MASK_L1_AWHB_SQ_CONF_SQ2SW  BIT(5)
+#define MASK_L1_AWHB_SQ_CONF_SQ1POL BIT(6)
+#define MASK_L1_AWHB_SQ_CONF_SQ1SW  BIT(7)
+
+#define REG_L1_AWHB_YGATEH	   0x2fb8
+#define REG_L1_AWHB_YGATEL	   0x2fbc
+#define REG_L1_AWHB_BYCUT0P	   0x2fc8
+#define REG_L1_AWHB_BYCUT0N	   0x2fcc
+#define REG_L1_AWHB_RYCUT0P	   0x2fd0
+#define REG_L1_AWHB_RYCUT0N	   0x2fd4
+#define REG_L1_AWHB_RBCUT0H	   0x2fd8
+#define REG_L1_AWHB_RBCUT0L	   0x2fdc
+#define REG_L1_AWHB_BYCUT1H	   0x2ff8
+#define REG_L1_AWHB_BYCUT1L	   0x2ffc
+#define REG_L1_AWHB_RYCUT1H	   0x3000
+#define REG_L1_AWHB_RYCUT1L	   0x3004
+#define REG_L1_AWHB_BYCUT2H	   0x3008
+#define REG_L1_AWHB_BYCUT2L	   0x300c
+#define REG_L1_AWHB_RYCUT2H	   0x3010
+#define REG_L1_AWHB_RYCUT2L	   0x3014
+#define REG_L1_AWHB_BYCUT3H	   0x3018
+#define REG_L1_AWHB_BYCUT3L	   0x301c
+#define REG_L1_AWHB_RYCUT3H	   0x3020
+#define REG_L1_AWHB_RYCUT3L	   0x3024
+#define REG_L1_AWHB_AWBSFTU	   0x3028
+#define REG_L1_AWHB_AWBSFTV	   0x302c
+#define REG_L1_AWHB_AWBSPD	   0x3030
+#define MASK_L1_AWHB_AWBSPD_HUECOR BIT(4)
+#define MASK_L1_AWHB_AWBSPD_SPD	   0x0f
+
+#define REG_L1_AWHB_AWBULV	0x3034
+#define REG_L1_AWHB_AWBVLV	0x3038
+#define REG_L1_AWHB_AWBWAIT	0x303c
+#define REG_L1_AWHB_AWBONDOT	0x3040
+#define REG_L1_AWHB_AWBFZTIM	0x3044
+#define REG_L1_AWHB_WBGRMAX	0x3048
+#define REG_L1_AWHB_WBGRMIN	0x304c
+#define REG_L1_AWHB_WBGBMAX	0x3050
+#define REG_L1_AWHB_WBGBMIN	0x3054
+#define REG_L1_AWHB_AVE_USIG	0x308c
+#define REG_L1_AWHB_AVE_VSIG	0x3090
+#define REG_L1_AWHB_NUM_UVON	0x3094
+#define REG_L1_AWHB_AWBGAINR	0x3098
+#define REG_L1_AWHB_AWBGAING	0x309c
+#define REG_L1_AWHB_AWBGAINB	0x30a0
+#define REG_L1_AWHB_R_CTR_STOP	0x30b0
+#define REG_L1_HOBC_MARGIN	0x30c4
+#define REG_L1_HDRC_EN		0x3200
+#define REG_L1_HDRC_THR_SFT_AMT 0x3204
+#define REG_L1_HDRC_RATIO	0x320c
+#define REG_L1_HDRC_PT_RATIO	0x321c
+#define REG_L1_HDRC_PT_BLEND	0x3220
+#define REG_L1_HDRC_PT_BLEND2	0x3224
+#define REG_L1_HDRC_PT_SAT	0x3228
+#define REG_L1_HDRC_TN_TYPE	0x322c
+#define REG_L1_HDRC_TNP_MAX	0x3230
+#define REG_L1_HDRC_TNP_MAG	0x3234
+
+#define LEN_L1_HDRC_TNP_FIL    5
+#define REG_L1_HDRC_TNP_FIL(x) (0x3248 + 4 * (x))
+
+#define LEN_L1_HDRC_UTN_TBL    20
+#define REG_L1_HDRC_UTN_TBL(x) (0x325c + 4 * (x))
+
+#define REG_L1_HDRC_FLR_VAL		   0x32ac
+#define REG_L1_HDRC_FLR_ADP		   0x32b0
+#define REG_L1_HDRC_YBR_OFF		   0x32ec
+#define REG_L1_HDRC_ORGY_BLEND		   0x32f0
+#define REG_L1_HDRC_MAR_TOP		   0x3300
+#define REG_L1_HDRC_MAR_LEFT		   0x3304
+#define REG_L1_CRGBF_ACC_CONF		   0x3700
+#define VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS  0
+#define VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0 1
+
+#define REG_L1_CRGBF_TRN_A_CONF		 0x370c
+#define VAL_L1_CRGBF_TRN_AUTO_READ_BANK0 BIT(16)
+
+#define REG_L1_CRGBF_INT_STAT	     0x3718
+#define REG_L1_CRGBF_INT_MASK	     0x371c
+#define REG_L1_CRGBF_INT_MASKED_STAT 0x3720
+#define REG_L1_CRGBF_TRN_RBADDR	     0x372c
+#define REG_L1_CRGBF_TRN_READDR	     0x3730
+#define REG_L1_CRGBF_ISP_INT_MASK    0x3738
+#define REG_L2_SENSOR_CROP_OFS_H     0x5000
+#define REG_L2_SENSOR_CROP_OFS_V     0x5004
+#define REG_L2_SENSOR_CROP_HSIZE     0x5008
+#define REG_L2_SENSOR_CROP_VSIZE     0x500c
+#define REG_L2_BUS_L2_STATUS	     0x5018
+#define REG_L2_ROI_NUM		     0x5040
+/* x: 0-1 */
+#define REG_L2_ROI_TO_POST(x)		(0x5044 + 4 * (x))
+#define REG_L2_ROI_X_BASE(x)		(0x5050 + 32 * (x))
+#define REG_L2_ROI_X_SCALE(x)		(REG_L2_ROI_X_BASE(x) + 0)
+#define REG_L2_ROI_X_SCALE_INV(x)	(REG_L2_ROI_X_BASE(x) + 4)
+#define REG_L2_ROI_X_CORRECTED_HSIZE(x) (REG_L2_ROI_X_BASE(x) + 8)
+#define REG_L2_ROI_X_CORRECTED_VSIZE(x) (REG_L2_ROI_X_BASE(x) + 12)
+#define REG_L2_ROI_X_OUT_OFS_H(x)	(REG_L2_ROI_X_BASE(x) + 16)
+#define REG_L2_ROI_X_OUT_HSIZE(x)	(REG_L2_ROI_X_BASE(x) + 24)
+#define REG_L2_ROI_X_OUT_OFS_V(x)	(REG_L2_ROI_X_BASE(x) + 20)
+#define REG_L2_ROI_X_OUT_VSIZE(x)	(REG_L2_ROI_X_BASE(x) + 28)
+#define REG_L2_VALID_R_NORM2_POLY	0x50b0
+#define REG_L2_VALID_R_NORM2_GRID	0x50b4
+#define REG_L2_MODE			0x5100
+#define REG_L2_NORM_SCALE		0x5104
+#define REG_L2_ROI_WRITE_AREA_DELTA(x)	(0x510c + 4 * (x))
+#define REG_L2_GRID_NODE_NUM_H		0x5118
+#define REG_L2_GRID_NODE_NUM_V		0x511c
+#define REG_L2_GRID_PATCH_HSIZE_INV	0x5120
+#define REG_L2_GRID_PATCH_VSIZE_INV	0x5124
+/* x: 0-10 */
+#define REG_L2_POLY10_WRITE_G_COEF(x) (0x5128 + 4 * (x))
+#define REG_L2_POLY10_READ_B_COEF(x)  (0x5154 + 4 * (x))
+#define REG_L2_POLY10_READ_G_COEF(x)  (0x5180 + 4 * (x))
+#define REG_L2_POLY10_READ_R_COEF(x)  (0x51ac + 4 * (x))
+/* x: 0-1 */
+#define REG_L2_POST_X_BASE(x)		    (0x5200 + 256 * (x))
+#define REG_L2_POST_X_CAP_OFFSET(x)	    (REG_L2_POST_X_BASE(x) + 0)
+#define REG_L2_POST_X_CAP_SIZE(x)	    (REG_L2_POST_X_BASE(x) + 4)
+#define REG_L2_POST_X_CSC_MTB_CB1(x)	    (REG_L2_POST_X_BASE(x) + 148)
+#define REG_L2_POST_X_CSC_MTB_CB2(x)	    (REG_L2_POST_X_BASE(x) + 152)
+#define REG_L2_POST_X_CSC_MTB_CB_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 144)
+#define REG_L2_POST_X_CSC_MTB_CB_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 156)
+#define REG_L2_POST_X_CSC_MTB_CR1(x)	    (REG_L2_POST_X_BASE(x) + 164)
+#define REG_L2_POST_X_CSC_MTB_CR2(x)	    (REG_L2_POST_X_BASE(x) + 168)
+#define REG_L2_POST_X_CSC_MTB_CR_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 160)
+#define REG_L2_POST_X_CSC_MTB_CR_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 172)
+#define REG_L2_POST_X_CSC_MTB(x)	    (REG_L2_POST_X_BASE(x) + 112)
+#define REG_L2_POST_X_CSC_MTB_YG1(x)	    (REG_L2_POST_X_BASE(x) + 132)
+#define REG_L2_POST_X_CSC_MTB_YG2(x)	    (REG_L2_POST_X_BASE(x) + 136)
+#define REG_L2_POST_X_CSC_MTB_YG_OFFSETI(x) (REG_L2_POST_X_BASE(x) + 128)
+#define REG_L2_POST_X_CSC_MTB_YG_OFFSETO(x) (REG_L2_POST_X_BASE(x) + 140)
+#define FIELD_CSC_MTB_UPPER(x)		    (FIELD_PREP(0xffff0000, (x)))
+#define FIELD_CSC_MTB_LOWER(x)		    (FIELD_PREP(0x0000ffff, (x)))
+
+#define REG_L2_POST_X_C_SELECT(x)	 (REG_L2_POST_X_BASE(x) + 96)
+#define REG_L2_POST_X_GAMMA_M(x)	 (REG_L2_POST_X_BASE(x) + 80)
+#define REG_L2_POST_X_HALF_SCALE_EN(x)	 (REG_L2_POST_X_BASE(x) + 8)
+#define REG_L2_POST_X_OPORTALP(x)	 (REG_L2_POST_X_BASE(x) + 176)
+#define REG_L2_POST_X_OPORTFMT(x)	 (REG_L2_POST_X_BASE(x) + 180)
+#define REG_L2_POST_X_OUT_PITCH_B(x)	 (REG_L2_POST_X_BASE(x) + 196)
+#define REG_L2_POST_X_OUT_PITCH_G(x)	 (REG_L2_POST_X_BASE(x) + 200)
+#define REG_L2_POST_X_OUT_PITCH_R(x)	 (REG_L2_POST_X_BASE(x) + 204)
+#define REG_L2_POST_X_OUT_STADR_B(x)	 (REG_L2_POST_X_BASE(x) + 184)
+#define REG_L2_POST_X_OUT_STADR_G(x)	 (REG_L2_POST_X_BASE(x) + 188)
+#define REG_L2_POST_X_OUT_STADR_R(x)	 (REG_L2_POST_X_BASE(x) + 192)
+#define REG_L2_CRGBF_TRN_A_CONF		 0x570c
+#define VAL_L2_CRGBF_TRN_AUTO_READ_BANK0 BIT(16)
+
+#define REG_L2_CRGBF_INT_STAT		  0x5718
+#define REG_L2_CRGBF_INT_MASK		  0x571c
+#define REG_L2_CRGBF_INT_MASKED_STAT	  0x5720
+#define REG_L2_CRGBF_TRN_RBADDR		  0x572c
+#define REG_L2_CRGBF_TRN_READDR		  0x5730
+#define REG_L2_CRGBF_ISP_INT		  0x5734
+#define REG_L2_CRGBF_ISP_INT_MASK	  0x5738
+#define MASK_L2_CRGBF_ISP_INT_DONE	  BIT(0)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_POST0 BIT(1)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_POST1 BIT(2)
+#define MASK_L2_CRGBF_ISP_INT_ABORT_OTHER BIT(4)
+#define MASK_L2_STATUS_ERR_ALL                                                   \
+	(MASK_L2_CRGBF_ISP_INT_ABORT_POST0 | MASK_L2_CRGBF_ISP_INT_ABORT_POST1 | \
+	 MASK_L2_CRGBF_ISP_INT_ABORT_OTHER)
+
+/*=============================================*/
+/* HWA bus interface registers */
+/*=============================================*/
+#define REG_HWAIF_HWAIF_EN	  0
+#define REG_HWAIF_HWAIF_CONF	  0x10
+#define REG_HWAIF_OSTD_RLEN	  0x14
+#define REG_HWAIF_OSTD_WREQ	  0x18
+#define REG_HWAIF_REGION_ENTRY_EN 0xf0
+
+/*=============================================*/
+/* Memory Protection Unit registers */
+/*=============================================*/
+#define REG_MPU_MP_EN 0
+#define REG_MPU_MF_EN 0x3a4
+
+#endif /* __VIIF_REGS_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_resizer.c b/drivers/media/platform/toshiba/visconti/viif_resizer.c
new file mode 100644
index 000000000000..ec056ff3adc4
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_resizer.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-rect.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_resizer.h"
+#include "viif_regs.h"
+
+/* default parameters for V4L2 subdevice node */
+#define VISCONTI_VIIF_ISP_DEFAULT_WIDTH	  1920
+#define VISCONTI_VIIF_ISP_DEFAULT_HEIGHT  1080
+#define VISCONTI_VIIF_MAX_COMPOSED_WIDTH  8190
+#define VISCONTI_VIIF_MAX_COMPOSED_HEIGHT 4094
+
+/* up to 2 ROIs are available to be passed to POSTs */
+/* set ROI_NONE for a POST currently not running */
+#define VIIF_L2_ROI_MAX_NUM 2U
+#define VIIF_L2_ROI_NONE    3U
+
+/* minimum crop width and height */
+#define VIIF_CROP_MIN_W 128U
+#define VIIF_CROP_MIN_H 128U
+
+/* Set ROI path condition when ROI num is 2 */
+static void viif_l2_set_roi_num_2(struct viif_device *viif_dev)
+{
+	struct viif_l2_roi_path_info *info = &viif_dev->l2_roi_path_info;
+	u32 i;
+
+	for (i = 0; i < VIIF_L2_ROI_MAX_NUM; i++) {
+		/* ROI-n is the same as CROP area of POST-n */
+		if (info->post_enable_flag[i]) {
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(i),
+					   info->post_crop_x[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(i),
+					   info->post_crop_y[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(i),
+					   info->post_crop_w[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(i),
+					   info->post_crop_h[i]);
+			viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i), i);
+		} else {
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(i), 0);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(i), 0);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(i), VIIF_CROP_MIN_W);
+			viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(i), VIIF_CROP_MIN_H);
+			viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i), VIIF_L2_ROI_NONE);
+		}
+	}
+}
+
+/* Set ROI path condition when ROI num is 1 */
+static void viif_l2_set_roi_num_1(struct viif_device *viif_dev)
+{
+	struct viif_l2_roi_path_info *info = &viif_dev->l2_roi_path_info;
+	u32 val, x_min, x_max, y_min, y_max;
+	u32 i, x, y, w, h;
+
+	/* ROI0 is input to POST0 and POST1 */
+	if (info->post_enable_flag[0]) {
+		/* POST0 is enabled */
+		x_min = info->post_crop_x[0];
+		x_max = info->post_crop_x[0] + info->post_crop_w[0];
+		y_min = info->post_crop_y[0];
+		y_max = info->post_crop_y[0] + info->post_crop_h[0];
+		if (info->post_enable_flag[1]) {
+			/* POST1 is enabled */
+			x_min = min(x_min, info->post_crop_x[1]);
+			val = info->post_crop_x[1] + info->post_crop_w[1];
+			x_max = max(x_max, val);
+			y_min = min(y_min, info->post_crop_y[1]);
+			val = info->post_crop_y[1] + info->post_crop_h[1];
+			y_max = max(y_max, val);
+		}
+		x = x_min;
+		y = y_min;
+		w = x_max - x_min;
+		h = y_max - y_min;
+	} else if (info->post_enable_flag[1]) {
+		/* POST0 is disabled and POST1 is enabled */
+		x = info->post_crop_x[1];
+		w = info->post_crop_w[1];
+		y = info->post_crop_y[1];
+		h = info->post_crop_h[1];
+	} else {
+		/* All POSTs are disabled */
+		x = 0;
+		y = 0;
+		w = VIIF_CROP_MIN_W;
+		h = VIIF_CROP_MIN_H;
+	}
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_H(0), x);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_OFS_V(0), y);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_HSIZE(0), w);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_OUT_VSIZE(0), h);
+
+	for (i = 0; i < VIIF_MAX_POST_NUM; i++)
+		viif_capture_write(viif_dev, REG_L2_ROI_TO_POST(i),
+				   info->post_enable_flag[i] ? 0 : VIIF_L2_ROI_NONE);
+}
+
+/* Set ROI path condition */
+void visconti_viif_l2_set_roi_path(struct viif_device *viif_dev)
+{
+	if (viif_dev->l2_roi_path_info.roi_num == 1U)
+		viif_l2_set_roi_num_1(viif_dev);
+	else
+		viif_l2_set_roi_num_2(viif_dev);
+}
+
+static int visconti_viif_resizer_enable_streams(struct v4l2_subdev *sd,
+						struct v4l2_subdev_state *state, u32 pad,
+						u64 streams_mask)
+{
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VIIF_RESIZER_PAD_SINK]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* currently RESIZER.sink supports only stream0 */
+	return v4l2_subdev_enable_streams(remote_sd, remote_pad->index, BIT(0));
+}
+
+static int visconti_viif_resizer_disable_streams(struct v4l2_subdev *sd,
+						 struct v4l2_subdev_state *state, u32 pad,
+						 u64 streams_mask)
+{
+	struct v4l2_subdev *remote_sd;
+	struct media_pad *remote_pad;
+
+	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VIIF_RESIZER_PAD_SINK]);
+	if (!remote_pad)
+		return -ENODEV;
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	/* currently RESIZER.sink supports only stream0 */
+	return v4l2_subdev_disable_streams(remote_sd, remote_pad->index, BIT(0));
+}
+
+static int visconti_viif_resizer_enum_mbus_code(struct v4l2_subdev *sd,
+						struct v4l2_subdev_state *sd_state,
+						struct v4l2_subdev_mbus_code_enum *code)
+{
+	static const unsigned int sink_codes[] = { MEDIA_BUS_FMT_RGB888_1X24,
+						   MEDIA_BUS_FMT_YUV8_1X24 };
+
+	if (code->pad == VIIF_RESIZER_PAD_SINK) {
+		if (code->index >= ARRAY_SIZE(sink_codes))
+			return -EINVAL;
+		code->code = sink_codes[code->index];
+	} else {
+		/* source pad: same as the sink pad */
+		struct v4l2_mbus_framefmt *sink_fmt;
+
+		sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SINK);
+		code->code = sink_fmt->code;
+	}
+
+	return 0;
+}
+
+static void visconti_viif_resizer_set_sink_fmt(struct v4l2_subdev_state *sd_state,
+					       struct v4l2_mbus_framefmt *format)
+{
+	static const unsigned int sink_codes[] = { MEDIA_BUS_FMT_RGB888_1X24,
+						   MEDIA_BUS_FMT_YUV8_1X24 };
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	struct v4l2_rect sink_rect;
+	unsigned int code;
+	int i;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SINK);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SRC);
+
+	/* sink format */
+	code = sink_codes[0];
+	for (i = 0; i < ARRAY_SIZE(sink_codes); i++)
+		if (format->code == sink_codes[i])
+			code = format->code;
+	sink_fmt->code = code;
+	sink_fmt->width = format->width;
+	sink_fmt->height = format->height;
+
+	sink_rect.top = 0;
+	sink_rect.left = 0;
+	sink_rect.width = sink_fmt->width;
+	sink_rect.height = sink_fmt->height;
+
+	/* sink compose */
+	*v4l2_subdev_state_get_compose(sd_state, VIIF_RESIZER_PAD_SINK) = sink_rect;
+
+	/* src crop */
+	*v4l2_subdev_state_get_crop(sd_state, VIIF_RESIZER_PAD_SRC) = sink_rect;
+
+	/* src format */
+	src_fmt->code = sink_fmt->code;
+	src_fmt->width = sink_fmt->width;
+	src_fmt->height = sink_fmt->height;
+
+	*format = *sink_fmt;
+}
+
+static void visconti_viif_resizer_set_src_fmt(struct v4l2_subdev_state *sd_state,
+					      struct v4l2_mbus_framefmt *format)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SINK);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SRC);
+
+	src_fmt->code = sink_fmt->code;
+	src_fmt->width = sink_fmt->width;
+	src_fmt->height = sink_fmt->height;
+
+	*format = *src_fmt;
+}
+
+static int visconti_viif_resizer_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
+					 struct v4l2_subdev_format *fmt)
+{
+	if (fmt->pad == VIIF_RESIZER_PAD_SINK)
+		visconti_viif_resizer_set_sink_fmt(sd_state, &fmt->format);
+	else
+		visconti_viif_resizer_set_src_fmt(sd_state, &fmt->format);
+
+	return 0;
+}
+
+static int visconti_viif_resizer_init_state(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+	struct v4l2_rect *src_crop, *sink_compose;
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SINK);
+	sink_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	sink_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+	sink_compose = v4l2_subdev_state_get_compose(sd_state, VIIF_RESIZER_PAD_SINK);
+	sink_compose->top = 0;
+	sink_compose->left = 0;
+	sink_compose->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	sink_compose->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SRC);
+	src_fmt->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_fmt->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+	src_fmt->field = V4L2_FIELD_NONE;
+	src_fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+	src_crop = v4l2_subdev_state_get_crop(sd_state, VIIF_RESIZER_PAD_SRC);
+	src_crop->top = 0;
+	src_crop->left = 0;
+	src_crop->width = VISCONTI_VIIF_ISP_DEFAULT_WIDTH;
+	src_crop->height = VISCONTI_VIIF_ISP_DEFAULT_HEIGHT;
+
+	return 0;
+}
+
+static const struct v4l2_rect viif_resizer_sink_compose_bound = {
+	.top = 0,
+	.left = 0,
+	.width = VISCONTI_VIIF_MAX_COMPOSED_WIDTH,
+	.height = VISCONTI_VIIF_MAX_COMPOSED_HEIGHT,
+};
+
+static int visconti_viif_resizer_get_selection(struct v4l2_subdev *sd,
+					       struct v4l2_subdev_state *sd_state,
+					       struct v4l2_subdev_selection *sel)
+{
+	if (sel->pad == VIIF_RESIZER_PAD_SINK) {
+		struct v4l2_mbus_framefmt *sink_fmt;
+
+		switch (sel->target) {
+		case V4L2_SEL_TGT_CROP:
+			sink_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SINK);
+			sel->r.top = 0;
+			sel->r.left = 0;
+			sel->r.width = sink_fmt->width;
+			sel->r.height = sink_fmt->height;
+			return 0;
+		case V4L2_SEL_TGT_COMPOSE:
+			sel->r = *v4l2_subdev_state_get_compose(sd_state, VIIF_RESIZER_PAD_SINK);
+			return 0;
+		case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+			sel->r = viif_resizer_sink_compose_bound;
+			return 0;
+		}
+	} else {
+		switch (sel->target) {
+		case V4L2_SEL_TGT_CROP:
+			sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int visconti_viif_resizer_set_selection(struct v4l2_subdev *sd,
+					       struct v4l2_subdev_state *sd_state,
+					       struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_rect *rect_compose;
+	struct v4l2_mbus_framefmt *src_fmt;
+
+	if (sel->pad == VIIF_RESIZER_PAD_SINK && sel->target == V4L2_SEL_TGT_COMPOSE) {
+		rect_compose = v4l2_subdev_state_get_compose(sd_state, VIIF_RESIZER_PAD_SINK);
+		v4l2_rect_set_max_size(&sel->r, &viif_resizer_sink_compose_bound);
+		v4l2_rect_map_inside(&sel->r, &viif_resizer_sink_compose_bound);
+		*rect_compose = sel->r;
+
+		/* update SRC::CROP with SINK::COMPOSE */
+		*v4l2_subdev_state_get_crop(sd_state, VIIF_RESIZER_PAD_SRC) = *rect_compose;
+
+		/* update SRC::FMT with SINK_COMPOSE */
+		src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SRC);
+		src_fmt->width = rect_compose->width;
+		src_fmt->height = rect_compose->height;
+		return 0;
+	}
+	if (sel->pad == VIIF_RESIZER_PAD_SRC && sel->target == V4L2_SEL_TGT_CROP) {
+		struct v4l2_rect *rect, rect_crop_bound;
+
+		rect_compose = v4l2_subdev_state_get_compose(sd_state, VIIF_RESIZER_PAD_SINK);
+		rect_crop_bound.left = 1;
+		rect_crop_bound.top = 1;
+		rect_crop_bound.width = rect_compose->width - 2;
+		rect_crop_bound.height = rect_compose->height - 2;
+		v4l2_rect_set_max_size(&sel->r, &rect_crop_bound);
+		v4l2_rect_map_inside(&sel->r, &rect_crop_bound);
+		rect = v4l2_subdev_state_get_crop(sd_state, VIIF_RESIZER_PAD_SRC);
+		*rect = sel->r;
+
+		/* update SRC::FMT with given SRC::CROP */
+		src_fmt = v4l2_subdev_state_get_format(sd_state, VIIF_RESIZER_PAD_SRC);
+		src_fmt->width = sel->r.width;
+		src_fmt->height = sel->r.height;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static const struct media_entity_operations visconti_viif_resizer_media_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_pad_ops visconti_viif_resizer_pad_ops = {
+	.disable_streams = visconti_viif_resizer_disable_streams,
+	.enable_streams = visconti_viif_resizer_enable_streams,
+	.enum_mbus_code = visconti_viif_resizer_enum_mbus_code,
+	.get_selection = visconti_viif_resizer_get_selection,
+	.set_selection = visconti_viif_resizer_set_selection,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = visconti_viif_resizer_set_fmt,
+	.link_validate = v4l2_subdev_link_validate_default,
+};
+
+static const struct v4l2_subdev_video_ops visconti_viif_resizer_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_ops visconti_viif_resizer_ops = {
+	.video = &visconti_viif_resizer_video_ops,
+	.pad = &visconti_viif_resizer_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops visconti_viif_resizer_internal_ops = {
+	.init_state = visconti_viif_resizer_init_state,
+};
+
+static int viif_resizer_register_node(struct resizer_subdev *resizer_subdev)
+{
+	struct viif_device *viif_dev = resizer_subdev->viif_dev;
+	struct media_pad *pads = resizer_subdev->pads;
+	struct v4l2_subdev *sd = &resizer_subdev->sd;
+	static const char *const node_name[] = {
+		"visconti-viif:resizer0",
+		"visconti-viif:resizer1",
+	};
+	int ret;
+
+	v4l2_subdev_init(sd, &visconti_viif_resizer_ops);
+	sd->internal_ops = &visconti_viif_resizer_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	sd->entity.ops = &visconti_viif_resizer_media_ops;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+	sd->owner = THIS_MODULE;
+	strscpy(sd->name, node_name[resizer_subdev->pathid], sizeof(sd->name));
+
+	pads[VIIF_RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	pads[VIIF_RESIZER_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
+
+	ret = media_entity_pads_init(&sd->entity, VIIF_RESIZER_PAD_NUM, pads);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed on media_entity_pads_init\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		goto err_cleanup_media_entity;
+
+	ret = v4l2_device_register_subdev(&viif_dev->v4l2_dev, sd);
+	if (ret) {
+		dev_err(viif_dev->dev, "Failed to register Resizer subdev\n");
+		goto err_cleanup_subdev;
+	}
+
+	return 0;
+
+err_cleanup_subdev:
+	v4l2_subdev_cleanup(sd);
+err_cleanup_media_entity:
+	media_entity_cleanup(&sd->entity);
+	return ret;
+}
+
+int visconti_viif_resizer_register(struct viif_device *viif_dev)
+{
+	int ret;
+
+	/* register MAIN POST0 (primary RGB) */
+	viif_dev->resizer_post0.pathid = RESIZER_PATH_MAIN_POST0;
+	viif_dev->resizer_post0.viif_dev = viif_dev;
+	ret = viif_resizer_register_node(&viif_dev->resizer_post0);
+	if (ret)
+		return ret;
+
+	/* register MAIN POST1 (additional RGB) */
+	viif_dev->resizer_post1.pathid = RESIZER_PATH_MAIN_POST1;
+	viif_dev->resizer_post1.viif_dev = viif_dev;
+	ret = viif_resizer_register_node(&viif_dev->resizer_post1);
+	if (ret)
+		return ret;
+
+	/* no resizer for SUB (RAW) */
+	return 0;
+}
+
+void visconti_viif_resizer_unregister(struct viif_device *viif_dev)
+{
+	v4l2_device_unregister_subdev(&viif_dev->resizer_post0.sd);
+	v4l2_device_unregister_subdev(&viif_dev->resizer_post1.sd);
+	media_entity_cleanup(&viif_dev->resizer_post0.sd.entity);
+	media_entity_cleanup(&viif_dev->resizer_post1.sd.entity);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_resizer.h b/drivers/media/platform/toshiba/visconti/viif_resizer.h
new file mode 100644
index 000000000000..2494be320494
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_resizer.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_RESIZER_H__
+#define __VIIF_RESIZER_H__
+
+struct viif_device;
+
+void visconti_viif_l2_set_roi_path(struct viif_device *viif_dev);
+
+int visconti_viif_resizer_register(struct viif_device *viif_dev);
+void visconti_viif_resizer_unregister(struct viif_device *viif_dev);
+
+#endif /* __VIIF_RESIZER_H__ */
diff --git a/include/uapi/linux/visconti_viif.h b/include/uapi/linux/visconti_viif.h
new file mode 100644
index 000000000000..b44e8a73173c
--- /dev/null
+++ b/include/uapi/linux/visconti_viif.h
@@ -0,0 +1,1921 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __UAPI_VISCONTI_VIIF_H_
+#define __UAPI_VISCONTI_VIIF_H_
+
+#include <linux/types.h>
+#include <linux/v4l2-controls.h>
+
+/* Enable/Disable flag */
+#define VIIF_DISABLE (0U)
+#define VIIF_ENABLE  (1U)
+
+/**
+ * enum viif_l1_input - L1ISP preprocessing mode,
+ *
+ * @VIIF_L1_INPUT_HDR: accepts HDR input; bypass preprocessing
+ * @VIIF_L1_INPUT_PWL: accepts PWL input; runs HDRE
+ * @VIIF_L1_INPUT_HDR_IMG_CORRECT: accepts HDR input; runs SLIC, ABPC, PWHB, RCNR, HDRS
+ * @VIIF_L1_INPUT_PWL_IMG_CORRECT: accepts PWR input; runs HDRE, SLIC, ABPC, PWHB, RCNR, HDRS
+ */
+enum viif_l1_input {
+	VIIF_L1_INPUT_HDR = 0,
+	VIIF_L1_INPUT_PWL = 1,
+	VIIF_L1_INPUT_HDR_IMG_CORRECT = 3,
+	VIIF_L1_INPUT_PWL_IMG_CORRECT = 4,
+};
+
+/**
+ * struct viif_l1_input_mode_config - L1ISP parameter for input mode.
+ *
+ * @mode: &enum viif_l1_input value.
+ */
+struct viif_l1_input_mode_config {
+	__u32 mode;
+};
+
+/**
+ * struct viif_l1_rgb_to_y_coef_config - L1ISP parameter for calculating Y from RGB
+ *
+ * @coef_r: R co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ * @coef_g: G co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ * @coef_b: B co-efficient. Range: [256..65024], Accuracy: 1/65536.
+ * @reserved: padding field
+ */
+struct viif_l1_rgb_to_y_coef_config {
+	__u16 coef_r;
+	__u16 coef_g;
+	__u16 coef_b;
+	__u16 reserved;
+};
+
+/**
+ * enum viif_l1_img_sensitivity_mode - L1ISP image sensitivity
+ *
+ * @VIIF_L1_IMG_SENSITIVITY_HIGH: high sensitivity
+ * @VIIF_L1_IMG_SENSITIVITY_MIDDLE_LED: middle sensitivity or led
+ * @VIIF_L1_IMG_SENSITIVITY_LOW: low sensitivity
+ */
+enum viif_l1_img_sensitivity_mode {
+	VIIF_L1_IMG_SENSITIVITY_HIGH = 0,
+	VIIF_L1_IMG_SENSITIVITY_MIDDLE_LED = 1,
+	VIIF_L1_IMG_SENSITIVITY_LOW = 2,
+};
+
+/**
+ * struct viif_l1_ag_mode_config - L1ISP parameter for analog gain
+ *
+ * @sysm_ag_grad: Analog gain slope. Range: [0..255], Index corresponds to psel id.
+ * @sysm_ag_ofst: Analog gain offset. Range: [0..65535], Index corresponds to psel id.
+ * @sysm_ag_cont_hobc_en_high: set 1 to enable  control analog gain
+ *                             for high sensitivity image of OBCC
+ * @sysm_ag_psel_hobc_high: Analog gain id for high sensitivity image of OBCC. Range: [0..3]
+ * @sysm_ag_cont_hobc_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of OBCC
+ * @sysm_ag_psel_hobc_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of OBCC. Range: [0..3]
+ * @sysm_ag_cont_hobc_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of OBCC
+ * @sysm_ag_psel_hobc_low: Analog gain id for low sensitivity image of OBCC. Range:[0..3]
+ * @sysm_ag_cont_abpc_en_high: set 1 to enable control analog gain
+ *                             for high sensitivity image of ABPC
+ * @sysm_ag_psel_abpc_high: Analog gain id for high sensitivity image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_abpc_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of ABPC
+ * @sysm_ag_psel_abpc_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_abpc_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of ABPC
+ * @sysm_ag_psel_abpc_low: Analog gain id for low sensitivity image of ABPC. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_high: set 1 to enable control analog gain
+ *                             for high sensitivity image of RCNR
+ * @sysm_ag_psel_rcnr_high: Analog gain id for high sensitivity image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_middle_led: set 1 to enable control analog gain
+ *                                   for middle sensitivity or LED image of RCNR
+ * @sysm_ag_psel_rcnr_middle_led: Analog gain id for middle sensitivity
+ *                                or LED image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_rcnr_en_low: set 1 to enable control analog gain
+ *                            for low sensitivity image of RCNR
+ * @sysm_ag_psel_rcnr_low: Analog gain id for low sensitivity image of RCNR. Range: [0..3]
+ * @sysm_ag_cont_lssc_en: set 1 to enable control analog gain for LSC
+ * @sysm_ag_ssel_lssc: &enum viif_l1_img_sensitivity_mode value. Sensitive image used for LSC.
+ * @sysm_ag_psel_lssc: Analog gain id for LSC. Range: [0..3]
+ * @sysm_ag_cont_mpro_en: set 1 to enable control analog gain for color matrix
+ * @sysm_ag_ssel_mpro: &enum viif_l1_img_sensitivity_mode value.
+ *                     Sensitive image used for color matrix.
+ * @sysm_ag_psel_mpro: Analog gain id for color matrix. Range: [0..3]
+ * @sysm_ag_cont_vpro_en: set 1 to enable control analog gain for image adjustment
+ * @sysm_ag_ssel_vpro: &enum viif_l1_img_sensitivity_mode value.
+ *                     Sensitive image used for image adjustment.
+ * @sysm_ag_psel_vpro: Analog gain id for image adjustment. Range: [0..3]
+ * @sysm_ag_cont_hobc_test_high: Manual analog gain for high sensitivity image
+ *                               of OBCC. Range: [0..255]
+ * @sysm_ag_cont_hobc_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of OBCC. Range: [0..255]
+ * @sysm_ag_cont_hobc_test_low: Manual analog gain for low sensitivity image
+ *                              of OBCC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_high: Manual analog gain for high sensitivity image
+ *                               of ABPC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of ABPC. Range: [0..255]
+ * @sysm_ag_cont_abpc_test_low: Manual analog gain for low sensitivity image
+ *                              of ABPC. Range: [0..255]
+ * @sysm_ag_cont_rcnr_test_high: Manual analog gain for high sensitivity image
+ *                               of RCNR. Range:  [0..255]
+ * @sysm_ag_cont_rcnr_test_middle_led: Manual analog gain for middle sensitivity
+ *                                     or led image of RCNR. Range: [0..255]
+ * @sysm_ag_cont_rcnr_test_low: Manual analog gain for low sensitivity image
+ *                              of RCNR. Range:  [0..255]
+ * @sysm_ag_cont_lssc_test: Manual analog gain for LSSC. Range: [0..255]
+ * @sysm_ag_cont_mpro_test: Manual analog gain for color matrix. Range: [0..255]
+ * @sysm_ag_cont_vpro_test: Manual analog gain for image adjustment. Range: [0..255]
+ *
+ * This parameter sets rules of generating analog gains for each feature in L1ISP.
+ * Related features are:
+ *
+ * - Optical Black Clamp Correction (OBCC)
+ * - Defect Pixel Correction (DPC)
+ * - RAW Color Noise Reduction (RCNR)
+ * - Lens Shading Correction (LSC)
+ * - Color matrix correction (MPRO)
+ * - Image quality adjustment (VPRO)
+ *
+ * The base gain is set with  &struct viif_l1_ag_config.
+ *
+ * If sysm_ag_cont_xxxx_en = 1, analog_gain for each module is generated from
+ * sysm_ag_grad, sysm_ag_ofst and the value specified with &struct viif_l1_ag_config.
+ * If sysm_ag_cont_xxxx_en = 0,
+ * the value of sysm_ag_cont_xxxx_test is used for analog_gain for each module.
+ *
+ * Up to 4 sets of parameters (sysm_ag_grad[4] and sysm_ag_ofst[4]) can be used
+ * to generate analog gain.
+ * The parameter sysm_ag_psel_xxxx specifies the set to be used for module xxxx.
+ * For example, if sysm_ag_psel_hobc_high is set to 2,
+ * values in sysm_ag_grad[2] and sysm_ag_ofst[2] are used
+ * to generate analog gain for high sensitivity images in OBCC processing.
+ *
+ * Analog gain generation for each L1ISP module is disabled when
+ * "sysm_ag_cont_xxxx_en=0" and "sysm_ag_cont_xxxx_test=0".
+ * Be sure to disable the analog gain generation
+ * if VIIF_L1_INPUT_HDR or VIIF_L1_INPUT_PWL is set to
+ * &struct viif_l1_input_mode_config
+ *
+ */
+struct viif_l1_ag_mode_config {
+	__u8 sysm_ag_grad[4];
+	__u16 sysm_ag_ofst[4];
+	__u32 sysm_ag_cont_hobc_en_high;
+	__u32 sysm_ag_psel_hobc_high;
+	__u32 sysm_ag_cont_hobc_en_middle_led;
+	__u32 sysm_ag_psel_hobc_middle_led;
+	__u32 sysm_ag_cont_hobc_en_low;
+	__u32 sysm_ag_psel_hobc_low;
+	__u32 sysm_ag_cont_abpc_en_high;
+	__u32 sysm_ag_psel_abpc_high;
+	__u32 sysm_ag_cont_abpc_en_middle_led;
+	__u32 sysm_ag_psel_abpc_middle_led;
+	__u32 sysm_ag_cont_abpc_en_low;
+	__u32 sysm_ag_psel_abpc_low;
+	__u32 sysm_ag_cont_rcnr_en_high;
+	__u32 sysm_ag_psel_rcnr_high;
+	__u32 sysm_ag_cont_rcnr_en_middle_led;
+	__u32 sysm_ag_psel_rcnr_middle_led;
+	__u32 sysm_ag_cont_rcnr_en_low;
+	__u32 sysm_ag_psel_rcnr_low;
+	__u32 sysm_ag_cont_lssc_en;
+	__u32 sysm_ag_ssel_lssc;
+	__u32 sysm_ag_psel_lssc;
+	__u32 sysm_ag_cont_mpro_en;
+	__u32 sysm_ag_ssel_mpro;
+	__u32 sysm_ag_psel_mpro;
+	__u32 sysm_ag_cont_vpro_en;
+	__u32 sysm_ag_ssel_vpro;
+	__u32 sysm_ag_psel_vpro;
+	__u8 sysm_ag_cont_hobc_test_high;
+	__u8 sysm_ag_cont_hobc_test_middle_led;
+	__u8 sysm_ag_cont_hobc_test_low;
+	__u8 sysm_ag_cont_abpc_test_high;
+	__u8 sysm_ag_cont_abpc_test_middle_led;
+	__u8 sysm_ag_cont_abpc_test_low;
+	__u8 sysm_ag_cont_rcnr_test_high;
+	__u8 sysm_ag_cont_rcnr_test_middle_led;
+	__u8 sysm_ag_cont_rcnr_test_low;
+	__u8 sysm_ag_cont_lssc_test;
+	__u8 sysm_ag_cont_mpro_test;
+	__u8 sysm_ag_cont_vpro_test;
+};
+
+/**
+ * struct viif_l1_ag_config - L1ISP parameter for analog gain
+ *
+ * @gain_h: Analog gain for high sensitive image. Range: [0..65535].
+ * @gain_m: Analog gain for middle sensitive image or LED image. Range: [0..65535].
+ * @gain_l: Analog gain for low sensitive image. Range:  [0..65535].
+ * @reserved: padding field
+ *
+ * This parameter provides base analog gain commonly used in L1ISP features.
+ * Analog gain for each L1ISP feature is generated from this base analog gain
+ * and a configuration via &struct viif_l1_ag_mode_config.
+ */
+struct viif_l1_ag_config {
+	__u16 gain_h;
+	__u16 gain_m;
+	__u16 gain_l;
+	__u16 reserved;
+};
+
+/**
+ * struct viif_l1_hdre_config - L1ISP parameter for HDR expansion at preprocessing
+ *
+ * @hdre_src_point: Knee point N value of PWL compressed signal. Range: [0..0x3fff].
+ * @hdre_dst_base: Offset value of HDR signal in Knee area M. Range: [0..0xffffff].
+ * @hdre_ratio: Slope of output pixel value in Knee area M.
+ *              Range: [0..0x3fffff], Accuracy: 1/64.
+ * @hdre_dst_max_val: Maximum value of output pixel. Range: [0..0xffffff].
+ */
+struct viif_l1_hdre_config {
+	__u32 hdre_src_point[16];
+	__u32 hdre_dst_base[17];
+	__u32 hdre_ratio[17];
+	__u32 hdre_dst_max_val;
+};
+
+/**
+ * struct viif_l1_img_extraction_config -  L1ISP parameter for black level of input image
+ *
+ * @input_black_gr: Black level of input pixel (Gr). Range: [0..0xffffff].
+ * @input_black_r: Black level of input pixel (R). Range: [0..0xffffff].
+ * @input_black_b: Black level of input pixel (B). Range: [0..0xffffff].
+ * @input_black_gb: Black level of input pixel (Gb). Range: [0..0xffffff].
+ */
+struct viif_l1_img_extraction_config {
+	__u32 input_black_gr;
+	__u32 input_black_r;
+	__u32 input_black_b;
+	__u32 input_black_gb;
+};
+
+/**
+ * enum viif_l1_dpc_mode - L1ISP defect pixel correction mode
+ * @VIIF_L1_DPC_1PIXEL: 1 pixel correction mode
+ * @VIIF_L1_DPC_2PIXEL: 2 pixel correction mode
+ */
+enum viif_l1_dpc_mode {
+	VIIF_L1_DPC_1PIXEL = 0,
+	VIIF_L1_DPC_2PIXEL = 1,
+};
+
+/**
+ * struct viif_l1_dpc - L1ISP defect pixel correction parameters
+ * for &struct viif_l1_dpc_config
+ * @abpc_sta_en: 1:enable/0:disable setting of Static DPC
+ * @abpc_dyn_en: 1:enable/0:disable setting of Dynamic DPC
+ * @abpc_dyn_mode: &enum viif_l1_dpc_mode value. Sets dynamic DPC mode.
+ * @abpc_ratio_limit: Variation adjustment of dynamic DPC. Range: [0..1023].
+ * @abpc_dark_limit: White defect judgment limit of dark area. Range: [0..1023].
+ * @abpc_sn_coef_w_ag_min: Luminance difference adjustment of white DPC
+ *                         (undere lower threshold).
+ * @abpc_sn_coef_w_ag_mid: Luminance difference adjustment of white DPC
+ *                         (between lower and upper threshold).
+ * @abpc_sn_coef_w_ag_max: Luminance difference adjustment of white DPC
+ *                         (over upper threshold).
+ * @abpc_sn_coef_b_ag_min: Luminance difference adjustment of black DPC
+ *                         (undere lower threshold).
+ * @abpc_sn_coef_b_ag_mid: Luminance difference adjustment of black DPC
+ *                         (between lower and upper threshold).
+ * @abpc_sn_coef_b_ag_max: Luminance difference adjustment of black DPC
+ *                         (over upper threshold).
+ * @abpc_sn_coef_w_th_min: Luminance difference adjustment of white DPC
+ *                         analog gain lower threshold.
+ * @abpc_sn_coef_w_th_max: Luminance difference adjustment of white DPC
+ *                         analog gain upper threshold.
+ * @abpc_sn_coef_b_th_min: Luminance difference adjustment of black DPC
+ *                         analog gain lower threshold.
+ * @abpc_sn_coef_b_th_max: Luminance difference adjustment of black DPC
+ *                         analog gain upper threshold.
+ *
+ * Range of abpc_sn_coef_{w,b}_ag_{min,mid,max} is:
+ *
+ * - Range: [1..31]
+ *
+ * Range and constraints of sn_coef_{w,b}_th_{min,max} are:
+ *
+ * - Range: [0..255]
+ * - Constraint: abpc_sn_coef_w_th_min < abpc_sn_coef_w_th_max
+ * - Constraint: abpc_sn_coef_b_th_min < abpc_sn_coef_b_th_max
+ */
+struct viif_l1_dpc {
+	__u32 abpc_sta_en;
+	__u32 abpc_dyn_en;
+	__u32 abpc_dyn_mode;
+	__u32 abpc_ratio_limit;
+	__u32 abpc_dark_limit;
+	__u32 abpc_sn_coef_w_ag_min;
+	__u32 abpc_sn_coef_w_ag_mid;
+	__u32 abpc_sn_coef_w_ag_max;
+	__u32 abpc_sn_coef_b_ag_min;
+	__u32 abpc_sn_coef_b_ag_mid;
+	__u32 abpc_sn_coef_b_ag_max;
+	__u8 abpc_sn_coef_w_th_min;
+	__u8 abpc_sn_coef_w_th_max;
+	__u8 abpc_sn_coef_b_th_min;
+	__u8 abpc_sn_coef_b_th_max;
+};
+
+/**
+ * struct viif_l1_dpc_config - L1ISP parameter for defect pixel correction
+ *
+ * @param_h: DPC parameter for high sensitive image. Refer to &struct viif_l1_dpc
+ * @param_m: DPC parameter for middle sensitive image. Refer to &struct viif_l1_dpc
+ * @param_l: DPC parameter for low sensitive image. Refer to &struct viif_l1_dpc
+ * @table_h: DPC table for high sensitive image.
+ *           The table is referred only when param_h.abpc_sta_en =1
+ * @table_m: DPC table for middle sensitive image or LED image.
+ *           The table is referred only when param_m.abpc_sta_en =1
+ * @table_l: DPC table for low sensitive image.
+ *           The table is referred only when param_l.abpc_sta_en =1
+ *
+ * The size of each table is 8192 Bytes (u32 * 2048)
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the DPC table.
+ */
+struct viif_l1_dpc_config {
+	struct viif_l1_dpc param_h;
+	struct viif_l1_dpc param_m;
+	struct viif_l1_dpc param_l;
+	__u32 table_h[2048];
+	__u32 table_m[2048];
+	__u32 table_l[2048];
+};
+
+/**
+ * struct viif_l1_preset_wb - L1ISP  preset white balance parameters
+ * for &struct viif_l1_preset_white_balance_config
+ * @gain_gr: Gr gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_r: R gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_b: B gain. Range: [0..524287], Accuracy 1/16384
+ * @gain_gb: Gb gain. Range: [0..524287], Accuracy 1/16384
+ */
+struct viif_l1_preset_wb {
+	__u32 gain_gr;
+	__u32 gain_r;
+	__u32 gain_b;
+	__u32 gain_gb;
+};
+
+/**
+ * struct viif_l1_preset_white_balance_config - L1ISP parameter for preset white balance
+ *
+ * @dstmaxval: Maximum value of output pixel. Range: [0..4095]
+ * @param_h: Preset white balance parameter for high sensitive image.
+ *           Refer to &struct viif_l1_preset_wb
+ * @param_m: Preset white balance parameters for middle sensitive image or LED image.
+ *           Refer to &struct viif_l1_preset_wb
+ * @param_l: Preset white balance parameters for low sensitive image.
+ *           Refer to &struct viif_l1_preset_wb
+ */
+struct viif_l1_preset_white_balance_config {
+	__u32 dstmaxval;
+	struct viif_l1_preset_wb param_h;
+	struct viif_l1_preset_wb param_m;
+	struct viif_l1_preset_wb param_l;
+};
+
+/**
+ * enum viif_l1_rcnr_type - L1ISP high resolution luminance filter type
+ *
+ * @VIIF_L1_RCNR_LOW_RESOLUTION: low resolution
+ * @VIIF_L1_RCNR_MIDDLE_RESOLUTION: middle resolution
+ * @VIIF_L1_RCNR_HIGH_RESOLUTION: high resolution
+ * @VIIF_L1_RCNR_ULTRA_HIGH_RESOLUTION: ultra high resolution
+ */
+enum viif_l1_rcnr_type {
+	VIIF_L1_RCNR_LOW_RESOLUTION = 0,
+	VIIF_L1_RCNR_MIDDLE_RESOLUTION = 1,
+	VIIF_L1_RCNR_HIGH_RESOLUTION = 2,
+	VIIF_L1_RCNR_ULTRA_HIGH_RESOLUTION = 3,
+};
+
+/**
+ * enum viif_l1_msf_blend_ratio - L1ISP MSF blend ratio
+ *
+ * @VIIF_L1_MSF_BLEND_RATIO_0_DIV_64: 0/64
+ * @VIIF_L1_MSF_BLEND_RATIO_1_DIV_64: 1/64
+ * @VIIF_L1_MSF_BLEND_RATIO_2_DIV_64: 2/64
+ */
+enum viif_l1_msf_blend_ratio {
+	VIIF_L1_MSF_BLEND_RATIO_0_DIV_64 = 0,
+	VIIF_L1_MSF_BLEND_RATIO_1_DIV_64 = 1,
+	VIIF_L1_MSF_BLEND_RATIO_2_DIV_64 = 2,
+};
+
+/**
+ * struct viif_l1_raw_color_noise_reduction - L1ISP RCNR parameters
+ * for &struct viif_l1_raw_color_noise_reduction_config
+ *
+ * @rcnr_sw: set 1 to enable RAW color noise reduction, 0 to disable.
+ * @rcnr_cnf_dark_ag0: Maximum value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_dark_ag1: Middle value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_dark_ag2: Minimum value of LSF dark noise adjustment. Range: [0..63].
+ * @rcnr_cnf_ratio_ag0: Maximum value of LSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_cnf_ratio_ag1: Middle value of LSF luminance interlocking noise adjustment:
+ *                      Range: [0..31].
+ * @rcnr_cnf_ratio_ag2: Minimum value of LSF luminance interlocking noise adjustment:
+ *                      Range: [0..31].
+ * @rcnr_cnf_clip_gain_r: LSF color correction limit adjustment gain R. Range: [0..3].
+ * @rcnr_cnf_clip_gain_g: LSF color correction limit adjustment gain G. Range: [0..3].
+ * @rcnr_cnf_clip_gain_b: LSF color correction limit adjustment gain B. Range: [0..3].
+ * @rcnr_a1l_dark_ag0: Maximum value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_dark_ag1: Middle value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_dark_ag2: Minimum value of MSF dark noise adjustment. Range: [0..63].
+ * @rcnr_a1l_ratio_ag0: Maximum value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_a1l_ratio_ag1: Middle value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_a1l_ratio_ag2: Minimum value of MSF luminance interlocking noise adjustment.
+ *                      Range: [0..31].
+ * @rcnr_inf_zero_clip: Input stage zero clip setting. Range: [0..256].
+ * @rcnr_merge_d2blend_ag0: Maximum value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_d2blend_ag1: Middle value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_d2blend_ag2: Minimum value of filter results and input blend ratio. Range: [0..16].
+ * @rcnr_merge_black: Black level minimum value. Range: [0..64].
+ * @rcnr_merge_mindiv: 0 div guard value of inverse arithmetic unit. Range: [4..16].
+ * @rcnr_hry_type: &enum viif_l1_rcnr_type value. Filter type for HSF filter process.
+ * @rcnr_anf_blend_ag0: &enum viif_l1_msf_blend_ratio value.
+ *                      Maximum value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_anf_blend_ag1: &enum viif_l1_msf_blend_ratio value.
+ *                      Middle value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_anf_blend_ag2: &enum viif_l1_msf_blend_ratio value.
+ *                      Minimum value of MSF result blend ratio in write back data to line memory.
+ * @rcnr_lpf_threshold: Multiplier value for calculating dark noise / luminance
+ *                      interlock noise of MSF. Range: [0..31], Accuracy: 1/8.
+ * @rcnr_merge_hlblend_ag0: Maximum value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_merge_hlblend_ag1: Middle value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_merge_hlblend_ag2: Minimum value of luminance signal generation blend. Range: [0..2].
+ * @rcnr_gnr_sw: set 1 to enable Gr/Gb sensitivity ratio correction function switching,
+ *                0 to disable.
+ * @rcnr_gnr_ratio: Upper limit of Gr/Gb sensitivity ratio correction factor. Range: [0..15].
+ * @rcnr_gnr_wide_en: set 1 to double correction upper limit ratio of rcnr_gnr_ratio,
+ *                    0 to just use the specified ratio.
+ */
+struct viif_l1_raw_color_noise_reduction {
+	__u32 rcnr_sw;
+	__u32 rcnr_cnf_dark_ag0;
+	__u32 rcnr_cnf_dark_ag1;
+	__u32 rcnr_cnf_dark_ag2;
+	__u32 rcnr_cnf_ratio_ag0;
+	__u32 rcnr_cnf_ratio_ag1;
+	__u32 rcnr_cnf_ratio_ag2;
+	__u32 rcnr_cnf_clip_gain_r;
+	__u32 rcnr_cnf_clip_gain_g;
+	__u32 rcnr_cnf_clip_gain_b;
+	__u32 rcnr_a1l_dark_ag0;
+	__u32 rcnr_a1l_dark_ag1;
+	__u32 rcnr_a1l_dark_ag2;
+	__u32 rcnr_a1l_ratio_ag0;
+	__u32 rcnr_a1l_ratio_ag1;
+	__u32 rcnr_a1l_ratio_ag2;
+	__u32 rcnr_inf_zero_clip;
+	__u32 rcnr_merge_d2blend_ag0;
+	__u32 rcnr_merge_d2blend_ag1;
+	__u32 rcnr_merge_d2blend_ag2;
+	__u32 rcnr_merge_black;
+	__u32 rcnr_merge_mindiv;
+	__u32 rcnr_hry_type;
+	__u32 rcnr_anf_blend_ag0;
+	__u32 rcnr_anf_blend_ag1;
+	__u32 rcnr_anf_blend_ag2;
+	__u32 rcnr_lpf_threshold;
+	__u32 rcnr_merge_hlblend_ag0;
+	__u32 rcnr_merge_hlblend_ag1;
+	__u32 rcnr_merge_hlblend_ag2;
+	__u32 rcnr_gnr_sw;
+	__u32 rcnr_gnr_ratio;
+	__u32 rcnr_gnr_wide_en;
+};
+
+/**
+ * struct viif_l1_raw_color_noise_reduction_config - L1ISP parameter for raw color noise reduction.
+ *
+ * @param_h: RAW color noise reduction parameter for high sensitive image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ * @param_m: RAW color noise reduction parameter for middle sensitive image or LED image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ * @param_l: RAW color noise reduction parameter for low sensitive image.
+ *           Refer to &struct viif_l1_raw_color_noise_reduction
+ */
+struct viif_l1_raw_color_noise_reduction_config {
+	struct viif_l1_raw_color_noise_reduction param_h;
+	struct viif_l1_raw_color_noise_reduction param_m;
+	struct viif_l1_raw_color_noise_reduction param_l;
+};
+
+/**
+ * enum viif_l1_hdrs_middle_img_mode - L1ISP HDR setting
+ *
+ * @VIIF_L1_HDRS_NOT_USE_MIDDLE_SENS_IMAGE: not use middle image
+ * @VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE: use middle image
+ */
+enum viif_l1_hdrs_middle_img_mode {
+	VIIF_L1_HDRS_NOT_USE_MIDDLE_SENS_IMAGE = 0,
+	VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE = 1,
+};
+
+/**
+ * struct viif_l1_hdrs_config - L1ISP parameter for HDR synthesis
+ *
+ * @hdrs_hdr_mode: &enum viif_l1_hdrs_middle_img_mode value.
+ *                 Switch for use of middle sensitivity image in HDRS.
+ * @hdrs_hdr_ratio_m: Magnification ratio of middle sensitivity image for high
+ *                    sensitivity image.
+ * @hdrs_hdr_ratio_l: Magnification ratio of low sensitivity image for high
+ *                    sensitivity image.
+ * @hdrs_hdr_ratio_e: Magnification ratio of LED image for high sensitivity image.
+ * @hdrs_dg_h: High sensitivity image digital gain.
+ * @hdrs_dg_m: Middle sensitivity image digital gain.
+ * @hdrs_dg_l: Low sensitivity image digital gain.
+ * @hdrs_dg_e: LED image digital gain.
+ * @hdrs_blendend_h: Maximum luminance used for blend high sensitivity image.
+ * @hdrs_blendend_m: Maximum luminance used for blend middle sensitivity image.
+ * @hdrs_blendend_e: Maximum luminance used for blend LED image.
+ * @hdrs_blendbeg_h: Minimum luminance used for blend high sensitivity image.
+ * @hdrs_blendbeg_m: Minimum luminance used for blend middle sensitivity image.
+ * @hdrs_blendbeg_e: Minimum luminance used for blend LED image.
+ * @hdrs_led_mode_on: set 1 to enable LED mode, 0 to disable
+ * @hdrs_dst_max_val: Maximum value of output pixel. Range: [0..0xffffff].
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - hdrs_hdr_ratio_{m,l,e}
+ *
+ *   - Range: [0x400..0x400000]
+ *   - Accuracy: 1/1024
+ *
+ * - hdrs_dg_{h,m,l,e}
+ *
+ *   - Range: [0..0x3fffff]
+ *   - Accuracy: 1/1024
+ *
+ * - hdrs_blend{end,beg}_{h,m,e}
+ *
+ *   - Range [0..4095]
+ *
+ * Parameter error will be returned when:
+ * (hdrs_hdr_mode == VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE) && (hdrs_led_mode_on == 1)
+ */
+struct viif_l1_hdrs_config {
+	__u32 hdrs_hdr_mode;
+	__u32 hdrs_hdr_ratio_m;
+	__u32 hdrs_hdr_ratio_l;
+	__u32 hdrs_hdr_ratio_e;
+	__u32 hdrs_dg_h;
+	__u32 hdrs_dg_m;
+	__u32 hdrs_dg_l;
+	__u32 hdrs_dg_e;
+	__u32 hdrs_blendend_h;
+	__u32 hdrs_blendend_m;
+	__u32 hdrs_blendend_e;
+	__u32 hdrs_blendbeg_h;
+	__u32 hdrs_blendbeg_m;
+	__u32 hdrs_blendbeg_e;
+	__u32 hdrs_led_mode_on;
+	__u32 hdrs_dst_max_val;
+};
+
+/**
+ * struct viif_l1_black_level_correction_config -  L1ISP parameter for black level correction.
+ *
+ * @srcblacklevel_gr: Black level of Gr input pixel. Range: [0..0xffffff].
+ * @srcblacklevel_r: Black level of R input pixel. Range: [0..0xffffff].
+ * @srcblacklevel_b: Black level of B input pixel. Range: [0..0xffffff].
+ * @srcblacklevel_gb: Black level of Gb input pixel. Range: [0..0xffffff].
+ * @mulval_gr: Gr gain. Range: [0..0xfffff], Accuracy: 1/256.
+ * @mulval_r: R gain. Range: [0..0xfffff], Accuracy: 1/256.
+ * @mulval_b: B gain. Range: [0..0xfffff], Accuracy: 1/256.
+ * @mulval_gb: Gb gain. Range: [0..0xfffff], Accuracy: 1/256.
+ * @dstmaxval: Maximum value of output pixel. Range: [0..0xffffff].
+ */
+struct viif_l1_black_level_correction_config {
+	__u32 srcblacklevel_gr;
+	__u32 srcblacklevel_r;
+	__u32 srcblacklevel_b;
+	__u32 srcblacklevel_gb;
+	__u32 mulval_gr;
+	__u32 mulval_r;
+	__u32 mulval_b;
+	__u32 mulval_gb;
+	__u32 dstmaxval;
+};
+
+/**
+ * enum viif_l1_para_coef_gain - L1ISP parabola shading correction coefficient ratio
+ *
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH: 1/8
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH: 1/4
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_SECOND: 1/2
+ * @VIIF_L1_PARA_COEF_GAIN_ONE_FIRST: 1/1
+ */
+enum viif_l1_para_coef_gain {
+	VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH = 0, /* 1/8 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH = 1, /* 1/4 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_SECOND = 2, /* 1/2 */
+	VIIF_L1_PARA_COEF_GAIN_ONE_FIRST = 3, /* 1/1 */
+};
+
+/**
+ * enum viif_l1_grid_coef_gain - L1ISP grid shading correction coefficient ratio
+ *
+ * @VIIF_L1_GRID_COEF_GAIN_X1: x1
+ * @VIIF_L1_GRID_COEF_GAIN_X2: x2
+ */
+enum viif_l1_grid_coef_gain {
+	VIIF_L1_GRID_COEF_GAIN_X1 = 0,
+	VIIF_L1_GRID_COEF_GAIN_X2 = 1,
+};
+
+/**
+ * struct viif_l1_lsc_parabola_ag_param - L2ISP parabola shading parameters
+ * for &struct viif_l1_lsc_parabola_param
+ * @lssc_paracoef_h_l_max: Parabola coefficient left maximum gain value
+ * @lssc_paracoef_h_l_min: Parabola coefficient left minimum gain value
+ * @lssc_paracoef_h_r_max: Parabola coefficient right maximum gain value
+ * @lssc_paracoef_h_r_min: Parabola coefficient right minimum gain value
+ * @lssc_paracoef_v_u_max: Parabola coefficient upper maximum gain value
+ * @lssc_paracoef_v_u_min: Parabola coefficient upper minimum gain value
+ * @lssc_paracoef_v_d_max: Parabola coefficient lower maximum gain value
+ * @lssc_paracoef_v_d_min: Parabola coefficient lower minimum gain value
+ * @lssc_paracoef_hv_lu_max: Parabola coefficient upper left gain maximum value
+ * @lssc_paracoef_hv_lu_min: Parabola coefficient upper left gain minimum value
+ * @lssc_paracoef_hv_ru_max: Parabola coefficient upper right gain maximum value
+ * @lssc_paracoef_hv_ru_min: Parabola coefficient upper right minimum gain value
+ * @lssc_paracoef_hv_ld_max: Parabola coefficient lower left gain maximum value
+ * @lssc_paracoef_hv_ld_min: Parabola coefficient lower left gain minimum value
+ * @lssc_paracoef_hv_rd_max: Parabola coefficient lower right gain maximum value
+ * @lssc_paracoef_hv_rd_min: Parabola coefficient lower right minimum gain value
+ *
+ * The Range, Accuracy and Constraint of each coefficient are:
+ *
+ * - Range: [-4096..4095]
+ * - Accuracy: accuracy: 1/256
+ * - Constraint: lssc_paracoef_xx_xx_min <= lssc_paracoef_xx_xx_max
+ */
+struct viif_l1_lsc_parabola_ag_param {
+	__s16 lssc_paracoef_h_l_max;
+	__s16 lssc_paracoef_h_l_min;
+	__s16 lssc_paracoef_h_r_max;
+	__s16 lssc_paracoef_h_r_min;
+	__s16 lssc_paracoef_v_u_max;
+	__s16 lssc_paracoef_v_u_min;
+	__s16 lssc_paracoef_v_d_max;
+	__s16 lssc_paracoef_v_d_min;
+	__s16 lssc_paracoef_hv_lu_max;
+	__s16 lssc_paracoef_hv_lu_min;
+	__s16 lssc_paracoef_hv_ru_max;
+	__s16 lssc_paracoef_hv_ru_min;
+	__s16 lssc_paracoef_hv_ld_max;
+	__s16 lssc_paracoef_hv_ld_min;
+	__s16 lssc_paracoef_hv_rd_max;
+	__s16 lssc_paracoef_hv_rd_min;
+};
+
+/**
+ * struct viif_l1_lsc_parabola_param - L2ISP parabola shading parameters
+ * for &struct viif_l1_lsc
+ * @lssc_para_h_center: Horizontal coordinate of central optical axis.
+ *                      Range: [0..(Input image width - 1)].
+ * @lssc_para_v_center: Vertical coordinate of central optical axis.
+ *                      Range: [0..(Input image height - 1)].
+ * @lssc_para_h_gain: Horizontal distance gain with the optical axis.
+ *                    Range: [0..4095], Accuracy: 1/256.
+ * @lssc_para_v_gain: Vertical distance gain with the optical axis.
+ *                    Range: [0..4095], Accuracy: 1/256.
+ * @lssc_para_mgsel2: &enum viif_l1_para_coef_gain value.
+ *                    Parabola 2D correction coefficient gain magnification ratio.
+ * @lssc_para_mgsel4: &enum viif_l1_para_coef_gain value.
+ *                    Parabola 4D correction coefficient gain magnification ratio.
+ * @r_2d: 2D parabola coefficient for R.
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @r_4d: 4D parabola coefficient for R.
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gr_2d: 2D parabola coefficient for Gr
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gr_4d: 4D parabola coefficient for Gr
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gb_2d: 2D parabola coefficient for Gb
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @gb_4d: 4D parabola coefficient for Gb
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @b_2d: 2D parabola coefficient for B
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ * @b_4d: 4D parabola coefficient for B
+ *        Refer to &struct viif_l1_lsc_parabola_ag_param
+ */
+struct viif_l1_lsc_parabola_param {
+	__u32 lssc_para_h_center;
+	__u32 lssc_para_v_center;
+	__u32 lssc_para_h_gain;
+	__u32 lssc_para_v_gain;
+	__u32 lssc_para_mgsel2;
+	__u32 lssc_para_mgsel4;
+	struct viif_l1_lsc_parabola_ag_param r_2d;
+	struct viif_l1_lsc_parabola_ag_param r_4d;
+	struct viif_l1_lsc_parabola_ag_param gr_2d;
+	struct viif_l1_lsc_parabola_ag_param gr_4d;
+	struct viif_l1_lsc_parabola_ag_param gb_2d;
+	struct viif_l1_lsc_parabola_ag_param gb_4d;
+	struct viif_l1_lsc_parabola_ag_param b_2d;
+	struct viif_l1_lsc_parabola_ag_param b_4d;
+};
+
+/**
+ * struct viif_l1_lsc_grid_param - L2ISP grid shading parameters
+ * for &struct viif_l1_lsc
+ * @lssc_grid_h_size:  Grid horizontal direction pixel count.
+ *                     Range: [32, 64, 128, 256, 512]
+ * @lssc_grid_v_size:  Grid vertical direction pixel count.
+ *                     Range: [32, 64, 128, 256, 512]
+ * @lssc_grid_h_center: Horizontal coordinates of grid (1, 1)
+ * @lssc_grid_v_center: Vertical coordinates of grid (1, 1)
+ * @lssc_grid_mgsel: &enum viif_l1_grid_coef_gain value.
+ *                   Grid correction coefficient gain value magnification ratio.
+ *
+ * Range and constraint of parameters are:
+ *
+ * - lssc_grid_h_center:
+ *
+ *    - Range: [1..lssc_grid_h_size]
+ *    - Constraint: "Input image width <= lssc_grid_h_center + lssc_grid_h_size * 31"
+ *
+ * - lssc_grid_v_center:
+ *
+ *    - Range: [1..lssc_grid_v_size]
+ *    - Constraint: "Input image height <= lssc_grid_v_center + lssc_grid_v_size * 23"
+ */
+struct viif_l1_lsc_grid_param {
+	__u32 lssc_grid_h_size;
+	__u32 lssc_grid_v_size;
+	__u32 lssc_grid_h_center;
+	__u32 lssc_grid_v_center;
+	__u32 lssc_grid_mgsel;
+};
+
+/**
+ * struct viif_l1_lsc - L2ISP LSC parameters for &struct viif_l1_lsc_config
+ * @lssc_parabola_param: see &struct viif_l1_lsc_parabola_param
+ * @lssc_grid_param: see &struct viif_l1_lsc_grid_param
+ * @lssc_pwhb_r_gain_max: PWB R correction processing coefficient maximum value
+ * @lssc_pwhb_r_gain_min: PWB R correction processing coefficient minimum value
+ * @lssc_pwhb_gr_gain_max: PWB Gr correction processing coefficient maximum value
+ * @lssc_pwhb_gr_gain_min: PWB Gr correction processing coefficient minimum value
+ * @lssc_pwhb_gb_gain_max: PWB Gb correction processing coefficient maximum value
+ * @lssc_pwhb_gb_gain_min: PWB Gb correction processing coefficient minimum value
+ * @lssc_pwhb_b_gain_max: PWB B correction processing coefficient maximum value
+ * @lssc_pwhb_b_gain_min: PWB B correction processing coefficient minimum value
+ *
+ * The range, accuracy and restriction of lssc_pwhb_{r,gr,gb,b}_gain_{max,min} are:
+ *
+ * - Range: [0..2047]
+ * - Accuracy: 1/256
+ * - Restriction: xxxx_gain_min <= xxxx_gain_max
+ */
+struct viif_l1_lsc {
+	struct viif_l1_lsc_parabola_param lssc_parabola_param;
+	struct viif_l1_lsc_grid_param lssc_grid_param;
+	__u32 lssc_pwhb_r_gain_max;
+	__u32 lssc_pwhb_r_gain_min;
+	__u32 lssc_pwhb_gr_gain_max;
+	__u32 lssc_pwhb_gr_gain_min;
+	__u32 lssc_pwhb_gb_gain_max;
+	__u32 lssc_pwhb_gb_gain_min;
+	__u32 lssc_pwhb_b_gain_max;
+	__u32 lssc_pwhb_b_gain_min;
+};
+
+/* MASKs for viif_l1_lsc_config::enable */
+#define VIIF_L1_LSC_PARABOLA_EN_MASK BIT(0)
+#define VIIF_L1_LSC_GRID_EN_MASK     BIT(1)
+
+/**
+ * struct viif_l1_lsc_config - L1ISP parameter for lens shading correction.
+ *
+ * @enable: set 0 to disable LSC operation,
+ *          1 to enable parabola shading,
+ *          2 to enable grid shading,
+ *          3 to enable both parabola and grid shadings.
+ * @param: see &struct viif_l1_lsc
+ * @table_gr: Grid table for LSC of Gr component.
+ *            This table is referred only when grid shading is used
+ * @table_r:  Grid table for LSC of R component.
+ *            This table is referred only when grid shading is used
+ * @table_b:  Grid table for LSC of B component.
+ *            This table is referred only when grid shading is used
+ * @table_gb: Grid table for LSC of Gb component.
+ *            This table is referred only when grid shading is used
+ *
+ * The size of each table is 1536 Bytes (u16 * 768).
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the grid table.
+ */
+struct viif_l1_lsc_config {
+	__u32 enable;
+	struct viif_l1_lsc param;
+	__u16 table_gr[768];
+	__u16 table_r[768];
+	__u16 table_b[768];
+	__u16 table_gb[768];
+};
+
+/**
+ * enum viif_l1_demosaic_mode - L1ISP demosaic modeenum viif_l1_demosaic_mode
+ *
+ * @VIIF_L1_DEMOSAIC_ACPI: Toshiba ACPI algorithm
+ * @VIIF_L1_DEMOSAIC_DMG: DMG algorithm
+ */
+enum viif_l1_demosaic_mode {
+	VIIF_L1_DEMOSAIC_ACPI = 0,
+	VIIF_L1_DEMOSAIC_DMG = 1,
+};
+
+/**
+ * struct viif_l1_color_matrix_correction - L1ISP color matrix correction
+ * parameters for &struct viif_l1_main_process_config
+ * @coef_rmg_min: (R-G) Minimum coefficient
+ * @coef_rmg_max: (R-G) Maximum coefficient
+ * @coef_rmb_min: (R-B) Minimum coefficient
+ * @coef_rmb_max: (R-B) Maximum coefficient
+ * @coef_gmr_min: (G-R) Minimum coefficient
+ * @coef_gmr_max: (G-R) Maximum coefficient
+ * @coef_gmb_min: (G-B) Minimum coefficient
+ * @coef_gmb_max: (G-B) Maximum coefficient
+ * @coef_bmr_min: (B-R) Minimum coefficient
+ * @coef_bmr_max: (B-R) Maximum coefficient
+ * @coef_bmg_min: (B-G) Minimum coefficient
+ * @coef_bmg_max: (B-G) Maximum coefficient
+ * @dst_minval: Minimum value of output pixel. Range: [0..0xffff].
+ * @reserved: padding field
+ *
+ * The range, accuracy and restriction of each coefficient are:
+ *
+ * - Range: [-32768..32767]
+ * - Accuracy: 1/4096
+ * - Restriction: coef_xxx_min <= coef_xxx_max
+ */
+struct viif_l1_color_matrix_correction {
+	__s16 coef_rmg_min;
+	__s16 coef_rmg_max;
+	__s16 coef_rmb_min;
+	__s16 coef_rmb_max;
+	__s16 coef_gmr_min;
+	__s16 coef_gmr_max;
+	__s16 coef_gmb_min;
+	__s16 coef_gmb_max;
+	__s16 coef_bmr_min;
+	__s16 coef_bmr_max;
+	__s16 coef_bmg_min;
+	__s16 coef_bmg_max;
+	__u16 dst_minval;
+	__u16 reserved;
+};
+
+/**
+ * struct viif_l1_main_process_config - L1ISP parameter for main process
+ *
+ * @demosaic_mode: &enum viif_l1_demosaic_mode value. Sets demosaic mode.
+ * @damp_lsbsel: Clipping range of output pixel value to AWB adjustment function. Range: [0..15].
+ * @colormat_enable: set 1 to enable color matrix correction, 0 to disable.
+ * @dst_maxval: Maximum value of output pixel. Range: [0..0xffffff].
+ *              Applicable to output of each process (digital amplifier,
+ *              demosaicing and color matrix correction) in L1ISP Main process.
+ * @colormat_param: see &struct viif_l1_color_matrix_correction
+ *
+ * L1ISP main process is composed of:
+ *  - demosaicing
+ *  - color matrix correction
+ */
+struct viif_l1_main_process_config {
+	__u32 demosaic_mode;
+	__u32 damp_lsbsel;
+	__u32 colormat_enable;
+	__u32 dst_maxval;
+	struct viif_l1_color_matrix_correction colormat_param;
+};
+
+/**
+ * enum viif_l1_awb_mag - L1ISP signal magnification before AWB adjustment
+ *
+ * @VIIF_L1_AWB_ONE_SECOND: x 1/2
+ * @VIIF_L1_AWB_X1: 1 times
+ * @VIIF_L1_AWB_X2: 2 times
+ * @VIIF_L1_AWB_X4: 4 times
+ */
+enum viif_l1_awb_mag {
+	VIIF_L1_AWB_ONE_SECOND = 0,
+	VIIF_L1_AWB_X1 = 1,
+	VIIF_L1_AWB_X2 = 2,
+	VIIF_L1_AWB_X4 = 3,
+};
+
+/**
+ * enum viif_l1_awb_area_mode - L1ISP AWB detection target area
+ *
+ * @VIIF_L1_AWB_AREA_MODE0: only center area
+ * @VIIF_L1_AWB_AREA_MODE1: center area when uv is in square gate
+ * @VIIF_L1_AWB_AREA_MODE2: all area except center area
+ * @VIIF_L1_AWB_AREA_MODE3: all area
+ */
+enum viif_l1_awb_area_mode {
+	VIIF_L1_AWB_AREA_MODE0 = 0,
+	VIIF_L1_AWB_AREA_MODE1 = 1,
+	VIIF_L1_AWB_AREA_MODE2 = 2,
+	VIIF_L1_AWB_AREA_MODE3 = 3,
+};
+
+/**
+ * enum viif_l1_awb_restart_cond - L1ISP AWB adjustment restart conditions
+ *
+ * @VIIF_L1_AWB_RESTART_NO: no restart
+ * @VIIF_L1_AWB_RESTART_128FRAME: restart after 128 frame
+ * @VIIF_L1_AWB_RESTART_64FRAME: restart after 64 frame
+ * @VIIF_L1_AWB_RESTART_32FRAME: restart after 32 frame
+ * @VIIF_L1_AWB_RESTART_16FRAME: restart after 16 frame
+ * @VIIF_L1_AWB_RESTART_8FRAME: restart after 8 frame
+ * @VIIF_L1_AWB_RESTART_4FRAME: restart after 4 frame
+ * @VIIF_L1_AWB_RESTART_2FRAME: restart after 2 frame
+ */
+enum viif_l1_awb_restart_cond {
+	VIIF_L1_AWB_RESTART_NO = 0,
+	VIIF_L1_AWB_RESTART_128FRAME = 1,
+	VIIF_L1_AWB_RESTART_64FRAME = 2,
+	VIIF_L1_AWB_RESTART_32FRAME = 3,
+	VIIF_L1_AWB_RESTART_16FRAME = 4,
+	VIIF_L1_AWB_RESTART_8FRAME = 5,
+	VIIF_L1_AWB_RESTART_4FRAME = 6,
+	VIIF_L1_AWB_RESTART_2FRAME = 7,
+};
+
+/**
+ * struct viif_l1_awb - L1ISP AWB adjustment parameters
+ * for &struct viif_l1_awb_config
+ * @awhb_ygate_sel: 1:Enable/0:Disable to fix Y value at YUV conversion
+ * @awhb_ygate_data: Y value when Y value is fixed. Range: [64, 128, 256, 512].
+ * @awhb_cgrange: &enum viif_l1_awb_mag value.
+ *                Signal output magnification ratio before AWB adjustment.
+ * @awhb_ygatesw: 1:Enable/0:Disable settings of luminance gate
+ * @awhb_hexsw: 1:Enable/0:Disable settings of hexa-gate
+ * @awhb_areamode: &enum viif_l1_awb_area_mode value.
+ *                 Final selection of accumulation area for detection target area.
+ * @awhb_area_hsize: Horizontal size per block in central area.
+ *                   Range: [1..(Input image width -8)/8].
+ * @awhb_area_vsize: Vertical size per block in central area.
+ *                   Range: [1..(Input image height -4)/8].
+ * @awhb_area_hofs: Horizontal offset of block [0] in central area.
+ *                  Range: [0..(Input image width -9)].
+ * @awhb_area_vofs: Vertical offset of block [0] in central area.
+ *                  Range: [0..(Input image height -5)].
+ * @awhb_area_maskh: Setting 1:Enable/0:Disable of accumulated selection.
+ *                   Each bit corresponds to the following:
+ *                   [31:0] = {
+ *                   (7, 3),(6, 3),(5, 3),(4, 3),(3, 3),(2, 3),(1, 3),(0, 3),
+ *                   (7, 2),(6, 2),(5, 2),(4, 2),(3, 2),(2, 2),(1, 2),(0, 2),
+ *                   (7, 1),(6, 1),(5, 1),(4, 1),(3, 1),(2, 1),(1, 1),(0, 1),
+ *                   (7, 0),(6, 0),(5, 0),(4, 0),(3, 0),(2, 0),(1, 0),(0, 0)}
+ * @awhb_area_maskl: Setting 1:Enable/0:Disable of accumulated selection.
+ *                   Each bit corresponds to the following:
+ *                   [31:0] = {
+ *                   (7, 7),(6, 7),(5, 7),(4, 7),(3, 7),(2, 7),(1, 7),(0, 7),
+ *                   (7, 6),(6, 6),(5, 6),(4, 6),(3, 6),(2, 6),(1, 6),(0, 6),
+ *                   (7, 5),(6, 5),(5, 5),(4, 5),(3, 5),(2, 5),(1, 5),(0, 5),
+ *                   (7, 4),(6, 4),(5, 4),(4, 4),(3, 4),(2, 4),(1, 4),(0, 4)}
+ * @awhb_sq_sw: 1:Enable/0:Disable each square gate
+ * @awhb_sq_pol: 1:Enable/0:Disable to add accumulated gate for each square gate
+ * @awhb_bycut0p: U upper end value. Range: [0..127].
+ * @awhb_bycut0n: U lower end value. Range: [0..127].
+ * @awhb_rycut0p: V upper end value. Range: [0..127].
+ * @awhb_rycut0n: V lower end value. Range: [0..127].
+ * @awhb_rbcut0h: V-axis intercept upper end. Range: [-127..127].
+ * @awhb_rbcut0l: V-axis intercept lower end. Range: [-127..127].
+ * @awhb_bycut_h: U direction center value of each square gate. Range:  [-127..127].
+ * @awhb_bycut_l: U direction width of each square gate. Range: [0..127].
+ * @awhb_rycut_h: V direction center value of each square gate. Range: [-127..127].
+ * @awhb_rycut_l: V direction width of each square gate. Range: [0..127].
+ * @awhb_awbsftu: U gain offset. Range: [-127..127].
+ * @awhb_awbsftv: V gain offset. Range: [-127..127].
+ * @awhb_awbhuecor: 1:Enable/0:Disable setting of color correlation retention function
+ * @awhb_awbspd: UV convergence speed multiplier. Range: [0..15] (0 means "stop").
+ * @awhb_awbulv: U convergence point level. Range: [0..31].
+ * @awhb_awbvlv: V convergence point level. Range: [0..31].
+ * @awhb_awbondot: Accumulation operation stop pixel count threshold. Range: [0..1023].
+ * @awhb_awbfztim: &enum viif_l1_awb_restart_cond value. Condition to restart AWB process.
+ * @awhb_wbgrmax: B gain adjustment range (Width from center to upper limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgbmax: R gain adjustment range (Width from center to upper limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgrmin: B gain adjustment range (Width from center to lower limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_wbgbmin: R gain adjustment range (Width from center to lower limit).
+ *                Range: [0..255], Accuracy: 1/64.
+ * @awhb_ygateh: Luminance gate maximum value. Range: [0..255].
+ * @awhb_ygatel: Luminance gate minimum value. Range: [0..255].
+ * @awhb_awbwait: Number of restart frames after UV convergence freeze. Range: [0..255].
+ * @reserved: padding field
+ */
+struct viif_l1_awb {
+	__u32 awhb_ygate_sel;
+	__u32 awhb_ygate_data;
+	__u32 awhb_cgrange;
+	__u32 awhb_ygatesw;
+	__u32 awhb_hexsw;
+	__u32 awhb_areamode;
+	__u32 awhb_area_hsize;
+	__u32 awhb_area_vsize;
+	__u32 awhb_area_hofs;
+	__u32 awhb_area_vofs;
+	__u32 awhb_area_maskh;
+	__u32 awhb_area_maskl;
+	__u32 awhb_sq_sw[3];
+	__u32 awhb_sq_pol[3];
+	__u32 awhb_bycut0p;
+	__u32 awhb_bycut0n;
+	__u32 awhb_rycut0p;
+	__u32 awhb_rycut0n;
+	__s32 awhb_rbcut0h;
+	__s32 awhb_rbcut0l;
+	__s32 awhb_bycut_h[3];
+	__u32 awhb_bycut_l[3];
+	__s32 awhb_rycut_h[3];
+	__u32 awhb_rycut_l[3];
+	__s32 awhb_awbsftu;
+	__s32 awhb_awbsftv;
+	__u32 awhb_awbhuecor;
+	__u32 awhb_awbspd;
+	__u32 awhb_awbulv;
+	__u32 awhb_awbvlv;
+	__u32 awhb_awbondot;
+	__u32 awhb_awbfztim;
+	__u8 awhb_wbgrmax;
+	__u8 awhb_wbgbmax;
+	__u8 awhb_wbgrmin;
+	__u8 awhb_wbgbmin;
+	__u8 awhb_ygateh;
+	__u8 awhb_ygatel;
+	__u8 awhb_awbwait;
+	__u8 reserved;
+};
+
+/**
+ * struct viif_l1_awb_config - L1ISP parameter for automatic white balance
+ *
+ * @enable: set 1 to enable AWB , 0 to disable
+ * @awhb_wbmrg: White balance adjustment R gain. Range: [64..1023], Accuracy: 1/256.
+ * @awhb_wbmgg: White balance adjustment G gain. Range: [64..1023], Accuracy: 1/256.
+ * @awhb_wbmbg: White balance adjustment B gain. Range: [64..1023], Accuracy: 1/256.
+ * @param: a &struct viif_l1_awb instance
+ */
+struct viif_l1_awb_config {
+	__u32 enable;
+	__u32 awhb_wbmrg;
+	__u32 awhb_wbmgg;
+	__u32 awhb_wbmbg;
+	struct viif_l1_awb param;
+};
+
+/**
+ * enum viif_l1_hdrc_tone_type - L1ISP HDRC tone type
+ *
+ * @VIIF_L1_HDRC_TONE_USER: User Tone
+ * @VIIF_L1_HDRC_TONE_PRESET: Preset Tone
+ */
+enum viif_l1_hdrc_tone_type {
+	VIIF_L1_HDRC_TONE_USER = 0,
+	VIIF_L1_HDRC_TONE_PRESET = 1,
+};
+
+/**
+ * struct viif_l1_hdrc - L1ISP HDRC parameters for &struct viif_l1_hdrc_config
+ * @hdrc_ratio: Data width of input image. Range: [10..24] bits.
+ * @hdrc_pt_ratio: Preset Tone curve slope. Range: [0..13].
+ * @hdrc_pt_blend: Preset Tone0 curve blend ratio. Range: [0..256], Accuracy: 1/256.
+ * @hdrc_pt_blend2: Preset Tone2 curve blend ratio. Range: [0..256], Accuracy: 1/256.
+ * @hdrc_tn_type: &enum viif_l1_hdrc_tone_type value. L1ISP HDRC tone type.
+ * @hdrc_utn_tbl: HDRC value of User Tone curve. Range: [0..0xffff].
+ * @hdrc_flr_val: Constant flare value. Range: [0..0xffffff].
+ * @hdrc_flr_adp: set 1 to enable dynamic flare measurement, 0 to disable.
+ * @hdrc_ybr_off: set 1 to turn OFF bilateral luminance filter, 0 to turn ON.
+ * @hdrc_orgy_blend: Blend settings of luminance correction data after HDRC
+ *                   and data before luminance correction. Range: [0..16]
+ *                   (0:Luminance correction 100%, 8:Luminance correction 50%,
+ *                   16:Luminance correction 0%).
+ * @hdrc_pt_sat: Preset Tone saturation value. Range: [0..0xffff].
+ * @reserved: padding field
+ *
+ * Restrictions for parameters
+ *
+ * - hdrc_pt_blend + hdrc_pt_blend2 <= 256
+ * - input_image_height % 64 != {18, 20, 22, 24, 26}
+ *
+ *   - only when dynamic flare control is enabled
+ *   - note that the driver will not return error if this condition is not satisfied.
+ *
+ * - hdrc_utn_tbl[N] <= hdrc_utn_tbl[N+1]
+ *
+ *   - note that the driver will not return error if this condition is not satisfied.
+ */
+struct viif_l1_hdrc {
+	__u32 hdrc_ratio;
+	__u32 hdrc_pt_ratio;
+	__u32 hdrc_pt_blend;
+	__u32 hdrc_pt_blend2;
+	__u32 hdrc_tn_type;
+	__u16 hdrc_utn_tbl[20];
+	__u32 hdrc_flr_val;
+	__u32 hdrc_flr_adp;
+	__u32 hdrc_ybr_off;
+	__u32 hdrc_orgy_blend;
+	__u16 hdrc_pt_sat;
+	__u16 reserved;
+};
+
+/**
+ * struct viif_l1_hdrc_config - L1ISP parameter for HDR compression
+ *
+ * @enable: set 1 to enable HDR compression, 0 to disable
+ * @hdrc_thr_sft_amt: Amount of right shift in through mode (HDRC disabled). Range: [0..8].
+ *                    Should be 0 if HDRC is enabled
+ * @param: HDR compression parameter; see &struct viif_l1_hdrc
+ */
+struct viif_l1_hdrc_config {
+	__u32 enable;
+	__u32 hdrc_thr_sft_amt;
+	struct viif_l1_hdrc param;
+};
+
+/**
+ * struct viif_l1_hdrc_ltm_config - L1ISP parameter for HDR compression local tone mapping
+ *
+ * @tnp_max: Tone blend rate maximum value of LTM function.
+ *           Range: [0..4194303], Accuracy: 1/64. Set 0 to turn off LTM function.
+ * @tnp_mag: Intensity adjustment of LTM function. Range: [0..16383], Accuracy: 1/64.
+ * @tnp_fil: Smoothing filter coefficient. Range: [0..255].
+ * @reserved: padding field
+ *
+ * Restriction: (tmp_fil[1] + tnp_fil[2] + tnp_fil[3] + tnp_fil[4]) * 2 + tnp_fil[0] = 1024
+ */
+struct viif_l1_hdrc_ltm_config {
+	__u32 tnp_max;
+	__u32 tnp_mag;
+	__u8 tnp_fil[5];
+	__u8 reserved[3];
+};
+
+/**
+ * struct viif_l1_gamma - L1ISP gamma correction parameters
+ * for &struct viif_l1_gamma_config
+ * @gam_p: Luminance value after gamma correction. Range: [0..8191].
+ * @blkadj: Black level adjustment value after gamma correction. Range: [0..65535].
+ * @reserved: padding field
+ */
+struct viif_l1_gamma {
+	__u16 gam_p[44];
+	__u16 blkadj;
+	__u16 reserved;
+};
+
+/**
+ * struct viif_l1_gamma_config - L1ISP parameter for gamma correction
+ * @enable: set 1 to enable gamma correction at L1ISP, 0 to disable.
+ * @param: see &struct viif_l1_gamma.
+ */
+struct viif_l1_gamma_config {
+	__u32 enable;
+	struct viif_l1_gamma param;
+};
+
+/**
+ * struct viif_l1_nonlinear_contrast -  L1ISP VPRO non-linear contrast parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @blk_knee: Black side peak luminance value. Range: [0..0xffff].
+ * @wht_knee: White side peak luminance value. Range: [0..0xffff].
+ * @blk_cont: Black side slope
+ * @wht_cont: White side slope
+ * @reserved: padding field
+ *
+ * Range, Accuracy and Index for {blk,wht}_cont is:
+ *
+ * - Range: [0..255]
+ * - Accuracy: 1/256
+ *
+ * - Index
+ *
+ *   - 0: the value at AG minimum
+ *   - 1: the value at AG less than 128
+ *   - 2: the value at AG equal to or more than 128
+ */
+struct viif_l1_nonlinear_contrast {
+	__u16 blk_knee;
+	__u16 wht_knee;
+	__u8 blk_cont[3];
+	__u8 wht_cont[3];
+	__u8 reserved[2];
+};
+
+/**
+ * struct viif_l1_lum_noise_reduction -  L1ISP VPRO luminance noise reduction parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @gain_min: Minimum value of extracted noise gain. Range: [0..0xffff], Accuracy: 1/256
+ * @gain_max: Maximum value of extracted noise gain. Range: [0..0xffff], Accuracy: 1/256
+ * @lim_min: Minimum value of extracted noise limit. Range: [0..0xffff]
+ * @lim_max: Maximum value of extracted noise limit. Range: [0..0xffff]
+ *
+ * Constraint: "gain_min <= gain_max" and "lim_min <= lim_max"
+ *
+ */
+struct viif_l1_lum_noise_reduction {
+	__u16 gain_min;
+	__u16 gain_max;
+	__u16 lim_min;
+	__u16 lim_max;
+};
+
+/**
+ * struct viif_l1_edge_enhancement -  L1ISP VPRO edge enhancement parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @gain_min: Extracted edge gain minimum value. Range: [0..0xffff], Accuracy: 1/256
+ * @gain_max: Extracted edge gain maximum value. Range: [0..0xffff], Accuracy: 1/256
+ * @lim_min: Extracted edge limit minimum value. Range: [0..0xffff]
+ * @lim_max: Extracted edge limit maximum value. Range: [0..0xffff]
+ * @coring_min: Extracted edge coring threshold minimum value. Range: [0..0xffff]
+ * @coring_max: Extracted edge coring threshold maximum value. Range: [0..0xffff]
+ *
+ * Constraint: "gain_min <= gain_max" and "lim_min <= lim_max" and "coring_min <= coring_max"
+ */
+struct viif_l1_edge_enhancement {
+	__u16 gain_min;
+	__u16 gain_max;
+	__u16 lim_min;
+	__u16 lim_max;
+	__u16 coring_min;
+	__u16 coring_max;
+};
+
+/**
+ * struct viif_l1_uv_suppression -  L1ISP VPRO UV suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @bk_mp: Black side slope. Range: [0..0x3fff], Accuracy: 1/16384
+ * @black: Minimum black side gain. Range: [0..0x3fff], Accuracy: 1/16384
+ * @wh_mp: White side slope. Range: [0..0x3fff], Accuracy: 1/16384
+ * @white: Minimum white side gain. Range: [0..0x3fff], Accuracy: 1/16384
+ * @bk_slv: Black side intercept. Range: [0..0xffff]
+ * @wh_slv: White side intercept. Range: [0..0xffff]
+ *
+ * Constraint: bk_slb < wh_slv
+ */
+struct viif_l1_uv_suppression {
+	__u32 bk_mp;
+	__u32 black;
+	__u32 wh_mp;
+	__u32 white;
+	__u16 bk_slv;
+	__u16 wh_slv;
+};
+
+/**
+ * struct viif_l1_coring_suppression -  L1ISP VPRO coring suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @lv_min: Minimum coring threshold. Range: [0..0xffff]
+ * @lv_max: Maximum coring threshold. Range: [0..0xffff]
+ * @gain_min: Minimum gain. Range: [0..0xffff], Accuracy: 1/65536
+ * @gain_max: Maximum gain. Range: [0..0xffff], Accuracy: 1/65536
+ *
+ * Constraint: "lv_min <= lv_max" and "gain_min <= gain_max"
+ */
+struct viif_l1_coring_suppression {
+	__u16 lv_min;
+	__u16 lv_max;
+	__u16 gain_min;
+	__u16 gain_max;
+};
+
+/**
+ * struct viif_l1_edge_suppression -  L1ISP VPRO edge suppression parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @gain: Gain of edge color suppression. Range: [0..0xffff], Accuracy: 1/256
+ * @lim: Limiter threshold of edge color suppression. Range: [0..15]
+ */
+struct viif_l1_edge_suppression {
+	__u16 gain;
+	__u16 lim;
+};
+
+/**
+ * struct viif_l1_color_level -  L1ISP VPRO color level parameters
+ * for &struct viif_l1_img_quality_adjustment_config
+ * @cb_gain: U component gain
+ * @cr_gain: V component gain
+ * @cbr_mgain_min: UV component gain
+ * @cbp_gain_max: Positive U component gain
+ * @cbm_gain_max: Negative V component gain
+ * @crp_gain_max: Positive U component gain
+ * @crm_gain_max: Negative V component gain
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - Range: [0..0xfff]
+ * - Accuracy: 1/2048
+ */
+struct viif_l1_color_level {
+	__u32 cb_gain;
+	__u32 cr_gain;
+	__u32 cbr_mgain_min;
+	__u32 cbp_gain_max;
+	__u32 cbm_gain_max;
+	__u32 crp_gain_max;
+	__u32 crm_gain_max;
+};
+
+/* MASKs for viif_l1_img_quality_adjustment_config::enable */
+#define VIIF_L1_IQA_NONLINEAR_CONTRAST_EN_MASK	  BIT(0)
+#define VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK	  BIT(1)
+#define VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK	  BIT(2)
+#define VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK	  BIT(3)
+#define VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK	  BIT(4)
+#define VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK	  BIT(5)
+#define VIIF_L1_IQA_COLOR_LEVEL_EN_MASK		  BIT(6)
+#define VIIF_L1_IQA_COLOR_NOISE_REDUCTION_EN_MASK BIT(7)
+
+/**
+ * struct viif_l1_img_quality_adjustment_config -  L1ISP parameter
+ * for image quality adjustment (VPRO)
+ *
+ * @enable: bit vector; set 1 to enable each function, 0 to disable.
+ *
+ *  - bit[0]: nonlinear contrast
+ *  - bit[1]: luminance noise reduction
+ *  - bit[2]: edge enhancement
+ *  - bit[3]: uv suppression
+ *  - bit[4]: coring suppression
+ *  - bit[5]: edge suppression
+ *  - bit[6]: color level
+ *  - bit[7]: color noise reduction
+ *
+ * @nonlinear_contrast: see &struct viif_l1_nonlinear_contrast; controlled by bit0 of enable.
+ * @lum_noise_reduction: see &struct viif_l1_lum_noise_reduction; controlled by bit1 of enable.
+ * @edge_enhancement: see &struct viif_l1_edge_enhancement; controlled by bit2 of enable.
+ * @uv_suppression: see &struct viif_l1_uv_suppression: controlled by bit3 of enable.
+ * @coring_suppression: see &struct viif_l1_coring_suppression; controlled by bit4 of enable.
+ * @edge_suppression: see &struct viif_l1_edge_suppression; controlled by bit5 of enable.
+ * @color_level: see &struct viif_l1_color_level; controlled by bit6 of enable.
+ * @coef_cb: Cb coefficient used in RGB to YUV conversion.
+ *           Range: [0..0xffff], Accuracy: 1/65536
+ * @coef_cr: Cr coefficient used in RGB to YUV conversion.
+ *           Range: [0..0xffff], Accuracy: 1/65536
+ * @brightness: Brightness adjustment value. Range: [-32768..32767] (0 to turn off)
+ * @linear_contrast: Linear contrast adjustment value.
+ *                   Range: [0..0xff], Accuracy: 1/128 (128 to turn off)
+ * @reserved: padding field
+ *
+ * The VPRO feature provides following functions:
+ *  - luminance adjustment:
+ *     - brightness adjustment
+ *     - linear contrast adjusment
+ *     - nonlinear contrast adjustment
+ *     - luminance noise reduction
+ *     - edge enhancement
+ *  - chroma adjustment:
+ *     - chroma suppression
+ *     - color level adjustment
+ *     - chroma noise reduction
+ *     - coring suppression
+ *     - edge chroma suppression
+ *     - color noise reduction
+ */
+struct viif_l1_img_quality_adjustment_config {
+	__u32 enable;
+	struct viif_l1_nonlinear_contrast nonlinear_contrast;
+	struct viif_l1_lum_noise_reduction lum_noise_reduction;
+	struct viif_l1_edge_enhancement edge_enhancement;
+	struct viif_l1_uv_suppression uv_suppression;
+	struct viif_l1_coring_suppression coring_suppression;
+	struct viif_l1_edge_suppression edge_suppression;
+	struct viif_l1_color_level color_level;
+	__u16 coef_cb;
+	__u16 coef_cr;
+	__s16 brightness;
+	__u8 linear_contrast;
+	__u8 reserved;
+};
+
+/**
+ * struct viif_l1_avg_lum_generation_config - L1ISP parameter for calculating average luminance
+ *
+ * @enable: set 1 to enable aggregation of AVG LUM, 0 to disable
+ * @aexp_start_x: horizontal position of block 0. Range: [0.."width of input image - 1"]
+ * @aexp_start_y: vertical position of block 0. Range: [0.."height of input image - 1"]
+ * @aexp_block_width: width of one block.
+ *                    Range: [64.."width of input image"] (Should be multiple of 64)
+ * @aexp_block_height: height of one block.
+ *                     Range: [64.."height of input image"] (Should be multiple of 64)
+ * @aexp_weight: weight of each block. Range: [0..3].
+ *               Nested indices are: [y position][x position].
+ * @aexp_satur_ratio: threshold to judge whether saturated block or not. Range: [0..256]
+ * @aexp_black_ratio: threshold to judge whether black block or not. Range: [0..256]
+ * @aexp_satur_level: threshold to judge whether saturated pixel or not. Range: [0x0..0xffffff]
+ * @aexp_ave4linesy: vertical position of the initial line
+ *                   for 4-lines average luminance.
+ *                   Range: [0.."height of input image - 4"]
+ */
+struct viif_l1_avg_lum_generation_config {
+	__u32 enable;
+	__u32 aexp_start_x;
+	__u32 aexp_start_y;
+	__u32 aexp_block_width;
+	__u32 aexp_block_height;
+	__u32 aexp_weight[8][8];
+	__u32 aexp_satur_ratio;
+	__u32 aexp_black_ratio;
+	__u32 aexp_satur_level;
+	__u32 aexp_ave4linesy[4];
+};
+
+/**
+ * enum viif_l2_undist_mode - L2ISP undistortion mode
+ * @VIIF_L2_UNDIST_POLY: polynomial mode
+ * @VIIF_L2_UNDIST_GRID: grid table mode
+ * @VIIF_L2_UNDIST_POLY_TO_GRID: polynomial, then grid table mode
+ * @VIIF_L2_UNDIST_GRID_TO_POLY: grid table, then polynomial mode
+ */
+enum viif_l2_undist_mode {
+	VIIF_L2_UNDIST_POLY = 0,
+	VIIF_L2_UNDIST_GRID = 1,
+	VIIF_L2_UNDIST_POLY_TO_GRID = 2,
+	VIIF_L2_UNDIST_GRID_TO_POLY = 3,
+};
+
+/**
+ * struct viif_l2_undist - L2ISP UNDIST parameters
+ * for &struct viif_l2_undist_config
+ * @through_mode: 1:enable or 0:disable through mode of undistortion
+ * @roi_mode: &enum viif_l2_undist_mode value. Sets L2ISP undistortion mode.
+ * @sensor_crop_ofs_h: Horizontal start position of sensor crop area.
+ * @sensor_crop_ofs_v: Vertical start position of sensor crop area.
+ * @norm_scale: Normalization coefficient for distance from center
+ * @valid_r_norm2_poly: Setting target area for polynomial correction
+ * @valid_r_norm2_grid: Setting target area for grid table correction
+ * @roi_write_area_delta: Error adjustment value of forward function and
+ *                        inverse function for pixel position calculation
+ * @poly_write_g_coef: 10th-order polynomial coefficient for G write pixel position calculation
+ * @poly_read_b_coef: 10th-order polynomial coefficient for B read pixel position calculation
+ * @poly_read_g_coef: 10th-order polynomial coefficient for G read pixel position calculation
+ * @poly_read_r_coef: 10th-order polynomial coefficient for R read pixel position calculation
+ * @grid_node_num_h: Number of horizontal grids
+ * @grid_node_num_v: Number of vertical grids
+ * @grid_patch_hsize_inv: Inverse pixel size between horizontal grids
+ * @grid_patch_vsize_inv: Inverse pixel size between vertical grids
+ *
+ * Range and Accuracy of parameters are:
+ *
+ * - sensor_crop_ofs_{h,v}
+ *
+ *   - Range: [-4296..4296]
+ *   - Accuracy: 1/2
+ *
+ * - norm_scale
+ *
+ *   - Range: [0..1677721]
+ *   - Accuracy: 1/33554432
+ *
+ * - valid_r_norm2_{poly,grid}
+ *
+ *   - Range: [0..0x3ffffff]
+ *   - Accuracy: 1/33554432
+ *
+ * - roi_write_area_delta
+ *
+ *   - Range: [0..0x7ff]
+ *   - Accuracy: 1/1024
+ *
+ * - poly_write_g_coef, poly_read_{b,g,r}_coef
+ *
+ *   - Range: [-2147352576..2147352576]
+ *   - Accuracy: 1/131072
+ *
+ * - grid_node_num_{v.h}
+ *
+ *   - Range: [16..64]
+ *
+ * - grid_patch_{hsize,vsize}_inv
+ *
+ *   - Range: [0..0x7fffff]
+ *   - Accuracy: 1/8388608
+ */
+struct viif_l2_undist {
+	__u32 through_mode;
+	__u32 roi_mode[2];
+	__s32 sensor_crop_ofs_h;
+	__s32 sensor_crop_ofs_v;
+	__u32 norm_scale;
+	__u32 valid_r_norm2_poly;
+	__u32 valid_r_norm2_grid;
+	__u32 roi_write_area_delta[2];
+	__s32 poly_write_g_coef[11];
+	__s32 poly_read_b_coef[11];
+	__s32 poly_read_g_coef[11];
+	__s32 poly_read_r_coef[11];
+	__u32 grid_node_num_h;
+	__u32 grid_node_num_v;
+	__u32 grid_patch_hsize_inv;
+	__u32 grid_patch_vsize_inv;
+};
+
+/**
+ * struct viif_l2_undist_config - L2ISP parameter for undistortion
+ *
+ * @param: &struct viif_l2_undist
+ * @write_g: write-G grid table.
+ * @read_b: read-B grid table.
+ * @read_g: read-G grid table.
+ * @read_r: read-R grid table.
+ * @size: Table size in bytes. Range: [1024..8192] or 0.
+ *        The value should be "grid_node_num_h * grid_node_num_v * 4".
+ *        See also &struct viif_l2_undist.
+ *
+ * The tables are referred when param.roi_mode[] is
+ * either of VIIF_L2_UNDIST_GRID, VIIF_L2_UNDIST_POLY_TO_GRID, VIIF_L2_UNDIST_GRID_TO_POLY
+ * Application should make sure that the table data is based on HW specification
+ * since this driver does not check the contents of specified grid table.
+ */
+struct viif_l2_undist_config {
+	struct viif_l2_undist param;
+	__u8 write_g[8192];
+	__u8 read_b[8192];
+	__u8 read_g[8192];
+	__u8 read_r[8192];
+	__u32 size;
+};
+
+/**
+ * struct viif_l2_roi_config - L2ISP parameter for specifying ROI
+ *
+ * @roi_num:
+ *     1 when only capture path0 is activated,
+ *     2 when both capture path 0 and path 1 are activated.
+ * @roi_scale: Scale value for each ROI. Range: [32768..131072], Accuracy: 1/65536
+ * @roi_scale_inv: Inverse scale value for each ROI. Range: [32768..131072], Accuracy: 1/65536
+ * @corrected_wo_scale_hsize: Corrected image width for each ROI. Range: [128..8190]
+ * @corrected_wo_scale_vsize: Corrected image height for each ROI. Range: [128..4094]
+ * @corrected_hsize: Corrected and scaled image width for each ROI. Range: [128..8190]
+ * @corrected_vsize: Corrected and scaled image height for each ROI. Range: [128..4094]
+ */
+struct viif_l2_roi_config {
+	__u32 roi_num;
+	__u32 roi_scale[2];
+	__u32 roi_scale_inv[2];
+	__u32 corrected_wo_scale_hsize[2];
+	__u32 corrected_wo_scale_vsize[2];
+	__u32 corrected_hsize[2];
+	__u32 corrected_vsize[2];
+};
+
+/** enum viif_gamma_mode - Gamma correction mode
+ *
+ * @VIIF_GAMMA_COMPRESSED: compressed table mode
+ * @VIIF_GAMMA_LINEAR: linear table mode
+ */
+enum viif_gamma_mode {
+	VIIF_GAMMA_COMPRESSED = 0,
+	VIIF_GAMMA_LINEAR = 1,
+};
+
+/**
+ * struct viif_l2_gamma_config - L2ISP parameter for gamma correction
+ *
+ * @table_en: 6bit vector to enable gamma table; all 0 to disable gamma correction
+ * @vsplit: Line switching position of first table and second table. Range: [0..4094].
+ *          Should set 0 in case 0 is set to @enable
+ * @mode: &enum viif_gamma_mode value.
+ *        Should set VIIF_GAMMA_COMPRESSED when 0 is set to @enable
+ * @table: gamma table for L2ISP gamma; 6 channels, each has __u16 typed 512 bytes.
+ *         [0]: G/Y(1st table), [1]: G/Y(2nd table), [2]: B/U(1st table)
+ *         [3]: B/U(2nd table), [4]: R/V(1st table), [5]: R/V(2nd table)
+ */
+struct viif_l2_gamma_config {
+	__u32 table_en;
+	__u32 vsplit;
+	__u32 mode;
+	__u16 table[6][256];
+};
+
+/**
+ * struct viif_csi2rx_dphy_calibration_status - CSI2RX status of DPHY Calibration
+ *
+ * @term_cal_with_rext: Result of termination calibration with rext
+ * @clock_lane_offset_cal: Result of offset calibration of clock lane
+ * @data_lane0_offset_cal: Result of offset calibration of data lane0
+ * @data_lane1_offset_cal: Result of offset calibration of data lane1
+ * @data_lane2_offset_cal: Result of offset calibration of data lane2
+ * @data_lane3_offset_cal: Result of offset calibration of data lane3
+ * @data_lane0_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane0
+ * @data_lane1_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane1
+ * @data_lane2_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane2
+ * @data_lane3_ddl_tuning_cal: Result of digital delay line tuning calibration of data lane3
+ *
+ * Possible returned values for each member are:
+ *
+ * - -EAGAIN: calibration is not done
+ * - -EIO: calibration was failed
+ * - 0; calibration is succeeded
+ */
+struct viif_csi2rx_dphy_calibration_status {
+	__s32 term_cal_with_rext;
+	__s32 clock_lane_offset_cal;
+	__s32 data_lane0_offset_cal;
+	__s32 data_lane1_offset_cal;
+	__s32 data_lane2_offset_cal;
+	__s32 data_lane3_offset_cal;
+	__s32 data_lane0_ddl_tuning_cal;
+	__s32 data_lane1_ddl_tuning_cal;
+	__s32 data_lane2_ddl_tuning_cal;
+	__s32 data_lane3_ddl_tuning_cal;
+};
+
+/**
+ * struct viif_csi2rx_err_status - CSI2RX status of errors
+ *
+ * @err_phy_fatal: D-PHY FATAL error.
+ *
+ *  - bit[3]: Start of transmission error on DATA Lane3.
+ *  - bit[2]: Start of transmission error on DATA Lane2.
+ *  - bit[1]: Start of transmission error on DATA Lane1.
+ *  - bit[0]: Start of transmission error on DATA Lane0.
+ *
+ * @err_pkt_fatal: Packet FATAL error.
+ *
+ *  - bit[16]: Header ECC contains 2 errors, unrecoverable.
+ *  - bit[3]: Checksum error detected on virtual channel 3.
+ *  - bit[2]: Checksum error detected on virtual channel 2.
+ *  - bit[1]: Checksum error detected on virtual channel 1.
+ *  - bit[0]: Checksum error detected on virtual channel 0.
+ *
+ * @err_frame_fatal: Frame FATAL error.
+ *
+ *  - bit[19]: Last received Frame, in virtual channel 3, has at least one CRC error.
+ *  - bit[18]: Last received Frame, in virtual channel 2, has at least one CRC error.
+ *  - bit[17]: Last received Frame, in virtual channel 1, has at least one CRC error.
+ *  - bit[16]: Last received Frame, in virtual channel 0, has at least one CRC error.
+ *  - bit[11]: Incorrect Frame Sequence detected in virtual channel 3.
+ *  - bit[10]: Incorrect Frame Sequence detected in virtual channel 2.
+ *  - bit[9]: Incorrect Frame Sequence detected in virtual channel 1.
+ *  - bit[8]: Incorrect Frame Sequence detected in virtual channel 0.
+ *  - bit[3]: Error matching Frame Start with Frame End for virtual channel 3.
+ *  - bit[2]: Error matching Frame Start with Frame End for virtual channel 2.
+ *  - bit[1]: Error matching Frame Start with Frame End for virtual channel 1.
+ *  - bit[0]: Error matching Frame Start with Frame End for virtual channel 0.
+ *
+ * @err_phy: D-PHY error.
+ *
+ *  - bit[19]: Escape Entry Error on Data Lane 3.
+ *  - bit[18]: Escape Entry Error on Data Lane 2.
+ *  - bit[17]: Escape Entry Error on Data Lane 1.
+ *  - bit[16]: Escape Entry Error on Data Lane 0.
+ *  - bit[3]: Start of Transmission Error on Data Lane 3 (synchronization can still be achieved).
+ *  - bit[2]: Start of Transmission Error on Data Lane 2 (synchronization can still be achieved).
+ *  - bit[1]: Start of Transmission Error on Data Lane 1 (synchronization can still be achieved).
+ *  - bit[0]: Start of Transmission Error on Data Lane 0 (synchronization can still be achieved).
+ *
+ * @err_pkt: Packet error.
+ *
+ *  - bit[19]: Header Error detected and corrected on virtual channel 3.
+ *  - bit[18]: Header Error detected and corrected on virtual channel 2.
+ *  - bit[17]: Header Error detected and corrected on virtual channel 1.
+ *  - bit[16]: Header Error detected and corrected on virtual channel 0.
+ *  - bit[3]: Unrecognized or unimplemented data type detected in virtual channel 3.
+ *  - bit[2]: Unrecognized or unimplemented data type detected in virtual channel 2.
+ *  - bit[1]: Unrecognized or unimplemented data type detected in virtual channel 1.
+ *  - bit[0]: Unrecognized or unimplemented data type detected in virtual channel 0.
+ *
+ * @err_line: Line error.
+ *
+ *  - bit[23]: Error in the sequence of lines for vc7 and dt7.
+ *  - bit[22]: Error in the sequence of lines for vc6 and dt6.
+ *  - bit[21]: Error in the sequence of lines for vc5 and dt5.
+ *  - bit[20]: Error in the sequence of lines for vc4 and dt4.
+ *  - bit[19]: Error in the sequence of lines for vc3 and dt3.
+ *  - bit[18]: Error in the sequence of lines for vc2 and dt2.
+ *  - bit[17]: Error in the sequence of lines for vc1 and dt1.
+ *  - bit[16]: Error in the sequence of lines for vc0 and dt0.
+ *  - bit[7]: Error matching Line Start with Line End for vc7 and dt7.
+ *  - bit[6]: Error matching Line Start with Line End for vc6 and dt6.
+ *  - bit[5]: Error matching Line Start with Line End for vc5 and dt5.
+ *  - bit[4]: Error matching Line Start with Line End for vc4 and dt4.
+ *  - bit[3]: Error matching Line Start with Line End for vc3 and dt3.
+ *  - bit[2]: Error matching Line Start with Line End for vc2 and dt2.
+ *  - bit[1]: Error matching Line Start with Line End for vc1 and dt1.
+ *  - bit[0]: Error matching Line Start with Line End for vc0 and dt0.
+ */
+struct viif_csi2rx_err_status {
+	__u32 err_phy_fatal;
+	__u32 err_pkt_fatal;
+	__u32 err_frame_fatal;
+	__u32 err_phy;
+	__u32 err_pkt;
+	__u32 err_line;
+};
+
+/**
+ * struct viif_l1_info - L1ISP status of automatic white balance and average luminance
+ *
+ * @avg_lum_weight: weighted average luminance value at average luminance generation
+ * @avg_lum_block: average luminance of each block.
+ *                 Nested indices are: [y position][x position].
+ * @avg_lum_four_line_lum: 4-lines average luminance.
+ *                         avg_lum_four_line_lum[n] corresponds to aexp_ave4linesy[n]
+ * @avg_satur_pixnum: the number of saturated pixel at average luminance generation
+ * @avg_black_pixnum: the number of black pixel at average luminance generation
+ * @awb_ave_u: U average value of AWB adjustment
+ * @awb_ave_v: V average value of AWB adjustment
+ * @awb_accumulated_pixel: Accumulated pixel count of AWB adjustment
+ * @awb_gain_r: R gain used in the next frame of AWB adjustment
+ * @awb_gain_g: G gain used in the next frame of AWB adjustment
+ * @awb_gain_b: B gain used in the next frame of AWB adjustment
+ * @awb_status_u: boolean value of U convergence state of AWB adjustment
+ *                (0: not-converged, 1: converged)
+ * @awb_status_v: boolean value of V convergence state of AWB adjustment
+ *                (0: not-converged, 1: converged)
+ * @reserved: padding field
+ */
+struct viif_l1_info {
+	__u32 avg_lum_weight;
+	__u32 avg_lum_block[8][8];
+	__u32 avg_lum_four_line_lum[4];
+	__u32 avg_satur_pixnum;
+	__u32 avg_black_pixnum;
+	__u32 awb_ave_u;
+	__u32 awb_ave_v;
+	__u32 awb_accumulated_pixel;
+	__u32 awb_gain_r;
+	__u32 awb_gain_g;
+	__u32 awb_gain_b;
+	__u8 awb_status_u;
+	__u8 awb_status_v;
+	__u8 reserved[2];
+};
+
+/**
+ * struct viif_isp_capture_status - L1ISP status of automatic white balance and average luminance
+ * @l1_info: L1ISP AWB information. Refer to &struct viif_l1_info
+ */
+struct viif_isp_capture_status {
+	struct viif_l1_info l1_info;
+};
+
+/**
+ * struct viif_reported_errors - VIIF status of errors
+ *
+ * @main: error flag value for capture device 0 and 1
+ *
+ *  - bit[24]: VSync generator error
+ *  - bit[20]: L1ISP input size inconsistency
+ *  - bit[19]: L1ISP output size inconsistency
+ *  - bit[18]: L1ISP ABPC table transfer error
+ *  - bit[17]: L1ISP LSSC table transfer error
+ *  - bit[11]: L2ISP grid table transfer error
+ *  - bit[9]: L2ISP POST1 table transfer error
+ *  - bit[8]: L2ISP POST0 table transfer error
+ *  - bit[0]: L2ISP size error
+ *
+ * @sub: error flag value for capture device 2
+ *
+ *  - bit[24]: VSync generator error
+ *  - bit[0]: data transfer error
+ *
+ * @csi2rx: error flag value for CSI2 receiver;
+ *          see also &struct viif_csi2_err_status for detailed cause
+ *
+ *  - bit[18]: Line error
+ *  - bit[17]: Packet error
+ *  - bit[16]: PHY error
+ *  - bit[2]: Frame fatal error
+ *  - bit[1]: Packet fatal error
+ *  - bit[0]: PHY fatal error
+ *
+ */
+struct viif_reported_errors {
+	__u32 main;
+	__u32 sub;
+	__u32 csi2rx;
+};
+
+/*==========Definitions for Param-buffer based I/F ============*/
+#define VISCONTI_VIIF_CFG_ISP_L1_INPUT_MODE		   (1U << 0)
+#define VISCONTI_VIIF_CFG_ISP_L1_RGB_TO_Y_COEF		   (1U << 1)
+#define VISCONTI_VIIF_CFG_ISP_L1_AG_MODE		   (1U << 2)
+#define VISCONTI_VIIF_CFG_ISP_L1_AG			   (1U << 3)
+#define VISCONTI_VIIF_CFG_ISP_L1_HDRE			   (1U << 4)
+#define VISCONTI_VIIF_CFG_ISP_L1_IMG_EXTRACTION		   (1U << 5)
+#define VISCONTI_VIIF_CFG_ISP_L1_DPC			   (1U << 6)
+#define VISCONTI_VIIF_CFG_ISP_L1_PRESET_WHITE_BALANCE	   (1U << 7)
+#define VISCONTI_VIIF_CFG_ISP_L1_RAW_COLOR_NOISE_REDUCTION (1U << 8)
+#define VISCONTI_VIIF_CFG_ISP_L1_HDRS			   (1U << 9)
+#define VISCONTI_VIIF_CFG_ISP_L1_BLACK_LEVEL_CORRECTION	   (1U << 10)
+#define VISCONTI_VIIF_CFG_ISP_L1_LSC			   (1U << 11)
+#define VISCONTI_VIIF_CFG_ISP_L1_MAIN_PROCESS		   (1U << 12)
+#define VISCONTI_VIIF_CFG_ISP_L1_AWB			   (1U << 13)
+#define VISCONTI_VIIF_CFG_ISP_L1_LOCK_AWB_GAIN		   (1U << 14)
+#define VISCONTI_VIIF_CFG_ISP_L1_HDRC			   (1U << 15)
+#define VISCONTI_VIIF_CFG_ISP_L1_HDRC_LTM		   (1U << 16)
+#define VISCONTI_VIIF_CFG_ISP_L1_GAMMA			   (1U << 17)
+#define VISCONTI_VIIF_CFG_ISP_L1_IMG_QUALITY_ADJUSTMENT	   (1U << 18)
+#define VISCONTI_VIIF_CFG_ISP_L1_AVG_LUM_GENERATION	   (1U << 19)
+#define VISCONTI_VIIF_CFG_ISP_L2_UNDIST			   (1U << 20)
+#define VISCONTI_VIIF_CFG_ISP_L2_ROI			   (1U << 21)
+#define VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST0		   (1U << 22)
+#define VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST1		   (1U << 23)
+
+#define VISCONTI_VIIF_STAT_CSI2RX_CALIBRATION  (1U << 0)
+#define VISCONTI_VIIF_STAT_CSI2RX_ERR_STATUS   (1U << 1)
+#define VISCONTI_VIIF_STAT_LAST_CAPTURE_STATUS (1U << 2)
+#define VISCONTI_VIIF_STAT_L1_INFO	       (1U << 3)
+#define VISCONTI_VIIF_STAT_ERRORS	       (1U << 4)
+
+/**
+ * struct visconti_viif_isp_config - Visconti VIIF ISP parameters metadata
+ *
+ * @update_cfg: each bit specifies whether a feature should be updated
+ * @l1_input_mode: input format and preprocessing mode
+ * @l1_rgb_to_y_coef: coefficient to yield Y from RGB
+ * @l1_ag_mode: rules to derive analog gains for each feature
+ * @l1_ag: base analog gain
+ * @l1_hdre: parameter for HDR expansion
+ * @l1_img_extraction: parameter for image extraction
+ * @l1_dpc: parameter for defect pixel correction
+ * @l1_preset_white_balance: parameter for preset white balance
+ * @l1_raw_color_noise_reduction: parameter for raw color noise reduction
+ * @l1_hdrs: parameter for HDR synthesis
+ * @l1_black_level_correction: parameter for black level correction
+ * @l1_lsc: parameter for lens shading correction
+ * @l1_main_process: parameter for demosaicing and color matrix
+ * @l1_awb: parameter for automatic white balance
+ * @lock_awb_gain: 0 to run AWB, 1 to lock AWB gain
+ * @l1_hdrc: parameter for HDR compression
+ * @l1_hdrc_ltm: parameter for HDR compression local tone mapping
+ * @l1_gamma: parameter for L1ISP gamma correction
+ * @l1_img_quality_adjustment: parameter for image quality adjustment (VPRO)
+ * @l1_avg_lum_generation: parameter for calculating average luminance
+ * @l2_undist: parameter for undistortion
+ * @l2_roi: parameter for l2 ROI and scaling
+ * @l2_gamma_post0: parameter for L2ISP POST0 gamma correction
+ * @l2_gamma_post1: parameter for L2ISP POST1 gamma correction
+ */
+struct visconti_viif_isp_config {
+	__u32 update_cfg;
+
+	struct viif_l1_input_mode_config l1_input_mode;
+	struct viif_l1_rgb_to_y_coef_config l1_rgb_to_y_coef;
+	struct viif_l1_ag_mode_config l1_ag_mode;
+	struct viif_l1_ag_config l1_ag;
+	struct viif_l1_hdre_config l1_hdre;
+	struct viif_l1_img_extraction_config l1_img_extraction;
+	struct viif_l1_dpc_config l1_dpc;
+	struct viif_l1_preset_white_balance_config l1_preset_white_balance;
+	struct viif_l1_raw_color_noise_reduction_config l1_raw_color_noise_reduction;
+	struct viif_l1_hdrs_config l1_hdrs;
+	struct viif_l1_black_level_correction_config l1_black_level_correction;
+	struct viif_l1_lsc_config l1_lsc;
+	struct viif_l1_main_process_config l1_main_process;
+	struct viif_l1_awb_config l1_awb;
+	__u32 lock_awb_gain;
+	struct viif_l1_hdrc_config l1_hdrc;
+	struct viif_l1_hdrc_ltm_config l1_hdrc_ltm;
+	struct viif_l1_gamma_config l1_gamma;
+	struct viif_l1_img_quality_adjustment_config l1_img_quality_adjustment;
+	struct viif_l1_avg_lum_generation_config l1_avg_lum_generation;
+	struct viif_l2_undist_config l2_undist;
+	struct viif_l2_roi_config l2_roi;
+	struct viif_l2_gamma_config l2_gamma_post0;
+	struct viif_l2_gamma_config l2_gamma_post1;
+};
+
+/**
+ * struct visconti_viif_isp_stat - Visconti VIIF ISP status metadata
+ *
+ * @stat_type: each bit specifies whether information is available
+ * @csi2rx_dphy_calibration: CSI2RX calibration status
+ * @csi2rx_err: CSI2RX error status
+ * @isp_capture: L1ISP status of whitebalance and average luminance
+ * @errors: VIIF error status
+ */
+struct visconti_viif_isp_stat {
+	__u32 stat_type;
+
+	struct viif_csi2rx_dphy_calibration_status csi2rx_dphy_calibration;
+	struct viif_csi2rx_err_status csi2rx_err;
+	struct viif_isp_capture_status isp_capture;
+	struct viif_reported_errors errors;
+};
+
+#endif /* __UAPI_VISCONTI_VIIF_H_ */
-- 
2.25.1



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

* [PATCH v12 6/8] media: platform: visconti: Add streaming interface for ISP parameters and status
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (4 preceding siblings ...)
  2024-11-25  9:21 ` [PATCH v12 5/8] media: platform: visconti: Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  2024-11-25  9:21 ` [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface Yuji Ishikawa
  7 siblings, 0 replies; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Add support to Image Signal Processors of Visconti's Video Input Interface.
This patch adds two streaming interfaces;
one for passing parameters to the signal processor,
the other for receiving status.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
---
Changelog v2:
- Resend v1 because a patch exceeds size limit.

Changelog v3:
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters

Changelog v4:
- Split patches because the v3 patch exceeds size limit
- Stop using ID number to identify driver instance:
  - Use dynamically allocated structure to hold HW specific context,
    instead of static one.
  - Call HW layer functions with the context structure instead of ID number

Changelog v5:
- no change

Changelog v6:
- remove unused macros
- removed hwd_ and HWD_ prefix
- update source code documentation
- Suggestion from Hans Verkuil
  - pointer to userland memory is removed from uAPI arguments
    - style of structure is now "nested" instead of "chained by pointer";
  - use div64_u64 for 64bit division
  - vendor specific controls support TRY_EXT_CTRLS
  - add READ_ONLY flag to GET_CALIBRATION_STATUS control and similar ones
  - human friendry control names for vendor specific controls
  - add initial value to each vendor specific control
  - GET_LAST_CAPTURE_STATUS control is updated asyncnously from workqueue
  - remove EXECUTE_ON_WRITE flag of vendor specific control
  - uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
  - applied v4l2-compliance
- Suggestion from Sakari Ailus
  - use div64_u64 for 64bit division
  - update copyright's year
  - remove redandunt cast
  - use bool instead of HWD_VIIF_ENABLE/DISABLE
  - simplify comparison to 0
  - simplify statements with trigram operator
  - remove redundant local variables
  - use general integer types instead of u32/s32
- Suggestion from Laurent Pinchart
  - moved VIIF driver to driver/platform/toshiba/visconti
  - change register access: struct-style to macro-style
  - remove unused type definitions
  - define enums instead of successive macro constants
  - remove redundant parenthesis of macro constant
  - embed struct hwd_res into struct viif_device
  - use xxx_dma instead of xxx_paddr for variable names of IOVA
  - literal value: just 0 instead of 0x0
  - use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register access
  - use true or false instead of HWD_VIIF_ENABLE, DISABLE for function calls
  - uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes

Changelog v7:
- remove unused variables
- split long statements which have multiple logical-OR and trigram operators

Changelog v8:
- define constant V4L2_CTRL_TYPE_VISCONTI_ISP for datatype
  of Visconti specific controls
- Suggestion from Hans Verkuil
  - remove pr_info()
  - use pm_runtime_get_if_in_use() to get power status

Changelog v9:
- fix warning for cast between ptr and dma_addr_t

Changelog v10:
- use parameter buffer instead of vendor specific compound controls
  - add viif_params interface for passing ISP parameters
  - add viif_stats interface for passing ISP status
- remove parameter validation routine; moved to userland library

Changelog v11:
- remove feature VB2_USERPTR from viif_params and viif_stats
- fix strange indents at initializations
- remove a redundant default setting of the ISP: L2_ROI
- update copyright year

Changelog v12:
- use guard(spinlock)(locked_variable) macros
  - also use custom guard macros for viif_isp_guard
- improve cast operations for viif_dev->tables_dma
- add default parameter for undistortion (identical transformation)
- add function to calculate the default scaling 
  according to the request from the resizer subdevice

 .../media/platform/toshiba/visconti/Makefile  |    2 +-
 .../media/platform/toshiba/visconti/viif.c    |   26 +-
 .../platform/toshiba/visconti/viif_isp.c      |    2 +
 .../platform/toshiba/visconti/viif_params.c   | 2034 +++++++++++++++++
 .../platform/toshiba/visconti/viif_params.h   |   24 +
 .../platform/toshiba/visconti/viif_resizer.c  |   30 +
 .../platform/toshiba/visconti/viif_stats.c    |  301 +++
 .../platform/toshiba/visconti/viif_stats.h    |   14 +
 8 files changed, 2430 insertions(+), 3 deletions(-)
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
 create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h

diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
index 4c7433744b64..e5bbfcf3f9d0 100644
--- a/drivers/media/platform/toshiba/visconti/Makefile
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -4,7 +4,7 @@
 #
 
 visconti-csi2rx-objs = csi2rx_drv.o
-visconti-viif-objs = viif.o viif_capture.o viif_common.o viif_isp.o viif_resizer.o
+visconti-viif-objs = viif.o viif_capture.o viif_common.o viif_isp.o viif_resizer.o viif_params.o viif_stats.o
 
 obj-$(CONFIG_VIDEO_VISCONTI_CSI2RX) += visconti-csi2rx.o
 obj-$(CONFIG_VIDEO_VISCONTI_VIIF) += visconti-viif.o
diff --git a/drivers/media/platform/toshiba/visconti/viif.c b/drivers/media/platform/toshiba/visconti/viif.c
index d2521718abe5..65e483b4b6aa 100644
--- a/drivers/media/platform/toshiba/visconti/viif.c
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -20,8 +20,10 @@
 #include "viif_capture.h"
 #include "viif_common.h"
 #include "viif_isp.h"
+#include "viif_params.h"
 #include "viif_regs.h"
 #include "viif_resizer.h"
+#include "viif_stats.h"
 
 /*=============================================*/
 /* Register Access */
@@ -106,6 +108,8 @@ static irqreturn_t viif_vsync_irq_handler(int irq, void *dev_id)
 						    l2_transfer_status, ts);
 		visconti_viif_capture_switch_buffer(&viif_dev->cap_post1, status_err,
 						    l2_transfer_status, ts);
+		visconti_viif_stats_isr(viif_dev, viif_dev->cap_post0.sequence, ts);
+		visconti_viif_params_isr(viif_dev);
 	}
 
 	/* Delayed Vsync of SUB unit */
@@ -457,16 +461,32 @@ static int visconti_viif_probe(struct platform_device *pdev)
 		goto error_resizer_unregister;
 	}
 
+	ret = visconti_viif_params_register(viif_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to register parameter node\n");
+		goto error_capture_unregister;
+	}
+
+	ret = visconti_viif_stats_register(viif_dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "failed to register stat node\n");
+		goto error_params_unregister;
+	}
+
 	ret = visconti_viif_create_links(viif_dev);
 	if (ret)
-		goto error_capture_unregister;
+		goto error_stats_unregister;
 
 	visconti_viif_subdev_notifier_register(viif_dev);
 	if (ret)
-		goto error_capture_unregister;
+		goto error_stats_unregister;
 
 	return 0;
 
+error_stats_unregister:
+	visconti_viif_stats_unregister(viif_dev);
+error_params_unregister:
+	visconti_viif_params_unregister(viif_dev);
 error_capture_unregister:
 	visconti_viif_capture_unregister(viif_dev);
 error_resizer_unregister:
@@ -490,6 +510,8 @@ static void visconti_viif_remove(struct platform_device *pdev)
 
 	v4l2_async_nf_unregister(&viif_dev->notifier);
 	v4l2_async_nf_cleanup(&viif_dev->notifier);
+	visconti_viif_stats_unregister(viif_dev);
+	visconti_viif_params_unregister(viif_dev);
 	visconti_viif_capture_unregister(viif_dev);
 	visconti_viif_resizer_unregister(viif_dev);
 	visconti_viif_isp_unregister(viif_dev);
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
index 0bcc6bba9bf1..1bb7b9122ede 100644
--- a/drivers/media/platform/toshiba/visconti/viif_isp.c
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -14,6 +14,7 @@
 #include "viif.h"
 #include "viif_common.h"
 #include "viif_isp.h"
+#include "viif_params.h"
 #include "viif_regs.h"
 
 /* disable CSI2 capture at viif_mux_start() */
@@ -583,6 +584,7 @@ static int visconti_viif_isp_enable_streams(struct v4l2_subdev *sd, struct v4l2_
 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
 
 	/* enabling: start ISP, MUX -> start CSI2RX, sensor */
+	visconti_viif_params_eval_queue(viif_dev);
 	viif_dev->masked_gamma_path = 0;
 	viif_mux_start(viif_dev, 0, 0);
 
diff --git a/drivers/media/platform/toshiba/visconti/viif_params.c b/drivers/media/platform/toshiba/visconti/viif_params.c
new file mode 100644
index 000000000000..af5a95217b83
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.c
@@ -0,0 +1,2034 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_params.h"
+#include "viif_regs.h"
+#include "viif_resizer.h"
+
+/* ISP_L1_SET_HDRC */
+#define VIIF_L1_HDRC_RATIO_OFFSET 10U
+#define VIIF_REGBUF_ACCESS_TIME	  15360UL
+#define VIIF_L1_DELAY_W_HDRC	  31U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST */
+#define VIIF_L2_UNDIST_POLY_NUM 11U
+
+/*=======================================================================*/
+/* ISP parameter configuration */
+/*=======================================================================*/
+static void viif_l1_set_input_mode(struct viif_device *viif_dev,
+				   const struct viif_l1_input_mode_config *arg)
+{
+	/* values are already tested in _try*/
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_SYSM_INPUT_MODE, (u32)arg->mode);
+}
+
+static void viif_l1_set_rgb_to_y_coef(struct viif_device *viif_dev,
+				      const struct viif_l1_rgb_to_y_coef_config *arg)
+{
+	/* value is already tested in _try*/
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_R, (u32)arg->coef_r);
+	viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_G, (u32)arg->coef_g);
+	viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_B, (u32)arg->coef_b);
+}
+
+static void viif_l1_set_ag_mode(struct viif_device *viif_dev,
+				const struct viif_l1_ag_mode_config *arg)
+{
+	u32 val;
+
+	/* value is already tested in _try*/
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* SYSM_AG_PARAM */
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_A,
+			   PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[0], arg->sysm_ag_ofst[0]));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_B,
+			   PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[1], arg->sysm_ag_ofst[1]));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_C,
+			   PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[2], arg->sysm_ag_ofst[2]));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_D,
+			   PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[3], arg->sysm_ag_ofst[3]));
+
+	/* SYSM_AG_SEL */
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_HOBC,
+			   PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_hobc_high,
+						   arg->sysm_ag_psel_hobc_middle_led,
+						   arg->sysm_ag_psel_hobc_low));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_ABPC,
+			   PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_abpc_high,
+						   arg->sysm_ag_psel_abpc_middle_led,
+						   arg->sysm_ag_psel_abpc_low));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_RCNR,
+			   PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_rcnr_high,
+						   arg->sysm_ag_psel_rcnr_middle_led,
+						   arg->sysm_ag_psel_rcnr_low));
+
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_LSSC,
+			   PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_lssc, arg->sysm_ag_psel_lssc));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_MPRO,
+			   PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_mpro, arg->sysm_ag_psel_mpro));
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_VPRO,
+			   PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_vpro, arg->sysm_ag_psel_vpro));
+
+	/* SYSM_AG_CONT */
+	val = arg->sysm_ag_cont_hobc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_hobc_test_middle_led);
+	val |= arg->sysm_ag_cont_hobc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_hobc_test_high);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC01_EN, val);
+
+	val = arg->sysm_ag_cont_hobc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_hobc_test_low);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC2_EN, val);
+
+	val = arg->sysm_ag_cont_abpc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_abpc_test_middle_led);
+	val |= arg->sysm_ag_cont_abpc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_abpc_test_high);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC01_EN, val);
+
+	val = arg->sysm_ag_cont_abpc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_abpc_test_low);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC2_EN, val);
+
+	val = arg->sysm_ag_cont_rcnr_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_rcnr_test_middle_led);
+	val |= arg->sysm_ag_cont_rcnr_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_rcnr_test_high);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR01_EN, val);
+
+	val = arg->sysm_ag_cont_rcnr_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_rcnr_test_low);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR2_EN, val);
+
+	val = arg->sysm_ag_cont_lssc_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_lssc_test);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_LSSC_EN, val);
+
+	val = arg->sysm_ag_cont_mpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_mpro_test);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_MPRO_EN, val);
+
+	val = arg->sysm_ag_cont_vpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+	val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_vpro_test);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_VPRO_EN, val);
+}
+
+static void viif_l1_set_ag(struct viif_device *viif_dev, const struct viif_l1_ag_config *arg)
+{
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_H, (u32)arg->gain_h);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_M, (u32)arg->gain_m);
+	viif_capture_write(viif_dev, REG_L1_SYSM_AG_L, (u32)arg->gain_l);
+}
+
+static void viif_l1_set_hdre(struct viif_device *viif_dev, const struct viif_l1_hdre_config *arg)
+{
+	int i;
+
+	/* value is already tested in _try*/
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	for (i = 0; i < LEN_L1_HDRE_SRCPOINT; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRE_SRCPOINT(i), arg->hdre_src_point[i]);
+
+	viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(0), 0);
+	for (i = 1; i < LEN_L1_HDRE_SRCBASE; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(i), arg->hdre_src_point[i - 1]);
+
+	for (i = 0; i < LEN_L1_HDRE_DSTBASE; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRE_DSTBASE(i), arg->hdre_dst_base[i]);
+
+	for (i = 0; i < LEN_L1_HDRE_RATIO; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRE_RATIO(i), arg->hdre_ratio[i]);
+
+	viif_capture_write(viif_dev, REG_L1_HDRE_DSTMAXVAL, arg->hdre_dst_max_val);
+}
+
+static void viif_l1_set_img_extraction(struct viif_device *viif_dev,
+				       const struct viif_l1_img_extraction_config *arg)
+{
+	/* value is already tested in _try*/
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GR, arg->input_black_gr);
+	viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_R, arg->input_black_r);
+	viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_B, arg->input_black_b);
+	viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GB, arg->input_black_gb);
+}
+
+static void viif_config_vdm_tgroup(struct viif_device *viif_dev, int idx)
+{
+	const struct {
+		u32 cfg;
+		u32 sram_base;
+		u32 sram_size;
+	} conf[] = {
+		/* T01: L1_SET_DPC, L1_SET_LSC */
+		{ VAL_TGROUP_CFG_64BIT_RD, 0x600, 0x20 },
+		/* T02: L2_UNDIST grid table */
+		{ VAL_TGROUP_CFG_32BIT_RD, 0x620, 0x20 },
+		/* T02: L2_GAMMA (path0) */
+		{ VAL_TGROUP_CFG_32BIT_RD, 0x640, 0x20 },
+		/* T03: L2 GAMMA (path1) */
+		{ VAL_TGROUP_CFG_32BIT_RD, 0x660, 0x20 },
+	};
+
+	viif_capture_write(viif_dev, REG_VDM_TGROUP_X_CFG(idx), conf[idx].cfg);
+	viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_BASE(idx), conf[idx].sram_base);
+	viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_SIZE(idx), conf[idx].sram_size);
+}
+
+static void dpc_table_transmission(struct viif_device *viif_dev, uintptr_t table_h,
+				   uintptr_t table_m, uintptr_t table_l)
+{
+	u32 val = 0x0U;
+
+	viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+	if (table_h) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_H),
+				   (u32)table_h);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_H),
+				   VIIF_DPC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_DPC_H;
+	}
+
+	if (table_m) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_M),
+				   (u32)table_m);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_M),
+				   VIIF_DPC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_DPC_M;
+	}
+
+	if (table_l) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_L),
+				   (u32)table_l);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_L),
+				   VIIF_DPC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_DPC_L;
+	}
+
+	val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_DPC);
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static void viif_l1_set_dpc(struct viif_device *viif_dev, const struct viif_l1_dpc_config *arg)
+{
+	const struct viif_l1_dpc *param_h, *param_m, *param_l;
+	dma_addr_t table_h = 0;
+	dma_addr_t table_m = 0;
+	dma_addr_t table_l = 0;
+	unsigned long irqflags;
+	u32 val;
+
+	if (arg->param_h.abpc_sta_en) {
+		memcpy(viif_dev->tables->dpc_table_h, arg->table_h, VIIF_DPC_TABLE_BYTES);
+		table_h = viif_dev->tables_dma + offsetof(struct viif_table_area, dpc_table_h);
+	}
+	if (arg->param_m.abpc_sta_en) {
+		memcpy(viif_dev->tables->dpc_table_m, arg->table_m, VIIF_DPC_TABLE_BYTES);
+		table_m = viif_dev->tables_dma + offsetof(struct viif_table_area, dpc_table_m);
+	}
+	if (arg->param_l.abpc_sta_en) {
+		memcpy(viif_dev->tables->dpc_table_l, arg->table_l, VIIF_DPC_TABLE_BYTES);
+		table_l = viif_dev->tables_dma + offsetof(struct viif_table_area, dpc_table_l);
+	}
+
+	spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+	hwd_viif_isp_guard_start(viif_dev);
+
+	dpc_table_transmission(viif_dev, table_h, table_m, table_l);
+
+	param_h = &arg->param_h;
+	param_m = &arg->param_m;
+	param_l = &arg->param_l;
+
+	val = (param_h->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_H : 0;
+	val |= (param_m->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_M : 0;
+	val |= (param_l->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_L : 0;
+	viif_capture_write(viif_dev, REG_L1_ABPC012_STA_EN, val);
+
+	val = (param_h->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_H : 0;
+	val |= (param_m->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_M : 0;
+	val |= (param_l->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_L : 0;
+	viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_EN, val);
+
+	val = (param_h->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_H : 0;
+	val |= (param_m->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_M : 0;
+	val |= (param_l->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_L : 0;
+	viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_MODE, val);
+
+	/* setup param_h */
+	viif_capture_write(viif_dev, REG_L1_ABPC0_RATIO_LIMIT, param_h->abpc_ratio_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_DARK_LIMIT, param_h->abpc_dark_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MIN, param_h->abpc_sn_coef_w_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MID, param_h->abpc_sn_coef_w_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MAX, param_h->abpc_sn_coef_w_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MIN, param_h->abpc_sn_coef_b_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MID, param_h->abpc_sn_coef_b_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MAX, param_h->abpc_sn_coef_b_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MIN, param_h->abpc_sn_coef_w_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MAX, param_h->abpc_sn_coef_w_th_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MIN, param_h->abpc_sn_coef_b_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MAX, param_h->abpc_sn_coef_b_th_max);
+
+	/* setup param_m */
+	viif_capture_write(viif_dev, REG_L1_ABPC1_RATIO_LIMIT, param_m->abpc_ratio_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_DARK_LIMIT, param_m->abpc_dark_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MIN, param_m->abpc_sn_coef_w_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MID, param_m->abpc_sn_coef_w_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MAX, param_m->abpc_sn_coef_w_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MIN, param_m->abpc_sn_coef_b_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MID, param_m->abpc_sn_coef_b_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MAX, param_m->abpc_sn_coef_b_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MIN, param_m->abpc_sn_coef_w_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MAX, param_m->abpc_sn_coef_w_th_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MIN, param_m->abpc_sn_coef_b_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MAX, param_m->abpc_sn_coef_b_th_max);
+
+	/* setup param_l */
+	viif_capture_write(viif_dev, REG_L1_ABPC2_RATIO_LIMIT, param_l->abpc_ratio_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_DARK_LIMIT, param_l->abpc_dark_limit);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MIN, param_l->abpc_sn_coef_w_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MID, param_l->abpc_sn_coef_w_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MAX, param_l->abpc_sn_coef_w_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MIN, param_l->abpc_sn_coef_b_ag_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MID, param_l->abpc_sn_coef_b_ag_mid);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MAX, param_l->abpc_sn_coef_b_ag_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MIN, param_l->abpc_sn_coef_w_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MAX, param_l->abpc_sn_coef_w_th_max);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MIN, param_l->abpc_sn_coef_b_th_min);
+	viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MAX, param_l->abpc_sn_coef_b_th_max);
+
+	hwd_viif_isp_guard_end(viif_dev);
+	spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_preset_white_balance(struct viif_device *viif_dev,
+					     const struct viif_l1_preset_white_balance_config *arg)
+{
+	const struct viif_l1_preset_wb *param_h, *param_m, *param_l;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	param_h = &arg->param_h;
+	param_m = &arg->param_m;
+	param_l = &arg->param_l;
+
+	viif_capture_write(viif_dev, REG_L1_PWHB_DSTMAXVAL, arg->dstmaxval);
+
+	viif_capture_write(viif_dev, REG_L1_PWHB_H_GR, param_h->gain_gr);
+	viif_capture_write(viif_dev, REG_L1_PWHB_HR, param_h->gain_r);
+	viif_capture_write(viif_dev, REG_L1_PWHB_HB, param_h->gain_b);
+	viif_capture_write(viif_dev, REG_L1_PWHB_H_GB, param_h->gain_gb);
+
+	viif_capture_write(viif_dev, REG_L1_PWHB_M_GR, param_m->gain_gr);
+	viif_capture_write(viif_dev, REG_L1_PWHB_MR, param_m->gain_r);
+	viif_capture_write(viif_dev, REG_L1_PWHB_MB, param_m->gain_b);
+	viif_capture_write(viif_dev, REG_L1_PWHB_M_GB, param_m->gain_gb);
+
+	viif_capture_write(viif_dev, REG_L1_PWHB_L_GR, param_l->gain_gr);
+	viif_capture_write(viif_dev, REG_L1_PWHB_LR, param_l->gain_r);
+	viif_capture_write(viif_dev, REG_L1_PWHB_LB, param_l->gain_b);
+	viif_capture_write(viif_dev, REG_L1_PWHB_L_GB, param_l->gain_gb);
+}
+
+static void
+viif_l1_set_raw_color_noise_reduction(struct viif_device *viif_dev,
+				      const struct viif_l1_raw_color_noise_reduction_config *arg)
+{
+	const struct viif_l1_raw_color_noise_reduction *params[] = {
+		&arg->param_h,
+		&arg->param_m,
+		&arg->param_l,
+	};
+	int i;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	for (i = 0; i < 3; i++) {
+		const struct viif_l1_raw_color_noise_reduction *param = params[i];
+		/* param_h */
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_SW(i), param->rcnr_sw ? 1 : 0);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG0(i),
+				   param->rcnr_cnf_dark_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG1(i),
+				   param->rcnr_cnf_dark_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG2(i),
+				   param->rcnr_cnf_dark_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG0(i),
+				   param->rcnr_cnf_ratio_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG1(i),
+				   param->rcnr_cnf_ratio_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG2(i),
+				   param->rcnr_cnf_ratio_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_R(i),
+				   param->rcnr_cnf_clip_gain_r);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_G(i),
+				   param->rcnr_cnf_clip_gain_g);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_B(i),
+				   param->rcnr_cnf_clip_gain_b);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG0(i),
+				   param->rcnr_a1l_dark_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG1(i),
+				   param->rcnr_a1l_dark_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG2(i),
+				   param->rcnr_a1l_dark_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG0(i),
+				   param->rcnr_a1l_ratio_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG1(i),
+				   param->rcnr_a1l_ratio_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG2(i),
+				   param->rcnr_a1l_ratio_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_INF_ZERO_CLIP(i),
+				   param->rcnr_inf_zero_clip);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG0(i),
+				   param->rcnr_merge_d2blend_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG1(i),
+				   param->rcnr_merge_d2blend_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG2(i),
+				   param->rcnr_merge_d2blend_ag2);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_BLACK(i), param->rcnr_merge_black);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_MINDIV(i),
+				   param->rcnr_merge_mindiv);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_HRY_TYPE(i), param->rcnr_hry_type);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG0(i),
+				   param->rcnr_anf_blend_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG1(i),
+				   param->rcnr_anf_blend_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG2(i),
+				   param->rcnr_anf_blend_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_LPF_THRESHOLD(i),
+				   param->rcnr_lpf_threshold);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG0(i),
+				   param->rcnr_merge_hlblend_ag0);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG1(i),
+				   param->rcnr_merge_hlblend_ag1);
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG2(i),
+				   param->rcnr_merge_hlblend_ag2);
+
+		viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_SW(i), param->rcnr_gnr_sw ? 1 : 0);
+
+		if (param->rcnr_gnr_sw) {
+			viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_RATIO(i),
+					   param->rcnr_gnr_ratio);
+			viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_WIDE_EN(i),
+					   param->rcnr_gnr_wide_en ? 1 : 0);
+		}
+	}
+}
+
+static void viif_l1_set_hdrs(struct viif_device *viif_dev, const struct viif_l1_hdrs_config *arg)
+{
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_HDRMODE, arg->hdrs_hdr_mode);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_M, arg->hdrs_hdr_ratio_m);
+	viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_L, arg->hdrs_hdr_ratio_l);
+	viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_E, arg->hdrs_hdr_ratio_e);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_DG_H, arg->hdrs_dg_h);
+	viif_capture_write(viif_dev, REG_L1_HDRS_DG_M, arg->hdrs_dg_m);
+	viif_capture_write(viif_dev, REG_L1_HDRS_DG_L, arg->hdrs_dg_l);
+	viif_capture_write(viif_dev, REG_L1_HDRS_DG_E, arg->hdrs_dg_e);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_H, arg->hdrs_blendend_h);
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_M, arg->hdrs_blendend_m);
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_E, arg->hdrs_blendend_e);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_H, arg->hdrs_blendbeg_h);
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_M, arg->hdrs_blendbeg_m);
+	viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_E, arg->hdrs_blendbeg_e);
+
+	viif_capture_write(viif_dev, REG_L1_HDRS_LEDMODE_ON, arg->hdrs_led_mode_on ? 1 : 0);
+	viif_capture_write(viif_dev, REG_L1_HDRS_DSTMAXVAL, arg->hdrs_dst_max_val);
+}
+
+static void
+viif_l1_set_black_level_correction(struct viif_device *viif_dev,
+				   const struct viif_l1_black_level_correction_config *arg)
+{
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_GR, arg->srcblacklevel_gr);
+	viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_R, arg->srcblacklevel_r);
+	viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_B, arg->srcblacklevel_b);
+	viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVELGB, arg->srcblacklevel_gb);
+
+	viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GR, arg->mulval_gr);
+	viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_R, arg->mulval_r);
+	viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_B, arg->mulval_b);
+	viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GB, arg->mulval_gb);
+
+	viif_capture_write(viif_dev, REG_L1_BLVC_DSTMAXVAL, arg->dstmaxval);
+}
+
+static void lsc_table_transmission(struct viif_device *viif_dev, dma_addr_t table_gr,
+				   dma_addr_t table_r, dma_addr_t table_b, dma_addr_t table_gb)
+{
+	u32 val = 0x0U;
+
+	viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+	if (table_gr) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GR),
+				   (u32)table_gr);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GR),
+				   VIIF_LSC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_LSSC_GR;
+	}
+
+	if (table_r) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_R),
+				   (u32)table_r);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_R),
+				   VIIF_LSC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_LSSC_R;
+	}
+
+	if (table_b) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_B),
+				   (u32)table_b);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_B),
+				   VIIF_LSC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_LSSC_B;
+	}
+
+	if (table_gb) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GB),
+				   (u32)table_gb);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GB),
+				   VIIF_LSC_TABLE_BYTES);
+		val |= MASK_VDM_T_ENABLE_L1_LSSC_GB;
+	}
+
+	val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_LSSC);
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static inline u32 gen_grid_size(u32 param)
+{
+	switch (param) {
+	case 32U:
+		return 5U;
+	case 64U:
+		return 6U;
+	case 128U:
+		return 7U;
+	case 256U:
+		return 8U;
+	case 512U:
+		return 9U;
+	default:
+		return 0;
+	}
+}
+
+#define PACK_PARA_COEF(max, min) (FIELD_PREP(0x1fff0000, (max)) | FIELD_PREP(0x1fff, (min)))
+
+static void viif_l1_set_lsc(struct viif_device *viif_dev, const struct viif_l1_lsc_config *arg)
+{
+	dma_addr_t table_gr = 0;
+	dma_addr_t table_gb = 0;
+	dma_addr_t table_r = 0;
+	dma_addr_t table_b = 0;
+	unsigned long irqflags;
+	u32 val;
+
+	if (!arg->enable) {
+		spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+		hwd_viif_isp_guard_start(viif_dev);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_EN, 0);
+
+		hwd_viif_isp_guard_end(viif_dev);
+		spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+		return;
+	}
+
+	if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+		memcpy(viif_dev->tables->lsc_table_gr, arg->table_gr, VIIF_LSC_TABLE_BYTES);
+		memcpy(viif_dev->tables->lsc_table_r, arg->table_r, VIIF_LSC_TABLE_BYTES);
+		memcpy(viif_dev->tables->lsc_table_b, arg->table_b, VIIF_LSC_TABLE_BYTES);
+		memcpy(viif_dev->tables->lsc_table_gb, arg->table_gb, VIIF_LSC_TABLE_BYTES);
+		table_gr = viif_dev->tables_dma + offsetof(struct viif_table_area, lsc_table_gr);
+		table_r = viif_dev->tables_dma + offsetof(struct viif_table_area, lsc_table_r);
+		table_b = viif_dev->tables_dma + offsetof(struct viif_table_area, lsc_table_b);
+		table_gb = viif_dev->tables_dma + offsetof(struct viif_table_area, lsc_table_gb);
+	}
+
+	spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+	hwd_viif_isp_guard_start(viif_dev);
+	lsc_table_transmission(viif_dev, table_gr, table_r, table_b, table_gb);
+
+	/* parabola shading */
+	if (arg->enable & VIIF_L1_LSC_PARABOLA_EN_MASK) {
+		const struct viif_l1_lsc_parabola_param *parabola_param =
+			&arg->param.lssc_parabola_param;
+		const struct viif_l1_lsc_parabola_ag_param *params[] = {
+			&parabola_param->r_2d,	&parabola_param->r_4d,	&parabola_param->gr_2d,
+			&parabola_param->gr_4d, &parabola_param->gb_2d, &parabola_param->gb_4d,
+			&parabola_param->b_2d,	&parabola_param->b_4d,
+		};
+		int i;
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 1);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_CENTER,
+				   parabola_param->lssc_para_h_center);
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_CENTER,
+				   parabola_param->lssc_para_v_center);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_GAIN,
+				   parabola_param->lssc_para_h_gain);
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_GAIN,
+				   parabola_param->lssc_para_v_gain);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL2,
+				   parabola_param->lssc_para_mgsel2);
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL4,
+				   parabola_param->lssc_para_mgsel4);
+
+		for (i = 0; i < 8; i++) {
+			const struct viif_l1_lsc_parabola_ag_param *p = params[i];
+
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_L(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_h_l_max,
+							  p->lssc_paracoef_h_l_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_R(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_h_r_max,
+							  p->lssc_paracoef_h_r_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_U(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_v_u_max,
+							  p->lssc_paracoef_v_u_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_D(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_v_d_max,
+							  p->lssc_paracoef_v_d_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LU(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_hv_lu_max,
+							  p->lssc_paracoef_hv_lu_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RU(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_hv_ru_max,
+							  p->lssc_paracoef_hv_ru_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LD(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_hv_ld_max,
+							  p->lssc_paracoef_hv_ld_min));
+			viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RD(i),
+					   PACK_PARA_COEF(p->lssc_paracoef_hv_rd_max,
+							  p->lssc_paracoef_hv_rd_min));
+		}
+	} else {
+		viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 0);
+	}
+
+	/* grid shading */
+	if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+		const struct viif_l1_lsc_grid_param *grid_param = &arg->param.lssc_grid_param;
+		u32 grid_h_size = gen_grid_size(grid_param->lssc_grid_h_size);
+		u32 grid_v_size = gen_grid_size(grid_param->lssc_grid_v_size);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 1);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_SIZE, grid_h_size);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_SIZE, grid_v_size);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_CENTER,
+				   grid_param->lssc_grid_h_center);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_CENTER,
+				   grid_param->lssc_grid_v_center);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_MGSEL, grid_param->lssc_grid_mgsel);
+
+	} else {
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 0);
+	}
+
+	/* preset white balance */
+	val = (arg->param.lssc_pwhb_r_gain_max << 16U) | (arg->param.lssc_pwhb_r_gain_min);
+	viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_R_GAIN, val);
+
+	val = (arg->param.lssc_pwhb_gr_gain_max << 16U) | (arg->param.lssc_pwhb_gr_gain_min);
+	viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GR_GAIN, val);
+
+	val = (arg->param.lssc_pwhb_gb_gain_max << 16U) | (arg->param.lssc_pwhb_gb_gain_min);
+	viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GB_GAIN, val);
+
+	val = (arg->param.lssc_pwhb_b_gain_max << 16U) | (arg->param.lssc_pwhb_b_gain_min);
+	viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_B_GAIN, val);
+
+	viif_capture_write(viif_dev, REG_L1_LSSC_EN, 1);
+
+	hwd_viif_isp_guard_end(viif_dev);
+	spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_main_process(struct viif_device *viif_dev,
+				     const struct viif_l1_main_process_config *arg)
+{
+	u32 val;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_MPRO_CONF, arg->damp_lsbsel << 4);
+	viif_capture_write(viif_dev, REG_L1_MPRO_LCS_MODE, arg->demosaic_mode);
+
+	if (arg->colormat_enable) {
+		const struct viif_l1_color_matrix_correction *color_matrix = &arg->colormat_param;
+
+		viif_capture_write(viif_dev, REG_L1_MPRO_SW, 1);
+
+		val = (u32)color_matrix->coef_rmg_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MIN, val);
+
+		val = (u32)color_matrix->coef_rmg_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MAX, val);
+
+		val = (u32)color_matrix->coef_rmb_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MIN, val);
+
+		val = (u32)color_matrix->coef_rmb_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MAX, val);
+
+		val = (u32)color_matrix->coef_gmr_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MIN, val);
+
+		val = (u32)color_matrix->coef_gmr_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MAX, val);
+
+		val = (u32)color_matrix->coef_gmb_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MIN, val);
+
+		val = (u32)color_matrix->coef_gmb_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MAX, val);
+
+		val = (u32)color_matrix->coef_bmr_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MIN, val);
+
+		val = (u32)color_matrix->coef_bmr_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MAX, val);
+
+		val = (u32)color_matrix->coef_bmg_min & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MIN, val);
+
+		val = (u32)color_matrix->coef_bmg_max & 0xffffU;
+		viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MAX, val);
+
+		viif_capture_write(viif_dev, REG_L1_MPRO_DST_MINVAL, (u32)color_matrix->dst_minval);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_MPRO_SW, 0);
+	}
+
+	viif_capture_write(viif_dev, REG_L1_MPRO_DST_MAXVAL, arg->dst_maxval);
+}
+
+static void viif_l1_set_awb(struct viif_device *viif_dev, const struct viif_l1_awb_config *arg)
+{
+	const struct viif_l1_awb *param = &arg->param;
+	u32 val, ygate_data;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBMRG, arg->awhb_wbmrg);
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBMGG, arg->awhb_wbmgg);
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBMBG, arg->awhb_wbmbg);
+
+	val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_EN;
+
+	/* disabling AWB */
+	if (!arg->enable) {
+		viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+		return;
+	}
+
+	/* enabling AWB */
+	viif_capture_write(viif_dev, REG_L1_AWHB_SW, val | MASK_L1_AWHB_SW_EN);
+
+	if (param->awhb_ygate_data == 64U)
+		ygate_data = 0U;
+	else if (param->awhb_ygate_data == 128U)
+		ygate_data = 1U;
+	else if (param->awhb_ygate_data == 256U)
+		ygate_data = 2U;
+	else
+		ygate_data = 3U;
+
+	val = param->awhb_ygate_sel ? MASK_L1_AWHB_GATE_YGATE_SEL : 0;
+	val |= FIELD_PREP(MASK_L1_AWHB_GATE_YGATE_DATA, ygate_data);
+	val |= FIELD_PREP(MASK_L1_AWHB_GATE_CGRANGE, param->awhb_cgrange);
+	viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF0, val);
+
+	val = param->awhb_ygatesw ? MASK_L1_AWHB_GATE_YGATESW : 0;
+	val |= param->awhb_hexsw ? MASK_L1_AWHB_GATE_HEXSW : 0;
+	val |= FIELD_PREP(MASK_L1_AWHB_GATE_AREAMODE, param->awhb_areamode);
+	viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF1, val);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HSIZE, param->awhb_area_hsize);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VSIZE, param->awhb_area_vsize);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HOFS, param->awhb_area_hofs);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VOFS, param->awhb_area_vofs);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKH, param->awhb_area_maskh);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKL, param->awhb_area_maskl);
+
+	val = param->awhb_sq_sw[0] ? MASK_L1_AWHB_SQ_CONF_SQ1SW : 0;
+	val |= param->awhb_sq_pol[0] ? MASK_L1_AWHB_SQ_CONF_SQ1POL : 0;
+	val |= param->awhb_sq_sw[1] ? MASK_L1_AWHB_SQ_CONF_SQ2SW : 0;
+	val |= param->awhb_sq_pol[1] ? MASK_L1_AWHB_SQ_CONF_SQ2POL : 0;
+	val |= param->awhb_sq_sw[2] ? MASK_L1_AWHB_SQ_CONF_SQ3SW : 0;
+	val |= param->awhb_sq_pol[2] ? MASK_L1_AWHB_SQ_CONF_SQ3POL : 0;
+	viif_capture_write(viif_dev, REG_L1_AWHB_SQ_CONF, val);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_YGATEH, (u32)param->awhb_ygateh);
+	viif_capture_write(viif_dev, REG_L1_AWHB_YGATEL, (u32)param->awhb_ygatel);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0P, param->awhb_bycut0p);
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0N, param->awhb_bycut0n);
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0P, param->awhb_rycut0p);
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0N, param->awhb_rycut0n);
+
+	val = (u32)param->awhb_rbcut0h & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0H, val);
+	val = (u32)param->awhb_rbcut0l & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0L, val);
+
+	val = (u32)param->awhb_bycut_h[0] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1L, param->awhb_bycut_l[0]);
+	val = (u32)param->awhb_bycut_h[1] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2L, param->awhb_bycut_l[1]);
+	val = (u32)param->awhb_bycut_h[2] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3L, param->awhb_bycut_l[2]);
+
+	val = (u32)param->awhb_rycut_h[0] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1L, param->awhb_rycut_l[0]);
+	val = (u32)param->awhb_rycut_h[1] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2L, param->awhb_rycut_l[1]);
+	val = (u32)param->awhb_rycut_h[2] & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3H, val);
+	viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3L, param->awhb_rycut_l[2]);
+
+	val = (u32)param->awhb_awbsftu & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTU, val);
+	val = (u32)param->awhb_awbsftv & 0xffU;
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTV, val);
+
+	val = (param->awhb_awbhuecor ? MASK_L1_AWHB_AWBSPD_HUECOR : 0);
+	val |= FIELD_PREP(MASK_L1_AWHB_AWBSPD_SPD, param->awhb_awbspd);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBSPD, val);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBULV, param->awhb_awbulv);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBVLV, param->awhb_awbvlv);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBWAIT, (u32)param->awhb_awbwait);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBONDOT, param->awhb_awbondot);
+	viif_capture_write(viif_dev, REG_L1_AWHB_AWBFZTIM, param->awhb_awbfztim);
+
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMAX, (u32)param->awhb_wbgrmax);
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMAX, (u32)param->awhb_wbgbmax);
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMIN, (u32)param->awhb_wbgrmin);
+	viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMIN, (u32)param->awhb_wbgbmin);
+}
+
+static void viif_l1_lock_awb_gain(struct viif_device *viif_dev, const u32 *enable)
+{
+	u32 val;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_LOCK;
+	val |= (*enable ? MASK_L1_AWHB_SW_LOCK : 0);
+	viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+}
+
+/* Convert the unit of time-period (from sysclk, to num lines in the image) */
+static u32 sysclk_to_numlines(u32 time_in_sysclk, const struct viif_img_clk *img_clk)
+{
+	u64 v1 = (u64)time_in_sysclk * img_clk->pixel_clock;
+	u64 v2 = (u64)img_clk->htotal_size * VIIF_SYS_CLK;
+
+	return (u32)div64_u64(v1, v2);
+}
+
+static void viif_l1_set_hdrc(struct viif_device *viif_dev, const struct viif_l1_hdrc_config *arg)
+{
+	const struct viif_l1_hdrc *param = &arg->param;
+	u32 val, sw_delay1;
+	int i;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* disabling HDRC */
+	if (!arg->enable) {
+		viif_capture_write(viif_dev, REG_L1_HDRC_THR_SFT_AMT, arg->hdrc_thr_sft_amt);
+		viif_capture_write(viif_dev, REG_L1_HDRC_EN, 0);
+		return;
+	}
+
+	/* enabling HDRC */
+	viif_capture_write(viif_dev, REG_L1_HDRC_RATIO,
+			   (param->hdrc_ratio - VIIF_L1_HDRC_RATIO_OFFSET));
+	viif_capture_write(viif_dev, REG_L1_HDRC_PT_RATIO, param->hdrc_pt_ratio);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND, param->hdrc_pt_blend);
+	viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND2, param->hdrc_pt_blend2);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_PT_SAT, param->hdrc_pt_sat);
+	viif_capture_write(viif_dev, REG_L1_HDRC_TN_TYPE, param->hdrc_tn_type);
+
+	for (i = 0; i < LEN_L1_HDRC_UTN_TBL; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRC_UTN_TBL(i), param->hdrc_utn_tbl[i]);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_FLR_VAL, param->hdrc_flr_val);
+	viif_capture_write(viif_dev, REG_L1_HDRC_FLR_ADP, param->hdrc_flr_adp ? 1 : 0);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_YBR_OFF, param->hdrc_ybr_off ? 1 : 0);
+	viif_capture_write(viif_dev, REG_L1_HDRC_ORGY_BLEND, param->hdrc_orgy_blend);
+
+	val = ((viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT)) % 64U) / 2U;
+	viif_capture_write(viif_dev, REG_L1_HDRC_MAR_TOP, val);
+	val = ((viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH)) % 64U) / 2U;
+	viif_capture_write(viif_dev, REG_L1_HDRC_MAR_LEFT, val);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_EN, 1);
+
+	/* update of sw_delay1 must be done when MAIN unit is NOT running. */
+	if (!viif_dev->run_flag_main) {
+		sw_delay1 = sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, &viif_dev->img_clk) +
+			    VIIF_L1_DELAY_W_HDRC + 1U;
+		val = viif_capture_read(viif_dev, REG_INT_M1_LINE) & 0xffffU;
+		val |= (sw_delay1 << 16U);
+		viif_capture_write(viif_dev, REG_INT_M1_LINE, val);
+		/* M2_LINE is the same condition as M1_LINE */
+		viif_capture_write(viif_dev, REG_INT_M2_LINE, val);
+	}
+}
+
+static void viif_l1_set_hdrc_ltm(struct viif_device *viif_dev,
+				 const struct viif_l1_hdrc_ltm_config *arg)
+{
+	int i;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAX, arg->tnp_max);
+	viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAG, arg->tnp_mag);
+
+	for (i = 0; i < LEN_L1_HDRC_TNP_FIL; i++)
+		viif_capture_write(viif_dev, REG_L1_HDRC_TNP_FIL(i), (u32)arg->tnp_fil[i]);
+}
+
+static void viif_l1_set_gamma(struct viif_device *viif_dev, const struct viif_l1_gamma_config *arg)
+{
+	const struct viif_l1_gamma *param = &arg->param;
+	int i;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* disabling L1 gamma */
+	if (!arg->enable) {
+		viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 0);
+		return;
+	}
+
+	/* enabling L1 gamma */
+	for (i = 0; i < 44; i++)
+		viif_capture_write(viif_dev, REG_L1_VPRO_GAMxP(i), param->gam_p[i]);
+	viif_capture_write(viif_dev, REG_L1_VPRO_BLKADJ, param->blkadj);
+	viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 1);
+}
+
+static void
+viif_l1_set_img_quality_adjustment(struct viif_device *viif_dev,
+				   const struct viif_l1_img_quality_adjustment_config *arg)
+{
+	u32 val;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* RGB to YUV (enabled by default, should be enabled) */
+	viif_capture_write(viif_dev, REG_L1_VPRO_YUVC_SW, 1);
+	viif_capture_write(viif_dev, REG_L1_VPRO_CB_MAT, (u32)arg->coef_cb);
+	viif_capture_write(viif_dev, REG_L1_VPRO_CR_MAT, (u32)arg->coef_cr);
+
+	/* brightness */
+	val = (u32)arg->brightness & 0xffffU;
+	if (val) {
+		viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT, val);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 0);
+	}
+
+	/* linear contrast */
+	if ((u32)arg->linear_contrast != 128U) {
+		viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_LCONT_LEV, arg->linear_contrast);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 0);
+	}
+
+	/* nonlinear contrast */
+	if (arg->enable & VIIF_L1_IQA_NONLINEAR_CONTRAST_EN_MASK) {
+		const struct viif_l1_nonlinear_contrast *nonlinear_contrast =
+			&arg->nonlinear_contrast;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_BLK_KNEE, nonlinear_contrast->blk_knee);
+		viif_capture_write(viif_dev, REG_L1_VPRO_WHT_KNEE, nonlinear_contrast->wht_knee);
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT0,
+				   nonlinear_contrast->blk_cont[0]);
+		viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT1,
+				   nonlinear_contrast->blk_cont[1]);
+		viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT2,
+				   nonlinear_contrast->blk_cont[2]);
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT0,
+				   nonlinear_contrast->wht_cont[0]);
+		viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT1,
+				   nonlinear_contrast->wht_cont[1]);
+		viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT2,
+				   nonlinear_contrast->wht_cont[2]);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 0);
+	}
+
+	/* luminance noise reduction */
+	if (arg->enable & VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK) {
+		const struct viif_l1_lum_noise_reduction *lum_noise_reduction =
+			&arg->lum_noise_reduction;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MIN,
+				   lum_noise_reduction->gain_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MAX,
+				   lum_noise_reduction->gain_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MIN, lum_noise_reduction->lim_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MAX, lum_noise_reduction->lim_max);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 0);
+	}
+
+	/* edge enhancement */
+	if (arg->enable & VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK) {
+		const struct viif_l1_edge_enhancement *edge_enhancement = &arg->edge_enhancement;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MIN, edge_enhancement->gain_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MAX, edge_enhancement->gain_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MIN, edge_enhancement->lim_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MAX, edge_enhancement->lim_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MIN,
+				   edge_enhancement->coring_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MAX,
+				   edge_enhancement->coring_max);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 0);
+	}
+
+	/* UV suppression */
+	if (arg->enable & VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK) {
+		const struct viif_l1_uv_suppression *uv_suppression = &arg->uv_suppression;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_SLV, uv_suppression->bk_slv);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_MP, uv_suppression->bk_mp);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BLACK, uv_suppression->black);
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_SLV, uv_suppression->wh_slv);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_MP, uv_suppression->wh_mp);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WHITE, uv_suppression->white);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 0);
+	}
+
+	/* coring suppression */
+	if (arg->enable & VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK) {
+		const struct viif_l1_coring_suppression *coring_suppression =
+			&arg->coring_suppression;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MIN,
+				   coring_suppression->lv_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MAX,
+				   coring_suppression->lv_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MIN,
+				   coring_suppression->gain_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MAX,
+				   coring_suppression->gain_max);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 0);
+	}
+
+	/* edge suppression */
+	if (arg->enable & VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK) {
+		const struct viif_l1_edge_suppression *edge_suppression = &arg->edge_suppression;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 1);
+		viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_GAIN, edge_suppression->gain);
+		viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_LIM, edge_suppression->lim);
+	} else {
+		viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 0);
+	}
+
+	/* color level */
+	if (arg->enable & VIIF_L1_IQA_COLOR_LEVEL_EN_MASK) {
+		const struct viif_l1_color_level *color_level = &arg->color_level;
+
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, color_level->cb_gain);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, color_level->cr_gain);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, color_level->cbr_mgain_min);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, color_level->cbp_gain_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, color_level->cbm_gain_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, color_level->crp_gain_max);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, color_level->crm_gain_max);
+	} else {
+		/* disable */
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, 1024U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, 1024U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, 1024U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, 0U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, 0U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, 0U);
+		viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, 0U);
+	}
+
+	/* color noise reduction */
+	viif_capture_write(viif_dev, REG_L1_VPRO_CNR_SW,
+			   arg->enable & VIIF_L1_IQA_COLOR_NOISE_REDUCTION_EN_MASK ? 1 : 0);
+}
+
+static inline u32 pack_weight(const u32 *vec)
+{
+	return (vec[0] << 14) | (vec[1] << 12) | (vec[2] << 10) | (vec[3] << 8) | (vec[4] << 6) |
+	       (vec[5] << 4) | (vec[6] << 2U) | (vec[7]);
+}
+
+static void viif_l1_set_avg_lum_generation(struct viif_device *viif_dev,
+					   const struct viif_l1_avg_lum_generation_config *arg)
+{
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* disabling aggregation */
+	if (!arg->enable) {
+		viif_capture_write(viif_dev, REG_L1_AEXP_ON, 0);
+		return;
+	}
+
+	/* enabling aggregation */
+	viif_capture_write(viif_dev, REG_L1_AEXP_ON, 1);
+	viif_capture_write(viif_dev, REG_L1_AEXP_START_X, arg->aexp_start_x);
+	viif_capture_write(viif_dev, REG_L1_AEXP_START_Y, arg->aexp_start_y);
+	viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_WIDTH, arg->aexp_block_width);
+	viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_HEIGHT, arg->aexp_block_height);
+
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_0, pack_weight(arg->aexp_weight[0]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_1, pack_weight(arg->aexp_weight[1]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_2, pack_weight(arg->aexp_weight[2]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[3]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[4]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_4, pack_weight(arg->aexp_weight[5]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_5, pack_weight(arg->aexp_weight[6]));
+	viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_7, pack_weight(arg->aexp_weight[7]));
+
+	viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_RATIO, arg->aexp_satur_ratio);
+	viif_capture_write(viif_dev, REG_L1_AEXP_BLACK_RATIO, arg->aexp_black_ratio);
+	viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_LEVEL, arg->aexp_satur_level);
+
+	viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY0, arg->aexp_ave4linesy[0]);
+	viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY1, arg->aexp_ave4linesy[1]);
+	viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY2, arg->aexp_ave4linesy[2]);
+	viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY3, arg->aexp_ave4linesy[3]);
+}
+
+static void undist_table_transmission(struct viif_device *viif_dev, dma_addr_t write_g,
+				      dma_addr_t read_b, dma_addr_t read_g, dma_addr_t read_r,
+				      u32 size)
+{
+	u32 val = 0U;
+
+	if (read_b) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_B),
+				   (u32)read_b);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_B), size);
+		val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_B;
+	}
+	if (read_g) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_G),
+				   (u32)read_g);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_G), size);
+		val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_G;
+	}
+	if (read_r) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_R),
+				   (u32)read_r);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_R), size);
+		val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_R;
+	}
+	if (write_g) {
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_WR_G),
+				   (u32)write_g);
+		viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_WR_G), size);
+		val |= MASK_VDM_T_ENABLE_L2_UNDIST_WR_G;
+	}
+
+	if (val)
+		viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_UNDIST);
+
+	val |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L2_UNDIST;
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static void undist_setup(struct viif_device *viif_dev, const struct viif_l2_undist *param)
+{
+	u32 val;
+	unsigned int i;
+
+	/* Undist through mode */
+	if (param->through_mode) {
+		/* Enable through mode */
+		viif_capture_write(viif_dev, REG_L2_MODE, 1);
+		return;
+	}
+
+	/* Undist operation */
+	val = (param->roi_mode[0] << 1U) | (param->roi_mode[1] << 3U);
+	viif_capture_write(viif_dev, REG_L2_MODE, val);
+	val = (u32)param->sensor_crop_ofs_h & GENMASK(13, 0);
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_H, val);
+	val = (u32)param->sensor_crop_ofs_v & GENMASK(12, 0);
+	viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_V, val);
+	viif_capture_write(viif_dev, REG_L2_NORM_SCALE, param->norm_scale);
+	viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_POLY, param->valid_r_norm2_poly);
+	viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_GRID, param->valid_r_norm2_grid);
+	viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(0),
+			   param->roi_write_area_delta[0]);
+	viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(1),
+			   param->roi_write_area_delta[1]);
+
+	for (i = 0; i < VIIF_L2_UNDIST_POLY_NUM; i++) {
+		val = (u32)param->poly_write_g_coef[i];
+		viif_capture_write(viif_dev, REG_L2_POLY10_WRITE_G_COEF(i), val);
+		val = (u32)param->poly_read_b_coef[i];
+		viif_capture_write(viif_dev, REG_L2_POLY10_READ_B_COEF(i), val);
+		val = (u32)param->poly_read_g_coef[i];
+		viif_capture_write(viif_dev, REG_L2_POLY10_READ_G_COEF(i), val);
+		val = (u32)param->poly_read_r_coef[i];
+		viif_capture_write(viif_dev, REG_L2_POLY10_READ_R_COEF(i), val);
+	}
+	viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_H, param->grid_node_num_h);
+	viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_V, param->grid_node_num_v);
+	viif_capture_write(viif_dev, REG_L2_GRID_PATCH_HSIZE_INV, param->grid_patch_hsize_inv);
+	viif_capture_write(viif_dev, REG_L2_GRID_PATCH_VSIZE_INV, param->grid_patch_vsize_inv);
+}
+
+static void viif_l2_set_undist(struct viif_device *viif_dev,
+			       const struct viif_l2_undist_config *arg)
+{
+	dma_addr_t table_write_g = 0;
+	dma_addr_t table_read_b = 0;
+	dma_addr_t table_read_g = 0;
+	dma_addr_t table_read_r = 0;
+
+	if (arg->param.roi_mode[0] != VIIF_L2_UNDIST_POLY ||
+	    arg->param.roi_mode[1] != VIIF_L2_UNDIST_POLY) {
+		memcpy(viif_dev->tables->undist_write_g, arg->write_g, arg->size);
+		memcpy(viif_dev->tables->undist_read_b, arg->read_b, arg->size);
+		memcpy(viif_dev->tables->undist_read_g, arg->read_g, arg->size);
+		memcpy(viif_dev->tables->undist_read_r, arg->read_r, arg->size);
+
+		table_write_g =
+			viif_dev->tables_dma + offsetof(struct viif_table_area, undist_write_g);
+		table_read_b =
+			viif_dev->tables_dma + offsetof(struct viif_table_area, undist_read_b);
+		table_read_g =
+			viif_dev->tables_dma + offsetof(struct viif_table_area, undist_read_g);
+		table_read_r =
+			viif_dev->tables_dma + offsetof(struct viif_table_area, undist_read_r);
+	}
+	{
+		guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+
+		undist_table_transmission(viif_dev, table_write_g, table_read_b, table_read_g,
+					  table_read_r, arg->size);
+		undist_setup(viif_dev, &arg->param);
+	}
+}
+
+void visconti_viif_l2_undist_through(struct viif_device *viif_dev)
+{
+	struct viif_l2_undist undist = { 0 };
+
+	undist.through_mode = VIIF_ENABLE;
+	undist.sensor_crop_ofs_h =
+		1 - FIELD_GET(0x1fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE));
+	undist.sensor_crop_ofs_v =
+		1 - FIELD_GET(0x0fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE));
+	undist.grid_node_num_h = 16;
+	undist.grid_node_num_v = 16;
+
+	undist_setup(viif_dev, &undist);
+}
+
+void visconti_viif_l2_undist_identity(struct viif_device *viif_dev)
+{
+	struct viif_l2_undist undist = {
+		.through_mode = 0,
+		.roi_mode = { 0, 0 },
+		.sensor_crop_ofs_h = 0,
+		.sensor_crop_ofs_v = 0,
+		.norm_scale = 30464,
+		.valid_r_norm2_poly = 33554432,
+		.valid_r_norm2_grid = 0,
+		.roi_write_area_delta = { 100, 100 },
+		.poly_write_g_coef = { 131072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+		.poly_read_b_coef = { 131072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+		.poly_read_g_coef = { 131072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+		.poly_read_r_coef = { 131072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+		.grid_node_num_h = 16,
+		.grid_node_num_v = 16,
+		.grid_patch_hsize_inv = 0,
+		.grid_patch_vsize_inv = 0,
+	};
+	undist.sensor_crop_ofs_h =
+		1 - FIELD_GET(0x1fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE));
+	undist.sensor_crop_ofs_v =
+		1 - FIELD_GET(0x0fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE));
+
+	undist_setup(viif_dev, &undist);
+}
+
+static void viif_l2_set_roi(struct viif_device *viif_dev, const struct viif_l2_roi_config *roi)
+{
+	u32 val;
+	int i;
+
+	/* update ROI parameter */
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* Set the number of ROI and update resource info with roi_num */
+	viif_capture_write(viif_dev, REG_L2_ROI_NUM, roi->roi_num);
+	viif_dev->l2_roi_path_info.roi_num = roi->roi_num;
+
+	/* Update ROI area and input to each POST */
+	visconti_viif_l2_set_roi_path(viif_dev);
+
+	/* Set the remaining parameters */
+	for (i = 0; i < 2; i++) {
+		viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE(i), roi->roi_scale[i]);
+		viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE_INV(i), roi->roi_scale_inv[i]);
+		val = (roi->corrected_wo_scale_hsize[i] << 13U) | roi->corrected_hsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_HSIZE(i), val);
+		val = (roi->corrected_wo_scale_vsize[i] << 12U) | roi->corrected_vsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_VSIZE(i), val);
+	}
+}
+
+static void viif_l2_set_roi1(struct viif_device *viif_dev, const struct viif_l2_roi_config *roi)
+{
+	u32 val;
+
+	/* update ROI parameter */
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* Check if ROI1 is already set */
+	if (viif_dev->l2_roi_path_info.roi_num != 1)
+		return;
+	viif_capture_write(viif_dev, REG_L2_ROI_NUM, roi->roi_num);
+	viif_dev->l2_roi_path_info.roi_num = roi->roi_num;
+
+	/* Update ROI area and input to each POST */
+	visconti_viif_l2_set_roi_path(viif_dev);
+
+	/* Set the remaining parameters */
+	viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE(1), roi->roi_scale[1]);
+	viif_capture_write(viif_dev, REG_L2_ROI_X_SCALE_INV(1), roi->roi_scale_inv[1]);
+	val = (roi->corrected_wo_scale_hsize[1] << 13U) | roi->corrected_hsize[1];
+	viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_HSIZE(1), val);
+	val = (roi->corrected_wo_scale_vsize[1] << 12U) | roi->corrected_vsize[1];
+	viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_VSIZE(1), val);
+}
+
+static void generate_scaler_parameter(struct viif_device *viif_dev, struct viif_l2_roi_config *roi,
+				      unsigned int width, unsigned int height)
+{
+	u32 src_width, src_height;
+	u32 scale_ratio, scale_ratio_inv;
+
+	src_width = FIELD_GET(0x1fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE));
+	src_height = FIELD_GET(0x0fff, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE));
+
+	if (width * src_height < height * src_width) {
+		/* scale_ratioX < scale_ratioY: use scale_ratioX */
+		scale_ratio = clamp(65536 * width / src_width, 32768, 131072);
+		scale_ratio_inv = clamp(65536 * src_width / width, 32768, 131072);
+	} else {
+		scale_ratio = clamp(65536 * height / src_height, 32768, 131072);
+		scale_ratio_inv = clamp(65536 * src_height / height, 32768, 131072);
+	}
+
+	struct viif_l2_roi_config roi_scaler = {
+		.roi_num = 0,
+		.roi_scale = { scale_ratio, scale_ratio },
+		.roi_scale_inv = { scale_ratio_inv, scale_ratio_inv },
+		.corrected_wo_scale_hsize = { src_width, src_width },
+		.corrected_wo_scale_vsize = { src_height, src_height },
+		.corrected_hsize = { width, width },
+		.corrected_vsize = { height, height },
+	};
+
+	*roi = roi_scaler;
+}
+
+void visconti_viif_l2_scale_default_roi0(struct viif_device *viif_dev, unsigned int width,
+					 unsigned int height)
+{
+	struct viif_l2_roi_config roi;
+
+	generate_scaler_parameter(viif_dev, &roi, width, height);
+	roi.roi_num = 1;
+	viif_l2_set_roi(viif_dev, &roi);
+}
+
+void visconti_viif_l2_scale_default_roi1(struct viif_device *viif_dev, unsigned int width,
+					 unsigned int height)
+{
+	struct viif_l2_roi_config roi;
+
+	generate_scaler_parameter(viif_dev, &roi, width, height);
+	roi.roi_num = 2;
+	viif_l2_set_roi1(viif_dev, &roi);
+}
+
+struct viif_l2_gamma_table {
+	dma_addr_t table[VIIF_L2_GAMMA_TABLE_CH_NUM];
+};
+
+static void l2_gamma_table_transmission(struct viif_device *viif_dev, u32 post_id,
+					const struct viif_l2_gamma_table *gamma_table)
+{
+	u32 vdm_enable = 0U;
+	u32 i;
+
+	/* 0: LUT0-G/Y, 1: LUT1-G/Y, 2: LUT0-B/U, 3: LUT1-B/U, 4: LUT0-R/V, 5: LUT1-R/V */
+	for (i = 0; i < VIIF_L2_GAMMA_TABLE_CH_NUM; i++) {
+		if (gamma_table->table[i]) {
+			int idx = IDX_TPORT_L2_GAMMA_LUT(post_id, i);
+
+			viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(idx),
+					   (u32)gamma_table->table[i]);
+			viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(idx),
+					   VIIF_L2_GAMMA_TABLE_BYTES);
+			vdm_enable |= MASK_VDM_T_ENABLE_L2_GAMMA(post_id, i);
+		}
+	}
+	if (vdm_enable)
+		viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_GAMMA_LUT(post_id));
+
+	vdm_enable |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) &
+		      ~MASK_VDM_T_ENABLE_L2_GAMMA_ALL(post_id);
+
+	viif_capture_write(viif_dev, REG_VDM_T_ENABLE, vdm_enable);
+}
+
+static void viif_l2_set_gamma(struct viif_device *viif_dev, int pathid,
+			      const struct viif_l2_gamma_config *l2_gamma)
+{
+	struct viif_l2_gamma_table dma_table = { 0 };
+	int postid = (pathid == CAPTURE_PATH_MAIN_POST0) ? VIIF_L2ISP_POST_0 : VIIF_L2ISP_POST_1;
+	int table_en;
+	u32 val;
+	int i;
+
+	table_en = l2_gamma->table_en;
+	for (i = 0; i < 6; i++) {
+		if (table_en & BIT(i)) {
+			memcpy(viif_dev->tables->l2_gamma_table[pathid][i], l2_gamma->table[i],
+			       VIIF_L2_GAMMA_TABLE_BYTES);
+			dma_table.table[i] =
+				viif_dev->tables_dma +
+				offsetof(struct viif_table_area, l2_gamma_table[pathid][i]);
+		}
+	}
+	{
+		guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+
+		l2_gamma_table_transmission(viif_dev, postid, &dma_table);
+
+		val = (l2_gamma->vsplit << 16U) | (l2_gamma->mode << 4U) | (table_en != 0 ? 1 : 0);
+		viif_capture_write(viif_dev, REG_L2_POST_X_GAMMA_M(postid), val);
+	}
+}
+
+static const struct viif_l1_input_mode_config defval_l1_set_input_mode = {
+	.mode = VIIF_L1_INPUT_HDR,
+};
+
+static const struct viif_l1_rgb_to_y_coef_config defval_l1_set_rgb_to_y_coef = {
+	/* ITU-R BT.601 */
+	.coef_r = 0x4c8c,
+	.coef_g = 0x9644,
+	.coef_b = 0x1d30,
+};
+
+static const struct viif_l1_ag_mode_config defval_l1_set_ag_mode = { 0 };
+
+static const struct viif_l1_ag_config defval_l1_set_ag = { 0 };
+
+static const struct viif_l1_hdre_config defval_l1_set_hdre = {
+	.hdre_src_point[0] = 0x3fff,
+	.hdre_dst_max_val = 0xffffff,
+};
+
+static const struct viif_l1_img_extraction_config defval_l1_set_img_extraction = {
+	.input_black_gr = 256,
+	.input_black_r = 256,
+	.input_black_b = 256,
+	.input_black_gb = 256,
+};
+
+static const struct viif_l1_dpc_config defval_l1_set_dpc = { 0 };
+
+static const struct viif_l1_preset_white_balance_config defval_l1_set_preset_white_balance = {
+	.dstmaxval = 0x0fff,
+	.param_h = {
+		.gain_gr = 0x4000,
+		.gain_r  = 0x4000,
+		.gain_b  = 0x4000,
+		.gain_gb = 0x4000,
+	},
+	.param_m = {
+		.gain_gr = 0x4000,
+		.gain_r  = 0x4000,
+		.gain_b  = 0x4000,
+		.gain_gb = 0x4000,
+	},
+	.param_l = {
+		.gain_gr = 0x4000,
+		.gain_r  = 0x4000,
+		.gain_b  = 0x4000,
+		.gain_gb = 0x4000,
+	},
+};
+
+static const
+struct viif_l1_raw_color_noise_reduction_config defval_l1_set_raw_color_noise_reduction = {
+	.param_h = {
+		.rcnr_cnf_clip_gain_r = 3,
+		.rcnr_cnf_clip_gain_g = 2,
+		.rcnr_cnf_clip_gain_b = 3,
+		.rcnr_merge_black = 0x20,
+		.rcnr_merge_mindiv = 4,
+		.rcnr_anf_blend_ag0 = 1,
+		.rcnr_anf_blend_ag1 = 2,
+		.rcnr_anf_blend_ag2 = 2,
+		.rcnr_lpf_threshold = 8,
+	},
+	.param_m = {
+		.rcnr_cnf_clip_gain_r = 3,
+		.rcnr_cnf_clip_gain_g = 2,
+		.rcnr_cnf_clip_gain_b = 3,
+		.rcnr_merge_black = 0x20,
+		.rcnr_merge_mindiv = 4,
+		.rcnr_anf_blend_ag0 = 1,
+		.rcnr_anf_blend_ag1 = 2,
+		.rcnr_anf_blend_ag2 = 2,
+		.rcnr_lpf_threshold = 8,
+	},
+	.param_l = {
+		.rcnr_cnf_clip_gain_r = 3,
+		.rcnr_cnf_clip_gain_g = 2,
+		.rcnr_cnf_clip_gain_b = 3,
+		.rcnr_merge_black = 0x20,
+		.rcnr_merge_mindiv = 4,
+		.rcnr_anf_blend_ag0 = 1,
+		.rcnr_anf_blend_ag1 = 2,
+		.rcnr_anf_blend_ag2 = 2,
+		.rcnr_lpf_threshold = 8,
+	},
+};
+
+static const struct viif_l1_hdrs_config defval_l1_set_hdrs = {
+	.hdrs_hdr_mode = 1,
+	.hdrs_hdr_ratio_m = 0x10000,
+	.hdrs_hdr_ratio_l = 0x400000,
+	.hdrs_hdr_ratio_e = 0x400,
+	.hdrs_dg_h = 0x400,
+	.hdrs_dg_m = 0x400,
+	.hdrs_dg_l = 0x400,
+	.hdrs_dg_e = 0x400,
+	.hdrs_blendend_h = 0xfa0,
+	.hdrs_blendend_m = 0xfa0,
+	.hdrs_blendend_e = 0xfa0,
+	.hdrs_blendbeg_h = 0x12c,
+	.hdrs_blendbeg_m = 0x12c,
+	.hdrs_blendbeg_e = 0x12c,
+	.hdrs_dst_max_val = 0xffffff,
+};
+
+static const struct viif_l1_black_level_correction_config defval_l1_set_black_level_correction = {
+	.srcblacklevel_gr = 0x40,
+	.srcblacklevel_r = 0x40,
+	.srcblacklevel_b = 0x40,
+	.srcblacklevel_gb = 0x40,
+	.mulval_gr = 0x40000,
+	.mulval_r = 0x40000,
+	.mulval_b = 0x40000,
+	.mulval_gb = 0x40000,
+	.dstmaxval = 0xffffff,
+};
+
+static const struct viif_l1_lsc_config defval_l1_set_lsc = { 0 };
+
+static const struct viif_l1_main_process_config defval_l1_set_main_process = {
+	.damp_lsbsel = 0x8,
+	.demosaic_mode = 1,
+	.colormat_enable = 0,
+	.dst_maxval = 0xffffff,
+};
+
+static const struct viif_l1_awb_config defval_l1_set_awb = {
+	.enable = 0,
+	.awhb_wbmrg = 256,
+	.awhb_wbmgg = 256,
+	.awhb_wbmbg = 256,
+};
+
+static const u32 defval_l1_lock_awb_gain;
+
+static const struct viif_l1_hdrc_config defval_l1_set_hdrc = {
+	.enable = 1,
+	.param = {
+		.hdrc_ratio = 0x0e + VIIF_L1_HDRC_RATIO_OFFSET,
+		.hdrc_pt_ratio = 7,
+		.hdrc_pt_sat = 0xffc0,
+		.hdrc_tn_type = 1,
+	},
+};
+
+static const struct viif_l1_hdrc_ltm_config defval_l1_set_hdrc_ltm = {
+	.tnp_max = 0x3fffff,
+	.tnp_mag = 0x40,
+	.tnp_fil = { 0x88, 0x84, 0x7a, 0x6a, 0x54 },
+};
+
+static const struct viif_l1_gamma_config defval_l1_set_gamma = {
+	.enable = 1,
+	.param = {
+		.gam_p = {
+			0x02f, 0x01b, 0x02a, 0x023, 0x020, 0x037, 0x031, 0x057, 0x04d, 0x088,
+			0x078, 0x0d6, 0x0bd, 0x14f, 0x12a, 0x20d, 0x1d3, 0x1ab, 0x18d, 0x2dc,
+			0x29e, 0x271, 0x47c, 0x41b, 0x3d4, 0x70a, 0x672, 0x601, 0xb0c, 0xa1d,
+			0x96c, 0x8e2, 0x874, 0xfdd, 0xec9, 0xdf2, 0xd42, 0xcb1, 0xc35, 0xbc9,
+			0xb6a, 0xb16, 0xacb, 0xa86},
+		.blkadj = 0x1000,
+	},
+};
+
+static const struct viif_l1_img_quality_adjustment_config defval_l1_set_img_quality_adjustment = {
+	.enable = 0,
+	.coef_cb = 0x9078,
+	.coef_cr = 0xb699,
+	.brightness = 0,
+	.linear_contrast = 128,
+};
+
+static const struct viif_l1_avg_lum_generation_config defval_l1_set_avg_lum_generation = {
+	.enable = 0
+};
+
+static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
+
+static void viif_apply_default_parameter(struct viif_device *viif_dev)
+{
+	viif_l1_set_input_mode(viif_dev, &defval_l1_set_input_mode);
+	viif_l1_set_rgb_to_y_coef(viif_dev, &defval_l1_set_rgb_to_y_coef);
+	viif_l1_set_ag_mode(viif_dev, &defval_l1_set_ag_mode);
+	viif_l1_set_ag(viif_dev, &defval_l1_set_ag);
+	viif_l1_set_hdre(viif_dev, &defval_l1_set_hdre);
+	viif_l1_set_img_extraction(viif_dev, &defval_l1_set_img_extraction);
+	viif_l1_set_dpc(viif_dev, &defval_l1_set_dpc);
+	viif_l1_set_preset_white_balance(viif_dev, &defval_l1_set_preset_white_balance);
+	viif_l1_set_raw_color_noise_reduction(viif_dev, &defval_l1_set_raw_color_noise_reduction);
+	viif_l1_set_hdrs(viif_dev, &defval_l1_set_hdrs);
+	viif_l1_set_black_level_correction(viif_dev, &defval_l1_set_black_level_correction);
+	viif_l1_set_lsc(viif_dev, &defval_l1_set_lsc);
+	viif_l1_set_main_process(viif_dev, &defval_l1_set_main_process);
+	viif_l1_set_awb(viif_dev, &defval_l1_set_awb);
+	viif_l1_lock_awb_gain(viif_dev, &defval_l1_lock_awb_gain);
+	viif_l1_set_hdrc(viif_dev, &defval_l1_set_hdrc);
+	viif_l1_set_hdrc_ltm(viif_dev, &defval_l1_set_hdrc_ltm);
+	viif_l1_set_gamma(viif_dev, &defval_l1_set_gamma);
+	viif_l1_set_img_quality_adjustment(viif_dev, &defval_l1_set_img_quality_adjustment);
+	viif_l1_set_avg_lum_generation(viif_dev, &defval_l1_set_avg_lum_generation);
+	/* l2_undist is already set with visconti_viif_l2_undist_identity() */
+	/* l2_roi is already set with visconti_viif_l2_scale_default_roiX() */
+	viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &defval_l2_set_gamma);
+	viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &defval_l2_set_gamma);
+}
+
+/*=======================================================================*/
+/* parameter buffer streaming interface */
+/*=======================================================================*/
+struct viif_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+};
+
+static bool viif_params_get_buffer(struct params_dev *params_dev, struct viif_buffer **buf,
+				   struct visconti_viif_isp_config **cfg)
+{
+	if (list_empty(&params_dev->params_queue))
+		return false;
+
+	*buf = list_first_entry(&params_dev->params_queue, struct viif_buffer, queue);
+	*cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
+
+	return true;
+}
+
+static int viif_apply_queued_parameter(struct viif_device *viif_dev, bool initial_cfg)
+{
+	struct params_dev *params_dev = &viif_dev->params_dev;
+	struct visconti_viif_isp_config *new_params;
+	struct viif_buffer *cur_buf;
+
+	guard(spinlock)(&params_dev->params_lock);
+
+	if (!viif_params_get_buffer(params_dev, &cur_buf, &new_params))
+		return 1;
+
+	/* evaluate new_params */
+	if (initial_cfg) {
+		if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_INPUT_MODE)
+			viif_l1_set_input_mode(viif_dev, &new_params->l1_input_mode);
+	}
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RGB_TO_Y_COEF)
+		viif_l1_set_rgb_to_y_coef(viif_dev, &new_params->l1_rgb_to_y_coef);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG_MODE)
+		viif_l1_set_ag_mode(viif_dev, &new_params->l1_ag_mode);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG)
+		viif_l1_set_ag(viif_dev, &new_params->l1_ag);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRE)
+		viif_l1_set_hdre(viif_dev, &new_params->l1_hdre);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_EXTRACTION)
+		viif_l1_set_img_extraction(viif_dev, &new_params->l1_img_extraction);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_DPC)
+		viif_l1_set_dpc(viif_dev, &new_params->l1_dpc);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_PRESET_WHITE_BALANCE)
+		viif_l1_set_preset_white_balance(viif_dev, &new_params->l1_preset_white_balance);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RAW_COLOR_NOISE_REDUCTION)
+		viif_l1_set_raw_color_noise_reduction(viif_dev,
+						      &new_params->l1_raw_color_noise_reduction);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRS)
+		viif_l1_set_hdrs(viif_dev, &new_params->l1_hdrs);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_BLACK_LEVEL_CORRECTION)
+		viif_l1_set_black_level_correction(viif_dev,
+						   &new_params->l1_black_level_correction);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LSC)
+		viif_l1_set_lsc(viif_dev, &new_params->l1_lsc);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_MAIN_PROCESS)
+		viif_l1_set_main_process(viif_dev, &new_params->l1_main_process);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AWB)
+		viif_l1_set_awb(viif_dev, &new_params->l1_awb);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LOCK_AWB_GAIN)
+		viif_l1_lock_awb_gain(viif_dev, &new_params->lock_awb_gain);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC)
+		viif_l1_set_hdrc(viif_dev, &new_params->l1_hdrc);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC_LTM)
+		viif_l1_set_hdrc_ltm(viif_dev, &new_params->l1_hdrc_ltm);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_GAMMA)
+		viif_l1_set_gamma(viif_dev, &new_params->l1_gamma);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_QUALITY_ADJUSTMENT)
+		viif_l1_set_img_quality_adjustment(viif_dev,
+						   &new_params->l1_img_quality_adjustment);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AVG_LUM_GENERATION)
+		viif_l1_set_avg_lum_generation(viif_dev, &new_params->l1_avg_lum_generation);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_UNDIST)
+		viif_l2_set_undist(viif_dev, &new_params->l2_undist);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_ROI)
+		viif_l2_set_roi(viif_dev, &new_params->l2_roi);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST0)
+		viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &new_params->l2_gamma_post0);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST1)
+		viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &new_params->l2_gamma_post1);
+
+	/* release buffer */
+	list_del(&cur_buf->queue);
+	cur_buf->vb.sequence = 0;
+	vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+	return 0;
+}
+
+void visconti_viif_params_isr(struct viif_device *viif_dev)
+{
+	viif_apply_queued_parameter(viif_dev, false);
+}
+
+void visconti_viif_params_eval_queue(struct viif_device *viif_dev)
+{
+	if (viif_apply_queued_parameter(viif_dev, true))
+		viif_apply_default_parameter(viif_dev);
+}
+
+static int viif_params_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (f->index > 0 || f->type != vdev->queue->type)
+		return -EINVAL;
+
+	f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
+
+	return 0;
+}
+
+static int viif_params_g_fmt_meta_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_meta_format *meta = &f->fmt.meta;
+
+	if (f->type != vdev->queue->type)
+		return -EINVAL;
+
+	memset(meta, 0, sizeof(*meta));
+	meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
+	meta->buffersize = sizeof(struct visconti_viif_isp_config);
+
+	return 0;
+}
+
+static int viif_params_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+	strscpy(cap->card, vdev->name, sizeof(cap->card));
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_params_ioctl = {
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_enum_fmt_meta_out = viif_params_enum_fmt_meta_out,
+	.vidioc_g_fmt_meta_out = viif_params_g_fmt_meta_out,
+	.vidioc_s_fmt_meta_out = viif_params_g_fmt_meta_out,
+	.vidioc_try_fmt_meta_out = viif_params_g_fmt_meta_out,
+	.vidioc_querycap = viif_params_querycap,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations viif_params_fops = {
+	.mmap = vb2_fop_mmap,
+	.unlocked_ioctl = video_ioctl2,
+	.poll = vb2_fop_poll,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+};
+
+static int viif_params_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+				       unsigned int *num_planes, unsigned int sizes[],
+				       struct device *alloc_devs[])
+{
+	*num_buffers = clamp_t(u32, *num_buffers, 2, 8);
+	*num_planes = 1;
+	sizes[0] = sizeof(struct visconti_viif_isp_config);
+	return 0;
+}
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+	return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct params_dev *vb2queue_to_paramsdev(struct vb2_queue *vq)
+{
+	return (struct params_dev *)vb2_get_drv_priv(vq);
+}
+
+static void viif_params_vb2_buf_queue(struct vb2_buffer *vb)
+{
+	struct params_dev *params_dev = vb2queue_to_paramsdev(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct viif_buffer *buf = vb2_to_viif(vbuf);
+
+	guard(spinlock_irq)(&params_dev->params_lock);
+	list_add_tail(&buf->queue, &params_dev->params_queue);
+}
+
+static int viif_params_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+	if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_config))
+		return -EINVAL;
+
+	vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_config));
+	return 0;
+}
+
+static int viif_params_vb2_start_streaming(struct vb2_queue *q, unsigned int arg)
+{
+	return 0;
+}
+
+static void viif_params_vb2_stop_streaming(struct vb2_queue *q)
+{
+	struct params_dev *params_dev = vb2queue_to_paramsdev(q);
+	struct viif_buffer *buf;
+	LIST_HEAD(tmp_list);
+
+	{
+		guard(spinlock_irq)(&params_dev->params_lock);
+		list_splice_init(&params_dev->params_queue, &tmp_list);
+	}
+
+	list_for_each_entry(buf, &tmp_list, queue)
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops viif_params_vb2_ops = {
+	.queue_setup = viif_params_vb2_queue_setup,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.buf_queue = viif_params_vb2_buf_queue,
+	.buf_prepare = viif_params_vb2_buf_prepare,
+	.start_streaming = viif_params_vb2_start_streaming,
+	.stop_streaming = viif_params_vb2_stop_streaming,
+};
+
+int visconti_viif_params_register(struct viif_device *viif_dev)
+{
+	struct params_dev *params_dev = &viif_dev->params_dev;
+	struct video_device *vdev = &params_dev->vdev;
+	struct vb2_queue *q = &params_dev->vb2_vq;
+	int ret;
+
+	mutex_init(&params_dev->vlock);
+	INIT_LIST_HEAD(&params_dev->params_queue);
+	spin_lock_init(&params_dev->params_lock);
+
+	strscpy(vdev->name, "viif_params", sizeof(vdev->name));
+
+	/* Register the video device */
+	video_set_drvdata(vdev, params_dev);
+	vdev->ioctl_ops = &viif_params_ioctl;
+	vdev->fops = &viif_params_fops;
+	vdev->release = video_device_release_empty;
+	vdev->lock = &params_dev->vlock;
+	vdev->v4l2_dev = &viif_dev->v4l2_dev;
+	vdev->queue = &params_dev->vb2_vq;
+	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT;
+	vdev->vfl_dir = VFL_DIR_TX;
+
+	/* Initialize vb2 queue */
+	q->type = V4L2_BUF_TYPE_META_OUTPUT;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->drv_priv = params_dev;
+	q->ops = &viif_params_vb2_ops;
+	q->mem_ops = &vb2_vmalloc_memops;
+	q->buf_struct_size = sizeof(struct viif_buffer);
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &params_dev->vlock;
+	q->dev = viif_dev->v4l2_dev.dev;
+
+	ret = vb2_queue_init(q);
+	if (ret)
+		return ret;
+
+	params_dev->params_pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&vdev->entity, VIIF_PARAMS_PAD_NUM, &params_dev->params_pad);
+	if (ret)
+		goto error;
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	media_entity_cleanup(&vdev->entity);
+	mutex_destroy(&params_dev->vlock);
+
+	return ret;
+}
+
+void visconti_viif_params_unregister(struct viif_device *viif_dev)
+{
+	struct params_dev *params = &viif_dev->params_dev;
+	struct video_device *vdev = &params->vdev;
+
+	if (!video_is_registered(vdev))
+		return;
+
+	vb2_video_unregister_device(vdev);
+	media_entity_cleanup(&vdev->entity);
+	mutex_destroy(&params->vlock);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_params.h b/drivers/media/platform/toshiba/visconti/viif_params.h
new file mode 100644
index 000000000000..1110400c19c9
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_PARAMS_H__
+#define __VIIF_PARAMS_H__
+
+struct viif_device;
+
+void visconti_viif_params_eval_queue(struct viif_device *viif_dev);
+void visconti_viif_params_isr(struct viif_device *viif_dev);
+int visconti_viif_params_register(struct viif_device *viif_dev);
+void visconti_viif_params_unregister(struct viif_device *viif_dev);
+
+void visconti_viif_l2_undist_through(struct viif_device *viif_dev);
+void visconti_viif_l2_undist_identity(struct viif_device *viif_dev);
+void visconti_viif_l2_scale_default_roi0(struct viif_device *viif_dev, unsigned int width,
+					 unsigned int height);
+void visconti_viif_l2_scale_default_roi1(struct viif_device *viif_dev, unsigned int width,
+					 unsigned int height);
+#endif /* __VIIF_PARAMS_H__ */
diff --git a/drivers/media/platform/toshiba/visconti/viif_resizer.c b/drivers/media/platform/toshiba/visconti/viif_resizer.c
index ec056ff3adc4..d81e8574a50c 100644
--- a/drivers/media/platform/toshiba/visconti/viif_resizer.c
+++ b/drivers/media/platform/toshiba/visconti/viif_resizer.c
@@ -13,6 +13,7 @@
 
 #include "viif.h"
 #include "viif_common.h"
+#include "viif_params.h"
 #include "viif_resizer.h"
 #include "viif_regs.h"
 
@@ -118,12 +119,41 @@ void visconti_viif_l2_set_roi_path(struct viif_device *viif_dev)
 		viif_l2_set_roi_num_2(viif_dev);
 }
 
+static struct resizer_subdev *subdev_to_resizer(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct resizer_subdev, sd);
+}
+
 static int visconti_viif_resizer_enable_streams(struct v4l2_subdev *sd,
 						struct v4l2_subdev_state *state, u32 pad,
 						u64 streams_mask)
 {
+	struct resizer_subdev *resizer = subdev_to_resizer(sd);
+	struct viif_device *viif_dev = resizer->viif_dev;
+	struct v4l2_rect *sink_compose;
 	struct v4l2_subdev *remote_sd;
 	struct media_pad *remote_pad;
+	int i;
+
+	if (resizer->pathid == RESIZER_PATH_MAIN_POST0) {
+		/* setup default undist/resize settings */
+		viif_dev->l2_roi_path_info.roi_num = 0;
+		for (i = 0; i < VIIF_MAX_POST_NUM; i++) {
+			viif_dev->l2_roi_path_info.post_enable_flag[i] = false;
+			viif_dev->l2_roi_path_info.post_crop_x[i] = 0;
+			viif_dev->l2_roi_path_info.post_crop_y[i] = 0;
+			viif_dev->l2_roi_path_info.post_crop_w[i] = 0;
+			viif_dev->l2_roi_path_info.post_crop_h[i] = 0;
+		}
+		visconti_viif_l2_undist_identity(viif_dev);
+		sink_compose = v4l2_subdev_state_get_compose(state, VIIF_RESIZER_PAD_SINK);
+		visconti_viif_l2_scale_default_roi0(viif_dev, sink_compose->width,
+						    sink_compose->height);
+	} else {
+		sink_compose = v4l2_subdev_state_get_compose(state, VIIF_RESIZER_PAD_SINK);
+		visconti_viif_l2_scale_default_roi1(viif_dev, sink_compose->width,
+						    sink_compose->height);
+	}
 
 	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VIIF_RESIZER_PAD_SINK]);
 	if (!remote_pad)
diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.c b/drivers/media/platform/toshiba/visconti/viif_stats.c
new file mode 100644
index 000000000000..14ced29070e9
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "viif.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_regs.h"
+#include "viif_stats.h"
+
+struct viif_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+};
+
+static void read_isp_capture_regs(struct viif_l1_info *l1_info, struct viif_device *viif_dev)
+{
+	int i, j;
+	u32 val;
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(viif_dev);
+
+	/* change register buffer to regbuf0 where driver gets information */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0);
+
+	/* get AWB info */
+	l1_info->awb_ave_u = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_USIG);
+	l1_info->awb_ave_v = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_VSIG);
+	l1_info->awb_accumulated_pixel = viif_capture_read(viif_dev, REG_L1_AWHB_NUM_UVON);
+	l1_info->awb_gain_r = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINR);
+	l1_info->awb_gain_g = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAING);
+	l1_info->awb_gain_b = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINB);
+	val = viif_capture_read(viif_dev, REG_L1_AWHB_R_CTR_STOP);
+	l1_info->awb_status_u = (FIELD_GET(BIT(1), val) != 0);
+	l1_info->awb_status_v = (FIELD_GET(BIT(0), val) != 0);
+
+	/* get average luminance info */
+	l1_info->avg_lum_weight = viif_capture_read(viif_dev, REG_L1_AEXP_RESULT_AVE);
+	val = viif_capture_read(viif_dev, REG_L1_AEXP_SATUR_BLACK_PIXNUM);
+	l1_info->avg_satur_pixnum = FIELD_GET(GENMASK(31, 16), val);
+	l1_info->avg_black_pixnum = FIELD_GET(GENMASK(15, 0), val);
+	for (i = 0; i < 8; i++) {
+		for (j = 0; j < 8; j++) {
+			l1_info->avg_lum_block[i][j] =
+				viif_capture_read(viif_dev, REG_L1_AEXP_AVE(i, j));
+		}
+	}
+	l1_info->avg_lum_four_line_lum[0] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES0);
+	l1_info->avg_lum_four_line_lum[1] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES1);
+	l1_info->avg_lum_four_line_lum[2] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES2);
+	l1_info->avg_lum_four_line_lum[3] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES3);
+
+	/* revert to register access from register buffer access */
+	viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS);
+}
+
+void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp)
+{
+	struct visconti_viif_isp_stat *cur_stat_buf;
+	struct stats_dev *stats_dev = &viif_dev->stats_dev;
+	struct viif_buffer *cur_buf;
+
+	guard(spinlock)(&stats_dev->stats_lock);
+
+	if (list_empty(&stats_dev->stats_queue))
+		return;
+
+	cur_buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
+	list_del(&cur_buf->queue);
+	cur_stat_buf = (struct visconti_viif_isp_stat *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
+
+	read_isp_capture_regs(&cur_stat_buf->isp_capture.l1_info, viif_dev);
+
+	{
+		guard(spinlock)(&viif_dev->repflag_lock);
+
+		cur_stat_buf->errors.main = viif_dev->reported_err_main;
+		cur_stat_buf->errors.sub = viif_dev->reported_err_sub;
+		viif_dev->reported_err_main = 0;
+		viif_dev->reported_err_sub = 0;
+	}
+
+	vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, sizeof(struct visconti_viif_isp_stat));
+
+	cur_buf->vb.sequence = sequence;
+	cur_buf->vb.vb2_buf.timestamp = timestamp;
+	vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+static int viif_stats_enum_fmt_meta_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (f->index > 0 || f->type != vdev->queue->type)
+		return -EINVAL;
+
+	f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
+
+	return 0;
+}
+
+static int viif_stats_g_fmt_meta_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_meta_format *meta = &f->fmt.meta;
+
+	if (f->type != vdev->queue->type)
+		return -EINVAL;
+
+	memset(meta, 0, sizeof(*meta));
+	meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
+	meta->buffersize = sizeof(struct visconti_viif_isp_stat);
+
+	return 0;
+}
+
+static int viif_stats_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+	strscpy(cap->card, vdev->name, sizeof(cap->card));
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_stats_ioctl = {
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_enum_fmt_meta_cap = viif_stats_enum_fmt_meta_cap,
+	.vidioc_g_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+	.vidioc_s_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+	.vidioc_try_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+	.vidioc_querycap = viif_stats_querycap,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations viif_stats_fops = {
+	.mmap = vb2_fop_mmap,
+	.unlocked_ioctl = video_ioctl2,
+	.poll = vb2_fop_poll,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+};
+
+static int viif_stats_vb2_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+				      unsigned int *num_planes, unsigned int sizes[],
+				      struct device *alloc_devs[])
+{
+	*num_planes = 1;
+	*num_buffers = clamp_t(u32, *num_buffers, 2, 8);
+	sizes[0] = sizeof(struct visconti_viif_isp_stat);
+
+	return 0;
+}
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+	return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct stats_dev *vb2queue_to_statsdev(struct vb2_queue *q)
+{
+	return (struct stats_dev *)vb2_get_drv_priv(q);
+}
+
+static void viif_stats_vb2_buf_queue(struct vb2_buffer *vb)
+{
+	struct stats_dev *stats_dev = vb2queue_to_statsdev(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct viif_buffer *buf = vb2_to_viif(vbuf);
+
+	guard(spinlock_irq)(&stats_dev->stats_lock);
+	list_add_tail(&buf->queue, &stats_dev->stats_queue);
+}
+
+static int viif_stats_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+	if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_stat))
+		return -EINVAL;
+
+	vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_stat));
+
+	return 0;
+}
+
+static void viif_stats_vb2_stop_streaming(struct vb2_queue *q)
+{
+	struct stats_dev *stats_dev = vb2queue_to_statsdev(q);
+	struct viif_buffer *buf;
+	unsigned int i;
+
+	guard(spinlock_irq)(&stats_dev->stats_lock);
+
+	for (i = 0; i < 8; i++) {
+		if (list_empty(&stats_dev->stats_queue))
+			break;
+		buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
+		list_del(&buf->queue);
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+	}
+}
+
+static const struct vb2_ops viif_stats_vb2_ops = {
+	.queue_setup = viif_stats_vb2_queue_setup,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.buf_queue = viif_stats_vb2_buf_queue,
+	.buf_prepare = viif_stats_vb2_buf_prepare,
+	.stop_streaming = viif_stats_vb2_stop_streaming,
+};
+
+int visconti_viif_stats_register(struct viif_device *viif_dev)
+{
+	struct stats_dev *stats_dev = &viif_dev->stats_dev;
+	struct video_device *vdev = &stats_dev->vdev;
+	struct vb2_queue *q = &stats_dev->vb2_vq;
+	int ret;
+
+	mutex_init(&stats_dev->vlock);
+	INIT_LIST_HEAD(&stats_dev->stats_queue);
+	spin_lock_init(&stats_dev->stats_lock);
+
+	strscpy(vdev->name, "viif_stats", sizeof(vdev->name));
+
+	/* Register the video device */
+	video_set_drvdata(vdev, stats_dev);
+	vdev->ioctl_ops = &viif_stats_ioctl;
+	vdev->fops = &viif_stats_fops;
+	vdev->release = video_device_release_empty;
+	vdev->lock = &stats_dev->vlock;
+	vdev->v4l2_dev = &viif_dev->v4l2_dev;
+	vdev->queue = &stats_dev->vb2_vq;
+	vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
+	vdev->vfl_dir = VFL_DIR_RX;
+
+	/* Initialize vb2 queue */
+	q->type = V4L2_BUF_TYPE_META_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->drv_priv = stats_dev;
+	q->ops = &viif_stats_vb2_ops;
+	q->mem_ops = &vb2_vmalloc_memops;
+	q->buf_struct_size = sizeof(struct viif_buffer);
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &stats_dev->vlock;
+	q->dev = viif_dev->v4l2_dev.dev;
+
+	ret = vb2_queue_init(q);
+	if (ret)
+		return ret;
+
+	stats_dev->stats_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_pads_init(&vdev->entity, VIIF_STATS_PAD_NUM, &stats_dev->stats_pad);
+	if (ret)
+		goto error;
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	media_entity_cleanup(&vdev->entity);
+	mutex_destroy(&stats_dev->vlock);
+
+	return ret;
+}
+
+void visconti_viif_stats_unregister(struct viif_device *viif_dev)
+{
+	struct stats_dev *stats_dev = &viif_dev->stats_dev;
+	struct video_device *vdev = &stats_dev->vdev;
+
+	if (!video_is_registered(vdev))
+		return;
+
+	vb2_video_unregister_device(vdev);
+	media_entity_cleanup(&vdev->entity);
+	mutex_destroy(&stats_dev->vlock);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.h b/drivers/media/platform/toshiba/visconti/viif_stats.h
new file mode 100644
index 000000000000..e17c0e5f5a0d
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2024 TOSHIBA CORPORATION
+ * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef __VIIF_STATS_H__
+#define __VIIF_STATS_H__
+
+void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp);
+int visconti_viif_stats_register(struct viif_device *viif_dev);
+void visconti_viif_stats_unregister(struct viif_device *viif_dev);
+#endif /* __VIIF_STATS_H__ */
-- 
2.25.1



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

* [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (5 preceding siblings ...)
  2024-11-25  9:21 ` [PATCH v12 6/8] media: platform: visconti: Add streaming interface for ISP parameters and status Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2025-01-02 21:26   ` Laurent Pinchart
  2024-11-25  9:21 ` [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface Yuji Ishikawa
  7 siblings, 1 reply; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Added description of Video Input Interface driver of
Toshiba Visconti architecture.
It includes hardware organization, structure of the driver
and metadata format for embedded image signal processor.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
---
Changelog v3:
- Newly add documentation to describe SW and HW

Changelog v4:
- no change

Changelog v5:
- no change

Changelog v6:
- add description of CSI2RX subdevice
- add ordering of ioctl(S_FMT) and ioctl(S_EXT_CTRLS)

Changelog v7:
- no change

Changelog v8:
- add usage of V4L2_CTRL_TYPE_VISCONTI_ISP

Changelog v9:
- fix warning: set reference target for keyword V4L2_CTRL_TYPE_VISCONTI_ISP

Changelog v10:
- use parameter buffers instead of compound control
  - removed description of vendor specific compound control
  - add description of parameter buffers for ISP control
- update directory structure
  - remove documents under driver-api
  - add documents to admin-guide, userspace-api

Changelog v11:
- update usage of the driver

Changelog v12:
- add description of CSI2RX driver
- description of resizer subdevice
- add block diagrams of VIIF and ISP
- update usage of the driver

 .../admin-guide/media/v4l-drivers.rst         |   1 +
 .../admin-guide/media/visconti-viif.dot       |  22 +
 .../admin-guide/media/visconti-viif.rst       | 435 ++++++++++++++++++
 .../userspace-api/media/v4l/meta-formats.rst  |   1 +
 .../media/v4l/metafmt-visconti-viif.rst       |  48 ++
 5 files changed, 507 insertions(+)
 create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
 create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
 create mode 100644 Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst

diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
index b6af448b9fe9..81054512e768 100644
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -32,5 +32,6 @@ Video4Linux (V4L) driver-specific documentation
 	si476x
 	starfive_camss
 	vimc
+	visconti-viif
 	visl
 	vivid
diff --git a/Documentation/admin-guide/media/visconti-viif.dot b/Documentation/admin-guide/media/visconti-viif.dot
new file mode 100644
index 000000000000..cc75c73336fb
--- /dev/null
+++ b/Documentation/admin-guide/media/visconti-viif.dot
@@ -0,0 +1,22 @@
+digraph board {
+        rankdir=TB
+        n00000001 [label="{{<port0> 0 | <port4> 4} | visconti-viif:isp\n/dev/v4l-subdev0 | {<port1> 1 | <port2> 2 | <port3> 3 | <port5> 5}}", shape=Mrecord, style=filled, fillcolor=green]
+        n00000001:port1 -> n00000008:port0
+        n00000001:port2 -> n0000000b:port0
+        n00000001:port3 -> n00000016
+        n00000001:port5 -> n0000001e
+        n00000008 [label="{{<port0> 0} | visconti-viif:resizer0\n/dev/v4l-subdev1 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+        n00000008:port1 -> n0000000e
+        n0000000b [label="{{<port0> 0} | visconti-viif:resizer1\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+        n0000000b:port1 -> n00000012
+        n0000000e [label="viif_capture_post0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+        n00000012 [label="viif_capture_post1\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
+        n00000016 [label="viif_capture_sub\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
+        n0000001a [label="viif_params\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
+        n0000001a -> n00000001:port4
+        n0000001e [label="viif_stats\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
+        n00000030 [label="{{<port0> 0} | visconti_csi2rx 1c008000.csi2rx\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+        n00000030:port1 -> n00000001:port0
+        n00000035 [label="{{} | imx219 1-0010\n/dev/v4l-subdev4 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
+        n00000035:port0 -> n00000030:port0
+}
diff --git a/Documentation/admin-guide/media/visconti-viif.rst b/Documentation/admin-guide/media/visconti-viif.rst
new file mode 100644
index 000000000000..c2e85fb6f8c1
--- /dev/null
+++ b/Documentation/admin-guide/media/visconti-viif.rst
@@ -0,0 +1,435 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================================
+Visconti Video Input Interface Driver (visconti-viif)
+======================================================
+
+Introduction
+============
+
+This file documents the driver for the Video Input Interface (VIIF) that is
+part of Toshiba Visconti SoCs.
+The driver is located under drivers/media/platform/toshiba/visconti and uses
+the Media-Controller API.
+
+The driver module is named visconti-viif,
+and is enabled through the CONFIG_VIDEO_VISCONTI_VIIF config option.
+The CSI-2 receiver part is controlled by another module named visconti-csi2rx,
+which is enabled through the CONFIG_VIDEO_VISCONTI_CSI2RX config option.
+
+The Visconti VIIF Hardware
+==========================
+
+The Visconti VIIF hardware is an internally developed video capture device.
+Following function modules are integrated:
+
+* MIPI CSI-2 receiver (CSI2RX)
+* L1 Image Signal Processor (L1ISP)
+
+  * Correction, enhancement, adjustment on bayer images.
+
+* L2 Image Signal Processor (L2ISP)
+
+  * Lens distortion correction
+  * Scaling & Cropping with up to 2 parameter sets
+  * Formatting picture (RGB, YUV, Grayscale, ...)
+  * Integrated DMAC: Writing picture into main memory
+
+* Video DMAC
+
+  * Writing picture into main memory
+
+Visconti5 SoC has two VIIF hardware instances.
+
+
+The hardware block diagram is shown below.::
+
+  The VIIF hardware
+                                                              "POST0"
+                                                              "RGB with scale 0"
+  +--------+    +----------+    +-----+    +-----+    +-----+    +--------+
+  | Sensor |--->|  CSI2RX  |--->|     |    |     |    |     |--->| memory |
+  +--------+    +----------+    |     |    |     |    |     |    +--------+
+                                |     |    | L1  |    | L2  | "POST1"
+                                |     |--->| ISP |--->| ISP | "RGB with scale 1"
+                                |     |    |     |    |     |    +--------+
+                                | MUX |    |     |    |     |--->| memory |
+                                |     |    +-----+    +-----+    +--------+
+                                |     |                       "SUB"
+                                |     |                       "RAW w/o scale"
+                                |     |        +------------+    +--------+
+                                |     |------> | Video DMAC |--->| memory |
+                                +-----+        +------------+    +--------+
+
+Topology
+========
+
+Graph
+-----
+
+.. _visconti_viif_topology_graph:
+
+.. kernel-figure:: visconti-viif.dot
+	:alt: Diagram of the default media pipeline topology
+	:align: center
+
+The driver has 3 video devices for capturing images:
+
+- viif_capture_post0: capture device for image.
+    - corresponds to L2ISP.
+- viif_capture_post1: capture device for image.
+    - corresponds to L2ISP.
+- viif_capture_sub: capture device for bayer image.
+    - corresponds to Video DMAC.
+
+The driver has 2 video devices for controlling ISP.
+
+- viif_params: a metadata output device that receives ISP parameters.
+    - corresponds to L1ISP and L2ISP.
+- viif_stats: a metadata capture device that sends statistics.
+    - corresponds to L1ISP and L2ISP.
+
+The driver has 2 subdevices:
+
+- visconti_csi2rx: CSI-2 receiver operation.
+    - corresponds to CSI2RX.
+- visconti-viif:isp: Image Signal Processor operation.
+    - corresponds to L1ISP and L2ISP.
+- visconti-viif:resizer: Scaling operation of Image Signal Processor.
+    - corresponds to L2ISP.
+
+visconti_csi2rx - CSI2 Receiver Subdevice Node
+---------------------------------------------------
+
+This subdevice node corresponds to a MIPI CSI2 receiver.
+It resides between an image sensor subdevice and the ISP subdevice.
+It controls CSI2 link configuration and training process.
+
+visconti-viif:isp - ISP Subdevice Node
+--------------------------------------
+
+This subdevice node corresponds to L1/L2 ISPs.
+It receives pictures from an sensor (via CSI2RX),
+applies multiple operations on pictures, then passes resulting images to capture nodes.
+
+ISP configurations/parameters are passed from userland via viif_params node.
+The status of ISP operations are passed to userland via viif_stats node.
+
+L1 ISP provides following operations:
+
+- Input: accepts 8, 10, 12, 14bit bayer format
+    - Operation selector; :c:type:`viif_l1_input_mode_config`
+        - HDR image / PWL (Piecewse Linear Compression) image
+        - with preprocessing / without preprocessing
+    - HDRE: HDR expansion (only for PWL image);
+      see :c:type:`viif_l1_hdre_config`
+- Preprocessing: generate intermediate data (24bit RAW)
+    - SLIC: Bit slicing (x3 12bit planes for preprocessing);
+      see :c:type:`viif_l1_img_extraction_config`
+    - ABPC/DPC: Blemish/Defect pixel correction :c:type:`viif_l1_dpc_config`
+    - PWHB: Preset white balance; see :c:type:`viif_l1_preset_white_balance_config`
+    - RCNR: RAW color noise reduction; see :c:type:`viif_l1_raw_color_noise_reduction_config`
+    - HDRS: HDR synthesis; see :c:type:`viif_l1_hdrs_config`
+- Processing on RAW image: Main Process (MPRO)
+    - BLVC: black level correction and normalization;
+      see :c:type:`viif_l1_black_level_correction_config`
+    - LSSC: Lens shading correction; see :c:type:`viif_l1_lsc_config`
+    - MPRO: digital amplifier; see :c:type:`viif_l1_main_process_config`
+    - MPRO: bayer demosaicing; see :c:type:`viif_l1_main_process_config`
+    - MPRO: color matrix correction; see :c:type:`viif_l1_main_process_config`
+    - HDRC: HDR compression;
+      see :c:type:`viif_l1_hdrc_config`, :c:type:`viif_l1_hdrc_ltm_config`,
+      :c:type:`viif_l1_rgb_to_y_coef_config`
+- Processing on RGB/YUV image: Video Process (VPRO)
+    - VPRO: gamma correction; see :c:type:`viif_l1_gamma_config`
+    - VPRO: RGB2YUV;
+      see :c:type:`viif_l1_rgb_to_y_coef_config`,
+      :c:type:`viif_l1_img_quality_adjustment_config`
+    - VPRO: image quality adjustment; see :c:type:`viif_l1_img_quality_adjustment_config`
+- Output: 16bit YUV
+- Feedback loop
+    - AWHB: auto white balance; see :c:type:`viif_l1_awb_config`,
+      :c:type:`viif_isp_capture_status`
+    - AEXP: auto exposure (average luminance calculation);
+      see :c:type:`viif_l1_avg_lum_generation_config`,
+      :c:type:`viif_l1_rgb_to_y_coef_config`, :c:type:`viif_isp_capture_status`
+    - AG: analog gain calculation;
+      see :c:type:`viif_l1_ag_mode_config`, :c:type:`viif_l1_ag_config`
+
+Below is the block diagram::
+
+  L1ISP::INPUT
+
+  +--------+                +-----+                      +-----+
+  | Input  |--------------->|     |--------------------->|     |
+  | 24bHDR |                |     |                      |     |
+  +--------+                | 24b |                      | 24b |
+                            | RAW |                      | RAW |
+  +--------+    +------+    | (0) |                      | (1) |
+  | Input  |--->| HDRE |--->|     |    +------------+    |     |
+  | 24bPWL |    |      |    |     |--->| preprocess |--->|     |
+  +--------+    +------+    +-----+    +------------+    +-----+
+
+  L1ISP::INPUT::preprocess
+
+  +-----+                                                                +-----+
+  | 24b |    +------+    +------+    +------+    +------+    +------+    | 24b |
+  | RAW |--->| SLIC |--->| ABPC |--->| PWHB |--->| RCNR |--->| HDRS |--->| RAW |
+  | (0) |    +------+    +------+    +------+    +------+    +------+    | (1) |
+  +-----+                                                                +-----+
+
+  L1ISP::MainProcess(MPRO)
+
+  +-----+
+  | 24b |    +------+    +------+
+  | RAW |--->| BLVC |--->| LSSC |---+
+  | (1) |    +------+    +------+   |
+  +-----+                           |
+                                    |
+     +------------------------------+
+     |
+     |    +-----------+    +-------------+    +--------+                +-----+
+     +--->|   MPRO    |    |    MPRO     |    |  MPRO  |    +------+    | 16b |
+          |  Digital  |--->| Demosaicing |----| Color  |--->| HDRC |--->| RGB |
+     +--->| Amplifier |    |             |    | Matrix |    +------+    |     |
+     |    +-----------+    +-------------+    +--------+                +-----+
+     |                         |    |
+     |    +--------------+     |    |    +------+
+     +----| Auto         |<----+    +--->| AEXP |---> Auto-Exposure statistics
+          | Whitebalance |               +------+
+          +--------------+
+                 |
+                 +------------------------------> Auto-Whitebalance statistics
+
+  L1ISP::VideoProcess(VPRO)
+
+  +-----+    +------------+    +------------+    +---------------+    +--------+
+  | 16b |--->| Gamma      |--->| RGB2YUV    |--->| Image Quality |--->| Output |
+  | RGB |    | Correction |    | Conversion |    | Adjustment    |    |  16b   |
+  |     |    +------------+    +------------+    +---------------+    |  YUV   |
+  +-----+                                                             +--------+
+
+  L1ISP::AnalogGain
+
+  statistics                     +-------------+    +------------------+
+  information ---> (user SW) --->| Analog Gain |--->| ABPC, RCNR, LSSC |
+                                 +-------------+    |       MPRO, VPRO |
+                                                    +------------------+
+
+L2 ISP provides following operations:
+
+- Input: accepts 16bit YUV / RGB
+- Operations:
+    - Lens undistortion; see :c:type:`viif_l2_undist`
+    - Scaling; see :c:type:`viif_l2_roi`
+    - Cropping; see :c:type:`viif_l2_roi`
+    - Gamma correction; see :c:type:`viif_l2_gamma_config`
+    - YUV2RGB
+- Output: RGB, YUV422, YUV444
+
+Below is the block diagram::
+
+  L2ISP
+
+  +-------+    +------------+    +--------------+    +---------+
+  | Input |--->| YUV2RGB    |--->| Lens         |--->| Scaling |---> |
+  | Image |    | Conversion |    | Undistortion |    |         |---> |
+  +-------+    +------------+    +--------------+    +---------+     |
+                                                                     |
+          +----------------------------------------------------------+
+          |
+          |    +----------+    +------------+    +--------+    +--------+
+          +--->|Gamma     |--->| Colorspace |--->| Data   |--->| Output |
+          |    |Correction|    | Conversion |    | Packer |    | Image  |
+          |    +----------+    +------------+    +--------+    +--------+
+          |
+          |    +----------+    +------------+    +--------+    +--------+
+          +--->|Gamma     |--->| Colorspace |--->| Data   |--->| Output |
+               |Correction|    | Conversion |    | Packer |    | Image  |
+               +----------+    +------------+    +--------+    +--------+
+
+visconti-viif:resizer - Resizer Subdevice Node
+----------------------------------------------
+
+The resizer subdevice resides between ISP subdevice and Capture device
+on a capture path for post0 and post1.
+It receives resize and crop parameters for the specific capture path
+and controls L2ISP HW.
+
+following selection rectangles can be passed at VIDIOC_S_SELECTION ioctl.
+
+- sink pads's compose rectangle (V4L2_SEL_TGT_COMPOSE) for scaling
+- source pad's crop rectangle (V4L2_SEL_TGT_CROP) for cropping
+
+
+viif_capture_post0, viif_capture_post1 - Processed Image Capture Video Node
+---------------------------------------------------------------------------
+
+These video nodes are used for capturing images processed at ISPs.
+Supported capture formats are as follows:
+
+- V4L2_PIX_FMT_RGB24
+- V4L2_PIX_FMT_ABGR32
+- V4L2_PIX_FMT_YUV422M
+- V4L2_PIX_FMT_YUV444M
+- V4L2_PIX_FMT_Y16
+
+Bayer format is not supported. Use viif_capture_sub instead.
+
+POST0 and POST1 can output images from the same input image
+using different cropping and scaling settings.
+
+viif_capture_sub - Raw Image Capture Video Node
+-----------------------------------------------
+
+This video node is used for capturing bayer image from the sensor.
+The output picture has exactly the same resolution and format as the sensor input.
+The pipeline does not edit pixel values.
+However, when writing pixel values to memory, they are shifted to the MSB
+to match either 8bit or 16bit.
+
+Therefore, resulting capture formats are as follows:
+
+- for 8bit RAW input:
+    - V4L2_PIX_FMT_SRGGB8
+    - V4L2_PIX_FMT_SGRBG8
+    - V4L2_PIX_FMT_SGBRG8
+    - V4L2_PIX_FMT_SBGGR8
+- for 10, 12, 14bit RAW input:
+    - V4L2_PIX_FMT_SRGGB16
+    - V4L2_PIX_FMT_SGRBG16
+    - V4L2_PIX_FMT_SGBRG16
+    - V4L2_PIX_FMT_SBGGR16
+
+.. _viif_params:
+
+viif_params - ISP Parameters Video Node
+---------------------------------------
+
+The viif_params video node receives a set of ISP parameters from userspace
+to be applied to the hardware during a video stream.
+
+The buffer format is defined by struct :c:type:`visconti_viif_isp_config`, and userspace should set
+:ref:`V4L2_META_FMT_VISCONTI_VIIF_PARAMS <v4l2-meta-fmt-visconti-viif-params>` as the data format.
+
+.. _viif_stats:
+
+viif_stats - Statistics Video Node
+----------------------------------
+
+The viif_stats video node provides current status of ISP.
+
+Following information is included:
+
+* statistics of auto white balance
+* average luminance information which can be used by auto exposure software impl.
+
+The buffer format is defined by struct :c:type:`visconti_viif_isp_stat`, and userspace should set
+:ref:`V4L2_META_FMT_VISCONTI_VIIF_STATS <v4l2-meta-fmt-visconti-viif-stats>` as the data format.
+
+Feedback Operations
+===================
+
+Among the so-called 3A functions, VIIF provides only auto-whitebalance and auto-exposure.
+Auto-whitebalance is a standalone hardware feature.
+Some status information is available through the ISP statistics interface.
+
+Auto-exposure is realized through a combination of hardware and userland software.
+VIIF provides weighted average luminance information through the ISP statistics interface.
+The userland application calculates the sensor gain, sensor exposure and ISP digital gain.
+The calculated parameters are then passed to sensor's controls and the ISP parameter interface.
+
+Among ISP parameters, there are parameters called AG (analog gain).
+Actually, AG parameters have nothing to do with auto-exposure.
+It controls "strength" in several signal correction algorithms.
+Below is the list of the functions which may be affected by AG parameters:
+
+- ABPC/DPC
+- RCNR
+- LSSC
+- MPRO: color matrix correction
+- VPRO
+
+Capturing Video Frames Example
+==============================
+
+In the following example,
+imx219 camera is connected to pad 0 of 'visconti_csi2rx' subdevice.
+
+The following commands yield three pictures with different zoom ratio:
+- main path 0: 1.5x zoom, crop 1920x1080, RGB picture
+- main path 1: 0.67x zoom, crop 640x480, RGB picture
+- sub path: 1920x1080 RAW picture
+
+.. code-block:: bash
+
+	# set the links
+	media-ctl -d platform:visconti-viif-0 -r
+	media-ctl -d platform:visconti-viif-0 -l '"imx219 1-0010":0 -> "visconti_csi2rx 1c008000.csi2rx":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti_csi2rx 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":1 -> "visconti-viif:resizer0":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":2 -> "visconti-viif:resizer1":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":3 -> "viif_capture_sub":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer0":1 -> "viif_capture_post0":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer1":1 -> "viif_capture_post1":0 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"viif_params":0 -> "visconti-viif:isp":4 [1]'
+	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":5 -> "viif_stats":0 [1]'
+
+	# set format for imx219
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"imx219 1-0010":0 [fmt:SRGGB10_1X10/1920x1080]'
+
+	# set format for csi2rx
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti_csi2rx 1c008000.csi2rx":0 [fmt:SRGGB10_1X10/1920x1080  field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]'
+
+	# set format for isp sink pad
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":0 [fmt:SRGGB10_1X10/1920x1080]'
+
+	# set format for resizer pads
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer0":0 '"[fmt:YUV8_1X24/1920x1080 compose:(0,0)/2880x1620]"
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer0":1 '"[crop:(480,16)/1920x1080]"
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer1":0 '"[fmt:YUV8_1X24/1920x1080 compose:(0,0)/1280x720]"
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer1":1 '"[crop:(320,32)/640x480]"
+
+	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":1 [fmt:YUV8_1X24/1024 crop:(640,0)/1024x1024]'
+
+	# set format for main path0
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "width=1920,height=1080"
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "pixelformat=RGB3"
+
+	# set format for main path1
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "width=640,height=480"
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "pixelformat=RGB3"
+
+	# start streaming
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 --stream-mmap --stream-count 1000 &
+
+	# start streaming with other devices while viif_capture_post0 is running
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post1 --stream-mmap --stream-count 10
+	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_sub --stream-mmap --stream-count 10
+
+Use of coherent memory
+======================
+
+Visconti5 SoC has two independent DDR SDRAM controllers.
+Each controller is mapped to 36bit address space.
+
+Accelerator bus masters have two paths to access memory;
+one is directly connected to SDRAM controller,
+the another is connected via a cache coherency bus
+which keeps coherency among CPUs.
+
+From accelerators and CPUs, the address map is following:
+
+* 0x0_8000_0000 DDR0 direct access
+* 0x4_8000_0000 DDR0 coherency bus
+* 0x8_8000_0000 DDR1 direct access
+* 0xC_8000_0000 DDR1 coherency bus
+
+The base address can be specified with "memory" and "reserved-memory" elements
+in a device tree description.
+It's not recommended to mix direct address and coherent address.
+
+The Visconti5 VIIF driver always use only direct address to configure Video DMACs of the hardware.
+This design is to avoid great performance loss at coherency bus caused by massive memory access.
+You should not put the dma_coherent attribute to viif element in device tree.
+Cache operations are done automatically by videobuf2 driver.
diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst
index 86ffb3bc8ade..2336842f0c26 100644
--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
+++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
@@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata` interface only.
     metafmt-pisp-fe
     metafmt-rkisp1
     metafmt-uvc
+    metafmt-visconti-viif
     metafmt-vivid
     metafmt-vsp1-hgo
     metafmt-vsp1-hgt
diff --git a/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
new file mode 100644
index 000000000000..dc4b31627fe1
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _v4l2-meta-fmt-visconti-viif-params:
+
+.. _v4l2-meta-fmt-visconti-viif-stats:
+
+***************************************************************************************
+V4L2_META_FMT_VISCONTI_VIIF_PARAMS ('vifp'), V4L2_META_FMT_VISCONTI_VIIF_STATS ('vifs')
+***************************************************************************************
+
+Configuration parameters
+========================
+
+The configuration parameters are passed to the
+:ref:`viif_params <viif_params>` metadata output video node, using
+the :c:type:`v4l2_meta_format` interface. The buffer contains
+a single instance of the C structure :c:type:`visconti_viif_isp_config` defined in
+``visconti_viif.h``. So the structure can be obtained from the buffer by:
+
+.. code-block:: c
+
+	struct visconti_viif_isp_config *params = (struct visconti_viif_isp_config*) buffer;
+
+VIIF statistics
+===============
+
+The VIIF device collects different statistics over an input Bayer frame.
+Those statistics are obtained from the :ref:`viif_stats <viif_stats>`
+metadata capture video node,
+using the :c:type:`v4l2_meta_format` interface. The buffer contains a single
+instance of the C structure :c:type:`visconti_viif_isp_stat` defined in
+``visconti_viif.h``. So the structure can be obtained from the buffer by:
+
+.. code-block:: c
+
+	struct visconti_viif_isp_stat *stats = (struct visconti_viif_isp_stat*) buffer;
+
+The statistics collected are Exposure, AWB (auto white balance) and errors.
+See :c:type:`visconti_viif_isp_stat` for details of the statistics.
+
+The statistics and configuration parameters described here are usually
+consumed and produced by dedicated user space libraries that comprise the
+tuning tools using software control loop.
+
+visconti viif uAPI data types
+=============================
+
+.. kernel-doc:: include/uapi/linux/visconti_viif.h
-- 
2.25.1



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

* [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface
  2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (6 preceding siblings ...)
  2024-11-25  9:21 ` [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
@ 2024-11-25  9:21 ` Yuji Ishikawa
  2025-01-02 13:16   ` Laurent Pinchart
  7 siblings, 1 reply; 36+ messages in thread
From: Yuji Ishikawa @ 2024-11-25  9:21 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Hans Verkuil,
	Nobuhiro Iwamatsu, Yuji Ishikawa
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Added entries for visconti Video Input Interface driver, including;
* device tree bindings
* source files
* documentation files

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
---
Changelog v2:
- no change

Changelog v3:
- added entry for driver API documentation

Changelog v4:
- added entry for header file

Changelog v5:
- no change

Changelog v6:
- update path to VIIF driver source files

Changelog v7:
- no change

Changelog v8:
- rename bindings description file

Changelog v9:
- no change

Changelog v10:
- add a separate entry of VIIF driver

Changelog v11:
- no change

Changelog v12:
- add a bindings description of CSI2RX driver

 MAINTAINERS | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b878ddc99f94..b5c819e94e9b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23430,6 +23430,18 @@ F:	Documentation/devicetree/bindings/media/i2c/tc358743.txt
 F:	drivers/media/i2c/tc358743*
 F:	include/media/i2c/tc358743.h
 
+TOSHIBA VISCONTI VIIF DRIVER
+M:	Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	Documentation/admin-guide/media/visconti-viif.*
+F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
+F:	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
+F:	Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
+F:	drivers/media/platform/toshiba/visconti/
+F:	include/uapi/linux/visconti_viif.h
+
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
 L:	platform-driver-x86@vger.kernel.org
-- 
2.25.1



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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-11-25  9:21 ` [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
@ 2024-11-25 10:07   ` Krzysztof Kozlowski
  2024-12-17  0:00     ` yuji2.ishikawa
  2025-01-02  9:56   ` Laurent Pinchart
  1 sibling, 1 reply; 36+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-25 10:07 UTC (permalink / raw)
  To: Yuji Ishikawa, Laurent Pinchart, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus,
	Hans Verkuil, Nobuhiro Iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

On 25/11/2024 10:21, Yuji Ishikawa wrote:
> Adds the Device Tree binding documentation that allows to describe
> the Video Input Interface found in Toshiba Visconti SoCs.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>

Why this tag stayed and other was removed? What was the reason of tag
removal?


> ---
> Changelog v2:
> - no change
> 
> Changelog v3:
> - no change
> 
> Changelog v4:
> - fix style problems at the v3 patch
> - remove "index" member
> - update example
> 
> Changelog v5:
> - no change
> 
> Changelog v6:
> - add register definition of BUS-IF and MPU
> 
> Changelog v7:
> - remove trailing "bindings" from commit header message
> - remove trailing "Device Tree Bindings" from title
> - fix text wrapping of description
> - change compatible to visconti5-viif
> - explicitly define allowed properties for port::endpoint
> 
> Changelog v8:
> - Suggestion from Krzysztof Kozlowski
>   - rename bindings description file
>   - use block style array instead of inline style
>   - remove clock-lane (as it is fixed at position 0)
>   - update sample node's name
>   - use lowercase hex for literals
> - Suggestion from Laurent Pinchart
>   - update description message port::description
>   - remove port::endpoint::bus-type as it is fixed to <4>
>   - remove port::endpoint::clock-lanes from example
>   - add port::endpoint::data-lanes to required parameters list
>   - fix sequence of data-lanes: <1 2 3 4> because current driver does not support data reordering
>   - update port::endpoint::data-lanes::description
>   - remove redundant type definition for port::endpoint::data-lanes
> 
> Changelog v9:
> - place "required" after "properties"
> - dictionary ordering of properties
> 
> Changelog v10:
> - no change
> 
> Changelog v11:
> - no change
> 
> Changelog v12:
> - remove property "clock-noncontinuous" as VIIF switches both modes automatically
> - remove property "link-frequencies" as VIIF does not use the information

Driver does not use or hardware supports only one frequency?

> - remove reg[2] and interrupts[3] which are used for CSI2RX driver
> - update example to refer csi2rx for remote-endpoint

Were these the reasons?

I am really surprised that after 11 versions this binding still is being
totally reshaped and you need us to re-review.

Also, start using b4 tool, so:
1. your cover letter will have proper links to previous versions
2. b4 diff would work. Look, try by yourself:



b4 diff '<20241125092146.1561901-3-yuji2.ishikawa@toshiba.co.jp>'
Grabbing thread from
lore.kernel.org/all/20241125092146.1561901-3-yuji2.ishikawa@toshiba.co.jp/t.mbox.gz
Checking for older revisions
Grabbing search results from lore.kernel.org
  Added from v11: 7 patches
---
Analyzing 144 messages in the thread
Looking for additional code-review trailers on lore.kernel.org
Analyzing 13 code-review messages
Preparing fake-am for v11: Add Toshiba Visconti Video Input Interface driver
  range: e16e149ced15..4efb0d6768a6
Preparing fake-am for v12: dt-bindings: media: platform: visconti: Add
Toshiba Visconti MIPI CSI-2 Receiver
ERROR: v12 series incomplete; unable to create a fake-am range
---
Could not create fake-am range for upper series v12



How can I verify what happened here without too much effort?


> 
>  .../media/toshiba,visconti5-viif.yaml         | 95 +++++++++++++++++++
>  1 file changed, 95 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> new file mode 100644
> index 000000000000..ef0452a47e98
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> @@ -0,0 +1,95 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/toshiba,visconti5-viif.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Toshiba Visconti5 SoC Video Input Interface
> +
> +maintainers:
> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> +
> +description: |-

Since you ask for re-review, then:

Drop |-

Best regards,
Krzysztof

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

* Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
@ 2024-11-25 10:11   ` Krzysztof Kozlowski
  2024-12-16 23:57     ` yuji2.ishikawa
  2025-01-02  9:29   ` Laurent Pinchart
  1 sibling, 1 reply; 36+ messages in thread
From: Krzysztof Kozlowski @ 2024-11-25 10:11 UTC (permalink / raw)
  To: Yuji Ishikawa, Laurent Pinchart, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus,
	Hans Verkuil, Nobuhiro Iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

On 25/11/2024 10:21, Yuji Ishikawa wrote:
> Adds the Device Tree binding documentation that allows to describe
> the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>


How newly added patch can have already Rb tag? Was this review really,
really performed internally or you just satisfy some internal managers
requirements and fake the stats?

> ---
> 
> Changelog v12:
> - Newly add bindings for CSI2RX driver 
> 
>  .../media/toshiba,visconti5-csi2rx.yaml       | 104 ++++++++++++++++++
>  1 file changed, 104 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> new file mode 100644
> index 000000000000..5488072bc82a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> @@ -0,0 +1,104 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> +
> +maintainers:
> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> +
> +description: |-

Drop |-

> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI CSI-2 video
> +  stream. Use with VIIF device. T.B.D
> +
> +properties:
> +  compatible:
> +    const: toshiba,visconti5-csi2rx

Why this is called "RX"? Can you have a TX? I had impression that one
cannot.

> +
> +  reg:
> +    items:
> +      - description: Registers for CSI2 receiver control
> +
> +  interrupts:
> +    items:
> +      - description: CSI2 Receiver Interrupt
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    properties:
> +      port@0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description:
> +          Input port node, single endpoint describing the CSI-2 transmitter.
> +
> +        properties:
> +          endpoint:
> +            $ref: video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +            properties:
> +              data-lanes:
> +                description: CSI2 receiver supports 1, 2, 3 or 4 data lanes
> +                minItems: 1
> +                items:
> +                  - const: 1
> +                  - const: 2
> +                  - const: 3
> +                  - const: 4
> +            required:
> +              - data-lanes
> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description:
> +          Output port node, single endpoint describing the Visconti VIIF.
> +
> +    required:
> +      - port@0
> +      - port@1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        csi2rx@1c008000 {


csi@

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation



Best regards,
Krzysztof

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

* RE: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-11-25 10:11   ` Krzysztof Kozlowski
@ 2024-12-16 23:57     ` yuji2.ishikawa
  2024-12-17  5:44       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 36+ messages in thread
From: yuji2.ishikawa @ 2024-12-16 23:57 UTC (permalink / raw)
  To: krzk, laurent.pinchart, mchehab, robh, krzk+dt, conor+dt,
	sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Hello Krzysztof

Thank you for your review

> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Monday, November 25, 2024 7:11 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> <nobuhiro1.iwamatsu@toshiba.co.jp>
> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti MIPI CSI-2 Receiver
> 
> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> > Adds the Device Tree binding documentation that allows to describe the
> > MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> 
> 
> How newly added patch can have already Rb tag? Was this review really, really
> performed internally or you just satisfy some internal managers requirements
> and fake the stats?
> 

I added this Reviewed-by tag because the patch was reviewed internally.

> > ---
> >
> > Changelog v12:
> > - Newly add bindings for CSI2RX driver
> >
> >  .../media/toshiba,visconti5-csi2rx.yaml       | 104
> ++++++++++++++++++
> >  1 file changed, 104 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> > l
> > b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> > l
> > new file mode 100644
> > index 000000000000..5488072bc82a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx
> > +++ .yaml
> > @@ -0,0 +1,104 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> > +
> > +maintainers:
> > +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > +
> > +description: |-
> 
> Drop |-
> 

I'll drop "|-"

> > +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
> > + CSI-2 video  stream. Use with VIIF device. T.B.D
> > +
> > +properties:
> > +  compatible:
> > +    const: toshiba,visconti5-csi2rx
> 
> Why this is called "RX"? Can you have a TX? I had impression that one cannot.
> 

VIIF has only MIPI CSI2 receiver (CSI2RX). There's no TX for it.
Visconti also has VOIF (Video Output Interface) hardware which has MIPI CSI2 (not DSI) transmitter (CSI2TX).

> > +
> > +  reg:
> > +    items:
> > +      - description: Registers for CSI2 receiver control
> > +
> > +  interrupts:
> > +    items:
> > +      - description: CSI2 Receiver Interrupt
> > +
> > +  ports:
> > +    $ref: /schemas/graph.yaml#/properties/ports
> > +
> > +    properties:
> > +      port@0:
> > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > +        unevaluatedProperties: false
> > +        description:
> > +          Input port node, single endpoint describing the CSI-2
> transmitter.
> > +
> > +        properties:
> > +          endpoint:
> > +            $ref: video-interfaces.yaml#
> > +            unevaluatedProperties: false
> > +
> > +            properties:
> > +              data-lanes:
> > +                description: CSI2 receiver supports 1, 2, 3 or 4 data lanes
> > +                minItems: 1
> > +                items:
> > +                  - const: 1
> > +                  - const: 2
> > +                  - const: 3
> > +                  - const: 4
> > +            required:
> > +              - data-lanes
> > +
> > +      port@1:
> > +        $ref: /schemas/graph.yaml#/properties/port
> > +        description:
> > +          Output port node, single endpoint describing the Visconti VIIF.
> > +
> > +    required:
> > +      - port@0
> > +      - port@1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - ports
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    soc {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        csi2rx@1c008000 {
> 
> 
> csi@
> 
> Node names should be generic. See also an explanation and list of examples
> (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetre
> e-basics.html#generic-names-recommendation
> 

I'll fix the node names.

> 
> Best regards,
> Krzysztof


Best regards,
Yuji Ishikawa

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

* RE: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-11-25 10:07   ` Krzysztof Kozlowski
@ 2024-12-17  0:00     ` yuji2.ishikawa
  2024-12-17  5:43       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 36+ messages in thread
From: yuji2.ishikawa @ 2024-12-17  0:00 UTC (permalink / raw)
  To: krzk, laurent.pinchart, mchehab, robh, krzk+dt, conor+dt,
	sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

Hello Krzysztof

Thank you for your review

> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Monday, November 25, 2024 7:08 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> <nobuhiro1.iwamatsu@toshiba.co.jp>
> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti Video Input Interface
> 
> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> > Adds the Device Tree binding documentation that allows to describe the
> > Video Input Interface found in Toshiba Visconti SoCs.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> 
> Why this tag stayed and other was removed? What was the reason of tag
> removal?
> 

The stayed tag is due to internal review.
The removed tag is due to code's change (split of csi2rx part) after the last review.
If the code is largely changed following the instruction of another reviewer
after obtaining the tags, how should the tags be handled?

> > ---
> > Changelog v2:
> > - no change
> >
> > Changelog v3:
> > - no change
> >
> > Changelog v4:
> > - fix style problems at the v3 patch
> > - remove "index" member
> > - update example
> >
> > Changelog v5:
> > - no change
> >
> > Changelog v6:
> > - add register definition of BUS-IF and MPU
> >
> > Changelog v7:
> > - remove trailing "bindings" from commit header message
> > - remove trailing "Device Tree Bindings" from title
> > - fix text wrapping of description
> > - change compatible to visconti5-viif
> > - explicitly define allowed properties for port::endpoint
> >
> > Changelog v8:
> > - Suggestion from Krzysztof Kozlowski
> >   - rename bindings description file
> >   - use block style array instead of inline style
> >   - remove clock-lane (as it is fixed at position 0)
> >   - update sample node's name
> >   - use lowercase hex for literals
> > - Suggestion from Laurent Pinchart
> >   - update description message port::description
> >   - remove port::endpoint::bus-type as it is fixed to <4>
> >   - remove port::endpoint::clock-lanes from example
> >   - add port::endpoint::data-lanes to required parameters list
> >   - fix sequence of data-lanes: <1 2 3 4> because current driver does not
> support data reordering
> >   - update port::endpoint::data-lanes::description
> >   - remove redundant type definition for port::endpoint::data-lanes
> >
> > Changelog v9:
> > - place "required" after "properties"
> > - dictionary ordering of properties
> >
> > Changelog v10:
> > - no change
> >
> > Changelog v11:
> > - no change
> >
> > Changelog v12:
> > - remove property "clock-noncontinuous" as VIIF switches both modes
> > automatically
> > - remove property "link-frequencies" as VIIF does not use the
> > information
> 
> Driver does not use or hardware supports only one frequency?
> 

My comment was incorrect.
It should be "Driver does not use the information"

> > - remove reg[2] and interrupts[3] which are used for CSI2RX driver
> > - update example to refer csi2rx for remote-endpoint
> 
> Were these the reasons?
> 
> I am really surprised that after 11 versions this binding still is being totally
> reshaped and you need us to re-review.
>

Sorry for poor quality.
Several changes were brought about by the introduction of the CSI2RX driver.
The new driver was requested in the previous review.
The property "clock-noncontinuous" was pointed out as unnecessary (because HW supports both modes) in the previous review.
The property "link-frequencies" was dropped because It was found to be unused after re-check of the code.

> Also, start using b4 tool, so:
> 1. your cover letter will have proper links to previous versions 2. b4 diff would
> work. Look, try by yourself:
> 
> 
> 
> b4 diff '<20241125092146.1561901-3-yuji2.ishikawa@toshiba.co.jp>'
> Grabbing thread from
> lore.kernel.org/all/20241125092146.1561901-3-yuji2.ishikawa@toshiba.co.jp/t
> .mbox.gz
> Checking for older revisions
> Grabbing search results from lore.kernel.org
>   Added from v11: 7 patches
> ---
> Analyzing 144 messages in the thread
> Looking for additional code-review trailers on lore.kernel.org Analyzing 13
> code-review messages Preparing fake-am for v11: Add Toshiba Visconti Video
> Input Interface driver
>   range: e16e149ced15..4efb0d6768a6
> Preparing fake-am for v12: dt-bindings: media: platform: visconti: Add Toshiba
> Visconti MIPI CSI-2 Receiver
> ERROR: v12 series incomplete; unable to create a fake-am range
> ---
> Could not create fake-am range for upper series v12
> 
> 
> 
> How can I verify what happened here without too much effort?
> 
> 

I will use b4 tool for further submits.
Also I'll add links to previous versions in the cover letter.

I ran b4 diff with the HEAD of media_stage tree and confirmed that it produced non-error results.
I needed to fetch the tree to a certain depth to ensure everything worked smoothly.

$ git clone https://git.linuxtv.org/media_stage.git --depth 1
$ git fetch --shallow-exclude v6.4
$ git log --oneline | head -5
40384c840ea1 Linux 6.13-rc1
a14bf463e7df Merge tag 'i2c-for-6.13-rc1-part3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
88862eeb4763 Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
f788b5ef1ca9 Merge tag 'timers_urgent_for_v6.13_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
63f4993b792e Merge tag 'irq_urgent_for_v6.13_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

$ b4 diff '<20241125092146.1561901-3-yuji2.ishikawa@toshiba.co.jp>'

> >
> >  .../media/toshiba,visconti5-viif.yaml         | 95
> +++++++++++++++++++
> >  1 file changed, 95 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> > b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> > new file mode 100644
> > index 000000000000..ef0452a47e98
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.y
> > +++ aml
> > @@ -0,0 +1,95 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/toshiba,visconti5-viif.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Toshiba Visconti5 SoC Video Input Interface
> > +
> > +maintainers:
> > +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > +
> > +description: |-
> 
> Since you ask for re-review, then:
> 
> Drop |-
> 

I'll drop "|-"

> Best regards,
> Krzysztof

Best regards,
Yuji Ishikawa

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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-12-17  0:00     ` yuji2.ishikawa
@ 2024-12-17  5:43       ` Krzysztof Kozlowski
  2024-12-17  9:45         ` Laurent Pinchart
  2024-12-24  0:17         ` yuji2.ishikawa
  0 siblings, 2 replies; 36+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17  5:43 UTC (permalink / raw)
  To: yuji2.ishikawa, laurent.pinchart, mchehab, robh, krzk+dt,
	conor+dt, sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

On 17/12/2024 01:00, yuji2.ishikawa@toshiba.co.jp wrote:
> Hello Krzysztof
> 
> Thank you for your review
> 
>> -----Original Message-----
>> From: Krzysztof Kozlowski <krzk@kernel.org>
>> Sent: Monday, November 25, 2024 7:08 PM
>> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
>> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
>> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
>> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
>> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
>> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
>> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
>> <nobuhiro1.iwamatsu@toshiba.co.jp>
>> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
>> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
>> Toshiba Visconti Video Input Interface
>>
>> On 25/11/2024 10:21, Yuji Ishikawa wrote:
>>> Adds the Device Tree binding documentation that allows to describe the
>>> Video Input Interface found in Toshiba Visconti SoCs.
>>>
>>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
>>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
>>
>> Why this tag stayed and other was removed? What was the reason of tag
>> removal?
>>
> 
> The stayed tag is due to internal review.

Did the internal review really happened? How is it that immediately new
version has internal review without any traces?

I have doubts this review happened in the context of reviewer's
statement of oversight.


> The removed tag is due to code's change (split of csi2rx part) after the last review.
> If the code is largely changed following the instruction of another reviewer
> after obtaining the tags, how should the tags be handled?

Drop all reviews and perform reviews on the list.

Such internal review appearing afterwards is rather a proof it you are
adding just the tags to satisfy your process. I have no way to even
verify whether that person performed any reasonable review or maybe just
acked your patch. I cannot even verify that that person understands the
reviewer's statement of oversight.


...

>>>
>>> Changelog v11:
>>> - no change
>>>
>>> Changelog v12:
>>> - remove property "clock-noncontinuous" as VIIF switches both modes
>>> automatically
>>> - remove property "link-frequencies" as VIIF does not use the
>>> information
>>
>> Driver does not use or hardware supports only one frequency?
>>
> 
> My comment was incorrect.
> It should be "Driver does not use the information"

Then this is not that helping. Maybe hardware supports only one frequency?


Best regards,
Krzysztof

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

* Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-12-16 23:57     ` yuji2.ishikawa
@ 2024-12-17  5:44       ` Krzysztof Kozlowski
  2024-12-24  0:17         ` yuji2.ishikawa
  2024-12-26 16:15         ` Laurent Pinchart
  0 siblings, 2 replies; 36+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17  5:44 UTC (permalink / raw)
  To: yuji2.ishikawa, laurent.pinchart, mchehab, robh, krzk+dt,
	conor+dt, sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree

On 17/12/2024 00:57, yuji2.ishikawa@toshiba.co.jp wrote:
>> On 25/11/2024 10:21, Yuji Ishikawa wrote:
>>> Adds the Device Tree binding documentation that allows to describe the
>>> MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
>>>
>>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
>>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
>>
>>
>> How newly added patch can have already Rb tag? Was this review really, really
>> performed internally or you just satisfy some internal managers requirements
>> and fake the stats?
>>
> 
> I added this Reviewed-by tag because the patch was reviewed internally.


What issues were identified by internal review, especially in the
context of bindings?

> 
>>> ---
>>>
>>> Changelog v12:
>>> - Newly add bindings for CSI2RX driver
>>>
>>>  .../media/toshiba,visconti5-csi2rx.yaml       | 104
>> ++++++++++++++++++
>>>  1 file changed, 104 insertions(+)
>>>  create mode 100644
>>> Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
>>> l
>>> b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
>>> l
>>> new file mode 100644
>>> index 000000000000..5488072bc82a
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx
>>> +++ .yaml
>>> @@ -0,0 +1,104 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>>> +---
>>> +$id:
>>> +http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
>>> +
>>> +maintainers:
>>> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
>>> +
>>> +description: |-
>>
>> Drop |-
>>
> 
> I'll drop "|-"
> 
>>> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
>>> + CSI-2 video  stream. Use with VIIF device. T.B.D
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: toshiba,visconti5-csi2rx
>>
>> Why this is called "RX"? Can you have a TX? I had impression that one cannot.
>>
> 
> VIIF has only MIPI CSI2 receiver (CSI2RX). There's no TX for it.

So this device cannot be anything else? Then drop rx.

> Visconti also has VOIF (Video Output Interface) hardware which has MIPI CSI2 (not DSI) transmitter (CSI2TX).

Or this can be something else? Confusing.



Best regards,
Krzysztof

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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-12-17  5:43       ` Krzysztof Kozlowski
@ 2024-12-17  9:45         ` Laurent Pinchart
  2024-12-17 12:51           ` Krzysztof Kozlowski
  2024-12-24  0:17         ` yuji2.ishikawa
  1 sibling, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2024-12-17  9:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: yuji2.ishikawa, mchehab, robh, krzk+dt, conor+dt, sakari.ailus,
	hverkuil-cisco, nobuhiro1.iwamatsu, linux-media, linux-kernel,
	linux-arm-kernel, devicetree

On Tue, Dec 17, 2024 at 06:43:22AM +0100, Krzysztof Kozlowski wrote:
> On 17/12/2024 01:00, yuji2.ishikawa@toshiba.co.jp wrote:
> > Hello Krzysztof
> > 
> > Thank you for your review
> > 
> >> -----Original Message-----
> >> From: Krzysztof Kozlowski <krzk@kernel.org>
> >> Sent: Monday, November 25, 2024 7:08 PM
> >> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> >> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
> >> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
> >> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> >> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
> >> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
> >> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> >> <nobuhiro1.iwamatsu@toshiba.co.jp>
> >> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> >> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> >> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
> >> Toshiba Visconti Video Input Interface
> >>
> >> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> >>> Adds the Device Tree binding documentation that allows to describe the
> >>> Video Input Interface found in Toshiba Visconti SoCs.
> >>>
> >>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> >>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>
> >> Why this tag stayed and other was removed? What was the reason of tag
> >> removal?
> >>
> > 
> > The stayed tag is due to internal review.
> 
> Did the internal review really happened? How is it that immediately new
> version has internal review without any traces?
> 
> I have doubts this review happened in the context of reviewer's
> statement of oversight.
> 
> > The removed tag is due to code's change (split of csi2rx part) after the last review.
> > If the code is largely changed following the instruction of another reviewer
> > after obtaining the tags, how should the tags be handled?
> 
> Drop all reviews and perform reviews on the list.
> 
> Such internal review appearing afterwards is rather a proof it you are
> adding just the tags to satisfy your process. I have no way to even
> verify whether that person performed any reasonable review or maybe just
> acked your patch.

How do you verify that for public reviews ?

> I cannot even verify that that person understands the
> reviewer's statement of oversight.
> 
> 
> ...
> 
> >>>
> >>> Changelog v11:
> >>> - no change
> >>>
> >>> Changelog v12:
> >>> - remove property "clock-noncontinuous" as VIIF switches both modes
> >>> automatically
> >>> - remove property "link-frequencies" as VIIF does not use the
> >>> information
> >>
> >> Driver does not use or hardware supports only one frequency?
> > 
> > My comment was incorrect.
> > It should be "Driver does not use the information"
> 
> Then this is not that helping. Maybe hardware supports only one frequency?

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-12-17  9:45         ` Laurent Pinchart
@ 2024-12-17 12:51           ` Krzysztof Kozlowski
  2025-01-02  9:41             ` Laurent Pinchart
  0 siblings, 1 reply; 36+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17 12:51 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: yuji2.ishikawa, mchehab, robh, krzk+dt, conor+dt, sakari.ailus,
	hverkuil-cisco, nobuhiro1.iwamatsu, linux-media, linux-kernel,
	linux-arm-kernel, devicetree

On 17/12/2024 10:45, Laurent Pinchart wrote:
> On Tue, Dec 17, 2024 at 06:43:22AM +0100, Krzysztof Kozlowski wrote:
>> On 17/12/2024 01:00, yuji2.ishikawa@toshiba.co.jp wrote:
>>> Hello Krzysztof
>>>
>>> Thank you for your review
>>>
>>>> -----Original Message-----
>>>> From: Krzysztof Kozlowski <krzk@kernel.org>
>>>> Sent: Monday, November 25, 2024 7:08 PM
>>>> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
>>>> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
>>>> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
>>>> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
>>>> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
>>>> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
>>>> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
>>>> <nobuhiro1.iwamatsu@toshiba.co.jp>
>>>> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
>>>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
>>>> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
>>>> Toshiba Visconti Video Input Interface
>>>>
>>>> On 25/11/2024 10:21, Yuji Ishikawa wrote:
>>>>> Adds the Device Tree binding documentation that allows to describe the
>>>>> Video Input Interface found in Toshiba Visconti SoCs.
>>>>>
>>>>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
>>>>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
>>>>
>>>> Why this tag stayed and other was removed? What was the reason of tag
>>>> removal?
>>>>
>>>
>>> The stayed tag is due to internal review.
>>
>> Did the internal review really happened? How is it that immediately new
>> version has internal review without any traces?
>>
>> I have doubts this review happened in the context of reviewer's
>> statement of oversight.
>>
>>> The removed tag is due to code's change (split of csi2rx part) after the last review.
>>> If the code is largely changed following the instruction of another reviewer
>>> after obtaining the tags, how should the tags be handled?
>>
>> Drop all reviews and perform reviews on the list.
>>
>> Such internal review appearing afterwards is rather a proof it you are
>> adding just the tags to satisfy your process. I have no way to even
>> verify whether that person performed any reasonable review or maybe just
>> acked your patch.
> 
> How do you verify that for public reviews ?

By quality or amount of comments. Or timing. Or reviewing cover letter
without any feedback on individual patches.

There are many, many ways. Considering how many companies were adding
fake manager-review-tags in the past (or fake SoBs), I am pretty picky
on that.

Best regards,
Krzysztof

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

* RE: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-12-17  5:44       ` Krzysztof Kozlowski
@ 2024-12-24  0:17         ` yuji2.ishikawa
  2024-12-26 16:15         ` Laurent Pinchart
  1 sibling, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2024-12-24  0:17 UTC (permalink / raw)
  To: krzk, laurent.pinchart, mchehab, robh, krzk+dt, conor+dt,
	sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree



> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Tuesday, December 17, 2024 2:45 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; laurent.pinchart@ideasonboard.com;
> mchehab@kernel.org; robh@kernel.org; krzk+dt@kernel.org;
> conor+dt@kernel.org; sakari.ailus@linux.intel.com; hverkuil-cisco@xs4all.nl;
> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> <nobuhiro1.iwamatsu@toshiba.co.jp>
> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti MIPI CSI-2 Receiver
> 
> On 17/12/2024 00:57, yuji2.ishikawa@toshiba.co.jp wrote:
> >> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> >>> Adds the Device Tree binding documentation that allows to describe
> >>> the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> >>>
> >>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> >>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>
> >>
> >> How newly added patch can have already Rb tag? Was this review
> >> really, really performed internally or you just satisfy some internal
> >> managers requirements and fake the stats?
> >>
> >
> > I added this Reviewed-by tag because the patch was reviewed internally.
> 
> 
> What issues were identified by internal review, especially in the context of
> bindings?
> 

The review was insufficient. We discussed the splitting of drivers, but overlooked the schema.
I should have been more careful not to add an inappropriate tag.
I apologize for not understanding the attention and respect that should be given to the Reviewed-by tag.
From now on, I will add the tag to reviews discussed in the open mailing list.

> >
> >>> ---
> >>>
> >>> Changelog v12:
> >>> - Newly add bindings for CSI2RX driver
> >>>
> >>>  .../media/toshiba,visconti5-csi2rx.yaml       | 104
> >> ++++++++++++++++++
> >>>  1 file changed, 104 insertions(+)
> >>>  create mode 100644
> >>> Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> >>> l
> >>>
> >>> diff --git
> >>> a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.y
> >>> am
> >>> l
> >>> b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.y
> >>> am
> >>> l
> >>> new file mode 100644
> >>> index 000000000000..5488072bc82a
> >>> --- /dev/null
> >>> +++
> b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2
> >>> +++ rx
> >>> +++ .yaml
> >>> @@ -0,0 +1,104 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> 1.2
> >>> +---
> >>> +$id:
> >>> +http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> >>> +
> >>> +maintainers:
> >>> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>> +
> >>> +description: |-
> >>
> >> Drop |-
> >>
> >
> > I'll drop "|-"
> >
> >>> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
> >>> + CSI-2 video  stream. Use with VIIF device. T.B.D
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    const: toshiba,visconti5-csi2rx
> >>
> >> Why this is called "RX"? Can you have a TX? I had impression that one
> cannot.
> >>
> >
> > VIIF has only MIPI CSI2 receiver (CSI2RX). There's no TX for it.
> 
> So this device cannot be anything else? Then drop rx.
> 

I'll drop "rx". The new compatible string will be "toshiba,visconti5-csi2".
I'll also update the name of bindings document file.

> > Visconti also has VOIF (Video Output Interface) hardware which has MIPI
> CSI2 (not DSI) transmitter (CSI2TX).
> 
> Or this can be something else? Confusing.
> 

VOIF has only TX. There's no RX for it.
I just wanted to inform you that there is a node with similar name and function.
Please forget about it.

> 
> 
> Best regards,
> Krzysztof

Best regards,
Yuji Ishikawa

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

* RE: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-12-17  5:43       ` Krzysztof Kozlowski
  2024-12-17  9:45         ` Laurent Pinchart
@ 2024-12-24  0:17         ` yuji2.ishikawa
  1 sibling, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2024-12-24  0:17 UTC (permalink / raw)
  To: krzk, laurent.pinchart, mchehab, robh, krzk+dt, conor+dt,
	sakari.ailus, hverkuil-cisco, nobuhiro1.iwamatsu
  Cc: linux-media, linux-kernel, linux-arm-kernel, devicetree



> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Tuesday, December 17, 2024 2:43 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; laurent.pinchart@ideasonboard.com;
> mchehab@kernel.org; robh@kernel.org; krzk+dt@kernel.org;
> conor+dt@kernel.org; sakari.ailus@linux.intel.com; hverkuil-cisco@xs4all.nl;
> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> <nobuhiro1.iwamatsu@toshiba.co.jp>
> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti Video Input Interface
> 
> On 17/12/2024 01:00, yuji2.ishikawa@toshiba.co.jp wrote:
> > Hello Krzysztof
> >
> > Thank you for your review
> >
> >> -----Original Message-----
> >> From: Krzysztof Kozlowski <krzk@kernel.org>
> >> Sent: Monday, November 25, 2024 7:08 PM
> >> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> >> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
> >> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
> >> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof
> >> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>;
> >> Sakari Ailus <sakari.ailus@linux.intel.com>; Hans Verkuil
> >> <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC□DI
> T○OST)
> >> <nobuhiro1.iwamatsu@toshiba.co.jp>
> >> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> >> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> >> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti:
> >> Add Toshiba Visconti Video Input Interface
> >>
> >> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> >>> Adds the Device Tree binding documentation that allows to describe
> >>> the Video Input Interface found in Toshiba Visconti SoCs.
> >>>
> >>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> >>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>
> >> Why this tag stayed and other was removed? What was the reason of tag
> >> removal?
> >>
> >
> > The stayed tag is due to internal review.
> 
> Did the internal review really happened? How is it that immediately new version
> has internal review without any traces?
> 
> I have doubts this review happened in the context of reviewer's statement of
> oversight.
> 
> 
> > The removed tag is due to code's change (split of csi2rx part) after the last
> review.
> > If the code is largely changed following the instruction of another
> > reviewer after obtaining the tags, how should the tags be handled?
> 
> Drop all reviews and perform reviews on the list.
> 
> Such internal review appearing afterwards is rather a proof it you are adding
> just the tags to satisfy your process. I have no way to even verify whether that
> person performed any reasonable review or maybe just acked your patch. I
> cannot even verify that that person understands the reviewer's statement of
> oversight.
> 

I understand the importance and usage of the Reviewed-by tag.
We will continue to conduct internal reviews, but from now on, I will add the tag to reviews discussed in the open mailing list.

> 
> ...
> 
> >>>
> >>> Changelog v11:
> >>> - no change
> >>>
> >>> Changelog v12:
> >>> - remove property "clock-noncontinuous" as VIIF switches both modes
> >>> automatically
> >>> - remove property "link-frequencies" as VIIF does not use the
> >>> information
> >>
> >> Driver does not use or hardware supports only one frequency?
> >>
> >
> > My comment was incorrect.
> > It should be "Driver does not use the information"
> 
> Then this is not that helping. Maybe hardware supports only one frequency?
> 

The reason for the removal is the hardware PLL is configured using information from the sensor's V4L2_CID_PIXEL_RATE control.

> 
> Best regards,
> Krzysztof

Best regards,
Yuji Ishikawa

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

* Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-12-17  5:44       ` Krzysztof Kozlowski
  2024-12-24  0:17         ` yuji2.ishikawa
@ 2024-12-26 16:15         ` Laurent Pinchart
  1 sibling, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2024-12-26 16:15 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: yuji2.ishikawa, mchehab, robh, krzk+dt, conor+dt, sakari.ailus,
	hverkuil-cisco, nobuhiro1.iwamatsu, linux-media, linux-kernel,
	linux-arm-kernel, devicetree

On Tue, Dec 17, 2024 at 06:44:58AM +0100, Krzysztof Kozlowski wrote:
> On 17/12/2024 00:57, yuji2.ishikawa@toshiba.co.jp wrote:
> >> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> >>> Adds the Device Tree binding documentation that allows to describe the
> >>> MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> >>>
> >>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> >>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>
> >> How newly added patch can have already Rb tag? Was this review really, really
> >> performed internally or you just satisfy some internal managers requirements
> >> and fake the stats?
> >>
> > 
> > I added this Reviewed-by tag because the patch was reviewed internally.
> 
> What issues were identified by internal review, especially in the
> context of bindings?
> 
> >>> ---
> >>>
> >>> Changelog v12:
> >>> - Newly add bindings for CSI2RX driver
> >>>
> >>>  .../media/toshiba,visconti5-csi2rx.yaml       | 104
> >> ++++++++++++++++++
> >>>  1 file changed, 104 insertions(+)
> >>>  create mode 100644
> >>> Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> >>>
> >>> diff --git
> >>> a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> >>> l
> >>> b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> >>> l
> >>> new file mode 100644
> >>> index 000000000000..5488072bc82a
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx
> >>> +++ .yaml
> >>> @@ -0,0 +1,104 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> >>> +---
> >>> +$id:
> >>> +http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> >>> +
> >>> +maintainers:
> >>> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>> +
> >>> +description: |-
> >>
> >> Drop |-
> >>
> > 
> > I'll drop "|-"
> > 
> >>> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
> >>> + CSI-2 video  stream. Use with VIIF device. T.B.D
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    const: toshiba,visconti5-csi2rx
> >>
> >> Why this is called "RX"? Can you have a TX? I had impression that one cannot.
> >>
> > 
> > VIIF has only MIPI CSI2 receiver (CSI2RX). There's no TX for it.
> 
> So this device cannot be anything else? Then drop rx.

It's a compatible string, it identifies the IP core. As the SoC also has
a CSI-2 transmitter (as mentioned by Ishikawa-san), it makes sense to
name the CSI-2 receiver csi2rx.

> > Visconti also has VOIF (Video Output Interface) hardware which has
> > MIPI CSI2 (not DSI) transmitter (CSI2TX).
> 
> Or this can be something else? Confusing.

In a camera capture pipeline the CSI-2 interface of the SoC is a CSI-2
receiver, but SoCs commonly have CSI-2 transmitters as well (even if
that's less common than receivers).

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
  2024-11-25 10:11   ` Krzysztof Kozlowski
@ 2025-01-02  9:29   ` Laurent Pinchart
  2025-01-20  0:10     ` yuji2.ishikawa
  1 sibling, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02  9:29 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hello Ishikawa-san,

Thank you for the patch.

On Mon, Nov 25, 2024 at 06:21:39PM +0900, Yuji Ishikawa wrote:
> Adds the Device Tree binding documentation that allows to describe
> the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> ---
> 
> Changelog v12:
> - Newly add bindings for CSI2RX driver 
> 
>  .../media/toshiba,visconti5-csi2rx.yaml       | 104 ++++++++++++++++++
>  1 file changed, 104 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> new file mode 100644
> index 000000000000..5488072bc82a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> @@ -0,0 +1,104 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> +
> +maintainers:
> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> +
> +description: |-

As Krzysztof mentioned, '|-' isn't needed. See
https://yaml-multiline.info/ for more information. The literal block
style indicator ('|') is only needed when line breaks need to be
preserved, e.g. when the description contains ASCII art.

> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI CSI-2 video
> +  stream. Use with VIIF device. T.B.D

T.B.D ?

> +
> +properties:
> +  compatible:
> +    const: toshiba,visconti5-csi2rx
> +
> +  reg:
> +    items:
> +      - description: Registers for CSI2 receiver control
> +
> +  interrupts:
> +    items:
> +      - description: CSI2 Receiver Interrupt
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    properties:
> +      port@0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description:
> +          Input port node, single endpoint describing the CSI-2 transmitter.
> +
> +        properties:
> +          endpoint:
> +            $ref: video-interfaces.yaml#

Please use a full path for the ref:

            $ref: /schemas/media/video-interfaces.yaml#

> +            unevaluatedProperties: false
> +
> +            properties:
> +              data-lanes:
> +                description: CSI2 receiver supports 1, 2, 3 or 4 data lanes

You can drop the description. The video-interfaces.yaml schema has a
more complete description, and the fact that the receiver supports
between 1 and 4 lanes is conveyed by minItems and items below.

> +                minItems: 1
> +                items:
> +                  - const: 1
> +                  - const: 2
> +                  - const: 3
> +                  - const: 4
> +            required:
> +              - data-lanes
> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description:
> +          Output port node, single endpoint describing the Visconti VIIF.
> +
> +    required:
> +      - port@0
> +      - port@1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        csi2rx@1c008000 {

Node names should describe the function of the node, not the precise
model of the device. "csi2" would be a more appropriate name.

> +            compatible = "toshiba,visconti5-csi2rx";
> +            reg = <0 0x1c008000 0 0x400>;
> +            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +                port@0 {
> +                    reg = <0>;
> +                    csi2rx_in0: endpoint {
> +                        data-lanes = <1 2>;
> +                        remote-endpoint = <&imx219_out0>;
> +                    };
> +                };
> +                port@1 {
> +                    reg = <1>;
> +                    csi2rx_out0: endpoint {
> +                        remote-endpoint = <&csi_in0>;
> +                    };
> +                };
> +            };
> +        };
> +    };

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-12-17 12:51           ` Krzysztof Kozlowski
@ 2025-01-02  9:41             ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02  9:41 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: yuji2.ishikawa, mchehab, robh, krzk+dt, conor+dt, sakari.ailus,
	hverkuil-cisco, nobuhiro1.iwamatsu, linux-media, linux-kernel,
	linux-arm-kernel, devicetree

On Tue, Dec 17, 2024 at 01:51:54PM +0100, Krzysztof Kozlowski wrote:
> On 17/12/2024 10:45, Laurent Pinchart wrote:
> > On Tue, Dec 17, 2024 at 06:43:22AM +0100, Krzysztof Kozlowski wrote:
> >> On 17/12/2024 01:00, yuji2.ishikawa@toshiba.co.jp wrote:
> >>> Hello Krzysztof
> >>>
> >>> Thank you for your review
> >>>
> >>>> -----Original Message-----
> >>>> From: Krzysztof Kozlowski <krzk@kernel.org>
> >>>> Sent: Monday, November 25, 2024 7:08 PM
> >>>> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> >>>> <yuji2.ishikawa@toshiba.co.jp>; Laurent Pinchart
> >>>> <laurent.pinchart@ideasonboard.com>; Mauro Carvalho Chehab
> >>>> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> >>>> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Sakari Ailus
> >>>> <sakari.ailus@linux.intel.com>; Hans Verkuil <hverkuil-cisco@xs4all.nl>;
> >>>> iwamatsu nobuhiro(岩松 信洋 ○DITC□DIT○OST)
> >>>> <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>>> Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> >>>> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> >>>> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
> >>>> Toshiba Visconti Video Input Interface
> >>>>
> >>>> On 25/11/2024 10:21, Yuji Ishikawa wrote:
> >>>>> Adds the Device Tree binding documentation that allows to describe the
> >>>>> Video Input Interface found in Toshiba Visconti SoCs.
> >>>>>
> >>>>> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> >>>>> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> >>>>
> >>>> Why this tag stayed and other was removed? What was the reason of tag
> >>>> removal?
> >>>>
> >>>
> >>> The stayed tag is due to internal review.
> >>
> >> Did the internal review really happened? How is it that immediately new
> >> version has internal review without any traces?
> >>
> >> I have doubts this review happened in the context of reviewer's
> >> statement of oversight.
> >>
> >>> The removed tag is due to code's change (split of csi2rx part) after the last review.
> >>> If the code is largely changed following the instruction of another reviewer
> >>> after obtaining the tags, how should the tags be handled?
> >>
> >> Drop all reviews and perform reviews on the list.
> >>
> >> Such internal review appearing afterwards is rather a proof it you are
> >> adding just the tags to satisfy your process. I have no way to even
> >> verify whether that person performed any reasonable review or maybe just
> >> acked your patch.
> > 
> > How do you verify that for public reviews ?
> 
> By quality or amount of comments. Or timing. Or reviewing cover letter
> without any feedback on individual patches.
> 
> There are many, many ways. Considering how many companies were adding
> fake manager-review-tags in the past (or fake SoBs), I am pretty picky
> on that.

On the other hand I've heard numerous complains about patches being sent
by new developers from large companies to upstream lists without first
being reviewed internally by more experienced developers. You can't ask
people to review patches internally before submitting them upstream and
at the same time complain about R-b tags coming from internal reviews.

The value of a R-b tag, regardless of whether or not it comes from an
internal review, ultimately depends on the trust you have on the
reviewer. You can take that into account to decide when you consider a
patch to be ready to be merged, or to skip reviewing it if enough
reviewers you trust have looked at it first.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2024-11-25  9:21 ` [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
  2024-11-25 10:07   ` Krzysztof Kozlowski
@ 2025-01-02  9:56   ` Laurent Pinchart
  2025-01-20  0:13     ` yuji2.ishikawa
  1 sibling, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02  9:56 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hi Ishikawa-san,

Thank you for the patch.

On Mon, Nov 25, 2024 at 06:21:40PM +0900, Yuji Ishikawa wrote:
> Adds the Device Tree binding documentation that allows to describe
> the Video Input Interface found in Toshiba Visconti SoCs.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> ---
> Changelog v2:
> - no change
> 
> Changelog v3:
> - no change
> 
> Changelog v4:
> - fix style problems at the v3 patch
> - remove "index" member
> - update example
> 
> Changelog v5:
> - no change
> 
> Changelog v6:
> - add register definition of BUS-IF and MPU
> 
> Changelog v7:
> - remove trailing "bindings" from commit header message
> - remove trailing "Device Tree Bindings" from title
> - fix text wrapping of description
> - change compatible to visconti5-viif
> - explicitly define allowed properties for port::endpoint
> 
> Changelog v8:
> - Suggestion from Krzysztof Kozlowski
>   - rename bindings description file
>   - use block style array instead of inline style
>   - remove clock-lane (as it is fixed at position 0)
>   - update sample node's name
>   - use lowercase hex for literals
> - Suggestion from Laurent Pinchart
>   - update description message port::description
>   - remove port::endpoint::bus-type as it is fixed to <4>
>   - remove port::endpoint::clock-lanes from example
>   - add port::endpoint::data-lanes to required parameters list
>   - fix sequence of data-lanes: <1 2 3 4> because current driver does not support data reordering
>   - update port::endpoint::data-lanes::description
>   - remove redundant type definition for port::endpoint::data-lanes
> 
> Changelog v9:
> - place "required" after "properties"
> - dictionary ordering of properties
> 
> Changelog v10:
> - no change
> 
> Changelog v11:
> - no change
> 
> Changelog v12:
> - remove property "clock-noncontinuous" as VIIF switches both modes automatically
> - remove property "link-frequencies" as VIIF does not use the information
> - remove reg[2] and interrupts[3] which are used for CSI2RX driver
> - update example to refer csi2rx for remote-endpoint
> 
>  .../media/toshiba,visconti5-viif.yaml         | 95 +++++++++++++++++++
>  1 file changed, 95 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> new file mode 100644
> index 000000000000..ef0452a47e98
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> @@ -0,0 +1,95 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/toshiba,visconti5-viif.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Toshiba Visconti5 SoC Video Input Interface
> +
> +maintainers:
> +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> +
> +description: |-
> +  Toshiba Visconti5 SoC Video Input Interface (VIIF) receives videostream
> +  from MIPI CSI-2 receiver device, processes the stream with image signal
> +  processors (L1ISP, L2ISP), then stores pictures to main memory.
> +
> +properties:
> +  compatible:
> +    const: toshiba,visconti5-viif
> +
> +  reg:
> +    items:
> +      - description: Registers for capture control
> +      - description: Registers for bus interface unit control
> +      - description: Registers for Memory Protection Unit

I'm a bit surprised by the lack of clocks.

> +
> +  interrupts:
> +    items:
> +      - description: Sync Interrupt
> +      - description: Status (Error) Interrupt
> +      - description: L1ISP Interrupt
> +
> +  port:
> +    $ref: /schemas/graph.yaml#/$defs/port-base
> +    unevaluatedProperties: false
> +    description: CSI-2 input port, with a single endpoint connected to the CSI-2 transmitter.
> +
> +    properties:
> +      endpoint:
> +        $ref: video-interfaces.yaml#
> +        additionalProperties: false
> +
> +        properties:
> +          data-lanes:
> +            description: VIIF supports 1, 2, 3 or 4 data lanes
> +            minItems: 1
> +            items:
> +              - const: 1
> +              - const: 2
> +              - const: 3
> +              - const: 4

Now that the CSI-2 receiver is modeled as a separate DT node, I don't
think data-lanes is applicable anymore. The interface between the CSI-2
receiver and the VIIF isn't a CSI-2 bus.

I think you can simplify the bindings by switching from port-base to
port, as you don't need to specify additional properties for the
endpoint:

  port:
    $ref: /schemas/graph.yaml#/$defs/port
    description:
      CSI-2 input port, with a single endpoint connected to the CSI-2
      transmitter.

Please test this though (by running the DT bindings checks).

> +
> +          remote-endpoint: true
> +
> +        required:
> +          - data-lanes
> +          - remote-endpoint
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - port
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        video@1c000000 {
> +            compatible = "toshiba,visconti5-viif";
> +            reg = <0 0x1c000000 0 0x6000>,
> +                  <0 0x1c00e000 0 0x1000>,
> +                  <0 0x2417a000 0 0x1000>;
> +            interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
> +                         <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
> +                         <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
> +
> +            port {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                csi_in0: endpoint {
> +                    data-lanes = <1 2>;
> +                    remote-endpoint = <&csi2rx_out0>;
> +                };
> +            };
> +        };
> +    };

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2024-11-25  9:21 ` [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
@ 2025-01-02 13:08   ` Laurent Pinchart
  2025-01-20  0:21     ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02 13:08 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hello Ishikawa-san,

Thank you for the patch.

On Mon, Nov 25, 2024 at 06:21:42PM +0900, Yuji Ishikawa wrote:
> Add support to MIPI CSI-2 Receiver on Toshiba Visconti ARM SoCs.
> This driver is used with Visconti Video Input Interface driver.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> ---
> Changelog v12:
> - Separate CSI2RX driver and made it independent driver
> - viif_csi2rx subdevice driver (in v11 patch) was removed.
> - dictionary order at Kconfig and Makefile
> 
>  drivers/media/platform/Kconfig                |   1 +
>  drivers/media/platform/Makefile               |   1 +
>  drivers/media/platform/toshiba/Kconfig        |   6 +
>  drivers/media/platform/toshiba/Makefile       |   2 +
>  .../media/platform/toshiba/visconti/Kconfig   |  16 +
>  .../media/platform/toshiba/visconti/Makefile  |   8 +
>  .../platform/toshiba/visconti/csi2rx_drv.c    | 791 ++++++++++++++++++
>  7 files changed, 825 insertions(+)
>  create mode 100644 drivers/media/platform/toshiba/Kconfig
>  create mode 100644 drivers/media/platform/toshiba/Makefile
>  create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
>  create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
>  create mode 100644 drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> 
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 85d2627776b6..761b15b07b90 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -86,6 +86,7 @@ source "drivers/media/platform/samsung/Kconfig"
>  source "drivers/media/platform/st/Kconfig"
>  source "drivers/media/platform/sunxi/Kconfig"
>  source "drivers/media/platform/ti/Kconfig"
> +source "drivers/media/platform/toshiba/Kconfig"
>  source "drivers/media/platform/verisilicon/Kconfig"
>  source "drivers/media/platform/via/Kconfig"
>  source "drivers/media/platform/xilinx/Kconfig"
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index ace4e34483dd..917145fe5171 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -29,6 +29,7 @@ obj-y += samsung/
>  obj-y += st/
>  obj-y += sunxi/
>  obj-y += ti/
> +obj-y += toshiba/
>  obj-y += verisilicon/
>  obj-y += via/
>  obj-y += xilinx/
> diff --git a/drivers/media/platform/toshiba/Kconfig b/drivers/media/platform/toshiba/Kconfig
> new file mode 100644
> index 000000000000..f02983f4fc97
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/Kconfig
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +comment "Toshiba media platform drivers"
> +
> +source "drivers/media/platform/toshiba/visconti/Kconfig"
> +
> diff --git a/drivers/media/platform/toshiba/Makefile b/drivers/media/platform/toshiba/Makefile
> new file mode 100644
> index 000000000000..2bce85ef3b48
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0-only

A blank line would be nice here.

> +obj-y += visconti/
> diff --git a/drivers/media/platform/toshiba/visconti/Kconfig b/drivers/media/platform/toshiba/visconti/Kconfig
> new file mode 100644
> index 000000000000..e5c92d598f8b
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0-only

A blank line would be nice here too.

> +config VIDEO_VISCONTI_CSI2RX
> +	tristate "Visconti MIPI CSI-2 Receiver driver"
> +	depends on V4L_PLATFORM_DRIVERS
> +	depends on VIDEO_DEV && OF
> +	depends on ARCH_VISCONTI || COMPILE_TEST
> +	select MEDIA_CONTROLLER
> +	select VIDEO_V4L2_SUBDEV_API
> +	select V4L2_FWNODE
> +	help
> +	  Support for Toshiba Visconti MIPI CSI-2 receiver,
> +	  which is used with Visconti Camera Interface driver.
> +
> +	  This driver yields 1 subdevice node for a hardware instance.
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called visconti-csi2rx.
> diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
> new file mode 100644
> index 000000000000..62a029376134
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile for the Visconti video input device driver
> +#
> +
> +visconti-csi2rx-objs = csi2rx_drv.o
> +
> +obj-$(CONFIG_VIDEO_VISCONTI_CSI2RX) += visconti-csi2rx.o
> diff --git a/drivers/media/platform/toshiba/visconti/csi2rx_drv.c b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> new file mode 100644
> index 000000000000..94567963872a
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> @@ -0,0 +1,791 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/* Toshiba Visconti Video Capture Support

/*
 * Toshiba Visconti Video Capture Support
 *

> + *
> + * (C) Copyright 2024 TOSHIBA CORPORATION
> + * (C) Copyright 2024 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>

You don't need those two headers. You however need to include

- linux/device.h (for devm_kzalloc)
- linux/property.h (for the fwnode_* API)

> +#include <linux/platform_device.h>
> +
> +#include <media/mipi-csi2.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +/* CSI2HOST register space */
> +#define REG_CSI2RX_NLANES	 0x4
> +#define REG_CSI2RX_RESETN	 0x8
> +#define REG_CSI2RX_INT_ST_MAIN	 0xc
> +#define REG_CSI2RX_DATA_IDS_1	 0x10
> +#define REG_CSI2RX_DATA_IDS_2	 0x14
> +#define REG_CSI2RX_PHY_SHUTDOWNZ 0x40
> +#define REG_CSI2RX_PHY_RSTZ	 0x44
> +
> +/* access to dphy external registers */

/* Access to dphy external registers */

Same in other comments below.

> +#define REG_CSI2RX_PHY_TESTCTRL0 0x50
> +#define BIT_TESTCTRL0_CLK_0	 0
> +#define BIT_TESTCTRL0_CLK_1	 BIT(1)
> +
> +#define REG_CSI2RX_PHY_TESTCTRL1 0x54
> +#define BIT_TESTCTRL1_ADDR	 BIT(16)
> +#define MASK_TESTCTRL1_DIN	 0xff
> +#define MASK_TESTCTRL1_DOUT	 0xff00
> +
> +#define REG_CSI2RX_INT_ST_PHY_FATAL  0xe0
> +#define REG_CSI2RX_INT_MSK_PHY_FATAL 0xe4
> +#define MASK_PHY_FATAL_ALL	     0x0000000f
> +
> +#define REG_CSI2RX_INT_ST_PKT_FATAL  0xf0
> +#define REG_CSI2RX_INT_MSK_PKT_FATAL 0xf4
> +#define MASK_PKT_FATAL_ALL	     0x0001000f
> +
> +#define REG_CSI2RX_INT_ST_FRAME_FATAL  0x100
> +#define REG_CSI2RX_INT_MSK_FRAME_FATAL 0x104
> +#define MASK_FRAME_FATAL_ALL	       0x000f0f0f
> +
> +#define REG_CSI2RX_INT_ST_PHY  0x110
> +#define REG_CSI2RX_INT_MSK_PHY 0x114
> +#define MASK_PHY_ERROR_ALL     0x000f000f
> +
> +#define REG_CSI2RX_INT_ST_PKT  0x120
> +#define REG_CSI2RX_INT_MSK_PKT 0x124
> +#define MASK_PKT_ERROR_ALL     0x000f000f
> +
> +#define REG_CSI2RX_INT_ST_LINE	0x130
> +#define REG_CSI2RX_INT_MSK_LINE 0x134
> +#define MASK_LINE_ERROR_ALL	0x00ff00ff
> +
> +/* DPHY register space */
> +enum dphy_testcode {
> +	DIG_TESTCODE_EXT = 0,
> +	DIG_SYS_0 = 0x001,
> +	DIG_SYS_1 = 0x002,
> +	DIG_SYS_3 = 0x004,
> +	DIG_SYS_7 = 0x008,
> +	DIG_RX_STARTUP_OVR_2 = 0x0e2,
> +	DIG_RX_STARTUP_OVR_3 = 0x0e3,
> +	DIG_RX_STARTUP_OVR_4 = 0x0e4,
> +	DIG_RX_STARTUP_OVR_5 = 0x0e5,
> +	DIG_CB_2 = 0x1ac,
> +	DIG_TERM_CAL_0 = 0x220,
> +	DIG_TERM_CAL_1 = 0x221,
> +	DIG_TERM_CAL_2 = 0x222,
> +	DIG_CLKLANE_LANE_6 = 0x307,
> +	DIG_CLKLANE_OFFSET_CAL_0 = 0x39d,
> +	DIG_LANE0_OFFSET_CAL_0 = 0x59f,
> +	DIG_LANE0_DDL_0 = 0x5e0,
> +	DIG_LANE1_OFFSET_CAL_0 = 0x79f,
> +	DIG_LANE1_DDL_0 = 0x7e0,
> +	DIG_LANE2_OFFSET_CAL_0 = 0x99f,
> +	DIG_LANE2_DDL_0 = 0x9e0,
> +	DIG_LANE3_OFFSET_CAL_0 = 0xb9f,
> +	DIG_LANE3_DDL_0 = 0xbe0,
> +};
> +
> +#define SYS_0_HSFREQRANGE_OVR  BIT(5)
> +#define SYS_3_NO_REXT	       BIT(4)
> +#define SYS_7_RESERVED	       FIELD_PREP(0x1f, 0x0c)
> +#define SYS_7_DESKEW_POL       BIT(5)
> +#define STARTUP_OVR_4_CNTVAL   FIELD_PREP(0x70, 0x01)
> +#define STARTUP_OVR_4_DDL_EN   BIT(0)
> +#define STARTUP_OVR_5_BYPASS   BIT(0)
> +#define CB_2_LPRX_BIAS	       BIT(6)
> +#define CB_2_RESERVED	       FIELD_PREP(0x3f, 0x0b)
> +#define CLKLANE_RXHS_PULL_LONG BIT(7)
> +
> +/* bit mask for calibration result registers */
> +#define MASK_TERM_CAL_ERR  0
> +#define MASK_TERM_CAL_DONE BIT(7)
> +#define MASK_CLK_CAL_ERR   BIT(4)
> +#define MASK_CLK_CAL_DONE  BIT(0)
> +#define MASK_CAL_ERR	   BIT(2)
> +#define MASK_CAL_DONE	   BIT(1)
> +#define MASK_DDL_ERR	   BIT(1)
> +#define MASK_DDL_DONE	   BIT(2)
> +
> +#define VISCONTI_CSI2RX_ERROR_MONITORS_NUM 8
> +
> +/**
> + * struct visconti_csi2rx_line_err_target
> + *
> + * Virtual Channel and Data Type pair for CSI2RX line error monitor
> + *
> + * When 0 is set to dt, line error detection is disabled.
> + *
> + * @vc: Virtual Channel to monitor; Range 0..3
> + * @dt: Data Type to monitor; Range 0, 0x10..0x3f
> + */
> +struct visconti_csi2rx_line_err_target {
> +	u32 vc[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
> +	u32 dt[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
> +};
> +
> +#define CSI2RX_MIN_DATA_RATE 80U
> +#define CSI2RX_MAX_DATA_RATE 1500U
> +
> +#define VISCONTI_CSI2RX_PAD_SINK 0
> +#define VISCONTI_CSI2RX_PAD_SRC	 1
> +#define VISCONTI_CSI2RX_PAD_NUM	 2
> +
> +#define VISCONTI_CSI2RX_DEF_WIDTH  1920
> +#define VISCONTI_CSI2RX_DEF_HEIGHT 1080
> +#define VISCONTI_CSI2RX_MIN_WIDTH  640
> +#define VISCONTI_CSI2RX_MAX_WIDTH  3840
> +#define VISCONTI_CSI2RX_MIN_HEIGHT 480
> +#define VISCONTI_CSI2RX_MAX_HEIGHT 2160
> +
> +struct visconti_csi2rx {
> +	struct device *dev;
> +	void __iomem *base;
> +
> +	struct v4l2_subdev subdev;
> +	struct media_pad pads[VISCONTI_CSI2RX_PAD_NUM];
> +	struct v4l2_async_notifier notifier;
> +	struct v4l2_subdev *remote;
> +	unsigned int remote_pad;
> +
> +	unsigned int lanes;
> +
> +	unsigned int irq;
> +};
> +
> +static inline struct visconti_csi2rx *notifier_to_csi2(struct v4l2_async_notifier *n)
> +{
> +	return container_of(n, struct visconti_csi2rx, notifier);
> +}
> +
> +static inline struct visconti_csi2rx *sd_to_csi2(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct visconti_csi2rx, subdev);
> +}
> +
> +static inline void visconti_csi2rx_write(struct visconti_csi2rx *priv, u32 regid, u32 val)

The media subsystem tries to limit line lengths to 80 columns, when it
doesn't hinder readability. For instance here you could write

static inline void visconti_csi2rx_write(struct visconti_csi2rx *priv,
					 u32 regid, u32 val)

If lines are just a few characters over 80 columns the need to break
them is less than if they approach 100 columns. It's a "soft limit"
policy to try and maximize readability.

> +{
> +	writel(val, priv->base + regid);
> +}
> +
> +static inline u32 visconti_csi2rx_read(struct visconti_csi2rx *priv, u32 regid)
> +{
> +	return readl(priv->base + regid);
> +}
> +
> +static inline void tick_testclk(struct visconti_csi2rx *priv)

Don't inline this or the next function, compilers are smart enough to
decide by themselves these days.

> +{
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
> +}
> +
> +static inline void set_dphy_addr(struct visconti_csi2rx *priv, u32 test_mode)
> +{
> +	/* select testcode Ex space with top 4bits of test_mode */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> +			      BIT_TESTCTRL1_ADDR | DIG_TESTCODE_EXT);
> +	tick_testclk(priv);

If writing to REG_CSI2RX_PHY_TESTCTRL1 always needs to be followed by a
call to tick_testclk(), I would create a visconti_csi2rx_dphy_write()
function:

static void visconti_csi2rx_dphy_write(struct visconti_csi2rx *priv, u32 data)
{
	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, data);
	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
}

> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, FIELD_GET(0xf00, test_mode));

And here

	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
			      FIELD_GET(0xf00, test_mode));

There are many other places below that go over 80 columns.

> +	tick_testclk(priv);
> +
> +	/* set bottom 8bit of test_mode */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> +			      BIT_TESTCTRL1_ADDR | FIELD_GET(0xff, test_mode));
> +	tick_testclk(priv);
> +}
> +
> +static void write_dphy_param(struct visconti_csi2rx *priv, u32 test_mode, u8 test_in)
> +{
> +	set_dphy_addr(priv, test_mode);
> +
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, (u32)test_in);

Is the (u8) explicit cast needed ?

> +	tick_testclk(priv);
> +}
> +
> +struct csi2rx_dphy_hs_info {
> +	u32 rate;
> +	u32 hsfreqrange;
> +	u32 osc_freq_target;
> +};
> +
> +static const struct csi2rx_dphy_hs_info dphy_hs_info[] = {
> +	{ 80, 0x0, 0x1cc },   { 85, 0x10, 0x1cc },   { 95, 0x20, 0x1cc },   { 105, 0x30, 0x1cc },
> +	{ 115, 0x1, 0x1cc },  { 125, 0x11, 0x1cc },  { 135, 0x21, 0x1cc },  { 145, 0x31, 0x1cc },
> +	{ 155, 0x2, 0x1cc },  { 165, 0x12, 0x1cc },  { 175, 0x22, 0x1cc },  { 185, 0x32, 0x1cc },
> +	{ 198, 0x3, 0x1cc },  { 213, 0x13, 0x1cc },  { 228, 0x23, 0x1cc },  { 243, 0x33, 0x1cc },
> +	{ 263, 0x4, 0x1cc },  { 288, 0x14, 0x1cc },  { 313, 0x25, 0x1cc },  { 338, 0x35, 0x1cc },
> +	{ 375, 0x5, 0x1cc },  { 425, 0x16, 0x1cc },  { 475, 0x26, 0x1cc },  { 525, 0x37, 0x1cc },
> +	{ 575, 0x7, 0x1cc },  { 625, 0x18, 0x1cc },  { 675, 0x28, 0x1cc },  { 725, 0x39, 0x1cc },
> +	{ 775, 0x9, 0x1cc },  { 825, 0x19, 0x1cc },  { 875, 0x29, 0x1cc },  { 925, 0x3a, 0x1cc },
> +	{ 975, 0xa, 0x1cc },  { 1025, 0x1a, 0x1cc }, { 1075, 0x2a, 0x1cc }, { 1125, 0x3b, 0x1cc },
> +	{ 1175, 0xb, 0x1cc }, { 1225, 0x1b, 0x1cc }, { 1275, 0x2b, 0x1cc }, { 1325, 0x3c, 0x1cc },
> +	{ 1375, 0xc, 0x1cc }, { 1425, 0x1c, 0x1cc }, { 1475, 0x2c, 0x1cc }

osc_freq_target seems to always be 0x1cc, does it have to be stored in
this table ?

> +};
> +
> +static void get_dphy_hs_transfer_info(u32 dphy_rate, u32 *hsfreqrange, u32 *osc_freq_target)
> +{
> +	unsigned int i;
> +
> +	for (i = 1; i < ARRAY_SIZE(dphy_hs_info); i++) {
> +		if (dphy_rate < dphy_hs_info[i].rate) {
> +			*hsfreqrange = dphy_hs_info[i - 1].hsfreqrange;
> +			*osc_freq_target = dphy_hs_info[i - 1].osc_freq_target;
> +			return;
> +		}
> +	}
> +
> +	/* not found; return the largest entry */
> +	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].hsfreqrange;
> +	*osc_freq_target = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].osc_freq_target;
> +}
> +
> +static void visconti_csi2rx_set_dphy_rate(struct visconti_csi2rx *priv, u32 dphy_rate)
> +{
> +	u32 hsfreqrange, osc_freq_target;
> +
> +	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange, &osc_freq_target);
> +
> +	write_dphy_param(priv, DIG_SYS_1, (u8)hsfreqrange);

I don't think the explicit cast is needed here either.

> +	write_dphy_param(priv, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
> +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_5, STARTUP_OVR_5_BYPASS);
> +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL);
> +	write_dphy_param(priv, DIG_CB_2, CB_2_LPRX_BIAS | CB_2_RESERVED);
> +	write_dphy_param(priv, DIG_SYS_7, SYS_7_DESKEW_POL | SYS_7_RESERVED);
> +	write_dphy_param(priv, DIG_CLKLANE_LANE_6, CLKLANE_RXHS_PULL_LONG);
> +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_2, FIELD_GET(0xff, osc_freq_target));
> +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_3, FIELD_GET(0xf00, osc_freq_target));
> +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL | STARTUP_OVR_4_DDL_EN);
> +}
> +
> +static int visconti_csi2rx_initialize(struct visconti_csi2rx *priv, u32 num_lane, u32 dphy_rate,
> +				      const struct visconti_csi2rx_line_err_target *err_target)
> +{
> +	u32 val;
> +
> +	if (dphy_rate < CSI2RX_MIN_DATA_RATE || dphy_rate > CSI2RX_MAX_DATA_RATE) {
> +		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", dphy_rate);
> +		return -ERANGE;
> +	}
> +
> +	/* 1st phase of initialization */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 1);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> +	ndelay(15U);

I don't mind much, but the U suffix here and in many other places seems
unneeded.

> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 0);
> +
> +	/* Configure D-PHY frequency range */
> +	visconti_csi2rx_set_dphy_rate(priv, dphy_rate);
> +
> +	/* 2nd phase of initialization */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_NLANES, (num_lane - 1U));

No need for the inner parentheses.

> +	ndelay(5U);
> +
> +	/* Release D-PHY from Reset */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
> +	ndelay(5U);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 1);
> +
> +	/* configuration of line error target */
> +	val = (err_target->vc[3] << 30U) | (err_target->dt[3] << 24U) | (err_target->vc[2] << 22U) |
> +	      (err_target->dt[2] << 16U) | (err_target->vc[1] << 14U) | (err_target->dt[1] << 8U) |
> +	      (err_target->vc[0] << 6U) | (err_target->dt[0]);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_1, val);
> +	val = (err_target->vc[7] << 30U) | (err_target->dt[7] << 24U) | (err_target->vc[6] << 22U) |
> +	      (err_target->dt[6] << 16U) | (err_target->vc[5] << 14U) | (err_target->dt[5] << 8U) |
> +	      (err_target->vc[4] << 6U) | (err_target->dt[4]);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_2, val);
> +
> +	/* configuration of mask */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, MASK_PHY_FATAL_ALL);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, MASK_PKT_FATAL_ALL);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, MASK_FRAME_FATAL_ALL);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY, MASK_PHY_ERROR_ALL);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT, MASK_PKT_ERROR_ALL);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE, MASK_LINE_ERROR_ALL);
> +
> +	return 0;
> +}
> +
> +struct visconti_csi2rx_format {
> +	u32 code;
> +	unsigned int bpp;
> +};
> +
> +static const struct visconti_csi2rx_format visconti_csi2rx_formats[] = {
> +	{ .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24 },
> +	{ .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 },
> +	{ .code = MEDIA_BUS_FMT_UYVY10_1X20, .bpp = 20 },
> +	{ .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16 },
> +	{ .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8 },
> +	{ .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8 },
> +	{ .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8 },
> +	{ .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8 },
> +	{ .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10 },
> +	{ .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10 },
> +	{ .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10 },
> +	{ .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10 },
> +	{ .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12 },
> +	{ .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12 },
> +	{ .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12 },
> +	{ .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12 },
> +	{ .code = MEDIA_BUS_FMT_SBGGR14_1X14, .bpp = 14 },
> +	{ .code = MEDIA_BUS_FMT_SGBRG14_1X14, .bpp = 14 },
> +	{ .code = MEDIA_BUS_FMT_SGRBG14_1X14, .bpp = 14 },
> +	{ .code = MEDIA_BUS_FMT_SRGGB14_1X14, .bpp = 14 },
> +};
> +
> +static const struct visconti_csi2rx_format *fmt_for_mbus_code(unsigned int mbus_code)
> +{
> +	int i;

unsigned int

> +
> +	for (i = 0; ARRAY_SIZE(visconti_csi2rx_formats); i++)
> +		if (visconti_csi2rx_formats[i].code == mbus_code)
> +			return &visconti_csi2rx_formats[i];

Please use curly braces for the 'for' statement.

No return when the look doesn't find a match ?

> +}
> +
> +static unsigned int bpp_for_mbus_code(unsigned int mbus_code)
> +{
> +	const struct visconti_csi2rx_format *fmt = fmt_for_mbus_code(mbus_code);
> +
> +	return fmt ? fmt->bpp : 0;
> +}
> +
> +static int64_t get_pixelclock(struct v4l2_subdev *sd)
> +{
> +	struct v4l2_ctrl *ctrl;
> +
> +	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
> +	if (!ctrl)
> +		return -EINVAL;
> +
> +	return v4l2_ctrl_g_ctrl_int64(ctrl);
> +}
> +
> +static const struct visconti_csi2rx_line_err_target err_target_vc0_alldt = {
> +	/* select VC=0 */
> +	/* select all supported DataTypes */
> +	.dt = {
> +		MIPI_CSI2_DT_RGB565,
> +		MIPI_CSI2_DT_YUV422_8B,
> +		MIPI_CSI2_DT_YUV422_10B,
> +		MIPI_CSI2_DT_RGB888,
> +		MIPI_CSI2_DT_RAW8,
> +		MIPI_CSI2_DT_RAW10,
> +		MIPI_CSI2_DT_RAW12,
> +		MIPI_CSI2_DT_RAW14,
> +	}
> +};
> +
> +static int visconti_csi2rx_start(struct visconti_csi2rx *priv, struct v4l2_subdev_state *state)
> +{
> +	struct v4l2_mbus_framefmt *sink_fmt;

const

> +	int cur_bpp, dphy_rate;
> +	s64 pixelclock;
> +
> +	/* get bpp for current format */
> +	sink_fmt = v4l2_subdev_state_get_format(state, VISCONTI_CSI2RX_PAD_SINK);
> +	cur_bpp = bpp_for_mbus_code(sink_fmt->code);

	bpp = fmt_for_mbus_code(sink_fmt->code)->bpp;

and drop the bpp_for_mbus_code() function.

> +
> +	/* get pixel clock */
> +	pixelclock = get_pixelclock(priv->remote);

Use v4l2_get_link_freq() and drop the get_pixelclock() function.

> +	if (pixelclock < 0)
> +		return -EINVAL;
> +
> +	dphy_rate = div64_u64((u64)pixelclock * (u32)cur_bpp, priv->lanes * 1000000);
> +
> +	ndelay(15U);
> +
> +	return visconti_csi2rx_initialize(priv, priv->lanes, dphy_rate, &err_target_vc0_alldt);
> +}
> +
> +static void visconti_csi2rx_stop(struct visconti_csi2rx *priv)
> +{
> +	/* disable interrupt -> make sure registers cleared -> wait for current handlers finish */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE, 0);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY_FATAL);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT_FATAL);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT);
> +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_LINE);
> +	synchronize_irq(priv->irq);
> +
> +	/* shutdown hardware */
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> +	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 0);
> +}
> +
> +static int visconti_csi2rx_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
> +					  u32 pad, u64 streams_mask)
> +{
> +	struct visconti_csi2rx *priv = sd_to_csi2(sd);
> +	struct v4l2_subdev *remote_sd;
> +	struct media_pad *remote_pad;
> +	int ret;
> +
> +	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK]);
> +	if (!remote_pad)
> +		return -ENODEV;

Can't you use priv->remote and priv->remote_pad in this function instead
of getting the remote pad dynamically ? Same in
visconti_csi2rx_disable_streams().

> +	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
> +
> +	/* enabling: turn on CSI2RX -> turn on sensor */
> +	ret = visconti_csi2rx_start(priv, state);
> +	if (ret)
> +		return ret;
> +
> +	/* currently CSI2RX supports only stream0 in source pad */
> +	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, BIT(0));
> +	if (ret) {
> +		visconti_csi2rx_stop(priv);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int visconti_csi2rx_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
> +					   u32 pad, u64 streams_mask)
> +{
> +	struct visconti_csi2rx *priv = sd_to_csi2(sd);
> +	struct v4l2_subdev *remote_sd;
> +	struct media_pad *remote_pad;
> +
> +	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK]);
> +	if (!remote_pad)
> +		return -ENODEV;
> +	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
> +
> +	/* disabling: turn off sensor -> turn off CSI2RX */
> +	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, BIT(0));
> +	visconti_csi2rx_stop(priv);
> +
> +	return 0;
> +}
> +
> +static int visconti_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->pad == VISCONTI_CSI2RX_PAD_SRC) {
> +		const struct v4l2_mbus_framefmt *sink_fmt;
> +
> +		/* SRC pad supports exactly the same format as SINK pad */
> +		if (code->index)
> +			return -EINVAL;
> +		sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
> +		code->code = sink_fmt->code;
> +		return 0;
> +	}
> +
> +	if (code->index >= ARRAY_SIZE(visconti_csi2rx_formats))
> +		return -EINVAL;
> +	code->code = visconti_csi2rx_formats[code->index].code;
> +
> +	return 0;
> +}
> +
> +static int visconti_csi2rx_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state)
> +{
> +	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
> +
> +	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
> +	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SRC);
> +
> +	sink_fmt->width = VISCONTI_CSI2RX_DEF_WIDTH;
> +	sink_fmt->height = VISCONTI_CSI2RX_DEF_HEIGHT;
> +	sink_fmt->field = V4L2_FIELD_NONE;
> +	sink_fmt->code = visconti_csi2rx_formats[0].code;

Please also initialize the colourspace fields. V4L2_COLORSPACE_RAW,
V4L2_XFER_FUNC_NONE, V4L2_YCBCR_ENC_601 and V4L2_QUANTIZATION_FULL_RANGE
should be appropriate defaults.

> +
> +	*src_fmt = *sink_fmt;
> +
> +	return 0;
> +}
> +
> +static int visconti_csi2rx_set_pad_format(struct v4l2_subdev *sd,
> +					  struct v4l2_subdev_state *sd_state,
> +					  struct v4l2_subdev_format *fmt)
> +{
> +	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
> +
> +	/* SRC PAD has the same format as SINK PAD */
> +	if (fmt->pad == 1)

	if (fmt->pad == VISCONTI_CSI2RX_PAD_SRC)

> +		return v4l2_subdev_get_fmt(sd, sd_state, fmt);
> +
> +	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SINK);
> +
> +	*sink_fmt = fmt->format;
> +	sink_fmt->width = clamp_t(u32, fmt->format.width, VISCONTI_CSI2RX_MIN_WIDTH,
> +				  VISCONTI_CSI2RX_MAX_WIDTH);
> +	sink_fmt->height = clamp_t(u32, fmt->format.height, VISCONTI_CSI2RX_MIN_HEIGHT,
> +				   VISCONTI_CSI2RX_MAX_HEIGHT);
> +	if (!fmt_for_mbus_code(sink_fmt->code))
> +		sink_fmt->code = visconti_csi2rx_formats[0].code;
> +	fmt->format = *sink_fmt;
> +
> +	/* source pad should have the same format */
> +	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCONTI_CSI2RX_PAD_SRC);
> +	*src_fmt = *sink_fmt;
> +
> +	return 0;
> +}
> +
> +static const struct media_entity_operations visconti_csi2rx_entity_ops = {
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static const struct v4l2_subdev_video_ops visconti_csi2rx_video_ops = {
> +	.s_stream = v4l2_subdev_s_stream_helper,

As the only driver that will use this CSI-2 RX is the VIIF driver, and
that driver uses v4l2_subdev_enable_streams(), .s_stream() will never be
called. You can drop the v4l2_subdev_video_ops.

> +};
> +
> +static const struct v4l2_subdev_pad_ops visconti_csi2rx_pad_ops = {
> +	.enum_mbus_code = visconti_csi2rx_enum_mbus_code,

You also need to implement .enum_frame_size()

> +	.disable_streams = visconti_csi2rx_disable_streams,
> +	.enable_streams = visconti_csi2rx_enable_streams,
> +	.get_fmt = v4l2_subdev_get_fmt,
> +	.set_fmt = visconti_csi2rx_set_pad_format,
> +};
> +
> +static const struct v4l2_subdev_ops visconti_csi2rx_subdev_ops = {
> +	.video = &visconti_csi2rx_video_ops,
> +	.pad = &visconti_csi2rx_pad_ops,
> +};
> +
> +static const struct v4l2_subdev_internal_ops visconti_csi2rx_internal_ops = {
> +	.init_state = visconti_csi2rx_init_state,
> +};
> +
> +static int visconti_csi2rx_notify_bound(struct v4l2_async_notifier *notifier,
> +					struct v4l2_subdev *subdev,
> +					struct v4l2_async_connection *asc)
> +{
> +	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
> +	int pad;
> +
> +	pad = media_entity_get_fwnode_pad(&subdev->entity, asc->match.fwnode, MEDIA_PAD_FL_SOURCE);
> +	if (pad < 0) {
> +		dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name);
> +		return pad;
> +	}
> +
> +	priv->remote = subdev;
> +	priv->remote_pad = pad;
> +
> +	return media_create_pad_link(&subdev->entity, pad, &priv->subdev.entity, 0,
> +				     MEDIA_LNK_FL_ENABLED);

Can you have multiple sources connected to the same CSI-2 receiver ? If
not, you can make the link to the source immutable.

> +}
> +
> +static void visconti_csi2rx_notify_unbind(struct v4l2_async_notifier *notifier,
> +					  struct v4l2_subdev *subdev,
> +					  struct v4l2_async_connection *asc)
> +{
> +	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
> +
> +	priv->remote = NULL;
> +}
> +
> +static const struct v4l2_async_notifier_operations visconti_csi2rx_notify_ops = {
> +	.bound = visconti_csi2rx_notify_bound,
> +	.unbind = visconti_csi2rx_notify_unbind,
> +};
> +
> +static int visconti_csi2rx_parse_v4l2(struct visconti_csi2rx *priv,
> +				      struct v4l2_fwnode_endpoint *vep)
> +{
> +	/* Only port 0 endpoint 0 is valid. */
> +	if (vep->base.port || vep->base.id)
> +		return -ENOTCONN;

You call fwnode_graph_get_endpoint_by_id() with port and endpoint set to
0, so I think you can drop this check.

> +
> +	priv->lanes = vep->bus.mipi_csi2.num_data_lanes;
> +
> +	/* got trouble */
> +	if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
> +		dev_err(priv->dev, "Specified bus type is not supported\n");

If you only support D-PHY, then set the bus_type to V4L2_MBUS_CSI2_DPHY
instead of V4L2_MBUS_UNKNOWN in visconti_csi2rx_parse_dt().
v4l2_fwnode_endpoint_parse() will return an error if the bus type is not
D-PHY, and you can drop this check.

> +		return -EINVAL;
> +	}
> +
> +	if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) {
> +		dev_err(priv->dev, "Unsupported number of data-lanes for D-PHY: %u\n", priv->lanes);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int visconti_csi2rx_parse_dt(struct visconti_csi2rx *priv)
> +{
> +	struct v4l2_async_connection *asc;
> +	struct fwnode_handle *fwnode;
> +	struct fwnode_handle *ep;
> +	struct v4l2_fwnode_endpoint v4l2_ep = {
> +		.bus_type = V4L2_MBUS_UNKNOWN,
> +	};
> +	int ret;
> +
> +	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0);
> +	if (!ep) {
> +		dev_err(priv->dev, "Not connected to subdevice\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
> +	if (ret) {
> +		dev_err(priv->dev, "Could not parse v4l2 endpoint\n");
> +		fwnode_handle_put(ep);
> +		return -EINVAL;
> +	}
> +
> +	ret = visconti_csi2rx_parse_v4l2(priv, &v4l2_ep);

I would inline what is left of that function in here.

> +	if (ret) {
> +		fwnode_handle_put(ep);
> +		return ret;
> +	}
> +
> +	fwnode = fwnode_graph_get_remote_endpoint(ep);
> +	fwnode_handle_put(ep);
> +
> +	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
> +	priv->notifier.ops = &visconti_csi2rx_notify_ops;
> +
> +	asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, struct v4l2_async_connection);
> +	fwnode_handle_put(fwnode);
> +	if (IS_ERR(asc))
> +		return PTR_ERR(asc);
> +
> +	ret = v4l2_async_nf_register(&priv->notifier);
> +	if (ret)
> +		v4l2_async_nf_cleanup(&priv->notifier);
> +
> +	return ret;
> +}
> +
> +static irqreturn_t visconti_csi2rx_irq(int irq, void *dev_id)
> +{
> +	struct visconti_csi2rx *priv = dev_id;
> +	u32 event;
> +
> +	event = visconti_csi2rx_read(priv, REG_CSI2RX_INT_ST_MAIN);
> +	dev_err(priv->dev, "CSI2RX error 0x%x.\n", event);

Should this be at least rate-limited ?

> +
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct of_device_id visconti_csi2rx_of_table[] = {
> +	{
> +		.compatible = "toshiba,visconti5-csi2rx",
> +	},
> +	{},

	{ /* Sentinel */ },

is customary. You can also drop the trailing comma, as there should
never be any entry after this one.

> +};
> +
> +static int visconti_csi2rx_probe(struct platform_device *pdev)
> +{
> +	struct visconti_csi2rx *priv;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = &pdev->dev;
> +
> +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(priv->base)) {
> +		dev_err(priv->dev, "Failed to get registers\n");

devm_platform_ioremap_resource() prints an error message already, you
can drop this one.

> +		return PTR_ERR(priv->base);
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;

Here, on the other hand, an error message would be useful. You can use
dev_err_probe():

		return dev_err_probe(priv->dev, irq, "Failed to get IRQ\n");

> +	ret = devm_request_irq(&pdev->dev, irq, visconti_csi2rx_irq, 0, KBUILD_MODNAME, priv);
> +	priv->irq = irq;
> +	if (ret) {
> +		dev_err(priv->dev, "request irq failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	ret = visconti_csi2rx_parse_dt(priv); /*this function does v4l2_async_nf_register */
> +	if (ret)
> +		return ret;
> +
> +	priv->subdev.owner = THIS_MODULE;

Not needed, this is handled by v4l2_async_register_subdev()

> +	priv->subdev.dev = &pdev->dev;
> +	v4l2_subdev_init(&priv->subdev, &visconti_csi2rx_subdev_ops);
> +	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
> +	snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", KBUILD_MODNAME,
> +		 dev_name(&pdev->dev));
> +
> +	priv->subdev.internal_ops = &visconti_csi2rx_internal_ops;
> +	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;

MEDIA_ENT_F_VID_IF_BRIDGE seems more appropriate.

> +	priv->subdev.entity.ops = &visconti_csi2rx_entity_ops;
> +
> +	priv->pads[VISCONTI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	priv->pads[VISCONTI_CSI2RX_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
> +
> +	ret = media_entity_pads_init(&priv->subdev.entity, VISCONTI_CSI2RX_PAD_NUM, priv->pads);

	ret = media_entity_pads_init(&priv->subdev.entity, ARRAY_SIZE(priv->pads), 
				     priv->pads);


> +	if (ret)
> +		goto err_cleanup_async;
> +
> +	ret = v4l2_subdev_init_finalize(&priv->subdev);
> +	if (ret)
> +		goto err_cleanup_media_entity;
> +
> +	ret = v4l2_async_register_subdev(&priv->subdev);
> +	if (ret < 0)
> +		goto err_cleanup_subdev_state;
> +
> +	return 0;
> +
> +err_cleanup_subdev_state:
> +	v4l2_subdev_cleanup(&priv->subdev);
> +
> +err_cleanup_media_entity:
> +	media_entity_cleanup(&priv->subdev.entity);
> +
> +err_cleanup_async:
> +	v4l2_async_nf_unregister(&priv->notifier);
> +	v4l2_async_nf_cleanup(&priv->notifier);
> +
> +	return ret;
> +}
> +
> +static void visconti_csi2rx_remove(struct platform_device *pdev)
> +{
> +	struct visconti_csi2rx *priv = platform_get_drvdata(pdev);
> +
> +	v4l2_async_nf_unregister(&priv->notifier);
> +	v4l2_async_nf_cleanup(&priv->notifier);
> +	v4l2_async_unregister_subdev(&priv->subdev);
> +
> +	v4l2_subdev_cleanup(&priv->subdev);
> +	media_entity_cleanup(&priv->subdev.entity);
> +}
> +
> +static struct platform_driver visconti_csi2rx_driver = {
> +	.probe = visconti_csi2rx_probe,
> +	.remove = visconti_csi2rx_remove,
> +	.driver = {
> +		.name = "visconti_csi2rx_dev",
> +		.of_match_table = visconti_csi2rx_of_table,
> +	},
> +};
> +
> +module_platform_driver(visconti_csi2rx_driver);
> +
> +MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
> +MODULE_DESCRIPTION("Toshiba Visconti CSI-2 receiver driver");
> +MODULE_LICENSE("Dual BSD/GPL");

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format
  2024-11-25  9:21 ` [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format Yuji Ishikawa
@ 2025-01-02 13:10   ` Laurent Pinchart
  2025-01-20  0:15     ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02 13:10 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hi Ishikawa-san,

Thank you for the patch.


On Mon, Nov 25, 2024 at 06:21:41PM +0900, Yuji Ishikawa wrote:
> Adds the Toshiba Visconti VIIF specific metadata format

s/Adds/Add/
s/format/formats./

> 
> - V4L2_META_FMT_VISCONTI_VIIF_PARAMS for ISP parameters
> - V4L2_META_FMT_VISCONTI_VIIF_STATS for ISP statistics
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>

Assuming the documentation of the formats in subsequent patches is fine,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
> Changelog v10:
> - add entry for V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> - add entry for V4L2_META_FMT_VISCONTI_VIIF_STATS
> 
> Changelog v11:
> - no change
> 
> Changelog v12:
> - add description for meta formats at v4l2-ioctl.c
> 
>  drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
>  include/uapi/linux/videodev2.h       | 4 ++++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 0304daa8471d..f7facb63b8ea 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -1470,6 +1470,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
>  	case V4L2_META_FMT_RPI_BE_CFG:	descr = "RPi PiSP BE Config format"; break;
>  	case V4L2_META_FMT_RPI_FE_CFG:  descr = "RPi PiSP FE Config format"; break;
>  	case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics format"; break;
> +	case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti ISP Parameters"; break;
> +	case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP Statistics"; break;
>  	case V4L2_META_FMT_GENERIC_8:	descr = "8-bit Generic Metadata"; break;
>  	case V4L2_META_FMT_GENERIC_CSI2_10:	descr = "8-bit Generic Meta, 10b CSI-2"; break;
>  	case V4L2_META_FMT_GENERIC_CSI2_12:	descr = "8-bit Generic Meta, 12b CSI-2"; break;
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index a5418759e2ba..9e1f66fdf038 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -863,6 +863,10 @@ struct v4l2_pix_format {
>  #define V4L2_META_FMT_RPI_FE_CFG	v4l2_fourcc('R', 'P', 'F', 'C') /* PiSP FE configuration */
>  #define V4L2_META_FMT_RPI_FE_STATS	v4l2_fourcc('R', 'P', 'F', 'S') /* PiSP FE stats */
>  
> +/* Vendor specific - used for Visconti VIIF sub-system */
> +#define V4L2_META_FMT_VISCONTI_VIIF_PARAMS	v4l2_fourcc('V', 'I', 'F', 'P') /* ISP Params */
> +#define V4L2_META_FMT_VISCONTI_VIIF_STATS	v4l2_fourcc('V', 'I', 'F', 'S') /* ISP Stats */
> +
>  #ifdef __KERNEL__
>  /*
>   * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface
  2024-11-25  9:21 ` [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface Yuji Ishikawa
@ 2025-01-02 13:16   ` Laurent Pinchart
  2025-02-05 12:31     ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02 13:16 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hi Ishikawa-san,

Thank you for the patch.

On Mon, Nov 25, 2024 at 06:21:46PM +0900, Yuji Ishikawa wrote:
> Added entries for visconti Video Input Interface driver, including;

Commit messages are written using the imperative mood, as if you were
giving orders to someone:

s/Added/Add/

> * device tree bindings
> * source files
> * documentation files
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>

I would have added the MAINTAINERS entry in 1/8 with just the DT binding
file, and added more files in corresponding patches. That would be
easier to review and check if entries are missing. I don't mind much
though, so if you prefer keeping it this way:

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
> Changelog v2:
> - no change
> 
> Changelog v3:
> - added entry for driver API documentation
> 
> Changelog v4:
> - added entry for header file
> 
> Changelog v5:
> - no change
> 
> Changelog v6:
> - update path to VIIF driver source files
> 
> Changelog v7:
> - no change
> 
> Changelog v8:
> - rename bindings description file
> 
> Changelog v9:
> - no change
> 
> Changelog v10:
> - add a separate entry of VIIF driver
> 
> Changelog v11:
> - no change
> 
> Changelog v12:
> - add a bindings description of CSI2RX driver
> 
>  MAINTAINERS | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b878ddc99f94..b5c819e94e9b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23430,6 +23430,18 @@ F:	Documentation/devicetree/bindings/media/i2c/tc358743.txt
>  F:	drivers/media/i2c/tc358743*
>  F:	include/media/i2c/tc358743.h
>  
> +TOSHIBA VISCONTI VIIF DRIVER
> +M:	Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> +M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> +L:	linux-media@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/admin-guide/media/visconti-viif.*
> +F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> +F:	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> +F:	Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> +F:	drivers/media/platform/toshiba/visconti/
> +F:	include/uapi/linux/visconti_viif.h
> +
>  TOSHIBA WMI HOTKEYS DRIVER
>  M:	Azael Avalos <coproscefalo@gmail.com>
>  L:	platform-driver-x86@vger.kernel.org

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver
  2024-11-25  9:21 ` [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
@ 2025-01-02 21:26   ` Laurent Pinchart
  2025-02-05 12:29     ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-02 21:26 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sakari Ailus, Hans Verkuil, Nobuhiro Iwamatsu,
	linux-media, linux-kernel, linux-arm-kernel, devicetree

Hi Ishikawa-san,

Thank you for the patch.

Overall the documentation looks quite good, it has significantly
improved compared to early versions.

On Mon, Nov 25, 2024 at 06:21:45PM +0900, Yuji Ishikawa wrote:
> Added description of Video Input Interface driver of

s/Added/Add/

> Toshiba Visconti architecture.
> It includes hardware organization, structure of the driver
> and metadata format for embedded image signal processor.
> 
> Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> ---
> Changelog v3:
> - Newly add documentation to describe SW and HW
> 
> Changelog v4:
> - no change
> 
> Changelog v5:
> - no change
> 
> Changelog v6:
> - add description of CSI2RX subdevice
> - add ordering of ioctl(S_FMT) and ioctl(S_EXT_CTRLS)
> 
> Changelog v7:
> - no change
> 
> Changelog v8:
> - add usage of V4L2_CTRL_TYPE_VISCONTI_ISP
> 
> Changelog v9:
> - fix warning: set reference target for keyword V4L2_CTRL_TYPE_VISCONTI_ISP
> 
> Changelog v10:
> - use parameter buffers instead of compound control
>   - removed description of vendor specific compound control
>   - add description of parameter buffers for ISP control
> - update directory structure
>   - remove documents under driver-api
>   - add documents to admin-guide, userspace-api
> 
> Changelog v11:
> - update usage of the driver
> 
> Changelog v12:
> - add description of CSI2RX driver
> - description of resizer subdevice
> - add block diagrams of VIIF and ISP
> - update usage of the driver
> 
>  .../admin-guide/media/v4l-drivers.rst         |   1 +
>  .../admin-guide/media/visconti-viif.dot       |  22 +
>  .../admin-guide/media/visconti-viif.rst       | 435 ++++++++++++++++++
>  .../userspace-api/media/v4l/meta-formats.rst  |   1 +
>  .../media/v4l/metafmt-visconti-viif.rst       |  48 ++
>  5 files changed, 507 insertions(+)
>  create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
>  create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
>  create mode 100644 Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> 
> diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
> index b6af448b9fe9..81054512e768 100644
> --- a/Documentation/admin-guide/media/v4l-drivers.rst
> +++ b/Documentation/admin-guide/media/v4l-drivers.rst
> @@ -32,5 +32,6 @@ Video4Linux (V4L) driver-specific documentation
>  	si476x
>  	starfive_camss
>  	vimc
> +	visconti-viif
>  	visl
>  	vivid
> diff --git a/Documentation/admin-guide/media/visconti-viif.dot b/Documentation/admin-guide/media/visconti-viif.dot
> new file mode 100644
> index 000000000000..cc75c73336fb
> --- /dev/null
> +++ b/Documentation/admin-guide/media/visconti-viif.dot
> @@ -0,0 +1,22 @@
> +digraph board {
> +        rankdir=TB
> +        n00000001 [label="{{<port0> 0 | <port4> 4} | visconti-viif:isp\n/dev/v4l-subdev0 | {<port1> 1 | <port2> 2 | <port3> 3 | <port5> 5}}", shape=Mrecord, style=filled, fillcolor=green]
> +        n00000001:port1 -> n00000008:port0
> +        n00000001:port2 -> n0000000b:port0
> +        n00000001:port3 -> n00000016
> +        n00000001:port5 -> n0000001e
> +        n00000008 [label="{{<port0> 0} | visconti-viif:resizer0\n/dev/v4l-subdev1 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
> +        n00000008:port1 -> n0000000e
> +        n0000000b [label="{{<port0> 0} | visconti-viif:resizer1\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
> +        n0000000b:port1 -> n00000012
> +        n0000000e [label="viif_capture_post0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
> +        n00000012 [label="viif_capture_post1\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
> +        n00000016 [label="viif_capture_sub\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
> +        n0000001a [label="viif_params\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
> +        n0000001a -> n00000001:port4
> +        n0000001e [label="viif_stats\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
> +        n00000030 [label="{{<port0> 0} | visconti_csi2rx 1c008000.csi2rx\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
> +        n00000030:port1 -> n00000001:port0
> +        n00000035 [label="{{} | imx219 1-0010\n/dev/v4l-subdev4 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
> +        n00000035:port0 -> n00000030:port0
> +}
> diff --git a/Documentation/admin-guide/media/visconti-viif.rst b/Documentation/admin-guide/media/visconti-viif.rst
> new file mode 100644
> index 000000000000..c2e85fb6f8c1
> --- /dev/null
> +++ b/Documentation/admin-guide/media/visconti-viif.rst
> @@ -0,0 +1,435 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======================================================
> +Visconti Video Input Interface Driver (visconti-viif)
> +======================================================
> +
> +Introduction
> +============
> +
> +This file documents the driver for the Video Input Interface (VIIF) that is
> +part of Toshiba Visconti SoCs.
> +The driver is located under drivers/media/platform/toshiba/visconti and uses
> +the Media-Controller API.

If you intend to make this two paragraphs, you should have a blank line
in-between:

--------
This file documents the driver for the Video Input Interface (VIIF) that is
part of Toshiba Visconti SoCs.

The driver is located under drivers/media/platform/toshiba/visconti and uses
the Media-Controller API.
--------

If you intend to make this a single paragraph, there should be no line
break after the first sentence:

--------
This file documents the driver for the Video Input Interface (VIIF) that is
part of Toshiba Visconti SoCs. The driver is located under
drivers/media/platform/toshiba/visconti and uses the Media-Controller API.
--------

> +
> +The driver module is named visconti-viif,
> +and is enabled through the CONFIG_VIDEO_VISCONTI_VIIF config option.
> +The CSI-2 receiver part is controlled by another module named visconti-csi2rx,
> +which is enabled through the CONFIG_VIDEO_VISCONTI_CSI2RX config option.

Please reflow text to reach as close to 80 columns:

--------
The driver module is named visconti-viif, and is enabled through the
CONFIG_VIDEO_VISCONTI_VIIF config option. The CSI-2 receiver part is controlled
by another module named visconti-csi2rx, which is enabled through the
CONFIG_VIDEO_VISCONTI_CSI2RX config option.
--------

Same comment below where applicable.

> +
> +The Visconti VIIF Hardware
> +==========================
> +
> +The Visconti VIIF hardware is an internally developed video capture device.
> +Following function modules are integrated:
> +
> +* MIPI CSI-2 receiver (CSI2RX)
> +* L1 Image Signal Processor (L1ISP)
> +
> +  * Correction, enhancement, adjustment on bayer images.
> +
> +* L2 Image Signal Processor (L2ISP)
> +
> +  * Lens distortion correction
> +  * Scaling & Cropping with up to 2 parameter sets
> +  * Formatting picture (RGB, YUV, Grayscale, ...)
> +  * Integrated DMAC: Writing picture into main memory
> +
> +* Video DMAC
> +
> +  * Writing picture into main memory
> +
> +Visconti5 SoC has two VIIF hardware instances.
> +
> +
> +The hardware block diagram is shown below.::
> +
> +  The VIIF hardware
> +                                                              "POST0"
> +                                                              "RGB with scale 0"
> +  +--------+    +----------+    +-----+    +-----+    +-----+    +--------+
> +  | Sensor |--->|  CSI2RX  |--->|     |    |     |    |     |--->| memory |
> +  +--------+    +----------+    |     |    |     |    |     |    +--------+
> +                                |     |    | L1  |    | L2  | "POST1"
> +                                |     |--->| ISP |--->| ISP | "RGB with scale 1"
> +                                |     |    |     |    |     |    +--------+
> +                                | MUX |    |     |    |     |--->| memory |
> +                                |     |    +-----+    +-----+    +--------+
> +                                |     |                       "SUB"
> +                                |     |                       "RAW w/o scale"
> +                                |     |        +------------+    +--------+
> +                                |     |------> | Video DMAC |--->| memory |
> +                                +-----+        +------------+    +--------+
> +
> +Topology
> +========
> +
> +Graph
> +-----
> +
> +.. _visconti_viif_topology_graph:
> +
> +.. kernel-figure:: visconti-viif.dot
> +	:alt: Diagram of the default media pipeline topology
> +	:align: center
> +
> +The driver has 3 video devices for capturing images:
> +
> +- viif_capture_post0: capture device for image.
> +    - corresponds to L2ISP.
> +- viif_capture_post1: capture device for image.
> +    - corresponds to L2ISP.
> +- viif_capture_sub: capture device for bayer image.
> +    - corresponds to Video DMAC.
> +
> +The driver has 2 video devices for controlling ISP.
> +
> +- viif_params: a metadata output device that receives ISP parameters.
> +    - corresponds to L1ISP and L2ISP.
> +- viif_stats: a metadata capture device that sends statistics.
> +    - corresponds to L1ISP and L2ISP.
> +
> +The driver has 2 subdevices:

I count three subdevs in the list below (and there are actually two
resizer instances, so that would be 4 subdevs).

> +
> +- visconti_csi2rx: CSI-2 receiver operation.
> +    - corresponds to CSI2RX.
> +- visconti-viif:isp: Image Signal Processor operation.
> +    - corresponds to L1ISP and L2ISP.
> +- visconti-viif:resizer: Scaling operation of Image Signal Processor.
> +    - corresponds to L2ISP.
> +
> +visconti_csi2rx - CSI2 Receiver Subdevice Node
> +---------------------------------------------------

The title underline should have the same length as the title.

> +
> +This subdevice node corresponds to a MIPI CSI2 receiver.
> +It resides between an image sensor subdevice and the ISP subdevice.
> +It controls CSI2 link configuration and training process.
> +
> +visconti-viif:isp - ISP Subdevice Node
> +--------------------------------------
> +
> +This subdevice node corresponds to L1/L2 ISPs.
> +It receives pictures from an sensor (via CSI2RX),

s/an sensor/a sensor/

> +applies multiple operations on pictures, then passes resulting images to capture nodes.
> +
> +ISP configurations/parameters are passed from userland via viif_params node.
> +The status of ISP operations are passed to userland via viif_stats node.

"stats" stands for "statistics", so I would write "The statistics
computed by the ISP are passed to ...".

And after reading more of this document, I realize that the viif_stats
node captures both statistics and status information. You could write
"The statistics computed by the ISP and the frame processing status are
passed to ...".

> +
> +L1 ISP provides following operations:
> +
> +- Input: accepts 8, 10, 12, 14bit bayer format
> +    - Operation selector; :c:type:`viif_l1_input_mode_config`
> +        - HDR image / PWL (Piecewse Linear Compression) image
> +        - with preprocessing / without preprocessing
> +    - HDRE: HDR expansion (only for PWL image);
> +      see :c:type:`viif_l1_hdre_config`
> +- Preprocessing: generate intermediate data (24bit RAW)
> +    - SLIC: Bit slicing (x3 12bit planes for preprocessing);
> +      see :c:type:`viif_l1_img_extraction_config`
> +    - ABPC/DPC: Blemish/Defect pixel correction :c:type:`viif_l1_dpc_config`
> +    - PWHB: Preset white balance; see :c:type:`viif_l1_preset_white_balance_config`
> +    - RCNR: RAW color noise reduction; see :c:type:`viif_l1_raw_color_noise_reduction_config`
> +    - HDRS: HDR synthesis; see :c:type:`viif_l1_hdrs_config`
> +- Processing on RAW image: Main Process (MPRO)
> +    - BLVC: black level correction and normalization;
> +      see :c:type:`viif_l1_black_level_correction_config`
> +    - LSSC: Lens shading correction; see :c:type:`viif_l1_lsc_config`
> +    - MPRO: digital amplifier; see :c:type:`viif_l1_main_process_config`
> +    - MPRO: bayer demosaicing; see :c:type:`viif_l1_main_process_config`
> +    - MPRO: color matrix correction; see :c:type:`viif_l1_main_process_config`
> +    - HDRC: HDR compression;

If my understanding is correct, this implements global and local tone
mapping. I would mention it explicitly here, those terms are more common
than "HDR compression". You could write for instance

   - HDRC: HDR compression (global and local tone mapping);

> +      see :c:type:`viif_l1_hdrc_config`, :c:type:`viif_l1_hdrc_ltm_config`,
> +      :c:type:`viif_l1_rgb_to_y_coef_config`
> +- Processing on RGB/YUV image: Video Process (VPRO)
> +    - VPRO: gamma correction; see :c:type:`viif_l1_gamma_config`
> +    - VPRO: RGB2YUV;
> +      see :c:type:`viif_l1_rgb_to_y_coef_config`,
> +      :c:type:`viif_l1_img_quality_adjustment_config`
> +    - VPRO: image quality adjustment; see :c:type:`viif_l1_img_quality_adjustment_config`
> +- Output: 16bit YUV
> +- Feedback loop
> +    - AWHB: auto white balance; see :c:type:`viif_l1_awb_config`,
> +      :c:type:`viif_isp_capture_status`

Does this mean that the ISP can compute white balance gains
automatically, implementing AWB in hardware ? That's interesting, it's a
feature I haven't seen before.

> +    - AEXP: auto exposure (average luminance calculation);
> +      see :c:type:`viif_l1_avg_lum_generation_config`,
> +      :c:type:`viif_l1_rgb_to_y_coef_config`, :c:type:`viif_isp_capture_status`
> +    - AG: analog gain calculation;
> +      see :c:type:`viif_l1_ag_mode_config`, :c:type:`viif_l1_ag_config`
> +
> +Below is the block diagram::
> +
> +  L1ISP::INPUT
> +
> +  +--------+                +-----+                      +-----+
> +  | Input  |--------------->|     |--------------------->|     |
> +  | 24bHDR |                |     |                      |     |
> +  +--------+                | 24b |                      | 24b |
> +                            | RAW |                      | RAW |
> +  +--------+    +------+    | (0) |                      | (1) |
> +  | Input  |--->| HDRE |--->|     |    +------------+    |     |
> +  | 24bPWL |    |      |    |     |--->| preprocess |--->|     |
> +  +--------+    +------+    +-----+    +------------+    +-----+

I'm not entirely sure to understand this correctly, could you please
correct me where I'm mistaken ?

I understand that the PWL input is HDR contents merged/stitched on the
sensor side, and compressed to a smaller than 24bpp width to reduce bus
bandwidth using a PWL function. The HDRE block applies the inverse
function to recover linear 24 bit data. In that case, the "preprocess"
pipeline operates on a single channel (using one of the param_h, param_m
and param_l set of parameters - which one ?). The HDRS blocks should be
disabled (how ?).

The HDR input, on the other hand, provides 2 or 3 channels with
different sensitivities (high, middle and low, from sensors that
implement DOL or DCG HDR). The preprocess pipeline operates on those
channels with different sets of parameters, and the HDRS combines the
channels into a single 24 bit image.

I'm not entirely sure how the two or three channels are provided to the
ISP, with DOL sensors there's a delay before the sensor starts
outputting the short (and very short) lines, so line buffers are needed
to realign the lines. I don't see this in the block diagram.

It would be nice to expand the documentation a bit with such information
about HDR processing, as I assume other developers may face similar
questions.

> +
> +  L1ISP::INPUT::preprocess
> +
> +  +-----+                                                                +-----+
> +  | 24b |    +------+    +------+    +------+    +------+    +------+    | 24b |
> +  | RAW |--->| SLIC |--->| ABPC |--->| PWHB |--->| RCNR |--->| HDRS |--->| RAW |
> +  | (0) |    +------+    +------+    +------+    +------+    +------+    | (1) |
> +  +-----+                                                                +-----+
> +
> +  L1ISP::MainProcess(MPRO)
> +
> +  +-----+
> +  | 24b |    +------+    +------+
> +  | RAW |--->| BLVC |--->| LSSC |---+
> +  | (1) |    +------+    +------+   |
> +  +-----+                           |
> +                                    |
> +     +------------------------------+
> +     |
> +     |    +-----------+    +-------------+    +--------+                +-----+
> +     +--->|   MPRO    |    |    MPRO     |    |  MPRO  |    +------+    | 16b |
> +          |  Digital  |--->| Demosaicing |----| Color  |--->| HDRC |--->| RGB |
> +     +--->| Amplifier |    |             |    | Matrix |    +------+    |     |
> +     |    +-----------+    +-------------+    +--------+                +-----+
> +     |                         |    |
> +     |    +--------------+     |    |    +------+
> +     +----| Auto         |<----+    +--->| AEXP |---> Auto-Exposure statistics
> +          | Whitebalance |               +------+
> +          +--------------+
> +                 |
> +                 +------------------------------> Auto-Whitebalance statistics
> +
> +  L1ISP::VideoProcess(VPRO)
> +
> +  +-----+    +------------+    +------------+    +---------------+    +--------+
> +  | 16b |--->| Gamma      |--->| RGB2YUV    |--->| Image Quality |--->| Output |
> +  | RGB |    | Correction |    | Conversion |    | Adjustment    |    |  16b   |
> +  |     |    +------------+    +------------+    +---------------+    |  YUV   |
> +  +-----+                                                             +--------+
> +
> +  L1ISP::AnalogGain
> +
> +  statistics                     +-------------+    +------------------+
> +  information ---> (user SW) --->| Analog Gain |--->| ABPC, RCNR, LSSC |
> +                                 +-------------+    |       MPRO, VPRO |
> +                                                    +------------------+

I'm a bit puzzled by "analog gain" here, as the ISP operates on digital
data only. Does the ISP need to be informed of the analog gain values
computed by the AEGC software algorithm and applied to the camera
sensor, for instance to estimate the noise level based on the analog
gain and adapt noise filtering accordingly ? Or is it something else ?

Edit: the text below answers this question :-)

> +
> +L2 ISP provides following operations:
> +
> +- Input: accepts 16bit YUV / RGB
> +- Operations:
> +    - Lens undistortion; see :c:type:`viif_l2_undist`

The structure is named viif_l2_undist_config. Please make sure to
compile the documentation, you should then get warnings for C types that
are not found.

> +    - Scaling; see :c:type:`viif_l2_roi`

viif_l2_roi_config

> +    - Cropping; see :c:type:`viif_l2_roi`

Looking at the implementation of the resizer subdevs, I see that the
crop and compose rectangles can be set, but they don't seem to ne used
to configure the resizer. Instead, the viif_l2_roi_config parameters are used
to configure cropping on the resizer input and scaling. This discrepancy
isn't good. I see two options to fix it:

- Keep configuring the resizer through viif_l2_roi_config and drop the resizer
  subdevs. This will simplify the driver. The main drawback is that it
  won't be possible to implement digital zoom (by changing the resizer
  configuration) asynchronously from the ISP parameters buffers, which
  can be useful to lower the latency of digital zoom.

- Drop viif_l2_roi_config, and configure the resizer from the formats,
  crop and selection rectangles on the resizer subdev pads. This makes
  the driver more complex. The main advantage is that digital zoom will
  be configurable with a smaller latency, but the drawback is that it
  won't be possible (or it will be more difficult) to configure it
  synchronously with other ISP parameters.

There are drivers in mainline that implement either of those options, so
you can pick the one you think is best.

An additional issue is that the hardware seems to implement cropping on
the output of the resizer only, not on the input. Given that the size of
the images output by the ISP pipeline must stay constant during video
capture (otherwise there would be a risk of buffer overflow), modifying
the crop rectangle on the output of the resizer is usually not allowed
during streaming. I think this could be worked around by allowing
modification only of the left and top coordinates during streaming, but
configuring everything through viif_l2_roi_config would likely be
easier. In that case, you should probably extend viif_l2_roi_config with
the crop offsets.

All of this reflects my current understanding of the ISP architecture,
based on this document and on the driver code, so please correct me if
there's anything I misunderstood. We can discuss the different options
further before you modify the driver and send a new version.

> +    - Gamma correction; see :c:type:`viif_l2_gamma_config`
> +    - YUV2RGB
> +- Output: RGB, YUV422, YUV444
> +
> +Below is the block diagram::
> +
> +  L2ISP
> +
> +  +-------+    +------------+    +--------------+    +---------+
> +  | Input |--->| YUV2RGB    |--->| Lens         |--->| Scaling |---> |
> +  | Image |    | Conversion |    | Undistortion |    |         |---> |
> +  +-------+    +------------+    +--------------+    +---------+     |

Is the scaling configuration for the two outputs independent ? If so I
would move the scaling block just before gamma correction, in each of
the branches below.

> +                                                                     |
> +          +----------------------------------------------------------+
> +          |
> +          |    +----------+    +------------+    +--------+    +--------+
> +          +--->|Gamma     |--->| Colorspace |--->| Data   |--->| Output |
> +          |    |Correction|    | Conversion |    | Packer |    | Image  |
> +          |    +----------+    +------------+    +--------+    +--------+
> +          |
> +          |    +----------+    +------------+    +--------+    +--------+
> +          +--->|Gamma     |--->| Colorspace |--->| Data   |--->| Output |
> +               |Correction|    | Conversion |    | Packer |    | Image  |
> +               +----------+    +------------+    +--------+    +--------+
> +
> +visconti-viif:resizer - Resizer Subdevice Node
> +----------------------------------------------
> +
> +The resizer subdevice resides between ISP subdevice and Capture device
> +on a capture path for post0 and post1.
> +It receives resize and crop parameters for the specific capture path
> +and controls L2ISP HW.
> +
> +following selection rectangles can be passed at VIDIOC_S_SELECTION ioctl.

s/following/The following/

> +
> +- sink pads's compose rectangle (V4L2_SEL_TGT_COMPOSE) for scaling
> +- source pad's crop rectangle (V4L2_SEL_TGT_CROP) for cropping
> +
> +
> +viif_capture_post0, viif_capture_post1 - Processed Image Capture Video Node
> +---------------------------------------------------------------------------
> +
> +These video nodes are used for capturing images processed at ISPs.
> +Supported capture formats are as follows:
> +
> +- V4L2_PIX_FMT_RGB24
> +- V4L2_PIX_FMT_ABGR32
> +- V4L2_PIX_FMT_YUV422M
> +- V4L2_PIX_FMT_YUV444M

The hardware doesn't support semi-planar formats (NV12 or NV16) or
packed formats (YUYV) ?

> +- V4L2_PIX_FMT_Y16
> +
> +Bayer format is not supported. Use viif_capture_sub instead.
> +
> +POST0 and POST1 can output images from the same input image
> +using different cropping and scaling settings.
> +
> +viif_capture_sub - Raw Image Capture Video Node
> +-----------------------------------------------
> +
> +This video node is used for capturing bayer image from the sensor.
> +The output picture has exactly the same resolution and format as the sensor input.
> +The pipeline does not edit pixel values.
> +However, when writing pixel values to memory, they are shifted to the MSB
> +to match either 8bit or 16bit.
> +
> +Therefore, resulting capture formats are as follows:
> +
> +- for 8bit RAW input:
> +    - V4L2_PIX_FMT_SRGGB8
> +    - V4L2_PIX_FMT_SGRBG8
> +    - V4L2_PIX_FMT_SGBRG8
> +    - V4L2_PIX_FMT_SBGGR8
> +- for 10, 12, 14bit RAW input:
> +    - V4L2_PIX_FMT_SRGGB16
> +    - V4L2_PIX_FMT_SGRBG16
> +    - V4L2_PIX_FMT_SGBRG16
> +    - V4L2_PIX_FMT_SBGGR16
> +
> +.. _viif_params:
> +
> +viif_params - ISP Parameters Video Node
> +---------------------------------------
> +
> +The viif_params video node receives a set of ISP parameters from userspace
> +to be applied to the hardware during a video stream.
> +
> +The buffer format is defined by struct :c:type:`visconti_viif_isp_config`, and userspace should set
> +:ref:`V4L2_META_FMT_VISCONTI_VIIF_PARAMS <v4l2-meta-fmt-visconti-viif-params>` as the data format.
> +
> +.. _viif_stats:
> +
> +viif_stats - Statistics Video Node
> +----------------------------------
> +
> +The viif_stats video node provides current status of ISP.

The viif_stats video node provides statistics computed by the ISP and
frame processing status.

> +
> +Following information is included:
> +
> +* statistics of auto white balance
> +* average luminance information which can be used by auto exposure software impl.

s/impl/implementation/

I would also add

 * CSI-2 receiver calibration and error status
 * ISP error status

It's quite uncommon to provide this kind of status through ISP stats
buffers, but it sounds like an interesting idea. Other drivers usually
keep error counters in the kernel and expose them through debugfs.

> +
> +The buffer format is defined by struct :c:type:`visconti_viif_isp_stat`, and userspace should set
> +:ref:`V4L2_META_FMT_VISCONTI_VIIF_STATS <v4l2-meta-fmt-visconti-viif-stats>` as the data format.
> +
> +Feedback Operations
> +===================
> +
> +Among the so-called 3A functions, VIIF provides only auto-whitebalance and auto-exposure.
> +Auto-whitebalance is a standalone hardware feature.
> +Some status information is available through the ISP statistics interface.
> +
> +Auto-exposure is realized through a combination of hardware and userland software.
> +VIIF provides weighted average luminance information through the ISP statistics interface.
> +The userland application calculates the sensor gain, sensor exposure and ISP digital gain.
> +The calculated parameters are then passed to sensor's controls and the ISP parameter interface.
> +
> +Among ISP parameters, there are parameters called AG (analog gain).
> +Actually, AG parameters have nothing to do with auto-exposure.
> +It controls "strength" in several signal correction algorithms.
> +Below is the list of the functions which may be affected by AG parameters:
> +
> +- ABPC/DPC
> +- RCNR
> +- LSSC
> +- MPRO: color matrix correction
> +- VPRO
> +
> +Capturing Video Frames Example
> +==============================
> +
> +In the following example,
> +imx219 camera is connected to pad 0 of 'visconti_csi2rx' subdevice.
> +
> +The following commands yield three pictures with different zoom ratio:
> +- main path 0: 1.5x zoom, crop 1920x1080, RGB picture
> +- main path 1: 0.67x zoom, crop 640x480, RGB picture
> +- sub path: 1920x1080 RAW picture
> +
> +.. code-block:: bash
> +
> +	# set the links
> +	media-ctl -d platform:visconti-viif-0 -r
> +	media-ctl -d platform:visconti-viif-0 -l '"imx219 1-0010":0 -> "visconti_csi2rx 1c008000.csi2rx":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti_csi2rx 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":1 -> "visconti-viif:resizer0":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":2 -> "visconti-viif:resizer1":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":3 -> "viif_capture_sub":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer0":1 -> "viif_capture_post0":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer1":1 -> "viif_capture_post1":0 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"viif_params":0 -> "visconti-viif:isp":4 [1]'
> +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":5 -> "viif_stats":0 [1]'
> +
> +	# set format for imx219
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"imx219 1-0010":0 [fmt:SRGGB10_1X10/1920x1080]'
> +
> +	# set format for csi2rx
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti_csi2rx 1c008000.csi2rx":0 [fmt:SRGGB10_1X10/1920x1080  field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]'
> +
> +	# set format for isp sink pad
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":0 [fmt:SRGGB10_1X10/1920x1080]'
> +
> +	# set format for resizer pads
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer0":0 '"[fmt:YUV8_1X24/1920x1080 compose:(0,0)/2880x1620]"
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer0":1 '"[crop:(480,16)/1920x1080]"
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer1":0 '"[fmt:YUV8_1X24/1920x1080 compose:(0,0)/1280x720]"
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:resizer1":1 '"[crop:(320,32)/640x480]"
> +
> +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":1 [fmt:YUV8_1X24/1024 crop:(640,0)/1024x1024]'
> +
> +	# set format for main path0
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "width=1920,height=1080"
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "pixelformat=RGB3"
> +
> +	# set format for main path1
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "width=640,height=480"
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v "pixelformat=RGB3"
> +
> +	# start streaming
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 --stream-mmap --stream-count 1000 &
> +
> +	# start streaming with other devices while viif_capture_post0 is running
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post1 --stream-mmap --stream-count 10
> +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_sub --stream-mmap --stream-count 10
> +
> +Use of coherent memory
> +======================
> +
> +Visconti5 SoC has two independent DDR SDRAM controllers.
> +Each controller is mapped to 36bit address space.
> +
> +Accelerator bus masters have two paths to access memory;
> +one is directly connected to SDRAM controller,
> +the another is connected via a cache coherency bus
> +which keeps coherency among CPUs.
> +
> +From accelerators and CPUs, the address map is following:
> +
> +* 0x0_8000_0000 DDR0 direct access
> +* 0x4_8000_0000 DDR0 coherency bus
> +* 0x8_8000_0000 DDR1 direct access
> +* 0xC_8000_0000 DDR1 coherency bus
> +
> +The base address can be specified with "memory" and "reserved-memory" elements
> +in a device tree description.
> +It's not recommended to mix direct address and coherent address.
> +
> +The Visconti5 VIIF driver always use only direct address to configure Video DMACs of the hardware.
> +This design is to avoid great performance loss at coherency bus caused by massive memory access.
> +You should not put the dma_coherent attribute to viif element in device tree.
> +Cache operations are done automatically by videobuf2 driver.
> diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst
> index 86ffb3bc8ade..2336842f0c26 100644
> --- a/Documentation/userspace-api/media/v4l/meta-formats.rst
> +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
> @@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata` interface only.
>      metafmt-pisp-fe
>      metafmt-rkisp1
>      metafmt-uvc
> +    metafmt-visconti-viif
>      metafmt-vivid
>      metafmt-vsp1-hgo
>      metafmt-vsp1-hgt
> diff --git a/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> new file mode 100644
> index 000000000000..dc4b31627fe1
> --- /dev/null
> +++ b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> @@ -0,0 +1,48 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +.. _v4l2-meta-fmt-visconti-viif-params:
> +
> +.. _v4l2-meta-fmt-visconti-viif-stats:
> +
> +***************************************************************************************
> +V4L2_META_FMT_VISCONTI_VIIF_PARAMS ('vifp'), V4L2_META_FMT_VISCONTI_VIIF_STATS ('vifs')
> +***************************************************************************************
> +
> +Configuration parameters
> +========================
> +
> +The configuration parameters are passed to the
> +:ref:`viif_params <viif_params>` metadata output video node, using
> +the :c:type:`v4l2_meta_format` interface. The buffer contains
> +a single instance of the C structure :c:type:`visconti_viif_isp_config` defined in
> +``visconti_viif.h``. So the structure can be obtained from the buffer by:
> +
> +.. code-block:: c
> +
> +	struct visconti_viif_isp_config *params = (struct visconti_viif_isp_config*) buffer;
> +
> +VIIF statistics
> +===============
> +
> +The VIIF device collects different statistics over an input Bayer frame.
> +Those statistics are obtained from the :ref:`viif_stats <viif_stats>`
> +metadata capture video node,
> +using the :c:type:`v4l2_meta_format` interface. The buffer contains a single
> +instance of the C structure :c:type:`visconti_viif_isp_stat` defined in
> +``visconti_viif.h``. So the structure can be obtained from the buffer by:
> +
> +.. code-block:: c
> +
> +	struct visconti_viif_isp_stat *stats = (struct visconti_viif_isp_stat*) buffer;
> +
> +The statistics collected are Exposure, AWB (auto white balance) and errors.
> +See :c:type:`visconti_viif_isp_stat` for details of the statistics.
> +
> +The statistics and configuration parameters described here are usually
> +consumed and produced by dedicated user space libraries that comprise the
> +tuning tools using software control loop.
> +
> +visconti viif uAPI data types
> +=============================
> +
> +.. kernel-doc:: include/uapi/linux/visconti_viif.h

Assuming the documentation in the header file is adequate, the level of
detail here is fine.

-- 
Regards,

Laurent Pinchart

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

* RE: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-01-02  9:29   ` Laurent Pinchart
@ 2025-01-20  0:10     ` yuji2.ishikawa
  0 siblings, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2025-01-20  0:10 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Thursday, January 2, 2025 6:29 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti MIPI CSI-2 Receiver
> 
> Hello Ishikawa-san,
> 
> Thank you for the patch.
> 
> On Mon, Nov 25, 2024 at 06:21:39PM +0900, Yuji Ishikawa wrote:
> > Adds the Device Tree binding documentation that allows to describe the
> > MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > ---
> >
> > Changelog v12:
> > - Newly add bindings for CSI2RX driver
> >
> >  .../media/toshiba,visconti5-csi2rx.yaml       | 104
> ++++++++++++++++++
> >  1 file changed, 104 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> > l
> > b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.yam
> > l
> > new file mode 100644
> > index 000000000000..5488072bc82a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx
> > +++ .yaml
> > @@ -0,0 +1,104 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/media/toshiba,visconti5-csi2rx.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> > +
> > +maintainers:
> > +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > +
> > +description: |-
> 
> As Krzysztof mentioned, '|-' isn't needed. See https://yaml-multiline.info/ for
> more information. The literal block style indicator ('|') is only needed when line
> breaks need to be preserved, e.g. when the description contains ASCII art.
> 

I'll remove "|-".

> > +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
> > + CSI-2 video  stream. Use with VIIF device. T.B.D
> 
> T.B.D ?
> 

This should have been removed.
I'll remove it.

> > +
> > +properties:
> > +  compatible:
> > +    const: toshiba,visconti5-csi2rx
> > +
> > +  reg:
> > +    items:
> > +      - description: Registers for CSI2 receiver control
> > +
> > +  interrupts:
> > +    items:
> > +      - description: CSI2 Receiver Interrupt
> > +
> > +  ports:
> > +    $ref: /schemas/graph.yaml#/properties/ports
> > +
> > +    properties:
> > +      port@0:
> > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > +        unevaluatedProperties: false
> > +        description:
> > +          Input port node, single endpoint describing the CSI-2
> transmitter.
> > +
> > +        properties:
> > +          endpoint:
> > +            $ref: video-interfaces.yaml#
> 
> Please use a full path for the ref:
> 
>             $ref: /schemas/media/video-interfaces.yaml#
> 

I'll use a full path description

> > +            unevaluatedProperties: false
> > +
> > +            properties:
> > +              data-lanes:
> > +                description: CSI2 receiver supports 1, 2, 3 or 4 data
> > + lanes
> 
> You can drop the description. The video-interfaces.yaml schema has a more
> complete description, and the fact that the receiver supports between 1 and 4
> lanes is conveyed by minItems and items below.
> 

I'll drop the description.

> > +                minItems: 1
> > +                items:
> > +                  - const: 1
> > +                  - const: 2
> > +                  - const: 3
> > +                  - const: 4
> > +            required:
> > +              - data-lanes
> > +
> > +      port@1:
> > +        $ref: /schemas/graph.yaml#/properties/port
> > +        description:
> > +          Output port node, single endpoint describing the Visconti VIIF.
> > +
> > +    required:
> > +      - port@0
> > +      - port@1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - ports
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    soc {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        csi2rx@1c008000 {
> 
> Node names should describe the function of the node, not the precise model of
> the device. "csi2" would be a more appropriate name.
> 

I'll use "csi2" for the node's name.

> > +            compatible = "toshiba,visconti5-csi2rx";
> > +            reg = <0 0x1c008000 0 0x400>;
> > +            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
> > +
> > +            ports {
> > +                #address-cells = <1>;
> > +                #size-cells = <0>;
> > +                port@0 {
> > +                    reg = <0>;
> > +                    csi2rx_in0: endpoint {
> > +                        data-lanes = <1 2>;
> > +                        remote-endpoint = <&imx219_out0>;
> > +                    };
> > +                };
> > +                port@1 {
> > +                    reg = <1>;
> > +                    csi2rx_out0: endpoint {
> > +                        remote-endpoint = <&csi_in0>;
> > +                    };
> > +                };
> > +            };
> > +        };
> > +    };
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,

Yuji Ishikawa

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

* RE: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2025-01-02  9:56   ` Laurent Pinchart
@ 2025-01-20  0:13     ` yuji2.ishikawa
  0 siblings, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2025-01-20  0:13 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent.

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Thursday, January 2, 2025 6:56 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti Video Input Interface
> 
> Hi Ishikawa-san,
> 
> Thank you for the patch.
> 
> On Mon, Nov 25, 2024 at 06:21:40PM +0900, Yuji Ishikawa wrote:
> > Adds the Device Tree binding documentation that allows to describe the
> > Video Input Interface found in Toshiba Visconti SoCs.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > ---
> > Changelog v2:
> > - no change
> >
> > Changelog v3:
> > - no change
> >
> > Changelog v4:
> > - fix style problems at the v3 patch
> > - remove "index" member
> > - update example
> >
> > Changelog v5:
> > - no change
> >
> > Changelog v6:
> > - add register definition of BUS-IF and MPU
> >
> > Changelog v7:
> > - remove trailing "bindings" from commit header message
> > - remove trailing "Device Tree Bindings" from title
> > - fix text wrapping of description
> > - change compatible to visconti5-viif
> > - explicitly define allowed properties for port::endpoint
> >
> > Changelog v8:
> > - Suggestion from Krzysztof Kozlowski
> >   - rename bindings description file
> >   - use block style array instead of inline style
> >   - remove clock-lane (as it is fixed at position 0)
> >   - update sample node's name
> >   - use lowercase hex for literals
> > - Suggestion from Laurent Pinchart
> >   - update description message port::description
> >   - remove port::endpoint::bus-type as it is fixed to <4>
> >   - remove port::endpoint::clock-lanes from example
> >   - add port::endpoint::data-lanes to required parameters list
> >   - fix sequence of data-lanes: <1 2 3 4> because current driver does not
> support data reordering
> >   - update port::endpoint::data-lanes::description
> >   - remove redundant type definition for port::endpoint::data-lanes
> >
> > Changelog v9:
> > - place "required" after "properties"
> > - dictionary ordering of properties
> >
> > Changelog v10:
> > - no change
> >
> > Changelog v11:
> > - no change
> >
> > Changelog v12:
> > - remove property "clock-noncontinuous" as VIIF switches both modes
> > automatically
> > - remove property "link-frequencies" as VIIF does not use the
> > information
> > - remove reg[2] and interrupts[3] which are used for CSI2RX driver
> > - update example to refer csi2rx for remote-endpoint
> >
> >  .../media/toshiba,visconti5-viif.yaml         | 95
> +++++++++++++++++++
> >  1 file changed, 95 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> > b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> > new file mode 100644
> > index 000000000000..ef0452a47e98
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.y
> > +++ aml
> > @@ -0,0 +1,95 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/toshiba,visconti5-viif.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Toshiba Visconti5 SoC Video Input Interface
> > +
> > +maintainers:
> > +  - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > +
> > +description: |-
> > +  Toshiba Visconti5 SoC Video Input Interface (VIIF) receives
> > +videostream
> > +  from MIPI CSI-2 receiver device, processes the stream with image
> > +signal
> > +  processors (L1ISP, L2ISP), then stores pictures to main memory.
> > +
> > +properties:
> > +  compatible:
> > +    const: toshiba,visconti5-viif
> > +
> > +  reg:
> > +    items:
> > +      - description: Registers for capture control
> > +      - description: Registers for bus interface unit control
> > +      - description: Registers for Memory Protection Unit
> 
> I'm a bit surprised by the lack of clocks.
> 

The VIIF HW requires clock input. However, since the clock controller driver is still in development and no corresponding clock source is available,
I did not describe the VIIF clock in the device tree and the binding.
I understand that a clock should be defined in the binding.
For the next patch, I'll add a clock definition to the binding.

> > +
> > +  interrupts:
> > +    items:
> > +      - description: Sync Interrupt
> > +      - description: Status (Error) Interrupt
> > +      - description: L1ISP Interrupt
> > +
> > +  port:
> > +    $ref: /schemas/graph.yaml#/$defs/port-base
> > +    unevaluatedProperties: false
> > +    description: CSI-2 input port, with a single endpoint connected to the
> CSI-2 transmitter.
> > +
> > +    properties:
> > +      endpoint:
> > +        $ref: video-interfaces.yaml#
> > +        additionalProperties: false
> > +
> > +        properties:
> > +          data-lanes:
> > +            description: VIIF supports 1, 2, 3 or 4 data lanes
> > +            minItems: 1
> > +            items:
> > +              - const: 1
> > +              - const: 2
> > +              - const: 3
> > +              - const: 4
> 
> Now that the CSI-2 receiver is modeled as a separate DT node, I don't think
> data-lanes is applicable anymore. The interface between the CSI-2 receiver
> and the VIIF isn't a CSI-2 bus.
>
> I think you can simplify the bindings by switching from port-base to port, as you
> don't need to specify additional properties for the
> endpoint:
> 
>   port:
>     $ref: /schemas/graph.yaml#/$defs/port
>     description:
>       CSI-2 input port, with a single endpoint connected to the CSI-2
>       transmitter.
> 
> Please test this though (by running the DT bindings checks).
>

I'll remove CSI-2 specific descriptions.
Also I'll use a reference to port.

> > +
> > +          remote-endpoint: true
> > +
> > +        required:
> > +          - data-lanes
> > +          - remote-endpoint
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - port
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    soc {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        video@1c000000 {
> > +            compatible = "toshiba,visconti5-viif";
> > +            reg = <0 0x1c000000 0 0x6000>,
> > +                  <0 0x1c00e000 0 0x1000>,
> > +                  <0 0x2417a000 0 0x1000>;
> > +            interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
> > +                         <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
> > +                         <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
> > +
> > +            port {
> > +                #address-cells = <1>;
> > +                #size-cells = <0>;
> > +
> > +                csi_in0: endpoint {
> > +                    data-lanes = <1 2>;
> > +                    remote-endpoint = <&csi2rx_out0>;
> > +                };
> > +            };
> > +        };
> > +    };
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,
Yuji Ishikawa

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

* RE: [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format
  2025-01-02 13:10   ` Laurent Pinchart
@ 2025-01-20  0:15     ` yuji2.ishikawa
  2025-01-20  1:49       ` Laurent Pinchart
  0 siblings, 1 reply; 36+ messages in thread
From: yuji2.ishikawa @ 2025-01-20  0:15 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent.

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Thursday, January 2, 2025 10:10 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format
> 
> Hi Ishikawa-san,
> 
> Thank you for the patch.
> 
> 
> On Mon, Nov 25, 2024 at 06:21:41PM +0900, Yuji Ishikawa wrote:
> > Adds the Toshiba Visconti VIIF specific metadata format
> 
> s/Adds/Add/
> s/format/formats./
> 

I'll fix the commit message.

> >
> > - V4L2_META_FMT_VISCONTI_VIIF_PARAMS for ISP parameters
> > - V4L2_META_FMT_VISCONTI_VIIF_STATS for ISP statistics
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> 
> Assuming the documentation of the formats in subsequent patches is fine,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> > ---
> > Changelog v10:
> > - add entry for V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> > - add entry for V4L2_META_FMT_VISCONTI_VIIF_STATS
> >
> > Changelog v11:
> > - no change
> >
> > Changelog v12:
> > - add description for meta formats at v4l2-ioctl.c
> >
> >  drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
> >  include/uapi/linux/videodev2.h       | 4 ++++
> >  2 files changed, 6 insertions(+)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c
> > b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 0304daa8471d..f7facb63b8ea 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -1470,6 +1470,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc
> *fmt)
> >  	case V4L2_META_FMT_RPI_BE_CFG:	descr = "RPi PiSP BE Config
> format"; break;
> >  	case V4L2_META_FMT_RPI_FE_CFG:  descr = "RPi PiSP FE Config
> format"; break;
> >  	case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE
> Statistics
> > format"; break;
> > +	case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti
> ISP Parameters"; break;
> > +	case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP
> > +Statistics"; break;

The media-ci has reported the following errors.
Is it all right to leave these errors unfixed and keep the lines with the same style as other entries?

# Test checkpatch:./0003-media-uapi-add-visconti-viif-meta-buffer-format.patch
ERROR: trailing statements should be on next line
#26: FILE: drivers/media/v4l2-core/v4l2-ioctl.c:1473:
+case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti ISP 
+Parameters"; break;

ERROR: trailing statements should be on next line
#27: FILE: drivers/media/v4l2-core/v4l2-ioctl.c:1474:
+case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP 
+Statistics"; break;

total: 2 errors, 0 warnings, 0 checks, 18 lines checked

> >  	case V4L2_META_FMT_GENERIC_8:	descr = "8-bit Generic
> Metadata"; break;
> >  	case V4L2_META_FMT_GENERIC_CSI2_10:	descr = "8-bit
> Generic Meta, 10b CSI-2"; break;
> >  	case V4L2_META_FMT_GENERIC_CSI2_12:	descr = "8-bit
> Generic Meta, 12b CSI-2"; break;
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index a5418759e2ba..9e1f66fdf038
> > 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -863,6 +863,10 @@ struct v4l2_pix_format {
> >  #define V4L2_META_FMT_RPI_FE_CFG	v4l2_fourcc('R', 'P', 'F', 'C') /*
> PiSP FE configuration */
> >  #define V4L2_META_FMT_RPI_FE_STATS	v4l2_fourcc('R', 'P', 'F', 'S') /*
> PiSP FE stats */
> >
> > +/* Vendor specific - used for Visconti VIIF sub-system */
> > +#define V4L2_META_FMT_VISCONTI_VIIF_PARAMS	v4l2_fourcc('V', 'I', 'F',
> 'P') /* ISP Params */
> > +#define V4L2_META_FMT_VISCONTI_VIIF_STATS	v4l2_fourcc('V', 'I', 'F',
> 'S') /* ISP Stats */
> > +
> >  #ifdef __KERNEL__
> >  /*
> >   * Line-based metadata formats. Remember to update v4l_fill_fmtdesc()
> > when
> 
> --
> Regards,
> 
> Laurent Pinchart

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

* RE: [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2025-01-02 13:08   ` Laurent Pinchart
@ 2025-01-20  0:21     ` yuji2.ishikawa
  0 siblings, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2025-01-20  0:21 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent.

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Thursday, January 2, 2025 10:08 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti
> CSI-2 Receiver driver
> 
> Hello Ishikawa-san,
> 
> Thank you for the patch.
> 
> On Mon, Nov 25, 2024 at 06:21:42PM +0900, Yuji Ishikawa wrote:
> > Add support to MIPI CSI-2 Receiver on Toshiba Visconti ARM SoCs.
> > This driver is used with Visconti Video Input Interface driver.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > ---
> > Changelog v12:
> > - Separate CSI2RX driver and made it independent driver
> > - viif_csi2rx subdevice driver (in v11 patch) was removed.
> > - dictionary order at Kconfig and Makefile
> >
> >  drivers/media/platform/Kconfig                |   1 +
> >  drivers/media/platform/Makefile               |   1 +
> >  drivers/media/platform/toshiba/Kconfig        |   6 +
> >  drivers/media/platform/toshiba/Makefile       |   2 +
> >  .../media/platform/toshiba/visconti/Kconfig   |  16 +
> >  .../media/platform/toshiba/visconti/Makefile  |   8 +
> >  .../platform/toshiba/visconti/csi2rx_drv.c    | 791
> ++++++++++++++++++
> >  7 files changed, 825 insertions(+)
> >  create mode 100644 drivers/media/platform/toshiba/Kconfig
> >  create mode 100644 drivers/media/platform/toshiba/Makefile
> >  create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
> >  create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
> >  create mode 100644
> > drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> >
> > diff --git a/drivers/media/platform/Kconfig
> > b/drivers/media/platform/Kconfig index 85d2627776b6..761b15b07b90
> > 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -86,6 +86,7 @@ source "drivers/media/platform/samsung/Kconfig"
> >  source "drivers/media/platform/st/Kconfig"
> >  source "drivers/media/platform/sunxi/Kconfig"
> >  source "drivers/media/platform/ti/Kconfig"
> > +source "drivers/media/platform/toshiba/Kconfig"
> >  source "drivers/media/platform/verisilicon/Kconfig"
> >  source "drivers/media/platform/via/Kconfig"
> >  source "drivers/media/platform/xilinx/Kconfig"
> > diff --git a/drivers/media/platform/Makefile
> > b/drivers/media/platform/Makefile index ace4e34483dd..917145fe5171
> > 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -29,6 +29,7 @@ obj-y += samsung/
> >  obj-y += st/
> >  obj-y += sunxi/
> >  obj-y += ti/
> > +obj-y += toshiba/
> >  obj-y += verisilicon/
> >  obj-y += via/
> >  obj-y += xilinx/
> > diff --git a/drivers/media/platform/toshiba/Kconfig
> > b/drivers/media/platform/toshiba/Kconfig
> > new file mode 100644
> > index 000000000000..f02983f4fc97
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/Kconfig
> > @@ -0,0 +1,6 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +
> > +comment "Toshiba media platform drivers"
> > +
> > +source "drivers/media/platform/toshiba/visconti/Kconfig"
> > +
> > diff --git a/drivers/media/platform/toshiba/Makefile
> > b/drivers/media/platform/toshiba/Makefile
> > new file mode 100644
> > index 000000000000..2bce85ef3b48
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/Makefile
> > @@ -0,0 +1,2 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> 
> A blank line would be nice here.
> 

I'll add a blank line.

> > +obj-y += visconti/
> > diff --git a/drivers/media/platform/toshiba/visconti/Kconfig
> > b/drivers/media/platform/toshiba/visconti/Kconfig
> > new file mode 100644
> > index 000000000000..e5c92d598f8b
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/Kconfig
> > @@ -0,0 +1,16 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> 
> A blank line would be nice here too.
> 

I'll add a blank line here too.

> > +config VIDEO_VISCONTI_CSI2RX
> > +	tristate "Visconti MIPI CSI-2 Receiver driver"
> > +	depends on V4L_PLATFORM_DRIVERS
> > +	depends on VIDEO_DEV && OF
> > +	depends on ARCH_VISCONTI || COMPILE_TEST
> > +	select MEDIA_CONTROLLER
> > +	select VIDEO_V4L2_SUBDEV_API
> > +	select V4L2_FWNODE
> > +	help
> > +	  Support for Toshiba Visconti MIPI CSI-2 receiver,
> > +	  which is used with Visconti Camera Interface driver.
> > +
> > +	  This driver yields 1 subdevice node for a hardware instance.
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called visconti-csi2rx.
> > diff --git a/drivers/media/platform/toshiba/visconti/Makefile
> > b/drivers/media/platform/toshiba/visconti/Makefile
> > new file mode 100644
> > index 000000000000..62a029376134
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/Makefile
> > @@ -0,0 +1,8 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Makefile for the Visconti video input device driver #
> > +
> > +visconti-csi2rx-objs = csi2rx_drv.o
> > +
> > +obj-$(CONFIG_VIDEO_VISCONTI_CSI2RX) += visconti-csi2rx.o
> > diff --git a/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> > b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> > new file mode 100644
> > index 000000000000..94567963872a
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> > @@ -0,0 +1,791 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> > +/* Toshiba Visconti Video Capture Support
> 
> /*
>  * Toshiba Visconti Video Capture Support
>  *
> 

I'll fix it. Also I'll check for the similar cases.

> > + *
> > + * (C) Copyright 2024 TOSHIBA CORPORATION
> > + * (C) Copyright 2024 Toshiba Electronic Devices & Storage
> > + Corporation */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_graph.h>
> 
> You don't need those two headers. You however need to include
> 
> - linux/device.h (for devm_kzalloc)
> - linux/property.h (for the fwnode_* API)
> 

I'll update the include list.

> > +#include <linux/platform_device.h>
> > +
> > +#include <media/mipi-csi2.h>
> > +#include <media/v4l2-common.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include <media/v4l2-subdev.h>
> > +
> > +/* CSI2HOST register space */
> > +#define REG_CSI2RX_NLANES	 0x4
> > +#define REG_CSI2RX_RESETN	 0x8
> > +#define REG_CSI2RX_INT_ST_MAIN	 0xc
> > +#define REG_CSI2RX_DATA_IDS_1	 0x10
> > +#define REG_CSI2RX_DATA_IDS_2	 0x14
> > +#define REG_CSI2RX_PHY_SHUTDOWNZ 0x40
> > +#define REG_CSI2RX_PHY_RSTZ	 0x44
> > +
> > +/* access to dphy external registers */
> 
> /* Access to dphy external registers */
> 
> Same in other comments below.
> 

I'll fix it. Also I'll check for the similar cases.

> > +#define REG_CSI2RX_PHY_TESTCTRL0 0x50
> > +#define BIT_TESTCTRL0_CLK_0	 0
> > +#define BIT_TESTCTRL0_CLK_1	 BIT(1)
> > +
> > +#define REG_CSI2RX_PHY_TESTCTRL1 0x54
> > +#define BIT_TESTCTRL1_ADDR	 BIT(16)
> > +#define MASK_TESTCTRL1_DIN	 0xff
> > +#define MASK_TESTCTRL1_DOUT	 0xff00
> > +
> > +#define REG_CSI2RX_INT_ST_PHY_FATAL  0xe0 #define
> > +REG_CSI2RX_INT_MSK_PHY_FATAL 0xe4
> > +#define MASK_PHY_FATAL_ALL	     0x0000000f
> > +
> > +#define REG_CSI2RX_INT_ST_PKT_FATAL  0xf0 #define
> > +REG_CSI2RX_INT_MSK_PKT_FATAL 0xf4
> > +#define MASK_PKT_FATAL_ALL	     0x0001000f
> > +
> > +#define REG_CSI2RX_INT_ST_FRAME_FATAL  0x100 #define
> > +REG_CSI2RX_INT_MSK_FRAME_FATAL 0x104
> > +#define MASK_FRAME_FATAL_ALL	       0x000f0f0f
> > +
> > +#define REG_CSI2RX_INT_ST_PHY  0x110
> > +#define REG_CSI2RX_INT_MSK_PHY 0x114
> > +#define MASK_PHY_ERROR_ALL     0x000f000f
> > +
> > +#define REG_CSI2RX_INT_ST_PKT  0x120
> > +#define REG_CSI2RX_INT_MSK_PKT 0x124
> > +#define MASK_PKT_ERROR_ALL     0x000f000f
> > +
> > +#define REG_CSI2RX_INT_ST_LINE	0x130
> > +#define REG_CSI2RX_INT_MSK_LINE 0x134
> > +#define MASK_LINE_ERROR_ALL	0x00ff00ff
> > +
> > +/* DPHY register space */
> > +enum dphy_testcode {
> > +	DIG_TESTCODE_EXT = 0,
> > +	DIG_SYS_0 = 0x001,
> > +	DIG_SYS_1 = 0x002,
> > +	DIG_SYS_3 = 0x004,
> > +	DIG_SYS_7 = 0x008,
> > +	DIG_RX_STARTUP_OVR_2 = 0x0e2,
> > +	DIG_RX_STARTUP_OVR_3 = 0x0e3,
> > +	DIG_RX_STARTUP_OVR_4 = 0x0e4,
> > +	DIG_RX_STARTUP_OVR_5 = 0x0e5,
> > +	DIG_CB_2 = 0x1ac,
> > +	DIG_TERM_CAL_0 = 0x220,
> > +	DIG_TERM_CAL_1 = 0x221,
> > +	DIG_TERM_CAL_2 = 0x222,
> > +	DIG_CLKLANE_LANE_6 = 0x307,
> > +	DIG_CLKLANE_OFFSET_CAL_0 = 0x39d,
> > +	DIG_LANE0_OFFSET_CAL_0 = 0x59f,
> > +	DIG_LANE0_DDL_0 = 0x5e0,
> > +	DIG_LANE1_OFFSET_CAL_0 = 0x79f,
> > +	DIG_LANE1_DDL_0 = 0x7e0,
> > +	DIG_LANE2_OFFSET_CAL_0 = 0x99f,
> > +	DIG_LANE2_DDL_0 = 0x9e0,
> > +	DIG_LANE3_OFFSET_CAL_0 = 0xb9f,
> > +	DIG_LANE3_DDL_0 = 0xbe0,
> > +};
> > +
> > +#define SYS_0_HSFREQRANGE_OVR  BIT(5)
> > +#define SYS_3_NO_REXT	       BIT(4)
> > +#define SYS_7_RESERVED	       FIELD_PREP(0x1f, 0x0c)
> > +#define SYS_7_DESKEW_POL       BIT(5)
> > +#define STARTUP_OVR_4_CNTVAL   FIELD_PREP(0x70, 0x01)
> > +#define STARTUP_OVR_4_DDL_EN   BIT(0)
> > +#define STARTUP_OVR_5_BYPASS   BIT(0)
> > +#define CB_2_LPRX_BIAS	       BIT(6)
> > +#define CB_2_RESERVED	       FIELD_PREP(0x3f, 0x0b)
> > +#define CLKLANE_RXHS_PULL_LONG BIT(7)
> > +
> > +/* bit mask for calibration result registers */ #define
> > +MASK_TERM_CAL_ERR  0 #define MASK_TERM_CAL_DONE BIT(7)
> > +#define MASK_CLK_CAL_ERR   BIT(4)
> > +#define MASK_CLK_CAL_DONE  BIT(0)
> > +#define MASK_CAL_ERR	   BIT(2)
> > +#define MASK_CAL_DONE	   BIT(1)
> > +#define MASK_DDL_ERR	   BIT(1)
> > +#define MASK_DDL_DONE	   BIT(2)
> > +
> > +#define VISCONTI_CSI2RX_ERROR_MONITORS_NUM 8
> > +
> > +/**
> > + * struct visconti_csi2rx_line_err_target
> > + *
> > + * Virtual Channel and Data Type pair for CSI2RX line error monitor
> > + *
> > + * When 0 is set to dt, line error detection is disabled.
> > + *
> > + * @vc: Virtual Channel to monitor; Range 0..3
> > + * @dt: Data Type to monitor; Range 0, 0x10..0x3f  */ struct
> > +visconti_csi2rx_line_err_target {
> > +	u32 vc[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
> > +	u32 dt[VISCONTI_CSI2RX_ERROR_MONITORS_NUM];
> > +};
> > +
> > +#define CSI2RX_MIN_DATA_RATE 80U
> > +#define CSI2RX_MAX_DATA_RATE 1500U
> > +
> > +#define VISCONTI_CSI2RX_PAD_SINK 0
> > +#define VISCONTI_CSI2RX_PAD_SRC	 1
> > +#define VISCONTI_CSI2RX_PAD_NUM	 2
> > +
> > +#define VISCONTI_CSI2RX_DEF_WIDTH  1920 #define
> > +VISCONTI_CSI2RX_DEF_HEIGHT 1080 #define
> VISCONTI_CSI2RX_MIN_WIDTH
> > +640 #define VISCONTI_CSI2RX_MAX_WIDTH  3840 #define
> > +VISCONTI_CSI2RX_MIN_HEIGHT 480 #define
> VISCONTI_CSI2RX_MAX_HEIGHT
> > +2160
> > +
> > +struct visconti_csi2rx {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +
> > +	struct v4l2_subdev subdev;
> > +	struct media_pad pads[VISCONTI_CSI2RX_PAD_NUM];
> > +	struct v4l2_async_notifier notifier;
> > +	struct v4l2_subdev *remote;
> > +	unsigned int remote_pad;
> > +
> > +	unsigned int lanes;
> > +
> > +	unsigned int irq;
> > +};
> > +
> > +static inline struct visconti_csi2rx *notifier_to_csi2(struct
> > +v4l2_async_notifier *n) {
> > +	return container_of(n, struct visconti_csi2rx, notifier); }
> > +
> > +static inline struct visconti_csi2rx *sd_to_csi2(struct v4l2_subdev
> > +*sd) {
> > +	return container_of(sd, struct visconti_csi2rx, subdev); }
> > +
> > +static inline void visconti_csi2rx_write(struct visconti_csi2rx
> > +*priv, u32 regid, u32 val)
> 
> The media subsystem tries to limit line lengths to 80 columns, when it doesn't
> hinder readability. For instance here you could write
> 
> static inline void visconti_csi2rx_write(struct visconti_csi2rx *priv,
> 					 u32 regid, u32 val)
> 
> If lines are just a few characters over 80 columns the need to break them is less
> than if they approach 100 columns. It's a "soft limit"
> policy to try and maximize readability.
> 

I understand the policy.
I'll limit each line to around 80 columns.

> > +{
> > +	writel(val, priv->base + regid);
> > +}
> > +
> > +static inline u32 visconti_csi2rx_read(struct visconti_csi2rx *priv,
> > +u32 regid) {
> > +	return readl(priv->base + regid);
> > +}
> > +
> > +static inline void tick_testclk(struct visconti_csi2rx *priv)
> 
> Don't inline this or the next function, compilers are smart enough to decide by
> themselves these days.
> 

I'll remove inline specifier.
Do I also need to remove it from other multi-line functions?

> > +{
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0,
> BIT_TESTCTRL0_CLK_1);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0,
> > +BIT_TESTCTRL0_CLK_0); }
> > +
> > +static inline void set_dphy_addr(struct visconti_csi2rx *priv, u32
> > +test_mode) {
> > +	/* select testcode Ex space with top 4bits of test_mode */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> > +			      BIT_TESTCTRL1_ADDR |
> DIG_TESTCODE_EXT);
> > +	tick_testclk(priv);
> 
> If writing to REG_CSI2RX_PHY_TESTCTRL1 always needs to be followed by a
> call to tick_testclk(), I would create a visconti_csi2rx_dphy_write()
> function:
> 
> static void visconti_csi2rx_dphy_write(struct visconti_csi2rx *priv, u32 data) {
> 	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1, data);
> 	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0,
> BIT_TESTCTRL0_CLK_1);
> 	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0,
> BIT_TESTCTRL0_CLK_0); }
> 

The writing to REG_CSI2RX_PHY_TESTCTRL1 is always followed by a call to tick_testclk(). This sequence can be merged.
I'll add visconti_csi2rx_dphy_write().

> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> > +FIELD_GET(0xf00, test_mode));
> 
> And here
> 
> 	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> 			      FIELD_GET(0xf00, test_mode));
> 
> There are many other places below that go over 80 columns.
> 

I understand the policy.
I'll update the code not to go over 80 columns.

> > +	tick_testclk(priv);
> > +
> > +	/* set bottom 8bit of test_mode */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> > +			      BIT_TESTCTRL1_ADDR | FIELD_GET(0xff,
> test_mode));
> > +	tick_testclk(priv);
> > +}
> > +
> > +static void write_dphy_param(struct visconti_csi2rx *priv, u32
> > +test_mode, u8 test_in) {
> > +	set_dphy_addr(priv, test_mode);
> > +
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL1,
> (u32)test_in);
> 
> Is the (u8) explicit cast needed ?
> 

There's no need for it. I'll remove the cast operator.

> > +	tick_testclk(priv);
> > +}
> > +
> > +struct csi2rx_dphy_hs_info {
> > +	u32 rate;
> > +	u32 hsfreqrange;
> > +	u32 osc_freq_target;
> > +};
> > +
> > +static const struct csi2rx_dphy_hs_info dphy_hs_info[] = {
> > +	{ 80, 0x0, 0x1cc },   { 85, 0x10, 0x1cc },   { 95, 0x20, 0x1cc },   { 105,
> 0x30, 0x1cc },
> > +	{ 115, 0x1, 0x1cc },  { 125, 0x11, 0x1cc },  { 135, 0x21, 0x1cc },  { 145,
> 0x31, 0x1cc },
> > +	{ 155, 0x2, 0x1cc },  { 165, 0x12, 0x1cc },  { 175, 0x22, 0x1cc },  { 185,
> 0x32, 0x1cc },
> > +	{ 198, 0x3, 0x1cc },  { 213, 0x13, 0x1cc },  { 228, 0x23, 0x1cc },  { 243,
> 0x33, 0x1cc },
> > +	{ 263, 0x4, 0x1cc },  { 288, 0x14, 0x1cc },  { 313, 0x25, 0x1cc },  { 338,
> 0x35, 0x1cc },
> > +	{ 375, 0x5, 0x1cc },  { 425, 0x16, 0x1cc },  { 475, 0x26, 0x1cc },  { 525,
> 0x37, 0x1cc },
> > +	{ 575, 0x7, 0x1cc },  { 625, 0x18, 0x1cc },  { 675, 0x28, 0x1cc },  { 725,
> 0x39, 0x1cc },
> > +	{ 775, 0x9, 0x1cc },  { 825, 0x19, 0x1cc },  { 875, 0x29, 0x1cc },  { 925,
> 0x3a, 0x1cc },
> > +	{ 975, 0xa, 0x1cc },  { 1025, 0x1a, 0x1cc }, { 1075, 0x2a, 0x1cc }, { 1125,
> 0x3b, 0x1cc },
> > +	{ 1175, 0xb, 0x1cc }, { 1225, 0x1b, 0x1cc }, { 1275, 0x2b, 0x1cc }, { 1325,
> 0x3c, 0x1cc },
> > +	{ 1375, 0xc, 0x1cc }, { 1425, 0x1c, 0x1cc }, { 1475, 0x2c, 0x1cc }
> 
> osc_freq_target seems to always be 0x1cc, does it have to be stored in this
> table ?
> 

I checked the document and found that osc_freq_target is always 0x1cc for tested cases.
I'll remove the member from the table and make it a constant value.

> > +};
> > +
> > +static void get_dphy_hs_transfer_info(u32 dphy_rate, u32
> > +*hsfreqrange, u32 *osc_freq_target) {
> > +	unsigned int i;
> > +
> > +	for (i = 1; i < ARRAY_SIZE(dphy_hs_info); i++) {
> > +		if (dphy_rate < dphy_hs_info[i].rate) {
> > +			*hsfreqrange = dphy_hs_info[i - 1].hsfreqrange;
> > +			*osc_freq_target = dphy_hs_info[i -
> 1].osc_freq_target;
> > +			return;
> > +		}
> > +	}
> > +
> > +	/* not found; return the largest entry */
> > +	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) -
> 1].hsfreqrange;
> > +	*osc_freq_target = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) -
> > +1].osc_freq_target; }
> > +
> > +static void visconti_csi2rx_set_dphy_rate(struct visconti_csi2rx
> > +*priv, u32 dphy_rate) {
> > +	u32 hsfreqrange, osc_freq_target;
> > +
> > +	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange,
> > +&osc_freq_target);
> > +
> > +	write_dphy_param(priv, DIG_SYS_1, (u8)hsfreqrange);
> 
> I don't think the explicit cast is needed here either.
> 

I'll remove the cast operator.

> > +	write_dphy_param(priv, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
> > +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_5,
> STARTUP_OVR_5_BYPASS);
> > +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4,
> STARTUP_OVR_4_CNTVAL);
> > +	write_dphy_param(priv, DIG_CB_2, CB_2_LPRX_BIAS |
> CB_2_RESERVED);
> > +	write_dphy_param(priv, DIG_SYS_7, SYS_7_DESKEW_POL |
> SYS_7_RESERVED);
> > +	write_dphy_param(priv, DIG_CLKLANE_LANE_6,
> CLKLANE_RXHS_PULL_LONG);
> > +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_2, FIELD_GET(0xff,
> osc_freq_target));
> > +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_3, FIELD_GET(0xf00,
> osc_freq_target));
> > +	write_dphy_param(priv, DIG_RX_STARTUP_OVR_4,
> STARTUP_OVR_4_CNTVAL |
> > +STARTUP_OVR_4_DDL_EN); }
> > +
> > +static int visconti_csi2rx_initialize(struct visconti_csi2rx *priv, u32
> num_lane, u32 dphy_rate,
> > +				      const struct
> visconti_csi2rx_line_err_target *err_target) {
> > +	u32 val;
> > +
> > +	if (dphy_rate < CSI2RX_MIN_DATA_RATE || dphy_rate >
> CSI2RX_MAX_DATA_RATE) {
> > +		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)",
> dphy_rate);
> > +		return -ERANGE;
> > +	}
> > +
> > +	/* 1st phase of initialization */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 1);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> > +	ndelay(15U);
> 
> I don't mind much, but the U suffix here and in many other places seems
> unneeded.
> 

This suffix seems excessive. I'll remove U suffix in similar cases.

> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 0);
> > +
> > +	/* Configure D-PHY frequency range */
> > +	visconti_csi2rx_set_dphy_rate(priv, dphy_rate);
> > +
> > +	/* 2nd phase of initialization */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_NLANES, (num_lane - 1U));
> 
> No need for the inner parentheses.
> 

I'll remove them.

> > +	ndelay(5U);
> > +
> > +	/* Release D-PHY from Reset */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
> > +	ndelay(5U);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 1);
> > +
> > +	/* configuration of line error target */
> > +	val = (err_target->vc[3] << 30U) | (err_target->dt[3] << 24U) |
> (err_target->vc[2] << 22U) |
> > +	      (err_target->dt[2] << 16U) | (err_target->vc[1] << 14U) |
> (err_target->dt[1] << 8U) |
> > +	      (err_target->vc[0] << 6U) | (err_target->dt[0]);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_1, val);
> > +	val = (err_target->vc[7] << 30U) | (err_target->dt[7] << 24U) |
> (err_target->vc[6] << 22U) |
> > +	      (err_target->dt[6] << 16U) | (err_target->vc[5] << 14U) |
> (err_target->dt[5] << 8U) |
> > +	      (err_target->vc[4] << 6U) | (err_target->dt[4]);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_DATA_IDS_2, val);
> > +
> > +	/* configuration of mask */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL,
> MASK_PHY_FATAL_ALL);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL,
> MASK_PKT_FATAL_ALL);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL,
> MASK_FRAME_FATAL_ALL);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY,
> MASK_PHY_ERROR_ALL);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT,
> MASK_PKT_ERROR_ALL);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE,
> > +MASK_LINE_ERROR_ALL);
> > +
> > +	return 0;
> > +}
> > +
> > +struct visconti_csi2rx_format {
> > +	u32 code;
> > +	unsigned int bpp;
> > +};
> > +
> > +static const struct visconti_csi2rx_format visconti_csi2rx_formats[] = {
> > +	{ .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24 },
> > +	{ .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 },
> > +	{ .code = MEDIA_BUS_FMT_UYVY10_1X20, .bpp = 20 },
> > +	{ .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16 },
> > +	{ .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8 },
> > +	{ .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8 },
> > +	{ .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8 },
> > +	{ .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8 },
> > +	{ .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10 },
> > +	{ .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10 },
> > +	{ .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10 },
> > +	{ .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10 },
> > +	{ .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12 },
> > +	{ .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12 },
> > +	{ .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12 },
> > +	{ .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12 },
> > +	{ .code = MEDIA_BUS_FMT_SBGGR14_1X14, .bpp = 14 },
> > +	{ .code = MEDIA_BUS_FMT_SGBRG14_1X14, .bpp = 14 },
> > +	{ .code = MEDIA_BUS_FMT_SGRBG14_1X14, .bpp = 14 },
> > +	{ .code = MEDIA_BUS_FMT_SRGGB14_1X14, .bpp = 14 }, };
> > +
> > +static const struct visconti_csi2rx_format
> > +*fmt_for_mbus_code(unsigned int mbus_code) {
> > +	int i;
> 
> unsigned int
> 

I'll fix it.

> > +
> > +	for (i = 0; ARRAY_SIZE(visconti_csi2rx_formats); i++)
> > +		if (visconti_csi2rx_formats[i].code == mbus_code)
> > +			return &visconti_csi2rx_formats[i];
> 
> Please use curly braces for the 'for' statement.

I'll add curly braces.

> 
> No return when the look doesn't find a match ?
> 

There should have been "return NULL" at the end of the function.
I'll fix it.

> > +}
> > +
> > +static unsigned int bpp_for_mbus_code(unsigned int mbus_code) {
> > +	const struct visconti_csi2rx_format *fmt =
> > +fmt_for_mbus_code(mbus_code);
> > +
> > +	return fmt ? fmt->bpp : 0;
> > +}
> > +
> > +static int64_t get_pixelclock(struct v4l2_subdev *sd) {
> > +	struct v4l2_ctrl *ctrl;
> > +
> > +	ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
> > +	if (!ctrl)
> > +		return -EINVAL;
> > +
> > +	return v4l2_ctrl_g_ctrl_int64(ctrl); }
> > +
> > +static const struct visconti_csi2rx_line_err_target err_target_vc0_alldt = {
> > +	/* select VC=0 */
> > +	/* select all supported DataTypes */
> > +	.dt = {
> > +		MIPI_CSI2_DT_RGB565,
> > +		MIPI_CSI2_DT_YUV422_8B,
> > +		MIPI_CSI2_DT_YUV422_10B,
> > +		MIPI_CSI2_DT_RGB888,
> > +		MIPI_CSI2_DT_RAW8,
> > +		MIPI_CSI2_DT_RAW10,
> > +		MIPI_CSI2_DT_RAW12,
> > +		MIPI_CSI2_DT_RAW14,
> > +	}
> > +};
> > +
> > +static int visconti_csi2rx_start(struct visconti_csi2rx *priv, struct
> > +v4l2_subdev_state *state) {
> > +	struct v4l2_mbus_framefmt *sink_fmt;
> 
> const
> 

I'll add a const qualifier.

> > +	int cur_bpp, dphy_rate;
> > +	s64 pixelclock;
> > +
> > +	/* get bpp for current format */
> > +	sink_fmt = v4l2_subdev_state_get_format(state,
> VISCONTI_CSI2RX_PAD_SINK);
> > +	cur_bpp = bpp_for_mbus_code(sink_fmt->code);
> 
> 	bpp = fmt_for_mbus_code(sink_fmt->code)->bpp;
> 
> and drop the bpp_for_mbus_code() function.
> 

I'll drop bpp_for_mbus_code().
Is NULL check for fmt_for_mbus_code(sink_fmt->code) required?

> > +
> > +	/* get pixel clock */
> > +	pixelclock = get_pixelclock(priv->remote);
> 
> Use v4l2_get_link_freq() and drop the get_pixelclock() function.
> 

I'll use v4l2_get_link_freq().

> > +	if (pixelclock < 0)
> > +		return -EINVAL;
> > +
> > +	dphy_rate = div64_u64((u64)pixelclock * (u32)cur_bpp, priv->lanes *
> > +1000000);
> > +
> > +	ndelay(15U);
> > +
> > +	return visconti_csi2rx_initialize(priv, priv->lanes, dphy_rate,
> > +&err_target_vc0_alldt); }
> > +
> > +static void visconti_csi2rx_stop(struct visconti_csi2rx *priv) {
> > +	/* disable interrupt -> make sure registers cleared -> wait for current
> handlers finish */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PHY, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_PKT, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_INT_MSK_LINE, 0);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY_FATAL);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT_FATAL);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PHY);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_PKT);
> > +	visconti_csi2rx_read(priv, REG_CSI2RX_INT_MSK_LINE);
> > +	synchronize_irq(priv->irq);
> > +
> > +	/* shutdown hardware */
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> > +	visconti_csi2rx_write(priv, REG_CSI2RX_RESETN, 0); }
> > +
> > +static int visconti_csi2rx_enable_streams(struct v4l2_subdev *sd, struct
> v4l2_subdev_state *state,
> > +					  u32 pad, u64 streams_mask)
> > +{
> > +	struct visconti_csi2rx *priv = sd_to_csi2(sd);
> > +	struct v4l2_subdev *remote_sd;
> > +	struct media_pad *remote_pad;
> > +	int ret;
> > +
> > +	remote_pad =
> media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK
> ]);
> > +	if (!remote_pad)
> > +		return -ENODEV;
> 
> Can't you use priv->remote and priv->remote_pad in this function instead of
> getting the remote pad dynamically ? Same in
> visconti_csi2rx_disable_streams().
> 

I'll use priv->remote, and priv->remote_pad.

> > +	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
> > +
> > +	/* enabling: turn on CSI2RX -> turn on sensor */
> > +	ret = visconti_csi2rx_start(priv, state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* currently CSI2RX supports only stream0 in source pad */
> > +	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
> BIT(0));
> > +	if (ret) {
> > +		visconti_csi2rx_stop(priv);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int visconti_csi2rx_disable_streams(struct v4l2_subdev *sd, struct
> v4l2_subdev_state *state,
> > +					   u32 pad, u64 streams_mask)
> > +{
> > +	struct visconti_csi2rx *priv = sd_to_csi2(sd);
> > +	struct v4l2_subdev *remote_sd;
> > +	struct media_pad *remote_pad;
> > +
> > +	remote_pad =
> media_pad_remote_pad_first(&sd->entity.pads[VISCONTI_CSI2RX_PAD_SINK
> ]);
> > +	if (!remote_pad)
> > +		return -ENODEV;
> > +	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
> > +
> > +	/* disabling: turn off sensor -> turn off CSI2RX */
> > +	v4l2_subdev_disable_streams(remote_sd, remote_pad->index,
> BIT(0));
> > +	visconti_csi2rx_stop(priv);
> > +
> > +	return 0;
> > +}
> > +
> > +static int visconti_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
> > +					  struct v4l2_subdev_state
> *sd_state,
> > +					  struct
> v4l2_subdev_mbus_code_enum *code) {
> > +	if (code->pad == VISCONTI_CSI2RX_PAD_SRC) {
> > +		const struct v4l2_mbus_framefmt *sink_fmt;
> > +
> > +		/* SRC pad supports exactly the same format as SINK pad */
> > +		if (code->index)
> > +			return -EINVAL;
> > +		sink_fmt = v4l2_subdev_state_get_format(sd_state,
> VISCONTI_CSI2RX_PAD_SINK);
> > +		code->code = sink_fmt->code;
> > +		return 0;
> > +	}
> > +
> > +	if (code->index >= ARRAY_SIZE(visconti_csi2rx_formats))
> > +		return -EINVAL;
> > +	code->code = visconti_csi2rx_formats[code->index].code;
> > +
> > +	return 0;
> > +}
> > +
> > +static int visconti_csi2rx_init_state(struct v4l2_subdev *sd, struct
> > +v4l2_subdev_state *sd_state) {
> > +	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
> > +
> > +	sink_fmt = v4l2_subdev_state_get_format(sd_state,
> VISCONTI_CSI2RX_PAD_SINK);
> > +	src_fmt = v4l2_subdev_state_get_format(sd_state,
> > +VISCONTI_CSI2RX_PAD_SRC);
> > +
> > +	sink_fmt->width = VISCONTI_CSI2RX_DEF_WIDTH;
> > +	sink_fmt->height = VISCONTI_CSI2RX_DEF_HEIGHT;
> > +	sink_fmt->field = V4L2_FIELD_NONE;
> > +	sink_fmt->code = visconti_csi2rx_formats[0].code;
> 
> Please also initialize the colourspace fields. V4L2_COLORSPACE_RAW,
> V4L2_XFER_FUNC_NONE, V4L2_YCBCR_ENC_601 and
> V4L2_QUANTIZATION_FULL_RANGE should be appropriate defaults.
> 

I'll set the default value to colourspace fields.

> > +
> > +	*src_fmt = *sink_fmt;
> > +
> > +	return 0;
> > +}
> > +
> > +static int visconti_csi2rx_set_pad_format(struct v4l2_subdev *sd,
> > +					  struct v4l2_subdev_state
> *sd_state,
> > +					  struct v4l2_subdev_format *fmt) {
> > +	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
> > +
> > +	/* SRC PAD has the same format as SINK PAD */
> > +	if (fmt->pad == 1)
> 
> 	if (fmt->pad == VISCONTI_CSI2RX_PAD_SRC)
> 

I'll use the constant macro.

> > +		return v4l2_subdev_get_fmt(sd, sd_state, fmt);
> > +
> > +	sink_fmt = v4l2_subdev_state_get_format(sd_state,
> > +VISCONTI_CSI2RX_PAD_SINK);
> > +
> > +	*sink_fmt = fmt->format;
> > +	sink_fmt->width = clamp_t(u32, fmt->format.width,
> VISCONTI_CSI2RX_MIN_WIDTH,
> > +				  VISCONTI_CSI2RX_MAX_WIDTH);
> > +	sink_fmt->height = clamp_t(u32, fmt->format.height,
> VISCONTI_CSI2RX_MIN_HEIGHT,
> > +				   VISCONTI_CSI2RX_MAX_HEIGHT);
> > +	if (!fmt_for_mbus_code(sink_fmt->code))
> > +		sink_fmt->code = visconti_csi2rx_formats[0].code;
> > +	fmt->format = *sink_fmt;
> > +
> > +	/* source pad should have the same format */
> > +	src_fmt = v4l2_subdev_state_get_format(sd_state,
> VISCONTI_CSI2RX_PAD_SRC);
> > +	*src_fmt = *sink_fmt;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct media_entity_operations visconti_csi2rx_entity_ops = {
> > +	.link_validate = v4l2_subdev_link_validate, };
> > +
> > +static const struct v4l2_subdev_video_ops visconti_csi2rx_video_ops = {
> > +	.s_stream = v4l2_subdev_s_stream_helper,
> 
> As the only driver that will use this CSI-2 RX is the VIIF driver, and that driver
> uses v4l2_subdev_enable_streams(), .s_stream() will never be called. You can
> drop the v4l2_subdev_video_ops.
> 

I'll drop visconti_csi2rx_video_ops.

> > +};
> > +
> > +static const struct v4l2_subdev_pad_ops visconti_csi2rx_pad_ops = {
> > +	.enum_mbus_code = visconti_csi2rx_enum_mbus_code,
> 
> You also need to implement .enum_frame_size()
> 

I'll implement it.

> > +	.disable_streams = visconti_csi2rx_disable_streams,
> > +	.enable_streams = visconti_csi2rx_enable_streams,
> > +	.get_fmt = v4l2_subdev_get_fmt,
> > +	.set_fmt = visconti_csi2rx_set_pad_format, };
> > +
> > +static const struct v4l2_subdev_ops visconti_csi2rx_subdev_ops = {
> > +	.video = &visconti_csi2rx_video_ops,
> > +	.pad = &visconti_csi2rx_pad_ops,
> > +};
> > +
> > +static const struct v4l2_subdev_internal_ops visconti_csi2rx_internal_ops =
> {
> > +	.init_state = visconti_csi2rx_init_state, };
> > +
> > +static int visconti_csi2rx_notify_bound(struct v4l2_async_notifier *notifier,
> > +					struct v4l2_subdev *subdev,
> > +					struct v4l2_async_connection *asc) {
> > +	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
> > +	int pad;
> > +
> > +	pad = media_entity_get_fwnode_pad(&subdev->entity,
> asc->match.fwnode, MEDIA_PAD_FL_SOURCE);
> > +	if (pad < 0) {
> > +		dev_err(priv->dev, "Failed to find pad for %s\n",
> subdev->name);
> > +		return pad;
> > +	}
> > +
> > +	priv->remote = subdev;
> > +	priv->remote_pad = pad;
> > +
> > +	return media_create_pad_link(&subdev->entity, pad,
> &priv->subdev.entity, 0,
> > +				     MEDIA_LNK_FL_ENABLED);
> 
> Can you have multiple sources connected to the same CSI-2 receiver ? If not,
> you can make the link to the source immutable.
> 

Assuming that "sources" mean image sensors, the CSI-2 receiver does not support multiple sources.
I'll set MEDIA_LNK_FL_IMMUTABLE flag.

> > +}
> > +
> > +static void visconti_csi2rx_notify_unbind(struct v4l2_async_notifier
> *notifier,
> > +					  struct v4l2_subdev *subdev,
> > +					  struct v4l2_async_connection *asc)
> {
> > +	struct visconti_csi2rx *priv = notifier_to_csi2(notifier);
> > +
> > +	priv->remote = NULL;
> > +}
> > +
> > +static const struct v4l2_async_notifier_operations
> visconti_csi2rx_notify_ops = {
> > +	.bound = visconti_csi2rx_notify_bound,
> > +	.unbind = visconti_csi2rx_notify_unbind, };
> > +
> > +static int visconti_csi2rx_parse_v4l2(struct visconti_csi2rx *priv,
> > +				      struct v4l2_fwnode_endpoint *vep) {
> > +	/* Only port 0 endpoint 0 is valid. */
> > +	if (vep->base.port || vep->base.id)
> > +		return -ENOTCONN;
> 
> You call fwnode_graph_get_endpoint_by_id() with port and endpoint set to 0,
> so I think you can drop this check.
> 

I'll drop the check.

> > +
> > +	priv->lanes = vep->bus.mipi_csi2.num_data_lanes;
> > +
> > +	/* got trouble */
> > +	if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
> > +		dev_err(priv->dev, "Specified bus type is not supported\n");
> 
> If you only support D-PHY, then set the bus_type to V4L2_MBUS_CSI2_DPHY
> instead of V4L2_MBUS_UNKNOWN in visconti_csi2rx_parse_dt().
> v4l2_fwnode_endpoint_parse() will return an error if the bus type is not D-PHY,
> and you can drop this check.
> 

I'll update the query and drop this check.

> > +		return -EINVAL;
> > +	}
> > +
> > +	if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) {
> > +		dev_err(priv->dev, "Unsupported number of data-lanes for
> D-PHY: %u\n", priv->lanes);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int visconti_csi2rx_parse_dt(struct visconti_csi2rx *priv) {
> > +	struct v4l2_async_connection *asc;
> > +	struct fwnode_handle *fwnode;
> > +	struct fwnode_handle *ep;
> > +	struct v4l2_fwnode_endpoint v4l2_ep = {
> > +		.bus_type = V4L2_MBUS_UNKNOWN,
> > +	};
> > +	int ret;
> > +
> > +	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0,
> 0);
> > +	if (!ep) {
> > +		dev_err(priv->dev, "Not connected to subdevice\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
> > +	if (ret) {
> > +		dev_err(priv->dev, "Could not parse v4l2 endpoint\n");
> > +		fwnode_handle_put(ep);
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = visconti_csi2rx_parse_v4l2(priv, &v4l2_ep);
> 
> I would inline what is left of that function in here.
> 

I'll inline visconti_csi2rx_parse_v4l2()

> > +	if (ret) {
> > +		fwnode_handle_put(ep);
> > +		return ret;
> > +	}
> > +
> > +	fwnode = fwnode_graph_get_remote_endpoint(ep);
> > +	fwnode_handle_put(ep);
> > +
> > +	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
> > +	priv->notifier.ops = &visconti_csi2rx_notify_ops;
> > +
> > +	asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, struct
> v4l2_async_connection);
> > +	fwnode_handle_put(fwnode);
> > +	if (IS_ERR(asc))
> > +		return PTR_ERR(asc);
> > +
> > +	ret = v4l2_async_nf_register(&priv->notifier);
> > +	if (ret)
> > +		v4l2_async_nf_cleanup(&priv->notifier);
> > +
> > +	return ret;
> > +}
> > +
> > +static irqreturn_t visconti_csi2rx_irq(int irq, void *dev_id) {
> > +	struct visconti_csi2rx *priv = dev_id;
> > +	u32 event;
> > +
> > +	event = visconti_csi2rx_read(priv, REG_CSI2RX_INT_ST_MAIN);
> > +	dev_err(priv->dev, "CSI2RX error 0x%x.\n", event);
> 
> Should this be at least rate-limited ?
> 

I'll use dev_err_ratelimited().

> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static const struct of_device_id visconti_csi2rx_of_table[] = {
> > +	{
> > +		.compatible = "toshiba,visconti5-csi2rx",
> > +	},
> > +	{},
> 
> 	{ /* Sentinel */ },
> 
> is customary. You can also drop the trailing comma, as there should never be
> any entry after this one.
> 

I'll update the initializer.

> > +};
> > +
> > +static int visconti_csi2rx_probe(struct platform_device *pdev) {
> > +	struct visconti_csi2rx *priv;
> > +	int irq, ret;
> > +
> > +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->dev = &pdev->dev;
> > +
> > +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(priv->base)) {
> > +		dev_err(priv->dev, "Failed to get registers\n");
> 
> devm_platform_ioremap_resource() prints an error message already, you can
> drop this one.
> 

I'll drop the message output.

> > +		return PTR_ERR(priv->base);
> > +	}
> > +
> > +	irq = platform_get_irq(pdev, 0);
> > +	if (irq < 0)
> > +		return irq;
> 
> Here, on the other hand, an error message would be useful. You can use
> dev_err_probe():
> 
> 		return dev_err_probe(priv->dev, irq, "Failed to get IRQ\n");
> 

I'll keep it.

> > +	ret = devm_request_irq(&pdev->dev, irq, visconti_csi2rx_irq, 0,
> KBUILD_MODNAME, priv);
> > +	priv->irq = irq;
> > +	if (ret) {
> > +		dev_err(priv->dev, "request irq failed: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +
> > +	ret = visconti_csi2rx_parse_dt(priv); /*this function does
> v4l2_async_nf_register */
> > +	if (ret)
> > +		return ret;
> > +
> > +	priv->subdev.owner = THIS_MODULE;
> 
> Not needed, this is handled by v4l2_async_register_subdev()
> 

I'll drop it.

> > +	priv->subdev.dev = &pdev->dev;
> > +	v4l2_subdev_init(&priv->subdev, &visconti_csi2rx_subdev_ops);
> > +	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
> > +	snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s",
> KBUILD_MODNAME,
> > +		 dev_name(&pdev->dev));
> > +
> > +	priv->subdev.internal_ops = &visconti_csi2rx_internal_ops;
> > +	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> > +	priv->subdev.entity.function =
> > +MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
> 
> MEDIA_ENT_F_VID_IF_BRIDGE seems more appropriate.
> 

I'll use MEDIA_ENT_F_VID_IF_BRIDGE.

> > +	priv->subdev.entity.ops = &visconti_csi2rx_entity_ops;
> > +
> > +	priv->pads[VISCONTI_CSI2RX_PAD_SINK].flags =
> MEDIA_PAD_FL_SINK;
> > +	priv->pads[VISCONTI_CSI2RX_PAD_SRC].flags =
> MEDIA_PAD_FL_SOURCE;
> > +
> > +	ret = media_entity_pads_init(&priv->subdev.entity,
> > +VISCONTI_CSI2RX_PAD_NUM, priv->pads);
> 
> 	ret = media_entity_pads_init(&priv->subdev.entity,
> ARRAY_SIZE(priv->pads),
> 				     priv->pads);
> 
> 

I'll use ARRAY_SIZE.

> > +	if (ret)
> > +		goto err_cleanup_async;
> > +
> > +	ret = v4l2_subdev_init_finalize(&priv->subdev);
> > +	if (ret)
> > +		goto err_cleanup_media_entity;
> > +
> > +	ret = v4l2_async_register_subdev(&priv->subdev);
> > +	if (ret < 0)
> > +		goto err_cleanup_subdev_state;
> > +
> > +	return 0;
> > +
> > +err_cleanup_subdev_state:
> > +	v4l2_subdev_cleanup(&priv->subdev);
> > +
> > +err_cleanup_media_entity:
> > +	media_entity_cleanup(&priv->subdev.entity);
> > +
> > +err_cleanup_async:
> > +	v4l2_async_nf_unregister(&priv->notifier);
> > +	v4l2_async_nf_cleanup(&priv->notifier);
> > +
> > +	return ret;
> > +}
> > +
> > +static void visconti_csi2rx_remove(struct platform_device *pdev) {
> > +	struct visconti_csi2rx *priv = platform_get_drvdata(pdev);
> > +
> > +	v4l2_async_nf_unregister(&priv->notifier);
> > +	v4l2_async_nf_cleanup(&priv->notifier);
> > +	v4l2_async_unregister_subdev(&priv->subdev);
> > +
> > +	v4l2_subdev_cleanup(&priv->subdev);
> > +	media_entity_cleanup(&priv->subdev.entity);
> > +}
> > +
> > +static struct platform_driver visconti_csi2rx_driver = {
> > +	.probe = visconti_csi2rx_probe,
> > +	.remove = visconti_csi2rx_remove,
> > +	.driver = {
> > +		.name = "visconti_csi2rx_dev",
> > +		.of_match_table = visconti_csi2rx_of_table,
> > +	},
> > +};
> > +
> > +module_platform_driver(visconti_csi2rx_driver);
> > +
> > +MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
> > +MODULE_DESCRIPTION("Toshiba Visconti CSI-2 receiver driver");
> > +MODULE_LICENSE("Dual BSD/GPL");
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,

Yuji Ishikawa

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

* Re: [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format
  2025-01-20  0:15     ` yuji2.ishikawa
@ 2025-01-20  1:49       ` Laurent Pinchart
  0 siblings, 0 replies; 36+ messages in thread
From: Laurent Pinchart @ 2025-01-20  1:49 UTC (permalink / raw)
  To: yuji2.ishikawa
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

On Mon, Jan 20, 2025 at 12:15:43AM +0000, yuji2.ishikawa@toshiba.co.jp wrote:
> On Thursday, January 2, 2025 10:10 PM, Laurent Pinchart wrote:
> > On Mon, Nov 25, 2024 at 06:21:41PM +0900, Yuji Ishikawa wrote:
> > > Adds the Toshiba Visconti VIIF specific metadata format
> > 
> > s/Adds/Add/
> > s/format/formats./
> 
> I'll fix the commit message.
> 
> > > - V4L2_META_FMT_VISCONTI_VIIF_PARAMS for ISP parameters
> > > - V4L2_META_FMT_VISCONTI_VIIF_STATS for ISP statistics
> > >
> > > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > 
> > Assuming the documentation of the formats in subsequent patches is fine,
> > 
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > > ---
> > > Changelog v10:
> > > - add entry for V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> > > - add entry for V4L2_META_FMT_VISCONTI_VIIF_STATS
> > >
> > > Changelog v11:
> > > - no change
> > >
> > > Changelog v12:
> > > - add description for meta formats at v4l2-ioctl.c
> > >
> > >  drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
> > >  include/uapi/linux/videodev2.h       | 4 ++++
> > >  2 files changed, 6 insertions(+)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > index 0304daa8471d..f7facb63b8ea 100644
> > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > @@ -1470,6 +1470,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
> > >  	case V4L2_META_FMT_RPI_BE_CFG:	descr = "RPi PiSP BE Config format"; break;
> > >  	case V4L2_META_FMT_RPI_FE_CFG:  descr = "RPi PiSP FE Config format"; break;
> > >  	case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics format"; break;
> > > +	case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti ISP Parameters"; break;
> > > +	case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP Statistics"; break;
> 
> The media-ci has reported the following errors.
> Is it all right to leave these errors unfixed and keep the lines with
> the same style as other entries?

Yes, you can ignore those issues.

> # Test checkpatch:./0003-media-uapi-add-visconti-viif-meta-buffer-format.patch
> ERROR: trailing statements should be on next line
> #26: FILE: drivers/media/v4l2-core/v4l2-ioctl.c:1473:
> +case V4L2_META_FMT_VISCONTI_VIIF_PARAMS: descr = "Visconti ISP 
> +Parameters"; break;
> 
> ERROR: trailing statements should be on next line
> #27: FILE: drivers/media/v4l2-core/v4l2-ioctl.c:1474:
> +case V4L2_META_FMT_VISCONTI_VIIF_STATS: descr = "Visconti ISP 
> +Statistics"; break;
> 
> total: 2 errors, 0 warnings, 0 checks, 18 lines checked
> 
> > >  	case V4L2_META_FMT_GENERIC_8:	descr = "8-bit Generic Metadata"; break;
> > >  	case V4L2_META_FMT_GENERIC_CSI2_10:	descr = "8-bit Generic Meta, 10b CSI-2"; break;
> > >  	case V4L2_META_FMT_GENERIC_CSI2_12:	descr = "8-bit Generic Meta, 12b CSI-2"; break;
> > > diff --git a/include/uapi/linux/videodev2.h
> > > b/include/uapi/linux/videodev2.h index a5418759e2ba..9e1f66fdf038
> > > 100644
> > > --- a/include/uapi/linux/videodev2.h
> > > +++ b/include/uapi/linux/videodev2.h
> > > @@ -863,6 +863,10 @@ struct v4l2_pix_format {
> > >  #define V4L2_META_FMT_RPI_FE_CFG	v4l2_fourcc('R', 'P', 'F', 'C') /* PiSP FE configuration */
> > >  #define V4L2_META_FMT_RPI_FE_STATS	v4l2_fourcc('R', 'P', 'F', 'S') /* PiSP FE stats */
> > >
> > > +/* Vendor specific - used for Visconti VIIF sub-system */
> > > +#define V4L2_META_FMT_VISCONTI_VIIF_PARAMS	v4l2_fourcc('V', 'I', 'F', 'P') /* ISP Params */
> > > +#define V4L2_META_FMT_VISCONTI_VIIF_STATS	v4l2_fourcc('V', 'I', 'F', 'S') /* ISP Stats */
> > > +
> > >  #ifdef __KERNEL__
> > >  /*
> > >   * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when

-- 
Regards,

Laurent Pinchart

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

* RE: [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver
  2025-01-02 21:26   ` Laurent Pinchart
@ 2025-02-05 12:29     ` yuji2.ishikawa
  2025-04-15  9:01       ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: yuji2.ishikawa @ 2025-02-05 12:29 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Friday, January 3, 2025 6:26 AM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 7/8] documentation: media: add documentation for
> Toshiba Visconti Video Input Interface driver
> 
> Hi Ishikawa-san,
> 
> Thank you for the patch.
> 
> Overall the documentation looks quite good, it has significantly improved
> compared to early versions.
> 
> On Mon, Nov 25, 2024 at 06:21:45PM +0900, Yuji Ishikawa wrote:
> > Added description of Video Input Interface driver of
> 
> s/Added/Add/
> 

I'll fix it

> > Toshiba Visconti architecture.
> > It includes hardware organization, structure of the driver and
> > metadata format for embedded image signal processor.
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > ---
> > Changelog v3:
> > - Newly add documentation to describe SW and HW
> >
> > Changelog v4:
> > - no change
> >
> > Changelog v5:
> > - no change
> >
> > Changelog v6:
> > - add description of CSI2RX subdevice
> > - add ordering of ioctl(S_FMT) and ioctl(S_EXT_CTRLS)
> >
> > Changelog v7:
> > - no change
> >
> > Changelog v8:
> > - add usage of V4L2_CTRL_TYPE_VISCONTI_ISP
> >
> > Changelog v9:
> > - fix warning: set reference target for keyword
> > V4L2_CTRL_TYPE_VISCONTI_ISP
> >
> > Changelog v10:
> > - use parameter buffers instead of compound control
> >   - removed description of vendor specific compound control
> >   - add description of parameter buffers for ISP control
> > - update directory structure
> >   - remove documents under driver-api
> >   - add documents to admin-guide, userspace-api
> >
> > Changelog v11:
> > - update usage of the driver
> >
> > Changelog v12:
> > - add description of CSI2RX driver
> > - description of resizer subdevice
> > - add block diagrams of VIIF and ISP
> > - update usage of the driver
> >
> >  .../admin-guide/media/v4l-drivers.rst         |   1 +
> >  .../admin-guide/media/visconti-viif.dot       |  22 +
> >  .../admin-guide/media/visconti-viif.rst       | 435
> ++++++++++++++++++
> >  .../userspace-api/media/v4l/meta-formats.rst  |   1 +
> >  .../media/v4l/metafmt-visconti-viif.rst       |  48 ++
> >  5 files changed, 507 insertions(+)
> >  create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
> >  create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
> >  create mode 100644
> > Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> >
> > diff --git a/Documentation/admin-guide/media/v4l-drivers.rst
> > b/Documentation/admin-guide/media/v4l-drivers.rst
> > index b6af448b9fe9..81054512e768 100644
> > --- a/Documentation/admin-guide/media/v4l-drivers.rst
> > +++ b/Documentation/admin-guide/media/v4l-drivers.rst
> > @@ -32,5 +32,6 @@ Video4Linux (V4L) driver-specific documentation
> >  	si476x
> >  	starfive_camss
> >  	vimc
> > +	visconti-viif
> >  	visl
> >  	vivid
> > diff --git a/Documentation/admin-guide/media/visconti-viif.dot
> > b/Documentation/admin-guide/media/visconti-viif.dot
> > new file mode 100644
> > index 000000000000..cc75c73336fb
> > --- /dev/null
> > +++ b/Documentation/admin-guide/media/visconti-viif.dot
> > @@ -0,0 +1,22 @@
> > +digraph board {
> > +        rankdir=TB
> > +        n00000001 [label="{{<port0> 0 | <port4> 4} |
> visconti-viif:isp\n/dev/v4l-subdev0 | {<port1> 1 | <port2> 2 | <port3> 3 |
> <port5> 5}}", shape=Mrecord, style=filled, fillcolor=green]
> > +        n00000001:port1 -> n00000008:port0
> > +        n00000001:port2 -> n0000000b:port0
> > +        n00000001:port3 -> n00000016
> > +        n00000001:port5 -> n0000001e
> > +        n00000008 [label="{{<port0> 0} |
> visconti-viif:resizer0\n/dev/v4l-subdev1 | {<port1> 1}}", shape=Mrecord,
> style=filled, fillcolor=green]
> > +        n00000008:port1 -> n0000000e
> > +        n0000000b [label="{{<port0> 0} |
> visconti-viif:resizer1\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord,
> style=filled, fillcolor=green]
> > +        n0000000b:port1 -> n00000012
> > +        n0000000e [label="viif_capture_post0\n/dev/video0", shape=box,
> style=filled, fillcolor=yellow]
> > +        n00000012 [label="viif_capture_post1\n/dev/video1", shape=box,
> style=filled, fillcolor=yellow]
> > +        n00000016 [label="viif_capture_sub\n/dev/video2", shape=box,
> style=filled, fillcolor=yellow]
> > +        n0000001a [label="viif_params\n/dev/video3", shape=box,
> style=filled, fillcolor=yellow]
> > +        n0000001a -> n00000001:port4
> > +        n0000001e [label="viif_stats\n/dev/video4", shape=box,
> style=filled, fillcolor=yellow]
> > +        n00000030 [label="{{<port0> 0} | visconti_csi2rx
> 1c008000.csi2rx\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord,
> style=filled, fillcolor=green]
> > +        n00000030:port1 -> n00000001:port0
> > +        n00000035 [label="{{} | imx219 1-0010\n/dev/v4l-subdev4 |
> {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
> > +        n00000035:port0 -> n00000030:port0 }
> > diff --git a/Documentation/admin-guide/media/visconti-viif.rst
> > b/Documentation/admin-guide/media/visconti-viif.rst
> > new file mode 100644
> > index 000000000000..c2e85fb6f8c1
> > --- /dev/null
> > +++ b/Documentation/admin-guide/media/visconti-viif.rst
> > @@ -0,0 +1,435 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> >
> +================================================
> ======
> > +Visconti Video Input Interface Driver (visconti-viif)
> >
> +================================================
> ======
> > +
> > +Introduction
> > +============
> > +
> > +This file documents the driver for the Video Input Interface (VIIF)
> > +that is part of Toshiba Visconti SoCs.
> > +The driver is located under drivers/media/platform/toshiba/visconti
> > +and uses the Media-Controller API.
> 
> If you intend to make this two paragraphs, you should have a blank line
> in-between:
> 
> --------
> This file documents the driver for the Video Input Interface (VIIF) that is part of
> Toshiba Visconti SoCs.
> 
> The driver is located under drivers/media/platform/toshiba/visconti and uses
> the Media-Controller API.
> --------
> 
> If you intend to make this a single paragraph, there should be no line break
> after the first sentence:
> 
> --------
> This file documents the driver for the Video Input Interface (VIIF) that is part of
> Toshiba Visconti SoCs. The driver is located under
> drivers/media/platform/toshiba/visconti and uses the Media-Controller API.
> --------
> 

I meant that the introduction has a single paragraph.
I'll update the paragraph's style.

> > +
> > +The driver module is named visconti-viif, and is enabled through the
> > +CONFIG_VIDEO_VISCONTI_VIIF config option.
> > +The CSI-2 receiver part is controlled by another module named
> > +visconti-csi2rx, which is enabled through the
> CONFIG_VIDEO_VISCONTI_CSI2RX config option.
> 
> Please reflow text to reach as close to 80 columns:
> 
> --------
> The driver module is named visconti-viif, and is enabled through the
> CONFIG_VIDEO_VISCONTI_VIIF config option. The CSI-2 receiver part is
> controlled by another module named visconti-csi2rx, which is enabled through
> the CONFIG_VIDEO_VISCONTI_CSI2RX config option.
> --------
> 
> Same comment below where applicable.
> 

I'll fix it.

> > +
> > +The Visconti VIIF Hardware
> > +==========================
> > +
> > +The Visconti VIIF hardware is an internally developed video capture device.
> > +Following function modules are integrated:
> > +
> > +* MIPI CSI-2 receiver (CSI2RX)
> > +* L1 Image Signal Processor (L1ISP)
> > +
> > +  * Correction, enhancement, adjustment on bayer images.
> > +
> > +* L2 Image Signal Processor (L2ISP)
> > +
> > +  * Lens distortion correction
> > +  * Scaling & Cropping with up to 2 parameter sets
> > +  * Formatting picture (RGB, YUV, Grayscale, ...)
> > +  * Integrated DMAC: Writing picture into main memory
> > +
> > +* Video DMAC
> > +
> > +  * Writing picture into main memory
> > +
> > +Visconti5 SoC has two VIIF hardware instances.
> > +
> > +
> > +The hardware block diagram is shown below.::
> > +
> > +  The VIIF hardware
> > +
> "POST0"
> > +                                                              "RGB
> with scale 0"
> > +  +--------+    +----------+    +-----+    +-----+    +-----+
> +--------+
> > +  | Sensor |--->|  CSI2RX  |--->|     |    |     |    |     |--->|
> memory |
> > +  +--------+    +----------+    |     |    |     |    |     |
> +--------+
> > +                                |     |    | L1  |    | L2  | "POST1"
> > +                                |     |--->| ISP |--->| ISP | "RGB with
> scale 1"
> > +                                |     |    |     |    |     |
> +--------+
> > +                                | MUX |    |     |    |     |--->|
> memory |
> > +                                |     |    +-----+    +-----+
> +--------+
> > +                                |     |                       "SUB"
> > +                                |     |                       "RAW
> w/o scale"
> > +                                |     |        +------------+
> +--------+
> > +                                |     |------> | Video DMAC |--->|
> memory |
> > +                                +-----+        +------------+
> +--------+
> > +
> > +Topology
> > +========
> > +
> > +Graph
> > +-----
> > +
> > +.. _visconti_viif_topology_graph:
> > +
> > +.. kernel-figure:: visconti-viif.dot
> > +	:alt: Diagram of the default media pipeline topology
> > +	:align: center
> > +
> > +The driver has 3 video devices for capturing images:
> > +
> > +- viif_capture_post0: capture device for image.
> > +    - corresponds to L2ISP.
> > +- viif_capture_post1: capture device for image.
> > +    - corresponds to L2ISP.
> > +- viif_capture_sub: capture device for bayer image.
> > +    - corresponds to Video DMAC.
> > +
> > +The driver has 2 video devices for controlling ISP.
> > +
> > +- viif_params: a metadata output device that receives ISP parameters.
> > +    - corresponds to L1ISP and L2ISP.
> > +- viif_stats: a metadata capture device that sends statistics.
> > +    - corresponds to L1ISP and L2ISP.
> > +
> > +The driver has 2 subdevices:
> 
> I count three subdevs in the list below (and there are actually two resizer
> instances, so that would be 4 subdevs).
> 

The number should have been updated.

> > +
> > +- visconti_csi2rx: CSI-2 receiver operation.
> > +    - corresponds to CSI2RX.
> > +- visconti-viif:isp: Image Signal Processor operation.
> > +    - corresponds to L1ISP and L2ISP.
> > +- visconti-viif:resizer: Scaling operation of Image Signal Processor.
> > +    - corresponds to L2ISP.
> > +
> > +visconti_csi2rx - CSI2 Receiver Subdevice Node
> > +---------------------------------------------------
> 
> The title underline should have the same length as the title.
> 

I'll fix it.

> > +
> > +This subdevice node corresponds to a MIPI CSI2 receiver.
> > +It resides between an image sensor subdevice and the ISP subdevice.
> > +It controls CSI2 link configuration and training process.
> > +
> > +visconti-viif:isp - ISP Subdevice Node
> > +--------------------------------------
> > +
> > +This subdevice node corresponds to L1/L2 ISPs.
> > +It receives pictures from an sensor (via CSI2RX),
> 
> s/an sensor/a sensor/
> 

I'll check the use of articles in comments/documents again.

> > +applies multiple operations on pictures, then passes resulting images to
> capture nodes.
> > +
> > +ISP configurations/parameters are passed from userland via viif_params
> node.
> > +The status of ISP operations are passed to userland via viif_stats node.
> 
> "stats" stands for "statistics", so I would write "The statistics computed by the
> ISP are passed to ...".
> 
> And after reading more of this document, I realize that the viif_stats node
> captures both statistics and status information. You could write "The statistics
> computed by the ISP and the frame processing status are passed to ...".
> 

Yes, the node captures both statistics and status information.
I'll update the sentence according to your suggestion.

> > +
> > +L1 ISP provides following operations:
> > +
> > +- Input: accepts 8, 10, 12, 14bit bayer format
> > +    - Operation selector; :c:type:`viif_l1_input_mode_config`
> > +        - HDR image / PWL (Piecewse Linear Compression) image
> > +        - with preprocessing / without preprocessing
> > +    - HDRE: HDR expansion (only for PWL image);
> > +      see :c:type:`viif_l1_hdre_config`
> > +- Preprocessing: generate intermediate data (24bit RAW)
> > +    - SLIC: Bit slicing (x3 12bit planes for preprocessing);
> > +      see :c:type:`viif_l1_img_extraction_config`
> > +    - ABPC/DPC: Blemish/Defect pixel
> correction :c:type:`viif_l1_dpc_config`
> > +    - PWHB: Preset white balance;
> see :c:type:`viif_l1_preset_white_balance_config`
> > +    - RCNR: RAW color noise reduction;
> see :c:type:`viif_l1_raw_color_noise_reduction_config`
> > +    - HDRS: HDR synthesis; see :c:type:`viif_l1_hdrs_config`
> > +- Processing on RAW image: Main Process (MPRO)
> > +    - BLVC: black level correction and normalization;
> > +      see :c:type:`viif_l1_black_level_correction_config`
> > +    - LSSC: Lens shading correction; see :c:type:`viif_l1_lsc_config`
> > +    - MPRO: digital amplifier; see :c:type:`viif_l1_main_process_config`
> > +    - MPRO: bayer demosaicing; see :c:type:`viif_l1_main_process_config`
> > +    - MPRO: color matrix correction;
> see :c:type:`viif_l1_main_process_config`
> > +    - HDRC: HDR compression;
> 
> If my understanding is correct, this implements global and local tone mapping. I
> would mention it explicitly here, those terms are more common than "HDR
> compression". You could write for instance
> 
>    - HDRC: HDR compression (global and local tone mapping);
> 

As you pointed out, VIIF provides global and local tone mapping.
I'll update the sentence according to your suggestion.

> > +      see :c:type:`viif_l1_hdrc_config`, :c:type:`viif_l1_hdrc_ltm_config`,
> > +      :c:type:`viif_l1_rgb_to_y_coef_config`
> > +- Processing on RGB/YUV image: Video Process (VPRO)
> > +    - VPRO: gamma correction; see :c:type:`viif_l1_gamma_config`
> > +    - VPRO: RGB2YUV;
> > +      see :c:type:`viif_l1_rgb_to_y_coef_config`,
> > +      :c:type:`viif_l1_img_quality_adjustment_config`
> > +    - VPRO: image quality adjustment; see
> > +:c:type:`viif_l1_img_quality_adjustment_config`
> > +- Output: 16bit YUV
> > +- Feedback loop
> > +    - AWHB: auto white balance; see :c:type:`viif_l1_awb_config`,
> > +      :c:type:`viif_isp_capture_status`
> 
> Does this mean that the ISP can compute white balance gains automatically,
> implementing AWB in hardware ? That's interesting, it's a feature I haven't seen
> before.
> 

Sorry for the lack of explanation.
The AWB HW calculates the average values of U and V for the specified area of
the input image and adjust R-gain and B-gain so that the difference of the two
values approaches to zero. The software specifies the configurations through
viif_l1_awb_config but does not intervene in the processing of each frame.
The software can know the final gain obtained, the average values of U and V,
and whether the calculation has converged.

It is also possible to calculate the average value in hardware, then compute
the gain in software, and set the gain in the register. However, this is not
recommended due to significant control delay.

> > +    - AEXP: auto exposure (average luminance calculation);
> > +      see :c:type:`viif_l1_avg_lum_generation_config`,
> >
> +      :c:type:`viif_l1_rgb_to_y_coef_config`, :c:type:`viif_isp_capture_status
> `
> > +    - AG: analog gain calculation;
> > +      see :c:type:`viif_l1_ag_mode_config`,
> > + :c:type:`viif_l1_ag_config`
> > +
> > +Below is the block diagram::
> > +
> > +  L1ISP::INPUT
> > +
> > +  +--------+                +-----+                      +-----+
> > +  | Input  |--------------->|     |--------------------->|     |
> > +  | 24bHDR |                |     |                      |     |
> > +  +--------+                | 24b |                      | 24b |
> > +                            | RAW |                      | RAW |
> > +  +--------+    +------+    | (0) |                      | (1) |
> > +  | Input  |--->| HDRE |--->|     |    +------------+    |     |
> > +  | 24bPWL |    |      |    |     |--->| preprocess |--->|     |
> > +  +--------+    +------+    +-----+    +------------+    +-----+
> 
> I'm not entirely sure to understand this correctly, could you please correct me
> where I'm mistaken ?
> 
> I understand that the PWL input is HDR contents merged/stitched on the
> sensor side, and compressed to a smaller than 24bpp width to reduce bus
> bandwidth using a PWL function. The HDRE block applies the inverse function
> to recover linear 24 bit data. In that case, the "preprocess"
> pipeline operates on a single channel (using one of the param_h, param_m and
> param_l set of parameters - which one ?). The HDRS blocks should be disabled
> (how ?).
> 
> The HDR input, on the other hand, provides 2 or 3 channels with different
> sensitivities (high, middle and low, from sensors that implement DOL or DCG
> HDR). The preprocess pipeline operates on those channels with different sets
> of parameters, and the HDRS combines the channels into a single 24 bit image.
> 
> I'm not entirely sure how the two or three channels are provided to the ISP, with
> DOL sensors there's a delay before the sensor starts outputting the short (and
> very short) lines, so line buffers are needed to realign the lines. I don't see this
> in the block diagram.
> 
> It would be nice to expand the documentation a bit with such information about
> HDR processing, as I assume other developers may face similar questions.
> 

The L1ISP hardware supports following RAW formats.
* uncompressed single HDR image [8-24 bit]
    * This driver supports 8-14bits, as 16-24bit is not fully tested.
* PWL compressed single HDR image [8-14 bit]
* multiple SDR images [8-12 bit, 1-3 planes]
    * This driver does not support it for the following reasons.

As you pointed out, the PWL input is an 8-14 bit image, which is expanded to
a 24-bit image in the HDRE block. In the preprocess stage, the SLIC (bit slice)
block divides the 24-bit image into three images with different sensitivities
for processing by ABPC, PWHB, and RCNR. Finally, the HDRS block generates a 24-bit image.

The L1ISP hardware supports DOL HDR for multiple SDR inputs. In the document's
diagram, up to three images bypass the SLIC and are processed by the HDRS block.
However, as you pointed out, it is not possible to connect a typical DOL sensor
due to the lack of sufficient line buffer depth. Because it is difficult to
operate in practical cases, this driver does not support multiple SDR image inputs
nor DOL HDR.

Although this driver does not support memory-to-memory operation, the VIIF hardware
has an option to read in-memory images via a DMA reader. With that (possible) datapath,
properly organized line-interleaved images can be processed as DOL HDR input.

> > +
> > +  L1ISP::INPUT::preprocess
> > +
> > +  +-----+
> +-----+
> > +  | 24b |    +------+    +------+    +------+    +------+
> +------+    | 24b |
> > +  | RAW |--->| SLIC |--->| ABPC |--->| PWHB |--->| RCNR |--->| HDRS
> |--->| RAW |
> > +  | (0) |    +------+    +------+    +------+    +------+    +------+
> | (1) |
> > +  +-----+
> +-----+
> > +
> > +  L1ISP::MainProcess(MPRO)
> > +
> > +  +-----+
> > +  | 24b |    +------+    +------+
> > +  | RAW |--->| BLVC |--->| LSSC |---+
> > +  | (1) |    +------+    +------+   |
> > +  +-----+                           |
> > +                                    |
> > +     +------------------------------+
> > +     |
> > +     |    +-----------+    +-------------+    +--------+
> +-----+
> > +     +--->|   MPRO    |    |    MPRO     |    |  MPRO  |
> +------+    | 16b |
> > +          |  Digital  |--->| Demosaicing |----| Color  |--->| HDRC
> |--->| RGB |
> > +     +--->| Amplifier |    |             |    | Matrix |    +------+
> |     |
> > +     |    +-----------+    +-------------+    +--------+
> +-----+
> > +     |                         |    |
> > +     |    +--------------+     |    |    +------+
> > +     +----| Auto         |<----+    +--->| AEXP |---> Auto-Exposure
> statistics
> > +          | Whitebalance |               +------+
> > +          +--------------+
> > +                 |
> > +                 +------------------------------> Auto-Whitebalance
> > + statistics
> > +
> > +  L1ISP::VideoProcess(VPRO)
> > +
> > +  +-----+    +------------+    +------------+    +---------------+
> +--------+
> > +  | 16b |--->| Gamma      |--->| RGB2YUV    |--->| Image Quality
> |--->| Output |
> > +  | RGB |    | Correction |    | Conversion |    | Adjustment    |    |
> 16b   |
> > +  |     |    +------------+    +------------+    +---------------+
> |  YUV   |
> > +  +-----+
> +--------+
> > +
> > +  L1ISP::AnalogGain
> > +
> > +  statistics                     +-------------+
> +------------------+
> > +  information ---> (user SW) --->| Analog Gain |--->| ABPC, RCNR, LSSC
> |
> > +                                 +-------------+    |       MPRO,
> VPRO |
> > +
> > + +------------------+
> 
> I'm a bit puzzled by "analog gain" here, as the ISP operates on digital data only.
> Does the ISP need to be informed of the analog gain values computed by the
> AEGC software algorithm and applied to the camera sensor, for instance to
> estimate the noise level based on the analog gain and adapt noise filtering
> accordingly ? Or is it something else ?
> 
> Edit: the text below answers this question :-)
>

The name "analog gain" was coined by the hardware team and is quite misleading.
It has nothing to do with the gain of the image sensor. Instead, it is a parameter
used to collectively change the processing intensity of several functional blocks
in the L1ISP. The intensity is calculated from the gain value provided by
viif_l1_ag_config and the linear transformation parameters (grad, ofst) provided
by viif_l1_ag_mode_config. Each of the blocks determines the coefficients and
thresholds from the passed intensity.

To avoid misunderstandings, it seems better to stop using the term 'analog gain'
and replace it with expressions like 'application gain' or 'algorithm gain,'
which maintain the abbreviation 'AG' that appears in register names 
and structure member names."


> > +
> > +L2 ISP provides following operations:
> > +
> > +- Input: accepts 16bit YUV / RGB
> > +- Operations:
> > +    - Lens undistortion; see :c:type:`viif_l2_undist`
> 
> The structure is named viif_l2_undist_config. Please make sure to compile the
> documentation, you should then get warnings for C types that are not found.
> 

It seems I missed error messages.
I'll fix it.

> > +    - Scaling; see :c:type:`viif_l2_roi`
> 
> viif_l2_roi_config
> 

I'll fix it too.

> > +    - Cropping; see :c:type:`viif_l2_roi`
> 
> Looking at the implementation of the resizer subdevs, I see that the crop and
> compose rectangles can be set, but they don't seem to ne used to configure the
> resizer. Instead, the viif_l2_roi_config parameters are used to configure
> cropping on the resizer input and scaling. This discrepancy isn't good. I see two
> options to fix it:
> 
> - Keep configuring the resizer through viif_l2_roi_config and drop the resizer
>   subdevs. This will simplify the driver. The main drawback is that it
>   won't be possible to implement digital zoom (by changing the resizer
>   configuration) asynchronously from the ISP parameters buffers, which
>   can be useful to lower the latency of digital zoom.
> 
> - Drop viif_l2_roi_config, and configure the resizer from the formats,
>   crop and selection rectangles on the resizer subdev pads. This makes
>   the driver more complex. The main advantage is that digital zoom will
>   be configurable with a smaller latency, but the drawback is that it
>   won't be possible (or it will be more difficult) to configure it
>   synchronously with other ISP parameters.
> 
> There are drivers in mainline that implement either of those options, so you can
> pick the one you think is best.
> 
> An additional issue is that the hardware seems to implement cropping on the
> output of the resizer only, not on the input. Given that the size of the images
> output by the ISP pipeline must stay constant during video capture (otherwise
> there would be a risk of buffer overflow), modifying the crop rectangle on the
> output of the resizer is usually not allowed during streaming. I think this could
> be worked around by allowing modification only of the left and top coordinates
> during streaming, but configuring everything through viif_l2_roi_config would
> likely be easier. In that case, you should probably extend viif_l2_roi_config with
> the crop offsets.
> 
> All of this reflects my current understanding of the ISP architecture, based on
> this document and on the driver code, so please correct me if there's anything I
> misunderstood. We can discuss the different options further before you modify
> the driver and send a new version.
> 

First of all, I apologize for attempting to make significant changes to the
driver structure without consulting you. The hardware specifications of VIIF
are unique, and the knowledge from the drivers I referred to (mainly rkisp1)
cannot be directly applied. As a result, I am still struggling with how to
write a driver that conforms to the V4L2 framework.

I am considering removing the resizer subdevice because viif_l2_roi_config
can set more detailed parameters compared to the resizer subdevice's pad.

To explain my idea and answer your questions, let me describe the processing of
the VIIF L2-ISP.

The central functions of the L2 ISP are lens undistortion and scaling. They are
integrated and executed simultaneously. To explain the coordinate transformation here,
several virtual images are defined.

* L1ISP output image
    * the input of L2ISP
    * geometry: {width, height}
    * mapped to sink.format
* Input image
    * geometry: {center_x, center_y, width, height}
    * relative to the L1ISP output image
    * mapped to sink.crop
    * resizer subdevice assumes that sink.crop = sink.format
* Corrected image after undistortion
    * geometry: {width, height}
    * relative to the Input image
* Corrected image with scale
    * geometry: {width, height}
    * relative to the Input image
    * mapped to sink.compose
    * resizer subdevice assumes that scale factor = sink.compose / sink.format
* ROI image
    * geometry: {left, top, width, height}
    * relative to the Corrected image with scale
    * mapped to source.crop
* Crop image
    * the output of L2ISP.
    * geometry: {left, top, width, height}
    * relative to the Corrected image with scale
    * mapped to source.crop

These images mentioned here do not have corresponding frame buffers. However,
there are control registers corresponding to the width and height of each image,
and appropriate values must be set. Otherwise, the output image may be corrupted,
or the L2ISP may abort.

Regarding your question of why sink.crop is not used.
According to the list above, sink.crop corresponds to the Input image. However,
the coordinates of the Input image must be set to align with the optical center
for undistortion, so it cannot be used to crop arbitrary rectangles.

Regarding digital zoom.
In the existing use cases of VIIF, the scale and crop are fixed during recording.
Therefore, I did not consider changing the selection parameter like digital zoom.

Regarding resizer subdevice.
The purpose of the resizer subdevice is to set the initial values of L2ISP
from pad's selection parameters. Most virtual image rectangles can be mapped to
the pad's parameters. Since the parameters of undistortion and the rectangle of
the Corrected image after undistortion are unknown, I assumed that undistortion 
is disabled (pass-through) and the Corrected image after undistortion matches
the Input image. In this case, the scaling parameters can be calculated from 
sink.compose and sink.input.
On the other hand, in cases where both undistortion and scaling are utilized,
it is necessary to set viif_l2_undist_config and viif_l2_roi_config. Therefore,
I made it possible to overwrite these parameters through the parameter buffer.

To configure cropping with the parameter buffer instead of pad's selection,
I'll add two members (left and top) to viif_l2_roi_config.
Otherwise, I'll newly add struct viif_l2_crop_config to the parameter buffer.

> > +    - Gamma correction; see :c:type:`viif_l2_gamma_config`
> > +    - YUV2RGB
> > +- Output: RGB, YUV422, YUV444
> > +
> > +Below is the block diagram::
> > +
> > +  L2ISP
> > +
> > +  +-------+    +------------+    +--------------+    +---------+
> > +  | Input |--->| YUV2RGB    |--->| Lens         |--->| Scaling |---> |
> > +  | Image |    | Conversion |    | Undistortion |    |         |---> |
> > +  +-------+    +------------+    +--------------+    +---------+
> |
> 
> Is the scaling configuration for the two outputs independent ? If so I would
> move the scaling block just before gamma correction, in each of the branches
> below.
> 

Scaling configurations are independent of each other.
I'll update the diagram as follows:

+--------------+      +---------+      +------------+
| Lens         | -+-> | Scaling | ---> | Gamma      | 
| Undistortion |  |   |         |      | Correction |
+--------------+  |   +---------+      +------------+
                  |
                  |   +---------+      +------------+
                  +-> | Scaling | ---> | Gamma      |
                      |         |      | Correction |
                      +---------+      +------------+

> > +
> |
> > +          +----------------------------------------------------------+
> > +          |
> > +          |    +----------+    +------------+    +--------+
> +--------+
> > +          +--->|Gamma     |--->| Colorspace |--->| Data   |--->|
> Output |
> > +          |    |Correction|    | Conversion |    | Packer |    | Image  |
> > +          |    +----------+    +------------+    +--------+
> +--------+
> > +          |
> > +          |    +----------+    +------------+    +--------+
> +--------+
> > +          +--->|Gamma     |--->| Colorspace |--->| Data   |--->|
> Output |
> > +               |Correction|    | Conversion |    | Packer |    | Image  |
> > +               +----------+    +------------+    +--------+
> +--------+
> > +
> > +visconti-viif:resizer - Resizer Subdevice Node
> > +----------------------------------------------
> > +
> > +The resizer subdevice resides between ISP subdevice and Capture
> > +device on a capture path for post0 and post1.
> > +It receives resize and crop parameters for the specific capture path
> > +and controls L2ISP HW.
> > +
> > +following selection rectangles can be passed at VIDIOC_S_SELECTION
> ioctl.
> 
> s/following/The following/
> 

I'll fix it.

> > +
> > +- sink pads's compose rectangle (V4L2_SEL_TGT_COMPOSE) for scaling
> > +- source pad's crop rectangle (V4L2_SEL_TGT_CROP) for cropping
> > +
> > +
> > +viif_capture_post0, viif_capture_post1 - Processed Image Capture
> > +Video Node
> > +---------------------------------------------------------------------
> > +------
> > +
> > +These video nodes are used for capturing images processed at ISPs.
> > +Supported capture formats are as follows:
> > +
> > +- V4L2_PIX_FMT_RGB24
> > +- V4L2_PIX_FMT_ABGR32
> > +- V4L2_PIX_FMT_YUV422M
> > +- V4L2_PIX_FMT_YUV444M
> 
> The hardware doesn't support semi-planar formats (NV12 or NV16) or packed
> formats (YUYV) ?
> 

The hardware does not support NV12 nor NV16.
For packed formats, UYVY is avaiable but not tested fully.
I'll check if there are any issues with adding UYVY.

> > +- V4L2_PIX_FMT_Y16
> > +
> > +Bayer format is not supported. Use viif_capture_sub instead.
> > +
> > +POST0 and POST1 can output images from the same input image using
> > +different cropping and scaling settings.
> > +
> > +viif_capture_sub - Raw Image Capture Video Node
> > +-----------------------------------------------
> > +
> > +This video node is used for capturing bayer image from the sensor.
> > +The output picture has exactly the same resolution and format as the
> sensor input.
> > +The pipeline does not edit pixel values.
> > +However, when writing pixel values to memory, they are shifted to the
> > +MSB to match either 8bit or 16bit.
> > +
> > +Therefore, resulting capture formats are as follows:
> > +
> > +- for 8bit RAW input:
> > +    - V4L2_PIX_FMT_SRGGB8
> > +    - V4L2_PIX_FMT_SGRBG8
> > +    - V4L2_PIX_FMT_SGBRG8
> > +    - V4L2_PIX_FMT_SBGGR8
> > +- for 10, 12, 14bit RAW input:
> > +    - V4L2_PIX_FMT_SRGGB16
> > +    - V4L2_PIX_FMT_SGRBG16
> > +    - V4L2_PIX_FMT_SGBRG16
> > +    - V4L2_PIX_FMT_SBGGR16
> > +
> > +.. _viif_params:
> > +
> > +viif_params - ISP Parameters Video Node
> > +---------------------------------------
> > +
> > +The viif_params video node receives a set of ISP parameters from
> > +userspace to be applied to the hardware during a video stream.
> > +
> > +The buffer format is defined by struct
> > +:c:type:`visconti_viif_isp_config`, and userspace should
> set :ref:`V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> <v4l2-meta-fmt-visconti-viif-params>` as the data format.
> > +
> > +.. _viif_stats:
> > +
> > +viif_stats - Statistics Video Node
> > +----------------------------------
> > +
> > +The viif_stats video node provides current status of ISP.
> 
> The viif_stats video node provides statistics computed by the ISP and frame
> processing status.
> 

I'll update the sentence as you suggested.

> > +
> > +Following information is included:
> > +
> > +* statistics of auto white balance
> > +* average luminance information which can be used by auto exposure
> software impl.
> 
> s/impl/implementation/
> 

I should not have abbreviated a word.
I'll fix it.

>
> I would also add
> 
>  * CSI-2 receiver calibration and error status
>  * ISP error status
> 
> It's quite uncommon to provide this kind of status through ISP stats buffers, but
> it sounds like an interesting idea. Other drivers usually keep error counters in
> the kernel and expose them through debugfs.
> 

These status information have existed since the initial implementation and must
be passed to the user space in some way. On the other hand, I think that these,
especially the CSI2 receiver error status, are not related to the 
frame-by-frame processing of the ISP, so they should not be included in the
parameter buffer. I should classify the information and update the members of
the parameter buffer accordingly. I think some of the information should be
exposed through debugfs. However, I'm not sure how to classify them and how to
implement the debugfs interface. Could you tell me the source code that
should be referred to?

> > +
> > +The buffer format is defined by struct
> > +:c:type:`visconti_viif_isp_stat`, and userspace should
> set :ref:`V4L2_META_FMT_VISCONTI_VIIF_STATS
> <v4l2-meta-fmt-visconti-viif-stats>` as the data format.
> > +
> > +Feedback Operations
> > +===================
> > +
> > +Among the so-called 3A functions, VIIF provides only auto-whitebalance
> and auto-exposure.
> > +Auto-whitebalance is a standalone hardware feature.
> > +Some status information is available through the ISP statistics interface.
> > +
> > +Auto-exposure is realized through a combination of hardware and userland
> software.
> > +VIIF provides weighted average luminance information through the ISP
> statistics interface.
> > +The userland application calculates the sensor gain, sensor exposure and
> ISP digital gain.
> > +The calculated parameters are then passed to sensor's controls and the ISP
> parameter interface.
> > +
> > +Among ISP parameters, there are parameters called AG (analog gain).
> > +Actually, AG parameters have nothing to do with auto-exposure.
> > +It controls "strength" in several signal correction algorithms.
> > +Below is the list of the functions which may be affected by AG parameters:
> > +
> > +- ABPC/DPC
> > +- RCNR
> > +- LSSC
> > +- MPRO: color matrix correction
> > +- VPRO
> > +
> > +Capturing Video Frames Example
> > +==============================
> > +
> > +In the following example,
> > +imx219 camera is connected to pad 0 of 'visconti_csi2rx' subdevice.
> > +
> > +The following commands yield three pictures with different zoom ratio:
> > +- main path 0: 1.5x zoom, crop 1920x1080, RGB picture
> > +- main path 1: 0.67x zoom, crop 640x480, RGB picture
> > +- sub path: 1920x1080 RAW picture
> > +
> > +.. code-block:: bash
> > +
> > +	# set the links
> > +	media-ctl -d platform:visconti-viif-0 -r
> > +	media-ctl -d platform:visconti-viif-0 -l '"imx219 1-0010":0 ->
> "visconti_csi2rx 1c008000.csi2rx":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti_csi2rx
> 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":1 ->
> "visconti-viif:resizer0":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":2 ->
> "visconti-viif:resizer1":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":3 ->
> "viif_capture_sub":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer0":1 ->
> "viif_capture_post0":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer1":1 ->
> "viif_capture_post1":0 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"viif_params":0 ->
> "visconti-viif:isp":4 [1]'
> > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":5 ->
> "viif_stats":0 [1]'
> > +
> > +	# set format for imx219
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"imx219 1-0010":0
> [fmt:SRGGB10_1X10/1920x1080]'
> > +
> > +	# set format for csi2rx
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti_csi2rx
> 1c008000.csi2rx":0 [fmt:SRGGB10_1X10/1920x1080  field:none
> colorspace:raw xfer:none ycbcr:601 quantization:full-range]'
> > +
> > +	# set format for isp sink pad
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":0
> [fmt:SRGGB10_1X10/1920x1080]'
> > +
> > +	# set format for resizer pads
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> '"visconti-viif:resizer0":0 '"[fmt:YUV8_1X24/1920x1080
> compose:(0,0)/2880x1620]"
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> '"visconti-viif:resizer0":1 '"[crop:(480,16)/1920x1080]"
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> '"visconti-viif:resizer1":0 '"[fmt:YUV8_1X24/1920x1080
> compose:(0,0)/1280x720]"
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> '"visconti-viif:resizer1":1 '"[crop:(320,32)/640x480]"
> > +
> > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":1
> [fmt:YUV8_1X24/1024 crop:(640,0)/1024x1024]'
> > +
> > +	# set format for main path0
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> "width=1920,height=1080"
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> "pixelformat=RGB3"
> > +
> > +	# set format for main path1
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> "width=640,height=480"
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> "pixelformat=RGB3"
> > +
> > +	# start streaming
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0
> > +--stream-mmap --stream-count 1000 &
> > +
> > +	# start streaming with other devices while viif_capture_post0 is
> running
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post1
> --stream-mmap --stream-count 10
> > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_sub
> > +--stream-mmap --stream-count 10
> > +
> > +Use of coherent memory
> > +======================
> > +
> > +Visconti5 SoC has two independent DDR SDRAM controllers.
> > +Each controller is mapped to 36bit address space.
> > +
> > +Accelerator bus masters have two paths to access memory; one is
> > +directly connected to SDRAM controller, the another is connected via
> > +a cache coherency bus which keeps coherency among CPUs.
> > +
> > +From accelerators and CPUs, the address map is following:
> > +
> > +* 0x0_8000_0000 DDR0 direct access
> > +* 0x4_8000_0000 DDR0 coherency bus
> > +* 0x8_8000_0000 DDR1 direct access
> > +* 0xC_8000_0000 DDR1 coherency bus
> > +
> > +The base address can be specified with "memory" and "reserved-memory"
> > +elements in a device tree description.
> > +It's not recommended to mix direct address and coherent address.
> > +
> > +The Visconti5 VIIF driver always use only direct address to configure Video
> DMACs of the hardware.
> > +This design is to avoid great performance loss at coherency bus caused by
> massive memory access.
> > +You should not put the dma_coherent attribute to viif element in device
> tree.
> > +Cache operations are done automatically by videobuf2 driver.
> > diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > index 86ffb3bc8ade..2336842f0c26 100644
> > --- a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > @@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata` interface
> only.
> >      metafmt-pisp-fe
> >      metafmt-rkisp1
> >      metafmt-uvc
> > +    metafmt-visconti-viif
> >      metafmt-vivid
> >      metafmt-vsp1-hgo
> >      metafmt-vsp1-hgt
> > diff --git
> > a/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > new file mode 100644
> > index 000000000000..dc4b31627fe1
> > --- /dev/null
> > +++ b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > @@ -0,0 +1,48 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +.. _v4l2-meta-fmt-visconti-viif-params:
> > +
> > +.. _v4l2-meta-fmt-visconti-viif-stats:
> > +
> > +*********************************************************************
> > +****************** V4L2_META_FMT_VISCONTI_VIIF_PARAMS ('vifp'),
> > +V4L2_META_FMT_VISCONTI_VIIF_STATS ('vifs')
> > +*********************************************************************
> > +******************
> > +
> > +Configuration parameters
> > +========================
> > +
> > +The configuration parameters are passed to the :ref:`viif_params
> > +<viif_params>` metadata output video node, using the
> > +:c:type:`v4l2_meta_format` interface. The buffer contains a single
> > +instance of the C structure :c:type:`visconti_viif_isp_config`
> > +defined in ``visconti_viif.h``. So the structure can be obtained from the
> buffer by:
> > +
> > +.. code-block:: c
> > +
> > +	struct visconti_viif_isp_config *params = (struct
> > +visconti_viif_isp_config*) buffer;
> > +
> > +VIIF statistics
> > +===============
> > +
> > +The VIIF device collects different statistics over an input Bayer frame.
> > +Those statistics are obtained from the :ref:`viif_stats <viif_stats>`
> > +metadata capture video node, using the :c:type:`v4l2_meta_format`
> > +interface. The buffer contains a single instance of the C structure
> > +:c:type:`visconti_viif_isp_stat` defined in ``visconti_viif.h``. So
> > +the structure can be obtained from the buffer by:
> > +
> > +.. code-block:: c
> > +
> > +	struct visconti_viif_isp_stat *stats = (struct
> > +visconti_viif_isp_stat*) buffer;
> > +
> > +The statistics collected are Exposure, AWB (auto white balance) and errors.
> > +See :c:type:`visconti_viif_isp_stat` for details of the statistics.
> > +
> > +The statistics and configuration parameters described here are
> > +usually consumed and produced by dedicated user space libraries that
> > +comprise the tuning tools using software control loop.
> > +
> > +visconti viif uAPI data types
> > +=============================
> > +
> > +.. kernel-doc:: include/uapi/linux/visconti_viif.h
> 
> Assuming the documentation in the header file is adequate, the level of detail
> here is fine.
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,

Yuji Ishikawa

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

* RE: [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface
  2025-01-02 13:16   ` Laurent Pinchart
@ 2025-02-05 12:31     ` yuji2.ishikawa
  0 siblings, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2025-02-05 12:31 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent,

Thank you for your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Thursday, January 2, 2025 10:17 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti
> Video Input Interface
> 
> Hi Ishikawa-san,
> 
> Thank you for the patch.
> 
> On Mon, Nov 25, 2024 at 06:21:46PM +0900, Yuji Ishikawa wrote:
> > Added entries for visconti Video Input Interface driver, including;
> 
> Commit messages are written using the imperative mood, as if you were giving
> orders to someone:
> 
> s/Added/Add/
> 

Thank you for the advice. I'll update commit messages.

> > * device tree bindings
> > * source files
> > * documentation files
> >
> > Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > Reviewed-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> 
> I would have added the MAINTAINERS entry in 1/8 with just the DT binding file,
> and added more files in corresponding patches. That would be easier to review
> and check if entries are missing. I don't mind much though, so if you prefer
> keeping it this way:
> 

From the next patch set, I'll update MAINTAINERS at the same time as new files are added.

> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> > ---
> > Changelog v2:
> > - no change
> >
> > Changelog v3:
> > - added entry for driver API documentation
> >
> > Changelog v4:
> > - added entry for header file
> >
> > Changelog v5:
> > - no change
> >
> > Changelog v6:
> > - update path to VIIF driver source files
> >
> > Changelog v7:
> > - no change
> >
> > Changelog v8:
> > - rename bindings description file
> >
> > Changelog v9:
> > - no change
> >
> > Changelog v10:
> > - add a separate entry of VIIF driver
> >
> > Changelog v11:
> > - no change
> >
> > Changelog v12:
> > - add a bindings description of CSI2RX driver
> >
> >  MAINTAINERS | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > b878ddc99f94..b5c819e94e9b 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -23430,6 +23430,18 @@ F:
> 	Documentation/devicetree/bindings/media/i2c/tc358743.txt
> >  F:	drivers/media/i2c/tc358743*
> >  F:	include/media/i2c/tc358743.h
> >
> > +TOSHIBA VISCONTI VIIF DRIVER
> > +M:	Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
> > +M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > +L:	linux-media@vger.kernel.org
> > +S:	Maintained
> > +F:	Documentation/admin-guide/media/visconti-viif.*
> > +F:
> 	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2rx.y
> aml
> > +F:
> 	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yam
> l
> > +F:	Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > +F:	drivers/media/platform/toshiba/visconti/
> > +F:	include/uapi/linux/visconti_viif.h
> > +
> >  TOSHIBA WMI HOTKEYS DRIVER
> >  M:	Azael Avalos <coproscefalo@gmail.com>
> >  L:	platform-driver-x86@vger.kernel.org
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,
Yuji Ishikawa

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

* RE: [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver
  2025-02-05 12:29     ` yuji2.ishikawa
@ 2025-04-15  9:01       ` yuji2.ishikawa
  2025-06-18  1:30         ` yuji2.ishikawa
  0 siblings, 1 reply; 36+ messages in thread
From: yuji2.ishikawa @ 2025-04-15  9:01 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent,

As I reconsider the implementation of the v12 driver, I have decided on how to 
change the important parts pointed out in the review comments. On the other hand, 
I'm still looking for better implementation methods in some other areas.
I would like to request your comments on these matters.

- Topic 1: Removing the resizer subdevice
- Topic 2: Adding new members to the parameter buffer
- Topic 3: Passing error information via debugfs
- Topic 4: Reconsidering the topology of the capture device (sub path)

> -----Original Message-----
> From: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> Sent: Wednesday, February 5, 2025 9:30 PM
> To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> Subject: RE: [PATCH v12 7/8] documentation: media: add documentation for
> Toshiba Visconti Video Input Interface driver
> 
> Hello Laurent
> 
> Thank you for your review comments.
> 

> > > +    - Cropping; see :c:type:`viif_l2_roi`
> >
> > Looking at the implementation of the resizer subdevs, I see that the crop and
> > compose rectangles can be set, but they don't seem to ne used to configure
> the
> > resizer. Instead, the viif_l2_roi_config parameters are used to configure
> > cropping on the resizer input and scaling. This discrepancy isn't good. I see
> two
> > options to fix it:
> >
> > - Keep configuring the resizer through viif_l2_roi_config and drop the resizer
> >   subdevs. This will simplify the driver. The main drawback is that it
> >   won't be possible to implement digital zoom (by changing the resizer
> >   configuration) asynchronously from the ISP parameters buffers, which
> >   can be useful to lower the latency of digital zoom.
> >
> > - Drop viif_l2_roi_config, and configure the resizer from the formats,
> >   crop and selection rectangles on the resizer subdev pads. This makes
> >   the driver more complex. The main advantage is that digital zoom will
> >   be configurable with a smaller latency, but the drawback is that it
> >   won't be possible (or it will be more difficult) to configure it
> >   synchronously with other ISP parameters.
> >
> > There are drivers in mainline that implement either of those options, so you
> can
> > pick the one you think is best.
> >
> > An additional issue is that the hardware seems to implement cropping on the
> > output of the resizer only, not on the input. Given that the size of the images
> > output by the ISP pipeline must stay constant during video capture
> (otherwise
> > there would be a risk of buffer overflow), modifying the crop rectangle on the
> > output of the resizer is usually not allowed during streaming. I think this could
> > be worked around by allowing modification only of the left and top
> coordinates
> > during streaming, but configuring everything through viif_l2_roi_config would
> > likely be easier. In that case, you should probably extend viif_l2_roi_config
> with
> > the crop offsets.
> >
> > All of this reflects my current understanding of the ISP architecture, based on
> > this document and on the driver code, so please correct me if there's anything
> I
> > misunderstood. We can discuss the different options further before you
> modify
> > the driver and send a new version.
> >
> 
> First of all, I apologize for attempting to make significant changes to the
> driver structure without consulting you. The hardware specifications of VIIF
> are unique, and the knowledge from the drivers I referred to (mainly rkisp1)
> cannot be directly applied. As a result, I am still struggling with how to
> write a driver that conforms to the V4L2 framework.
> 
> I am considering removing the resizer subdevice because viif_l2_roi_config
> can set more detailed parameters compared to the resizer subdevice's pad.
> 
> To explain my idea and answer your questions, let me describe the processing
> of
> the VIIF L2-ISP.
> 
> The central functions of the L2 ISP are lens undistortion and scaling. They are
> integrated and executed simultaneously. To explain the coordinate
> transformation here,
> several virtual images are defined.
> 
> * L1ISP output image
>     * the input of L2ISP
>     * geometry: {width, height}
>     * mapped to sink.format
> * Input image
>     * geometry: {center_x, center_y, width, height}
>     * relative to the L1ISP output image
>     * mapped to sink.crop
>     * resizer subdevice assumes that sink.crop = sink.format
> * Corrected image after undistortion
>     * geometry: {width, height}
>     * relative to the Input image
> * Corrected image with scale
>     * geometry: {width, height}
>     * relative to the Input image
>     * mapped to sink.compose
>     * resizer subdevice assumes that scale factor = sink.compose / sink.format
> * ROI image
>     * geometry: {left, top, width, height}
>     * relative to the Corrected image with scale
>     * mapped to source.crop
> * Crop image
>     * the output of L2ISP.
>     * geometry: {left, top, width, height}
>     * relative to the Corrected image with scale
>     * mapped to source.crop
> 
> These images mentioned here do not have corresponding frame buffers.
> However,
> there are control registers corresponding to the width and height of each image,
> and appropriate values must be set. Otherwise, the output image may be
> corrupted,
> or the L2ISP may abort.
> 
> Regarding your question of why sink.crop is not used.
> According to the list above, sink.crop corresponds to the Input image. However,
> the coordinates of the Input image must be set to align with the optical center
> for undistortion, so it cannot be used to crop arbitrary rectangles.
> 
> Regarding digital zoom.
> In the existing use cases of VIIF, the scale and crop are fixed during recording.
> Therefore, I did not consider changing the selection parameter like digital zoom.
> 
> Regarding resizer subdevice.
> The purpose of the resizer subdevice is to set the initial values of L2ISP
> from pad's selection parameters. Most virtual image rectangles can be mapped
> to
> the pad's parameters. Since the parameters of undistortion and the rectangle of
> the Corrected image after undistortion are unknown, I assumed that
> undistortion
> is disabled (pass-through) and the Corrected image after undistortion matches
> the Input image. In this case, the scaling parameters can be calculated from
> sink.compose and sink.input.
> On the other hand, in cases where both undistortion and scaling are utilized,
> it is necessary to set viif_l2_undist_config and viif_l2_roi_config. Therefore,
> I made it possible to overwrite these parameters through the parameter buffer.
> 
> To configure cropping with the parameter buffer instead of pad's selection,
> I'll add two members (left and top) to viif_l2_roi_config.
> Otherwise, I'll newly add struct viif_l2_crop_config to the parameter buffer.
> 

I am removing the resizer sub-device. In the new implementation, the undistortion
and scaling functions of L2ISP are controlled using the l2_undist member and
l2_roi member of the parameter buffer. To control the cropping function of L2ISP,
the l2_crop_post0 and l2_crop_post1 members are added to the parameter buffer
to indicate the top-left coordinates for cropping.
These new members have the type struct l2_crop_config {__u32 left; __u32 top}. 
The default values of the members are (0, 0).

ISP subdevice pads have the following specifications:
- The sink_pad::fmt and source_pad(post0)::fmt, source_pad(post1)::fmt can be set independently.
- Each pad cannot be set for crop and compose.
- The maximum size of source_pad::fmt is either the hardware limit of L2ISP or 2x sink_pad::fmt.
- The minimum size of source_pad::fmt is the hardware limit of L2ISP.
- Due to the inclusion relationship of the planes, the following constraint should be met:
  
  l2_crop_post0::left + source_pad(post0)::fmt::width <= l2_roi::corrected_width(post0)

  A similar constraint should be applied to the height and the post1.

There are two possible behaviors when constraints are not met. If the instructions
through the parameter buffer are not accepted, how should the driver behave?

- Increment the error counter (referred by debugfs) and ignore the instructions
  from the parameter buffer.
- Modify l2_roi::corrected_width(post0) and l2_crop_post0::left and apply them 
  to the hardware. As a result, an L2ISP error might occur. The drawback is that
  the user program cannot know the modified coordinates.

> > > +.. _viif_params:
> > > +
> > > +viif_params - ISP Parameters Video Node
> > > +---------------------------------------
> > > +
> > > +The viif_params video node receives a set of ISP parameters from
> > > +userspace to be applied to the hardware during a video stream.
> > > +
> > > +The buffer format is defined by struct
> > > +:c:type:`visconti_viif_isp_config`, and userspace should
> > set :ref:`V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> > <v4l2-meta-fmt-visconti-viif-params>` as the data format.
> > > +

Please advise on how to handle unverified ISP functions in the parameter buffer.

The L1ISP hardware has a function to calculate the luminance histogram.
The software for this function is experimental and has not yet been developed
as a Linux driver. However, since the structure that the parameter buffer
handles comprehensively represents all ISP functions, I understand that it
would be difficult to add members for the histogram function later.

Should members corresponding to the histogram function be added to the parameter
buffer structure even if the implementation does not exist? Or, is it permissible
to add new members to the parameter buffer structure based on certain conditions?

> > > +.. _viif_stats:
> > > +
> > > +viif_stats - Statistics Video Node
> > > +----------------------------------
> > > +
> > > +The viif_stats video node provides current status of ISP.
> >
> > The viif_stats video node provides statistics computed by the ISP and frame
> > processing status.
> >
> 
> I'll update the sentence as you suggested.
> 
> > > +
> > > +Following information is included:
> > > +
> > > +* statistics of auto white balance
> > > +* average luminance information which can be used by auto exposure
> > software impl.
> >
> > s/impl/implementation/
> >
> 
> I should not have abbreviated a word.
> I'll fix it.
> 
> >
> > I would also add
> >
> >  * CSI-2 receiver calibration and error status
> >  * ISP error status
> >
> > It's quite uncommon to provide this kind of status through ISP stats buffers,
> but
> > it sounds like an interesting idea. Other drivers usually keep error counters in
> > the kernel and expose them through debugfs.
> >
> 
> These status information have existed since the initial implementation and
> must
> be passed to the user space in some way. On the other hand, I think that these,
> especially the CSI2 receiver error status, are not related to the
> frame-by-frame processing of the ISP, so they should not be included in the
> parameter buffer. I should classify the information and update the members of
> the parameter buffer accordingly. I think some of the information should be
> exposed through debugfs. However, I'm not sure how to classify them and how
> to
> implement the debugfs interface. Could you tell me the source code that
> should be referred to?
>

In the new implementation, the following information will be passed to user
space using debugfs:

- Errors during capture (originally, struct viif_reported_errors)
  - Counters will be prepared for each error cause. This will be implemented
    using debugfs_create_ulong().
  - The original specification was to "clear on read", but since it seems
    difficult to implement concisely, it will be changed to a count-up operation.
- CSI2RX calibration status
  - Information in three states (OK, Not-done, Error) for each signal line. 
    This will be represented using debugfs_create_x8() or debugfs_create_file()
    in a human-readable format.
- CSI2RX error status
  - Bit vector information for each error cause. This will be represented using
    debugfs_create_x32().

The following information will remain in the parameter buffer's statistics interface:

- Average luminance information
- Auto white balance information

--------------------

I would like to reconsider the connection between the Capture device (sub) and
other subdevices. Could you provide some feedback?

Currently, the Capture device (sub) is connected to the ISP subdevice.
This topology is based on my best understanding of the media controller framework
at the time of design. However, the Capture device (sub) saves RAW images without
processing them, and its operation does not depend on ISP functions. Therefore, 
for better maintenance in the future, I am considering disconnecting
the Capture device (sub) from the ISP subdevice.

Additionally, I want to prepare for improvements regarding streams. The CSI2RX
hardware can handle multiple virtual channels. Both the ISP hardware and 
Capture hardware (sub) can each select and receive one virtual channel. Currently,
due to insufficient tests, both are limited to receiving virtual channel 0,
but in the future, I want to be able to handle multiple channels using the stream API.

I'm considering three options for the topology.

- Option 1: Connect the Capture device (sub) to the ISP subdevice as it is currently.
  The switching of streams will be realized as a function of the ISP subdevice.
- Option 2: Create a new MUX subdevice and connect the ISP subdevice and
  Capture device (sub) to it. When handling multiple streams in the future,
  the switching function will be realized by the MUX subdevice. This will reduce
  the complexity of the ISP subdevice implementation.
- Option 3: Connect both the ISP subdevice and Capture device (sub) to
  the source port of CSI2RX. Is such a configuration really possible? The switching
  of multiple streams will be handled by both the ISP subdevice and Capture device respectively.


[Option1: Current design]
CSI2RX|0 -- ISP|1 -- Capture(post0)
               |2 -- Capture(post1)
               |3 -- Capture(sub)

[Option2]
CSI2RX|0 -- MUX|1 -- ISP|1 -- Capture(post0)
               |        |2 -- Capture(post1)
               |2 -- Capture(sub)

[Option3]
CSI2RX|0 --+-- ISP|1 -- Capture(post0)
           |      |2 -- Capture(post1)
           +-- Capture(sub)

> > > +
> > > +The buffer format is defined by struct
> > > +:c:type:`visconti_viif_isp_stat`, and userspace should
> > set :ref:`V4L2_META_FMT_VISCONTI_VIIF_STATS
> > <v4l2-meta-fmt-visconti-viif-stats>` as the data format.
> > > +
> > > +Feedback Operations
> > > +===================
> > > +
> > > +Among the so-called 3A functions, VIIF provides only auto-whitebalance
> > and auto-exposure.
> > > +Auto-whitebalance is a standalone hardware feature.
> > > +Some status information is available through the ISP statistics interface.
> > > +
> > > +Auto-exposure is realized through a combination of hardware and
> userland
> > software.
> > > +VIIF provides weighted average luminance information through the ISP
> > statistics interface.
> > > +The userland application calculates the sensor gain, sensor exposure and
> > ISP digital gain.
> > > +The calculated parameters are then passed to sensor's controls and the
> ISP
> > parameter interface.
> > > +
> > > +Among ISP parameters, there are parameters called AG (analog gain).
> > > +Actually, AG parameters have nothing to do with auto-exposure.
> > > +It controls "strength" in several signal correction algorithms.
> > > +Below is the list of the functions which may be affected by AG
> parameters:
> > > +
> > > +- ABPC/DPC
> > > +- RCNR
> > > +- LSSC
> > > +- MPRO: color matrix correction
> > > +- VPRO
> > > +
> > > +Capturing Video Frames Example
> > > +==============================
> > > +
> > > +In the following example,
> > > +imx219 camera is connected to pad 0 of 'visconti_csi2rx' subdevice.
> > > +
> > > +The following commands yield three pictures with different zoom ratio:
> > > +- main path 0: 1.5x zoom, crop 1920x1080, RGB picture
> > > +- main path 1: 0.67x zoom, crop 640x480, RGB picture
> > > +- sub path: 1920x1080 RAW picture
> > > +
> > > +.. code-block:: bash
> > > +
> > > +	# set the links
> > > +	media-ctl -d platform:visconti-viif-0 -r
> > > +	media-ctl -d platform:visconti-viif-0 -l '"imx219 1-0010":0 ->
> > "visconti_csi2rx 1c008000.csi2rx":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti_csi2rx
> > 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":1 ->
> > "visconti-viif:resizer0":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":2 ->
> > "visconti-viif:resizer1":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":3 ->
> > "viif_capture_sub":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer0":1 ->
> > "viif_capture_post0":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:resizer1":1 ->
> > "viif_capture_post1":0 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"viif_params":0 ->
> > "visconti-viif:isp":4 [1]'
> > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":5 ->
> > "viif_stats":0 [1]'
> > > +
> > > +	# set format for imx219
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"imx219 1-0010":0
> > [fmt:SRGGB10_1X10/1920x1080]'
> > > +
> > > +	# set format for csi2rx
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti_csi2rx
> > 1c008000.csi2rx":0 [fmt:SRGGB10_1X10/1920x1080  field:none
> > colorspace:raw xfer:none ycbcr:601 quantization:full-range]'
> > > +
> > > +	# set format for isp sink pad
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":0
> > [fmt:SRGGB10_1X10/1920x1080]'
> > > +
> > > +	# set format for resizer pads
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > '"visconti-viif:resizer0":0 '"[fmt:YUV8_1X24/1920x1080
> > compose:(0,0)/2880x1620]"
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > '"visconti-viif:resizer0":1 '"[crop:(480,16)/1920x1080]"
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > '"visconti-viif:resizer1":0 '"[fmt:YUV8_1X24/1920x1080
> > compose:(0,0)/1280x720]"
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > '"visconti-viif:resizer1":1 '"[crop:(320,32)/640x480]"
> > > +
> > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"visconti-viif:isp":1
> > [fmt:YUV8_1X24/1024 crop:(640,0)/1024x1024]'
> > > +
> > > +	# set format for main path0
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > "width=1920,height=1080"
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > "pixelformat=RGB3"
> > > +
> > > +	# set format for main path1
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > "width=640,height=480"
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > "pixelformat=RGB3"
> > > +
> > > +	# start streaming
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0
> > > +--stream-mmap --stream-count 1000 &
> > > +
> > > +	# start streaming with other devices while viif_capture_post0 is
> > running
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post1
> > --stream-mmap --stream-count 10
> > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_sub
> > > +--stream-mmap --stream-count 10
> > > +
> > > +Use of coherent memory
> > > +======================
> > > +
> > > +Visconti5 SoC has two independent DDR SDRAM controllers.
> > > +Each controller is mapped to 36bit address space.
> > > +
> > > +Accelerator bus masters have two paths to access memory; one is
> > > +directly connected to SDRAM controller, the another is connected via
> > > +a cache coherency bus which keeps coherency among CPUs.
> > > +
> > > +From accelerators and CPUs, the address map is following:
> > > +
> > > +* 0x0_8000_0000 DDR0 direct access
> > > +* 0x4_8000_0000 DDR0 coherency bus
> > > +* 0x8_8000_0000 DDR1 direct access
> > > +* 0xC_8000_0000 DDR1 coherency bus
> > > +
> > > +The base address can be specified with "memory" and
> "reserved-memory"
> > > +elements in a device tree description.
> > > +It's not recommended to mix direct address and coherent address.
> > > +
> > > +The Visconti5 VIIF driver always use only direct address to configure
> Video
> > DMACs of the hardware.
> > > +This design is to avoid great performance loss at coherency bus caused by
> > massive memory access.
> > > +You should not put the dma_coherent attribute to viif element in device
> > tree.
> > > +Cache operations are done automatically by videobuf2 driver.
> > > diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > index 86ffb3bc8ade..2336842f0c26 100644
> > > --- a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > @@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata`
> interface
> > only.
> > >      metafmt-pisp-fe
> > >      metafmt-rkisp1
> > >      metafmt-uvc
> > > +    metafmt-visconti-viif
> > >      metafmt-vivid
> > >      metafmt-vsp1-hgo
> > >      metafmt-vsp1-hgt
> > > diff --git
> > > a/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > new file mode 100644
> > > index 000000000000..dc4b31627fe1
> > > --- /dev/null
> > > +++
> b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > @@ -0,0 +1,48 @@
> > > +.. SPDX-License-Identifier: GPL-2.0
> > > +
> > > +.. _v4l2-meta-fmt-visconti-viif-params:
> > > +
> > > +.. _v4l2-meta-fmt-visconti-viif-stats:
> > > +
> > > +*********************************************************************
> > > +****************** V4L2_META_FMT_VISCONTI_VIIF_PARAMS ('vifp'),
> > > +V4L2_META_FMT_VISCONTI_VIIF_STATS ('vifs')
> > > +*********************************************************************
> > > +******************
> > > +
> > > +Configuration parameters
> > > +========================
> > > +
> > > +The configuration parameters are passed to the :ref:`viif_params
> > > +<viif_params>` metadata output video node, using the
> > > +:c:type:`v4l2_meta_format` interface. The buffer contains a single
> > > +instance of the C structure :c:type:`visconti_viif_isp_config`
> > > +defined in ``visconti_viif.h``. So the structure can be obtained from the
> > buffer by:
> > > +
> > > +.. code-block:: c
> > > +
> > > +	struct visconti_viif_isp_config *params = (struct
> > > +visconti_viif_isp_config*) buffer;
> > > +
> > > +VIIF statistics
> > > +===============
> > > +
> > > +The VIIF device collects different statistics over an input Bayer frame.
> > > +Those statistics are obtained from the :ref:`viif_stats <viif_stats>`
> > > +metadata capture video node, using the :c:type:`v4l2_meta_format`
> > > +interface. The buffer contains a single instance of the C structure
> > > +:c:type:`visconti_viif_isp_stat` defined in ``visconti_viif.h``. So
> > > +the structure can be obtained from the buffer by:
> > > +
> > > +.. code-block:: c
> > > +
> > > +	struct visconti_viif_isp_stat *stats = (struct
> > > +visconti_viif_isp_stat*) buffer;
> > > +
> > > +The statistics collected are Exposure, AWB (auto white balance) and
> errors.
> > > +See :c:type:`visconti_viif_isp_stat` for details of the statistics.
> > > +
> > > +The statistics and configuration parameters described here are
> > > +usually consumed and produced by dedicated user space libraries that
> > > +comprise the tuning tools using software control loop.
> > > +
> > > +visconti viif uAPI data types
> > > +=============================
> > > +
> > > +.. kernel-doc:: include/uapi/linux/visconti_viif.h
> >
> > Assuming the documentation in the header file is adequate, the level of detail
> > here is fine.
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
> 
> Regards,
> 
> Yuji Ishikawa

Regards,

Yuji Ishikawa

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

* RE: [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver
  2025-04-15  9:01       ` yuji2.ishikawa
@ 2025-06-18  1:30         ` yuji2.ishikawa
  0 siblings, 0 replies; 36+ messages in thread
From: yuji2.ishikawa @ 2025-06-18  1:30 UTC (permalink / raw)
  To: laurent.pinchart
  Cc: mchehab, robh, krzk+dt, conor+dt, sakari.ailus, hverkuil-cisco,
	nobuhiro1.iwamatsu, linux-media, linux-kernel, linux-arm-kernel,
	devicetree

Hello Laurent,

I will begin the revision work on the VIIF driver v13 patch according to the following revision policy proposal submitted on 4/15. 
If there are more appropriate methods or points to consider, especially regarding structural-level changes to the driver, please let me know.

> -----Original Message-----
> From: ishikawa yuji(石川 悠司 □AIDC○EA開)
> Sent: Tuesday, April 15, 2025 6:01 PM
> To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor Dooley
> <conor+dt@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>; Hans
> Verkuil <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 □DITC
> ○CPT) <nobuhiro1.iwamatsu@toshiba.co.jp>; linux-media@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> devicetree@vger.kernel.org
> Subject: RE: [PATCH v12 7/8] documentation: media: add documentation for
> Toshiba Visconti Video Input Interface driver
> 
> Hello Laurent,
> 
> As I reconsider the implementation of the v12 driver, I have decided on how to
> change the important parts pointed out in the review comments. On the other
> hand, I'm still looking for better implementation methods in some other areas.
> I would like to request your comments on these matters.
> 
> - Topic 1: Removing the resizer subdevice
> - Topic 2: Adding new members to the parameter buffer
> - Topic 3: Passing error information via debugfs
> - Topic 4: Reconsidering the topology of the capture device (sub path)
> 
> > -----Original Message-----
> > From: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> > Sent: Wednesday, February 5, 2025 9:30 PM
> > To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Cc: Mauro Carvalho Chehab <mchehab@kernel.org>; Rob Herring
> > <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Conor
> > Dooley <conor+dt@kernel.org>; Sakari Ailus
> > <sakari.ailus@linux.intel.com>; Hans Verkuil
> > <hverkuil-cisco@xs4all.nl>; iwamatsu nobuhiro(岩松 信洋 ○DITC
> > □DIT○OST) <nobuhiro1.iwamatsu@toshiba.co.jp>;
> > linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> > linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org
> > Subject: RE: [PATCH v12 7/8] documentation: media: add documentation
> > for Toshiba Visconti Video Input Interface driver
> >
> > Hello Laurent
> >
> > Thank you for your review comments.
> >
> 
> > > > +    - Cropping; see :c:type:`viif_l2_roi`
> > >
> > > Looking at the implementation of the resizer subdevs, I see that the
> > > crop and compose rectangles can be set, but they don't seem to ne
> > > used to configure
> > the
> > > resizer. Instead, the viif_l2_roi_config parameters are used to
> > > configure cropping on the resizer input and scaling. This
> > > discrepancy isn't good. I see
> > two
> > > options to fix it:
> > >
> > > - Keep configuring the resizer through viif_l2_roi_config and drop the
> resizer
> > >   subdevs. This will simplify the driver. The main drawback is that it
> > >   won't be possible to implement digital zoom (by changing the resizer
> > >   configuration) asynchronously from the ISP parameters buffers, which
> > >   can be useful to lower the latency of digital zoom.
> > >
> > > - Drop viif_l2_roi_config, and configure the resizer from the formats,
> > >   crop and selection rectangles on the resizer subdev pads. This makes
> > >   the driver more complex. The main advantage is that digital zoom will
> > >   be configurable with a smaller latency, but the drawback is that it
> > >   won't be possible (or it will be more difficult) to configure it
> > >   synchronously with other ISP parameters.
> > >
> > > There are drivers in mainline that implement either of those
> > > options, so you
> > can
> > > pick the one you think is best.
> > >
> > > An additional issue is that the hardware seems to implement cropping
> > > on the output of the resizer only, not on the input. Given that the
> > > size of the images output by the ISP pipeline must stay constant
> > > during video capture
> > (otherwise
> > > there would be a risk of buffer overflow), modifying the crop
> > > rectangle on the output of the resizer is usually not allowed during
> > > streaming. I think this could be worked around by allowing
> > > modification only of the left and top
> > coordinates
> > > during streaming, but configuring everything through
> > > viif_l2_roi_config would likely be easier. In that case, you should
> > > probably extend viif_l2_roi_config
> > with
> > > the crop offsets.
> > >
> > > All of this reflects my current understanding of the ISP
> > > architecture, based on this document and on the driver code, so
> > > please correct me if there's anything
> > I
> > > misunderstood. We can discuss the different options further before
> > > you
> > modify
> > > the driver and send a new version.
> > >
> >
> > First of all, I apologize for attempting to make significant changes
> > to the driver structure without consulting you. The hardware
> > specifications of VIIF are unique, and the knowledge from the drivers
> > I referred to (mainly rkisp1) cannot be directly applied. As a result,
> > I am still struggling with how to write a driver that conforms to the V4L2
> framework.
> >
> > I am considering removing the resizer subdevice because
> > viif_l2_roi_config can set more detailed parameters compared to the resizer
> subdevice's pad.
> >
> > To explain my idea and answer your questions, let me describe the
> > processing of the VIIF L2-ISP.
> >
> > The central functions of the L2 ISP are lens undistortion and scaling.
> > They are integrated and executed simultaneously. To explain the
> > coordinate transformation here, several virtual images are defined.
> >
> > * L1ISP output image
> >     * the input of L2ISP
> >     * geometry: {width, height}
> >     * mapped to sink.format
> > * Input image
> >     * geometry: {center_x, center_y, width, height}
> >     * relative to the L1ISP output image
> >     * mapped to sink.crop
> >     * resizer subdevice assumes that sink.crop = sink.format
> > * Corrected image after undistortion
> >     * geometry: {width, height}
> >     * relative to the Input image
> > * Corrected image with scale
> >     * geometry: {width, height}
> >     * relative to the Input image
> >     * mapped to sink.compose
> >     * resizer subdevice assumes that scale factor = sink.compose /
> > sink.format
> > * ROI image
> >     * geometry: {left, top, width, height}
> >     * relative to the Corrected image with scale
> >     * mapped to source.crop
> > * Crop image
> >     * the output of L2ISP.
> >     * geometry: {left, top, width, height}
> >     * relative to the Corrected image with scale
> >     * mapped to source.crop
> >
> > These images mentioned here do not have corresponding frame buffers.
> > However,
> > there are control registers corresponding to the width and height of
> > each image, and appropriate values must be set. Otherwise, the output
> > image may be corrupted, or the L2ISP may abort.
> >
> > Regarding your question of why sink.crop is not used.
> > According to the list above, sink.crop corresponds to the Input image.
> > However, the coordinates of the Input image must be set to align with
> > the optical center for undistortion, so it cannot be used to crop arbitrary
> rectangles.
> >
> > Regarding digital zoom.
> > In the existing use cases of VIIF, the scale and crop are fixed during recording.
> > Therefore, I did not consider changing the selection parameter like digital
> zoom.
> >
> > Regarding resizer subdevice.
> > The purpose of the resizer subdevice is to set the initial values of
> > L2ISP from pad's selection parameters. Most virtual image rectangles
> > can be mapped to the pad's parameters. Since the parameters of
> > undistortion and the rectangle of the Corrected image after
> > undistortion are unknown, I assumed that undistortion is disabled
> > (pass-through) and the Corrected image after undistortion matches the
> > Input image. In this case, the scaling parameters can be calculated
> > from sink.compose and sink.input.
> > On the other hand, in cases where both undistortion and scaling are
> > utilized, it is necessary to set viif_l2_undist_config and
> > viif_l2_roi_config. Therefore, I made it possible to overwrite these parameters
> through the parameter buffer.
> >
> > To configure cropping with the parameter buffer instead of pad's
> > selection, I'll add two members (left and top) to viif_l2_roi_config.
> > Otherwise, I'll newly add struct viif_l2_crop_config to the parameter buffer.
> >
> 
> I am removing the resizer sub-device. In the new implementation, the
> undistortion and scaling functions of L2ISP are controlled using the l2_undist
> member and l2_roi member of the parameter buffer. To control the cropping
> function of L2ISP, the l2_crop_post0 and l2_crop_post1 members are added to
> the parameter buffer to indicate the top-left coordinates for cropping.
> These new members have the type struct l2_crop_config {__u32 left; __u32 top}.
> The default values of the members are (0, 0).
> 
> ISP subdevice pads have the following specifications:
> - The sink_pad::fmt and source_pad(post0)::fmt, source_pad(post1)::fmt can
> be set independently.
> - Each pad cannot be set for crop and compose.
> - The maximum size of source_pad::fmt is either the hardware limit of L2ISP or
> 2x sink_pad::fmt.
> - The minimum size of source_pad::fmt is the hardware limit of L2ISP.
> - Due to the inclusion relationship of the planes, the following constraint should
> be met:
> 
>   l2_crop_post0::left + source_pad(post0)::fmt::width <=
> l2_roi::corrected_width(post0)
> 
>   A similar constraint should be applied to the height and the post1.
> 
> There are two possible behaviors when constraints are not met. If the
> instructions through the parameter buffer are not accepted, how should the
> driver behave?
> 
> - Increment the error counter (referred by debugfs) and ignore the instructions
>   from the parameter buffer.
> - Modify l2_roi::corrected_width(post0) and l2_crop_post0::left and apply them
>   to the hardware. As a result, an L2ISP error might occur. The drawback is that
>   the user program cannot know the modified coordinates.
> 
> > > > +.. _viif_params:
> > > > +
> > > > +viif_params - ISP Parameters Video Node
> > > > +---------------------------------------
> > > > +
> > > > +The viif_params video node receives a set of ISP parameters from
> > > > +userspace to be applied to the hardware during a video stream.
> > > > +
> > > > +The buffer format is defined by struct
> > > > +:c:type:`visconti_viif_isp_config`, and userspace should
> > > set :ref:`V4L2_META_FMT_VISCONTI_VIIF_PARAMS
> > > <v4l2-meta-fmt-visconti-viif-params>` as the data format.
> > > > +
> 
> Please advise on how to handle unverified ISP functions in the parameter
> buffer.
> 
> The L1ISP hardware has a function to calculate the luminance histogram.
> The software for this function is experimental and has not yet been developed
> as a Linux driver. However, since the structure that the parameter buffer
> handles comprehensively represents all ISP functions, I understand that it
> would be difficult to add members for the histogram function later.
> 
> Should members corresponding to the histogram function be added to the
> parameter buffer structure even if the implementation does not exist? Or, is it
> permissible to add new members to the parameter buffer structure based on
> certain conditions?
> 
> > > > +.. _viif_stats:
> > > > +
> > > > +viif_stats - Statistics Video Node
> > > > +----------------------------------
> > > > +
> > > > +The viif_stats video node provides current status of ISP.
> > >
> > > The viif_stats video node provides statistics computed by the ISP
> > > and frame processing status.
> > >
> >
> > I'll update the sentence as you suggested.
> >
> > > > +
> > > > +Following information is included:
> > > > +
> > > > +* statistics of auto white balance
> > > > +* average luminance information which can be used by auto
> > > > +exposure
> > > software impl.
> > >
> > > s/impl/implementation/
> > >
> >
> > I should not have abbreviated a word.
> > I'll fix it.
> >
> > >
> > > I would also add
> > >
> > >  * CSI-2 receiver calibration and error status
> > >  * ISP error status
> > >
> > > It's quite uncommon to provide this kind of status through ISP stats
> > > buffers,
> > but
> > > it sounds like an interesting idea. Other drivers usually keep error
> > > counters in the kernel and expose them through debugfs.
> > >
> >
> > These status information have existed since the initial implementation
> > and must be passed to the user space in some way. On the other hand, I
> > think that these, especially the CSI2 receiver error status, are not
> > related to the frame-by-frame processing of the ISP, so they should
> > not be included in the parameter buffer. I should classify the
> > information and update the members of the parameter buffer
> > accordingly. I think some of the information should be exposed through
> > debugfs. However, I'm not sure how to classify them and how to
> > implement the debugfs interface. Could you tell me the source code
> > that should be referred to?
> >
> 
> In the new implementation, the following information will be passed to user
> space using debugfs:
> 
> - Errors during capture (originally, struct viif_reported_errors)
>   - Counters will be prepared for each error cause. This will be implemented
>     using debugfs_create_ulong().
>   - The original specification was to "clear on read", but since it seems
>     difficult to implement concisely, it will be changed to a count-up operation.
> - CSI2RX calibration status
>   - Information in three states (OK, Not-done, Error) for each signal line.
>     This will be represented using debugfs_create_x8() or
> debugfs_create_file()
>     in a human-readable format.
> - CSI2RX error status
>   - Bit vector information for each error cause. This will be represented using
>     debugfs_create_x32().
> 
> The following information will remain in the parameter buffer's statistics
> interface:
> 
> - Average luminance information
> - Auto white balance information
> 
> --------------------
> 
> I would like to reconsider the connection between the Capture device (sub) and
> other subdevices. Could you provide some feedback?
> 
> Currently, the Capture device (sub) is connected to the ISP subdevice.
> This topology is based on my best understanding of the media controller
> framework at the time of design. However, the Capture device (sub) saves RAW
> images without processing them, and its operation does not depend on ISP
> functions. Therefore, for better maintenance in the future, I am considering
> disconnecting the Capture device (sub) from the ISP subdevice.
> 
> Additionally, I want to prepare for improvements regarding streams. The
> CSI2RX hardware can handle multiple virtual channels. Both the ISP hardware
> and Capture hardware (sub) can each select and receive one virtual channel.
> Currently, due to insufficient tests, both are limited to receiving virtual channel
> 0, but in the future, I want to be able to handle multiple channels using the
> stream API.
> 
> I'm considering three options for the topology.
> 
> - Option 1: Connect the Capture device (sub) to the ISP subdevice as it is
> currently.
>   The switching of streams will be realized as a function of the ISP subdevice.
> - Option 2: Create a new MUX subdevice and connect the ISP subdevice and
>   Capture device (sub) to it. When handling multiple streams in the future,
>   the switching function will be realized by the MUX subdevice. This will
> reduce
>   the complexity of the ISP subdevice implementation.
> - Option 3: Connect both the ISP subdevice and Capture device (sub) to
>   the source port of CSI2RX. Is such a configuration really possible? The
> switching
>   of multiple streams will be handled by both the ISP subdevice and Capture
> device respectively.
> 
> 
> [Option1: Current design]
> CSI2RX|0 -- ISP|1 -- Capture(post0)
>                |2 -- Capture(post1)
>                |3 -- Capture(sub)
> 
> [Option2]
> CSI2RX|0 -- MUX|1 -- ISP|1 -- Capture(post0)
>                |        |2 -- Capture(post1)
>                |2 -- Capture(sub)
> 
> [Option3]
> CSI2RX|0 --+-- ISP|1 -- Capture(post0)
>            |      |2 -- Capture(post1)
>            +-- Capture(sub)
> 
> > > > +
> > > > +The buffer format is defined by struct
> > > > +:c:type:`visconti_viif_isp_stat`, and userspace should
> > > set :ref:`V4L2_META_FMT_VISCONTI_VIIF_STATS
> > > <v4l2-meta-fmt-visconti-viif-stats>` as the data format.
> > > > +
> > > > +Feedback Operations
> > > > +===================
> > > > +
> > > > +Among the so-called 3A functions, VIIF provides only
> > > > +auto-whitebalance
> > > and auto-exposure.
> > > > +Auto-whitebalance is a standalone hardware feature.
> > > > +Some status information is available through the ISP statistics
> interface.
> > > > +
> > > > +Auto-exposure is realized through a combination of hardware and
> > userland
> > > software.
> > > > +VIIF provides weighted average luminance information through the
> > > > +ISP
> > > statistics interface.
> > > > +The userland application calculates the sensor gain, sensor
> > > > +exposure and
> > > ISP digital gain.
> > > > +The calculated parameters are then passed to sensor's controls
> > > > +and the
> > ISP
> > > parameter interface.
> > > > +
> > > > +Among ISP parameters, there are parameters called AG (analog gain).
> > > > +Actually, AG parameters have nothing to do with auto-exposure.
> > > > +It controls "strength" in several signal correction algorithms.
> > > > +Below is the list of the functions which may be affected by AG
> > parameters:
> > > > +
> > > > +- ABPC/DPC
> > > > +- RCNR
> > > > +- LSSC
> > > > +- MPRO: color matrix correction
> > > > +- VPRO
> > > > +
> > > > +Capturing Video Frames Example
> > > > +==============================
> > > > +
> > > > +In the following example,
> > > > +imx219 camera is connected to pad 0 of 'visconti_csi2rx' subdevice.
> > > > +
> > > > +The following commands yield three pictures with different zoom ratio:
> > > > +- main path 0: 1.5x zoom, crop 1920x1080, RGB picture
> > > > +- main path 1: 0.67x zoom, crop 640x480, RGB picture
> > > > +- sub path: 1920x1080 RAW picture
> > > > +
> > > > +.. code-block:: bash
> > > > +
> > > > +	# set the links
> > > > +	media-ctl -d platform:visconti-viif-0 -r
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"imx219 1-0010":0 ->
> > > "visconti_csi2rx 1c008000.csi2rx":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti_csi2rx
> > > 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":1
> > > > +->
> > > "visconti-viif:resizer0":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":2
> > > > +->
> > > "visconti-viif:resizer1":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":3
> > > > +->
> > > "viif_capture_sub":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l
> > > > +'"visconti-viif:resizer0":1 ->
> > > "viif_capture_post0":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l
> > > > +'"visconti-viif:resizer1":1 ->
> > > "viif_capture_post1":0 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"viif_params":0 ->
> > > "visconti-viif:isp":4 [1]'
> > > > +	media-ctl -d platform:visconti-viif-0 -l '"visconti-viif:isp":5
> > > > +->
> > > "viif_stats":0 [1]'
> > > > +
> > > > +	# set format for imx219
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2 '"imx219
> > > > +1-0010":0
> > > [fmt:SRGGB10_1X10/1920x1080]'
> > > > +
> > > > +	# set format for csi2rx
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > > +'"visconti_csi2rx
> > > 1c008000.csi2rx":0 [fmt:SRGGB10_1X10/1920x1080  field:none
> > > colorspace:raw xfer:none ycbcr:601 quantization:full-range]'
> > > > +
> > > > +	# set format for isp sink pad
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > > +'"visconti-viif:isp":0
> > > [fmt:SRGGB10_1X10/1920x1080]'
> > > > +
> > > > +	# set format for resizer pads
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > '"visconti-viif:resizer0":0 '"[fmt:YUV8_1X24/1920x1080
> > > compose:(0,0)/2880x1620]"
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > '"visconti-viif:resizer0":1 '"[crop:(480,16)/1920x1080]"
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > '"visconti-viif:resizer1":0 '"[fmt:YUV8_1X24/1920x1080
> > > compose:(0,0)/1280x720]"
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > '"visconti-viif:resizer1":1 '"[crop:(320,32)/640x480]"
> > > > +
> > > > +	media-ctl -d platform:visconti-viif-0 --set-v4l2
> > > > +'"visconti-viif:isp":1
> > > [fmt:YUV8_1X24/1024 crop:(640,0)/1024x1024]'
> > > > +
> > > > +	# set format for main path0
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > > "width=1920,height=1080"
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > > "pixelformat=RGB3"
> > > > +
> > > > +	# set format for main path1
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > > "width=640,height=480"
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0 -v
> > > "pixelformat=RGB3"
> > > > +
> > > > +	# start streaming
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post0
> > > > +--stream-mmap --stream-count 1000 &
> > > > +
> > > > +	# start streaming with other devices while viif_capture_post0 is
> > > running
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_post1
> > > --stream-mmap --stream-count 10
> > > > +	v4l2-ctl -z platform:visconti-viif-0 -d viif_capture_sub
> > > > +--stream-mmap --stream-count 10
> > > > +
> > > > +Use of coherent memory
> > > > +======================
> > > > +
> > > > +Visconti5 SoC has two independent DDR SDRAM controllers.
> > > > +Each controller is mapped to 36bit address space.
> > > > +
> > > > +Accelerator bus masters have two paths to access memory; one is
> > > > +directly connected to SDRAM controller, the another is connected
> > > > +via a cache coherency bus which keeps coherency among CPUs.
> > > > +
> > > > +From accelerators and CPUs, the address map is following:
> > > > +
> > > > +* 0x0_8000_0000 DDR0 direct access
> > > > +* 0x4_8000_0000 DDR0 coherency bus
> > > > +* 0x8_8000_0000 DDR1 direct access
> > > > +* 0xC_8000_0000 DDR1 coherency bus
> > > > +
> > > > +The base address can be specified with "memory" and
> > "reserved-memory"
> > > > +elements in a device tree description.
> > > > +It's not recommended to mix direct address and coherent address.
> > > > +
> > > > +The Visconti5 VIIF driver always use only direct address to
> > > > +configure
> > Video
> > > DMACs of the hardware.
> > > > +This design is to avoid great performance loss at coherency bus
> > > > +caused by
> > > massive memory access.
> > > > +You should not put the dma_coherent attribute to viif element in
> > > > +device
> > > tree.
> > > > +Cache operations are done automatically by videobuf2 driver.
> > > > diff --git
> > > > a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > > b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > > index 86ffb3bc8ade..2336842f0c26 100644
> > > > --- a/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > > +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
> > > > @@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata`
> > interface
> > > only.
> > > >      metafmt-pisp-fe
> > > >      metafmt-rkisp1
> > > >      metafmt-uvc
> > > > +    metafmt-visconti-viif
> > > >      metafmt-vivid
> > > >      metafmt-vsp1-hgo
> > > >      metafmt-vsp1-hgt
> > > > diff --git
> > > > a/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > > b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > > new file mode 100644
> > > > index 000000000000..dc4b31627fe1
> > > > --- /dev/null
> > > > +++
> > b/Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> > > > @@ -0,0 +1,48 @@
> > > > +.. SPDX-License-Identifier: GPL-2.0
> > > > +
> > > > +.. _v4l2-meta-fmt-visconti-viif-params:
> > > > +
> > > > +.. _v4l2-meta-fmt-visconti-viif-stats:
> > > > +
> > > > +*****************************************************************
> > > > +****
> > > > +****************** V4L2_META_FMT_VISCONTI_VIIF_PARAMS ('vifp'),
> > > > +V4L2_META_FMT_VISCONTI_VIIF_STATS ('vifs')
> > > > +*****************************************************************
> > > > +****
> > > > +******************
> > > > +
> > > > +Configuration parameters
> > > > +========================
> > > > +
> > > > +The configuration parameters are passed to the :ref:`viif_params
> > > > +<viif_params>` metadata output video node, using the
> > > > +:c:type:`v4l2_meta_format` interface. The buffer contains a
> > > > +single instance of the C structure
> > > > +:c:type:`visconti_viif_isp_config`
> > > > +defined in ``visconti_viif.h``. So the structure can be obtained
> > > > +from the
> > > buffer by:
> > > > +
> > > > +.. code-block:: c
> > > > +
> > > > +	struct visconti_viif_isp_config *params = (struct
> > > > +visconti_viif_isp_config*) buffer;
> > > > +
> > > > +VIIF statistics
> > > > +===============
> > > > +
> > > > +The VIIF device collects different statistics over an input Bayer frame.
> > > > +Those statistics are obtained from the :ref:`viif_stats
> > > > +<viif_stats>` metadata capture video node, using the
> > > > +:c:type:`v4l2_meta_format` interface. The buffer contains a
> > > > +single instance of the C structure
> > > > +:c:type:`visconti_viif_isp_stat` defined in ``visconti_viif.h``. So the
> structure can be obtained from the buffer by:
> > > > +
> > > > +.. code-block:: c
> > > > +
> > > > +	struct visconti_viif_isp_stat *stats = (struct
> > > > +visconti_viif_isp_stat*) buffer;
> > > > +
> > > > +The statistics collected are Exposure, AWB (auto white balance)
> > > > +and
> > errors.
> > > > +See :c:type:`visconti_viif_isp_stat` for details of the statistics.
> > > > +
> > > > +The statistics and configuration parameters described here are
> > > > +usually consumed and produced by dedicated user space libraries
> > > > +that comprise the tuning tools using software control loop.
> > > > +
> > > > +visconti viif uAPI data types
> > > > +=============================
> > > > +
> > > > +.. kernel-doc:: include/uapi/linux/visconti_viif.h
> > >
> > > Assuming the documentation in the header file is adequate, the level
> > > of detail here is fine.
> > >
> > > --
> > > Regards,
> > >
> > > Laurent Pinchart
> >
> > Regards,
> >
> > Yuji Ishikawa
> 
> Regards,
> 
> Yuji Ishikawa

Regards,

Yuji Ishikawa

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

end of thread, other threads:[~2025-06-18  3:09 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-25  9:21 [PATCH v12 0/8] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
2024-11-25  9:21 ` [PATCH v12 1/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
2024-11-25 10:11   ` Krzysztof Kozlowski
2024-12-16 23:57     ` yuji2.ishikawa
2024-12-17  5:44       ` Krzysztof Kozlowski
2024-12-24  0:17         ` yuji2.ishikawa
2024-12-26 16:15         ` Laurent Pinchart
2025-01-02  9:29   ` Laurent Pinchart
2025-01-20  0:10     ` yuji2.ishikawa
2024-11-25  9:21 ` [PATCH v12 2/8] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
2024-11-25 10:07   ` Krzysztof Kozlowski
2024-12-17  0:00     ` yuji2.ishikawa
2024-12-17  5:43       ` Krzysztof Kozlowski
2024-12-17  9:45         ` Laurent Pinchart
2024-12-17 12:51           ` Krzysztof Kozlowski
2025-01-02  9:41             ` Laurent Pinchart
2024-12-24  0:17         ` yuji2.ishikawa
2025-01-02  9:56   ` Laurent Pinchart
2025-01-20  0:13     ` yuji2.ishikawa
2024-11-25  9:21 ` [PATCH v12 3/8] media: uapi: add visconti viif meta buffer format Yuji Ishikawa
2025-01-02 13:10   ` Laurent Pinchart
2025-01-20  0:15     ` yuji2.ishikawa
2025-01-20  1:49       ` Laurent Pinchart
2024-11-25  9:21 ` [PATCH v12 4/8] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
2025-01-02 13:08   ` Laurent Pinchart
2025-01-20  0:21     ` yuji2.ishikawa
2024-11-25  9:21 ` [PATCH v12 5/8] media: platform: visconti: Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
2024-11-25  9:21 ` [PATCH v12 6/8] media: platform: visconti: Add streaming interface for ISP parameters and status Yuji Ishikawa
2024-11-25  9:21 ` [PATCH v12 7/8] documentation: media: add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
2025-01-02 21:26   ` Laurent Pinchart
2025-02-05 12:29     ` yuji2.ishikawa
2025-04-15  9:01       ` yuji2.ishikawa
2025-06-18  1:30         ` yuji2.ishikawa
2024-11-25  9:21 ` [PATCH v12 8/8] MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface Yuji Ishikawa
2025-01-02 13:16   ` Laurent Pinchart
2025-02-05 12:31     ` yuji2.ishikawa

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).