public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver
@ 2025-10-16  2:24 Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Laurent Pinchart

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

Changelog v13:
- Link to v12: https://lore.kernel.org/all/20241125092146.1561901-1-yuji2.ishikawa@toshiba.co.jp/
- working tree: https://git.linuxtv.org/media_stage.git
  - base-commit(v12): 6390834c6f9b2c5e33f52f34579efa0d0df073db
  - base-commit(v13): 3a8660878839faadb4f1a6dd72c3179c1df56787
- corresponding update of clock framework driver is discussed in:
  - https://lore.kernel.org/all/20251016013328.303611-1-yuji2.ishikawa@toshiba.co.jp/
- remove resizer subdevice
- rebase to Linux 6.18-rc1
- wrap one line at 80 characters
- change banner comment style
- update comment style; spacing at the start and end, capitalize first letter
- add support for clock and reset framework. The clock driver will be updated
  by another submission.
- add debugfs to pass debug and status information
- add callback for ioctl(VIDIOC_ENUM_FRAMESIZES)
- MAINTAINERS: update email address of Nobuhiro Iwamatsu
- csi2: change compatible string
- viif: remove CROP and COMPOSE API from ISP subdevice, add struct
  viif_l2_crop_config instead.
- viif: correct teardown sequence at error of probe() and remove()
- document: VIIF specific keyword "AG" stands for "algorithm gain" instead of
  "analog gain"
- document: update illustration and description on preprocess part

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

---
Yuji Ishikawa (7):
      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 formats
      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 statistics
      documentation: media: Add documentation for Toshiba Visconti Video Input Interface driver

 Documentation/admin-guide/media/v4l-drivers.rst    |    1 +
 Documentation/admin-guide/media/visconti-viif.dot  |   18 +
 Documentation/admin-guide/media/visconti-viif.rst  |  540 +++++
 .../bindings/media/toshiba,visconti5-csi2.yaml     |  125 ++
 .../bindings/media/toshiba,visconti5-viif.yaml     |  110 +
 .../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            |    3 +
 drivers/media/platform/toshiba/visconti/Kconfig    |   35 +
 drivers/media/platform/toshiba/visconti/Makefile   |   10 +
 .../media/platform/toshiba/visconti/csi2rx_drv.c   |  954 +++++++++
 drivers/media/platform/toshiba/visconti/viif.c     |  710 ++++++
 drivers/media/platform/toshiba/visconti/viif.h     |  391 ++++
 .../media/platform/toshiba/visconti/viif_capture.c | 1470 +++++++++++++
 .../media/platform/toshiba/visconti/viif_capture.h |   24 +
 .../media/platform/toshiba/visconti/viif_common.c  |  250 +++
 .../media/platform/toshiba/visconti/viif_common.h  |   47 +
 drivers/media/platform/toshiba/visconti/viif_isp.c |  981 +++++++++
 drivers/media/platform/toshiba/visconti/viif_isp.h |   20 +
 .../media/platform/toshiba/visconti/viif_params.c  | 2257 ++++++++++++++++++++
 .../media/platform/toshiba/visconti/viif_params.h  |   20 +
 .../media/platform/toshiba/visconti/viif_regs.h    |  726 +++++++
 .../media/platform/toshiba/visconti/viif_stats.c   |  320 +++
 .../media/platform/toshiba/visconti/viif_stats.h   |   16 +
 drivers/media/v4l2-core/v4l2-ioctl.c               |    2 +
 include/uapi/linux/videodev2.h                     |    4 +
 include/uapi/linux/visconti_viif.h                 | 1911 +++++++++++++++++
 31 files changed, 11014 insertions(+)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20250925-visconti-viif-f9014920a58a
prerequisite-message-id: <20251016013328.303611-1-yuji2.ishikawa@toshiba.co.jp>
prerequisite-patch-id: 73a37b4200a5a30406de3bc8eb79af986ff9592d
prerequisite-patch-id: 78e9d304c8aeee089bc3381505724b466f01ae47

Best regards,
-- 
Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>




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

* [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  2025-10-16  4:34   ` Frank Li
  2025-10-16  6:38   ` Krzysztof Kozlowski
  2025-10-16  2:24 ` [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

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>
---
Changelog v12:
- Newly add bindings for CSI2RX driver

Changelog v13:
- add entries to MAINTAINERS file.
- update email address of Nobuhiro Iwamatsu in /maintainers
- add Yuji Ishikawa to /maintainers
- change /properties/compatible: toshiba,visconti5-csi2rx -> toshiba,visconti5-csi2
- change bindings file name: toshiba,visconti5-csi2rx -> toshiba,visconti5-csi2
- change node name in sample DTS: csi2rx -> csi
- remove "|-" from /description
- update /description
- add definitions of clock and reset
- update /properties/ports/properties/port@0/description for better comment
- update /properties/ports/properties/port@0/$ref to specify full pathname
- remove /properties/ports/properties/port@0/properties/endpoint/properties/data-lanes/description because the default text provides enough information.
- update sample dts
---
 .../bindings/media/toshiba,visconti5-csi2.yaml     | 125 +++++++++++++++++++++
 MAINTAINERS                                        |   7 ++
 2 files changed, 132 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
new file mode 100644
index 000000000000..21fb46de5b6e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
+
+maintainers:
+  - Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
+  - Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
+
+description:
+  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI CSI-2 video
+  stream. The obtained video stream is used as input for the Visconti5 VIIF.
+
+properties:
+  compatible:
+    const: toshiba,visconti5-csi2
+
+  reg:
+    items:
+      - description: Registers for CSI2 receiver control
+
+  interrupts:
+    items:
+      - description: CSI2 Receiver Interrupt
+
+  clocks:
+    items:
+      - description: MIPI DPHY configuration clock
+      - description: Register access clock
+
+  clock-names:
+    items:
+      - const: cfg
+      - const: apb
+
+  resets:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description:
+          Input port node, with an endpoint pointing to the image sensor.
+
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              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, with an endpoint pointing to the Visconti VIIF.
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/toshiba,tmpv770x.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        csi0: csi@1c008000 {
+            compatible = "toshiba,visconti5-csi2";
+            reg = <0 0x1c008000 0 0x400>;
+            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&pismu TMPV770X_CLK_VIIFBS0_CFG>,
+                     <&pismu TMPV770X_CLK_VIIFBS0_APB>;
+            clock-names = "cfg", "apb";
+            resets = <&pismu TMPV770X_RESET_VIIFBS0_APB>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                port@0 {
+                    reg = <0>;
+                    csi0_in: endpoint {
+                        data-lanes = <1 2>;
+                        remote-endpoint = <&imx219_out>;
+                    };
+                };
+                port@1 {
+                    reg = <1>;
+                    csi0_out: endpoint {
+                        remote-endpoint = <&video0_in>;
+                    };
+                };
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 46126ce2f968..e4634a0aad74 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25979,6 +25979,13 @@ F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358743.txt
 F:	drivers/media/i2c/tc358743*
 F:	include/media/i2c/tc358743.h
 
+TOSHIBA VISCONTI VIIF DRIVER
+M:	Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
+M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
+
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
 L:	platform-driver-x86@vger.kernel.org

-- 
2.34.1




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

* [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  2025-10-16  6:39   ` Krzysztof Kozlowski
  2025-10-16  2:24 ` [PATCH v13 3/7] media: uapi: Add visconti viif meta buffer formats Yuji Ishikawa
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

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

Changelog v13:
- add entries to MAINTAINERS flle
- update email address of Nobuhiro Iwamatsu in /maintainers
- add Yuji Ishikawa to /maintainers
- remove "|-" from /description
- add definitions of clock and reset
- update /port/$ref to point port instead of port-base
- update /port/description
- remove CSI2 receiver specific definition from /port/properties/endpoint/properties because CSI2 is handled by the CSI2 driver.
- update sample dts
---
 .../bindings/media/toshiba,visconti5-viif.yaml     | 110 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 2 files changed, 111 insertions(+)

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..92ffe844cdde
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
@@ -0,0 +1,110 @@
+# 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 <nobuhiro.iwamatsu.x90@mail.toshiba>
+  - Yuji Ishikawa <yuji2.ishikawa@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
+
+  clocks:
+    items:
+      - description: Common clock
+      - description: Interface clock
+      - description: L1ISP clock
+      - description: L2ISP clock
+
+  clock-names:
+    items:
+      - const: bsproc
+      - const: proc
+      - const: l1isp
+      - const: l2isp
+
+  resets:
+    items:
+      - description: Interface reset
+      - description: L1ISP reset
+      - description: L2ISP reset
+
+  reset-names:
+    items:
+      - const: core
+      - const: l1isp
+      - const: l2isp
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Input port node with an endpoint pointing to the CSI-2 receiver.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/toshiba,tmpv770x.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        video0: 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>;
+            clocks = <&pismu TMPV770X_CLK_VIIFBS0_PROC>,
+                     <&pismu TMPV770X_CLK_VIIF0_PROC>,
+                     <&pismu TMPV770X_CLK_VIIF0_L1ISP>,
+                     <&pismu TMPV770X_CLK_VIIF0_L2ISP>;
+            clock-names = "bsproc", "proc", "l1isp", "l2isp";
+            resets = <&pismu TMPV770X_RESET_VIIFBS0>,
+                     <&pismu TMPV770X_RESET_VIIFBS0_L1ISP>,
+                     <&pismu TMPV770X_RESET_VIIFBS0_L2ISP>;
+            reset-names = "core", "l1isp", "l2isp";
+
+            port {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                video0_in: endpoint {
+                    remote-endpoint = <&csi0_out>;
+                };
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index e4634a0aad74..c17c7ddba5af 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25985,6 +25985,7 @@ M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
 L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
+F:	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
 
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>

-- 
2.34.1




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

* [PATCH v13 3/7] media: uapi: Add visconti viif meta buffer formats
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Laurent Pinchart

Add the Toshiba Visconti VIIF specific metadata 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>
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

Changelog v13:
- no change
- Capitalize the first letter of the commit message header.
---
 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 01cf52c3ea33..cfc9a8ab66cb 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1479,6 +1479,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 becd08fdbddb..980ce7d2da1a 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -884,6 +884,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.34.1




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

* [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (2 preceding siblings ...)
  2025-10-16  2:24 ` [PATCH v13 3/7] media: uapi: Add visconti viif meta buffer formats Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  2025-10-16  4:45   ` Frank Li
  2025-10-16  2:24 ` [PATCH v13 6/7] media: platform: visconti: Add streaming interface for ISP parameters and statistics Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 7/7] documentation: media: Add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  5 siblings, 1 reply; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

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

Changelog v13:
- wrap one line at 80 characters
- change banner comment style
- update comment style; spacing at the start and end, capitalize first letter
- add support for clock and reset framework
- add debugfs to pass debug and status information
- add entries to MAINTAINERS file
- Kconfig: add a blank line just after License Identifier.
- update references to header files
- remove redundant inline qualifier
- shorten function/variable names: visconti_csi2rx -> viscsi2
- simplify dphy_write and dphy read operations
- remove osc_freq_target from struct csi2rx_dphy_hs_info, which is always the same value.
- add comment about MASK register's behavior (reversed polarity)
- use v4l2_get_link_freq() instead of get_pixelclock()
- set driver name according to module name: visconti_csi2rx_dev -> visconti-csi2rx
- check error before setting priv->irq in probe()
- check error at fmt_for_mbus_code()
- add callback for ioctl(VIDIOC_ENUM_FRAMESIZES)
- improve viscsi2_parse_dt() by assuming bus_type is CSI2_DPHY
- use dev_err_ratelimited() for irq handler
- bugfix on fmt_for_mbus_code(): in case unsupported mbus_code is given
- add goto based error handling sequence to viscsi2_parse_dt()
- specify default value of colorspace, ycbcr_enc, quantization and xfer_func of sink/src_fmt
- specify sensor at enable_streams() using previously set ID, instead of checking remote pad every time
- remove U suffix on numeric value
- use unsigned int variable for loop index
- remove redundant casting
- use GENMASK instead of literal
- remove unused constants
- remove unused visconti_csi2rx_video_ops
---
 MAINTAINERS                                        |   1 +
 drivers/media/platform/Kconfig                     |   1 +
 drivers/media/platform/Makefile                    |   1 +
 drivers/media/platform/toshiba/Kconfig             |   6 +
 drivers/media/platform/toshiba/Makefile            |   3 +
 drivers/media/platform/toshiba/visconti/Kconfig    |  17 +
 drivers/media/platform/toshiba/visconti/Makefile   |   8 +
 .../media/platform/toshiba/visconti/csi2rx_drv.c   | 954 +++++++++++++++++++++
 8 files changed, 991 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c17c7ddba5af..ce973791b367 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25986,6 +25986,7 @@ L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
 F:	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
+F:	drivers/media/platform/toshiba/visconti/
 
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 9287faafdce5..d5265aa16c88 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -87,6 +87,7 @@ source "drivers/media/platform/st/Kconfig"
 source "drivers/media/platform/sunxi/Kconfig"
 source "drivers/media/platform/synopsys/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 6fd7db0541c7..09e67ecb9559 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -30,6 +30,7 @@ obj-y += st/
 obj-y += sunxi/
 obj-y += synopsys/
 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..dd89a9a35704
--- /dev/null
+++ b/drivers/media/platform/toshiba/Makefile
@@ -0,0 +1,3 @@
+# 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..aa0b63f9f008
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/Kconfig
@@ -0,0 +1,17 @@
+# 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..53d112432a86
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2025 TOSHIBA CORPORATION
+ * (C) Copyright 2025 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+#include <linux/seq_file.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_DOUT	 GENMASK(15, 8)
+
+#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_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_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 VISCSI2_ERROR_MONITORS_NUM 8
+
+/**
+ * struct viscsi2_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 viscsi2_line_err_target {
+	u32 vc[VISCSI2_ERROR_MONITORS_NUM];
+	u32 dt[VISCSI2_ERROR_MONITORS_NUM];
+};
+
+#define CSI2RX_MIN_DATA_RATE 80
+#define CSI2RX_MAX_DATA_RATE 1500
+
+#define VISCSI2_PAD_SINK 0
+#define VISCSI2_PAD_SRC	 1
+#define VISCSI2_PAD_NUM	 2
+
+#define VISCSI2_DEF_WIDTH  1920
+#define VISCSI2_DEF_HEIGHT 1080
+#define VISCSI2_MIN_WIDTH  640
+#define VISCSI2_MAX_WIDTH  3840
+#define VISCSI2_MIN_HEIGHT 480
+#define VISCSI2_MAX_HEIGHT 2160
+
+struct viscsi2 {
+	struct device *dev;
+	void __iomem *base;
+
+	struct v4l2_subdev subdev;
+	struct media_pad pads[VISCSI2_PAD_NUM];
+	struct v4l2_async_notifier notifier;
+	struct v4l2_subdev *remote;
+	unsigned int remote_pad;
+
+	unsigned int lanes;
+
+	unsigned int irq;
+	struct clk *clk_apb;
+	struct clk *clk_cfg;
+	struct reset_control *rst;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_dir;
+	u32 debug_phy_fatal;
+	u32 debug_pkt_fatal;
+	u32 debug_frame_fatal;
+	u32 debug_phy;
+	u32 debug_pkt;
+	u32 debug_line;
+#endif
+	bool running;
+};
+
+static inline struct viscsi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct viscsi2, notifier);
+}
+
+static inline struct viscsi2 *sd_to_csi2(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct viscsi2, subdev);
+}
+
+static inline void viscsi2_write(struct viscsi2 *priv, u32 regid, u32 val)
+{
+	writel(val, priv->base + regid);
+}
+
+static inline u32 viscsi2_read(struct viscsi2 *priv, u32 regid)
+{
+	return readl(priv->base + regid);
+}
+
+static void viscsi2_set_dphy_param(struct viscsi2 *priv, u32 val)
+{
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL1, val);
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
+}
+
+static void viscsi2_set_dphy_addr(struct viscsi2 *priv, u32 test_mode)
+{
+	/* Select testcode Ex space with top 4bits of test_mode */
+	viscsi2_set_dphy_param(priv, BIT_TESTCTRL1_ADDR | DIG_TESTCODE_EXT);
+	viscsi2_set_dphy_param(priv, FIELD_GET(0xf00, test_mode));
+	viscsi2_set_dphy_param(priv,
+			       BIT_TESTCTRL1_ADDR | FIELD_GET(0xff, test_mode));
+}
+
+static void dphy_write(struct viscsi2 *priv, u32 test_mode, u8 test_in)
+{
+	viscsi2_set_dphy_addr(priv, test_mode);
+	viscsi2_set_dphy_param(priv, test_in);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static u8 dphy_read(struct viscsi2 *priv, u32 test_mode)
+{
+	u32 read_data;
+
+	viscsi2_set_dphy_addr(priv, test_mode);
+	read_data = viscsi2_read(priv, REG_CSI2RX_PHY_TESTCTRL1);
+	return FIELD_GET(MASK_TESTCTRL1_DOUT, read_data);
+}
+
+static int viscsi2_read_calibration_status(struct viscsi2 *priv, u32 test_mode,
+					   u32 mask_err, u32 mask_done)
+{
+	u32 read_data = (u32)dphy_read(priv, test_mode);
+
+	if (!(read_data & mask_done))
+		return -EAGAIN;
+
+	if (read_data & mask_err)
+		return -EIO;
+
+	return 0;
+}
+
+struct viscsi2_calibration_status_def {
+	const char *name;
+	u32 test_mode;
+	u32 mask_err;
+	u32 mask_done;
+};
+
+static const struct viscsi2_calibration_status_def viscsi2_caldef[] = {
+	{ "term_cal_with_rext", DIG_TERM_CAL_1, MASK_TERM_CAL_ERR,
+	  MASK_TERM_CAL_DONE },
+	{ "clock_lane_offset_cal", DIG_CLKLANE_OFFSET_CAL_0, MASK_CLK_CAL_ERR,
+	  MASK_CLK_CAL_DONE },
+	{ "data_lane0_offset_cal", DIG_LANE0_OFFSET_CAL_0, MASK_CAL_ERR,
+	  MASK_CAL_DONE },
+	{ "data_lane1_offset_cal", DIG_LANE1_OFFSET_CAL_0, MASK_CAL_ERR,
+	  MASK_CAL_DONE },
+	{ "data_lane2_offset_cal", DIG_LANE2_OFFSET_CAL_0, MASK_CAL_ERR,
+	  MASK_CAL_DONE },
+	{ "data_lane3_offset_cal", DIG_LANE3_OFFSET_CAL_0, MASK_CAL_ERR,
+	  MASK_CAL_DONE },
+	{ "data_lane0_ddl_tuning_cal", DIG_LANE0_DDL_0, MASK_DDL_ERR,
+	  MASK_DDL_DONE },
+	{ "data_lane1_ddl_tuning_cal", DIG_LANE1_DDL_0, MASK_DDL_ERR,
+	  MASK_DDL_DONE },
+	{ "data_lane2_ddl_tuning_cal", DIG_LANE2_DDL_0, MASK_DDL_ERR,
+	  MASK_DDL_DONE },
+	{ "data_lane3_ddl_tuning_cal", DIG_LANE3_DDL_0, MASK_DDL_ERR,
+	  MASK_DDL_DONE },
+};
+
+static int viscsi2_debug_calibration_status_show(struct seq_file *m, void *p)
+{
+	struct viscsi2 *priv = m->private;
+	unsigned int i;
+
+	if (!priv->running)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(viscsi2_caldef); i++) {
+		const struct viscsi2_calibration_status_def *cd =
+			&viscsi2_caldef[i];
+
+		seq_printf(m, "%s: %d\n", cd->name,
+			   viscsi2_read_calibration_status(priv, cd->test_mode,
+							   cd->mask_err,
+							   cd->mask_done));
+	}
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(viscsi2_debug_calibration_status);
+
+static int viscsi2_debug_err_status_show(struct seq_file *m, void *p)
+{
+	struct viscsi2 *priv = m->private;
+
+	seq_printf(m, "err_phy_fatal: 0x%08x\n", priv->debug_phy_fatal);
+	seq_printf(m, "err_pkt_fatal: 0x%08x\n", priv->debug_pkt_fatal);
+	seq_printf(m, "err_frame_fatal: 0x%08x\n", priv->debug_frame_fatal);
+	seq_printf(m, "err_phy: 0x%08x\n", priv->debug_phy);
+	seq_printf(m, "err_pkt: 0x%08x\n", priv->debug_pkt);
+	seq_printf(m, "err_line: 0x%08x\n", priv->debug_line);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(viscsi2_debug_err_status);
+
+static void viscsi2_debug_init(struct viscsi2 *csi2)
+{
+	csi2->debugfs_dir = debugfs_create_dir(dev_name(csi2->dev), NULL);
+	if (IS_ERR(csi2->debugfs_dir))
+		return;
+	debugfs_create_file("calibration_status", 0444, csi2->debugfs_dir, csi2,
+			    &viscsi2_debug_calibration_status_fops);
+	debugfs_create_file("err_status", 0444, csi2->debugfs_dir, csi2,
+			    &viscsi2_debug_err_status_fops);
+}
+
+static void viscsi2_debug_cleanup(struct viscsi2 *csi2)
+{
+	debugfs_remove_recursive(csi2->debugfs_dir);
+}
+#endif
+
+#define OSC_FREQ_TARGET 0x1cc
+
+struct viscsi2_dphy_hs_info {
+	u32 rate;
+	u32 hsfreqrange;
+};
+
+static const struct viscsi2_dphy_hs_info dphy_hs_info[] = {
+	{ 80, 0x0 },   { 85, 0x10 },   { 95, 0x20 },   { 105, 0x30 },
+	{ 115, 0x1 },  { 125, 0x11 },  { 135, 0x21 },  { 145, 0x31 },
+	{ 155, 0x2 },  { 165, 0x12 },  { 175, 0x22 },  { 185, 0x32 },
+	{ 198, 0x3 },  { 213, 0x13 },  { 228, 0x23 },  { 243, 0x33 },
+	{ 263, 0x4 },  { 288, 0x14 },  { 313, 0x25 },  { 338, 0x35 },
+	{ 375, 0x5 },  { 425, 0x16 },  { 475, 0x26 },  { 525, 0x37 },
+	{ 575, 0x7 },  { 625, 0x18 },  { 675, 0x28 },  { 725, 0x39 },
+	{ 775, 0x9 },  { 825, 0x19 },  { 875, 0x29 },  { 925, 0x3a },
+	{ 975, 0xa },  { 1025, 0x1a }, { 1075, 0x2a }, { 1125, 0x3b },
+	{ 1175, 0xb }, { 1225, 0x1b }, { 1275, 0x2b }, { 1325, 0x3c },
+	{ 1375, 0xc }, { 1425, 0x1c }, { 1475, 0x2c }
+};
+
+static void get_dphy_hs_transfer_info(u32 dphy_rate, u32 *hsfreqrange)
+{
+	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;
+			return;
+		}
+	}
+
+	/* Not found; return the largest entry */
+	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].hsfreqrange;
+}
+
+static void viscsi2_set_dphy_rate(struct viscsi2 *priv, u32 dphy_rate)
+{
+	u32 hsfreqrange;
+
+	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange);
+
+	dphy_write(priv, DIG_SYS_1, hsfreqrange);
+	dphy_write(priv, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
+	dphy_write(priv, DIG_RX_STARTUP_OVR_5, STARTUP_OVR_5_BYPASS);
+	dphy_write(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL);
+	dphy_write(priv, DIG_CB_2, CB_2_LPRX_BIAS | CB_2_RESERVED);
+	dphy_write(priv, DIG_SYS_7, SYS_7_DESKEW_POL | SYS_7_RESERVED);
+	dphy_write(priv, DIG_CLKLANE_LANE_6, CLKLANE_RXHS_PULL_LONG);
+	dphy_write(priv, DIG_RX_STARTUP_OVR_2,
+		   FIELD_GET(0xff, OSC_FREQ_TARGET));
+	dphy_write(priv, DIG_RX_STARTUP_OVR_3,
+		   FIELD_GET(0xf00, OSC_FREQ_TARGET));
+	dphy_write(priv, DIG_RX_STARTUP_OVR_4,
+		   STARTUP_OVR_4_CNTVAL | STARTUP_OVR_4_DDL_EN);
+}
+
+static int viscsi2_initialize(struct viscsi2 *priv, u32 num_lane, u32 dphy_rate,
+			      const struct viscsi2_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 */
+	viscsi2_write(priv, REG_CSI2RX_RESETN, 1);
+	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
+	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	ndelay(15);
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 0);
+
+	/* Configure D-PHY frequency range */
+	viscsi2_set_dphy_rate(priv, dphy_rate);
+
+	/* 2nd phase of initialization */
+	viscsi2_write(priv, REG_CSI2RX_NLANES, num_lane - 1);
+	ndelay(5);
+
+	/* Release D-PHY from Reset */
+	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
+	ndelay(5);
+	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 1);
+
+	/* Configuration of line error target */
+	val = (err_target->vc[3] << 30) | (err_target->dt[3] << 24) |
+	      (err_target->vc[2] << 22) | (err_target->dt[2] << 16) |
+	      (err_target->vc[1] << 14) | (err_target->dt[1] << 8) |
+	      (err_target->vc[0] << 6) | (err_target->dt[0]);
+	viscsi2_write(priv, REG_CSI2RX_DATA_IDS_1, val);
+	val = (err_target->vc[7] << 30) | (err_target->dt[7] << 24) |
+	      (err_target->vc[6] << 22) | (err_target->dt[6] << 16) |
+	      (err_target->vc[5] << 14) | (err_target->dt[5] << 8) |
+	      (err_target->vc[4] << 6) | (err_target->dt[4]);
+	viscsi2_write(priv, REG_CSI2RX_DATA_IDS_2, val);
+
+	/* Configuration of mask */
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, MASK_PHY_FATAL_ALL);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, MASK_PKT_FATAL_ALL);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL,
+		      MASK_FRAME_FATAL_ALL);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY, MASK_PHY_ERROR_ALL);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT, MASK_PKT_ERROR_ALL);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_LINE, MASK_LINE_ERROR_ALL);
+
+	return 0;
+}
+
+struct viscsi2_format {
+	u32 code;
+	unsigned int bpp;
+};
+
+static const struct viscsi2_format viscsi2_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 viscsi2_format *fmt_for_mbus_code(unsigned int mbus_code)
+{
+	unsigned int i;
+
+	for (i = 0; ARRAY_SIZE(viscsi2_formats); i++) {
+		if (viscsi2_formats[i].code == mbus_code)
+			return &viscsi2_formats[i];
+	}
+	return NULL;
+}
+
+static const struct viscsi2_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 viscsi2_start(struct viscsi2 *priv, struct v4l2_subdev_state *state)
+{
+	const struct v4l2_mbus_framefmt *sink_fmt;
+	const struct viscsi2_format *cur_fmt;
+	struct media_pad *src_pad;
+	int cur_bpp, dphy_rate;
+	s64 link_freq;
+	int ret = 0;
+
+	/* Get bpp for current format */
+	sink_fmt = v4l2_subdev_state_get_format(state, VISCSI2_PAD_SINK);
+	cur_fmt = fmt_for_mbus_code(sink_fmt->code);
+	if (!cur_fmt)
+		return -EINVAL;
+	cur_bpp = cur_fmt->bpp;
+
+	/* Get DPHY rate [unit: Mbps]; note that the signal is DDR */
+	src_pad = &priv->remote->entity.pads[priv->remote_pad];
+	link_freq = v4l2_get_link_freq(src_pad, cur_bpp, 2 * priv->lanes);
+	if (link_freq < 0)
+		return link_freq;
+	dphy_rate = div_s64(link_freq, 500000);
+
+	clk_prepare_enable(priv->clk_apb);
+	clk_prepare_enable(priv->clk_cfg);
+	ndelay(15);
+	reset_control_deassert(priv->rst);
+
+	ret = viscsi2_initialize(priv, priv->lanes, dphy_rate,
+				 &err_target_vc0_alldt);
+
+	if (ret) {
+		reset_control_assert(priv->rst);
+		clk_disable_unprepare(priv->clk_cfg);
+		clk_disable_unprepare(priv->clk_apb);
+		return ret;
+	}
+
+	priv->running = true;
+	return 0;
+}
+
+static void viscsi2_stop(struct viscsi2 *priv)
+{
+	priv->running = false;
+
+	/* Disable interrupt by clearing bits of MSK registers */
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, 0);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, 0);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, 0);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY, 0);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT, 0);
+	viscsi2_write(priv, REG_CSI2RX_INT_MSK_LINE, 0);
+	/* Make sure registers cleared */
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PHY_FATAL);
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PKT_FATAL);
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL);
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PHY);
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PKT);
+	viscsi2_read(priv, REG_CSI2RX_INT_MSK_LINE);
+	/* Wait for current handlers finish */
+	synchronize_irq(priv->irq);
+
+	/* Shutdown hardware */
+	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
+	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
+	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
+	viscsi2_write(priv, REG_CSI2RX_RESETN, 0);
+
+	reset_control_assert(priv->rst);
+	clk_disable_unprepare(priv->clk_cfg);
+	clk_disable_unprepare(priv->clk_apb);
+}
+
+static int viscsi2_enable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state, u32 pad,
+				  u64 streams_mask)
+{
+	struct viscsi2 *priv = sd_to_csi2(sd);
+	int ret;
+
+	/* Enabling: turn on CSI2RX -> turn on sensor */
+	ret = viscsi2_start(priv, state);
+	if (ret)
+		return ret;
+
+	/* Currently CSI2RX supports only stream0 in source pad */
+	ret = v4l2_subdev_enable_streams(priv->remote, priv->remote_pad,
+					 BIT(0));
+	if (ret) {
+		viscsi2_stop(priv);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int viscsi2_disable_streams(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state, u32 pad,
+				   u64 streams_mask)
+{
+	struct viscsi2 *priv = sd_to_csi2(sd);
+
+	/* Disabling: turn off sensor -> turn off CSI2RX */
+	v4l2_subdev_disable_streams(priv->remote, priv->remote_pad, BIT(0));
+	viscsi2_stop(priv);
+
+	return 0;
+}
+
+static int viscsi2_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *sd_state,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == VISCSI2_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,
+							VISCSI2_PAD_SINK);
+		code->code = sink_fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(viscsi2_formats))
+		return -EINVAL;
+	code->code = viscsi2_formats[code->index].code;
+
+	return 0;
+}
+
+static int viscsi2_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *sd_state,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index > 0)
+		return -EINVAL;
+
+	if (!fmt_for_mbus_code(fse->code))
+		return -EINVAL;
+
+	fse->min_width = VISCSI2_MIN_WIDTH;
+	fse->max_width = VISCSI2_MAX_WIDTH;
+	fse->min_height = VISCSI2_MIN_HEIGHT;
+	fse->max_height = VISCSI2_MAX_HEIGHT;
+
+	return 0;
+}
+
+static int viscsi2_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, VISCSI2_PAD_SINK);
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SRC);
+
+	sink_fmt->width = VISCSI2_DEF_WIDTH;
+	sink_fmt->height = VISCSI2_DEF_HEIGHT;
+	sink_fmt->field = V4L2_FIELD_NONE;
+	sink_fmt->code = viscsi2_formats[0].code;
+	sink_fmt->colorspace = V4L2_COLORSPACE_RAW;
+	sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+	sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+	sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static int viscsi2_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 == VISCSI2_PAD_SRC)
+		return v4l2_subdev_get_fmt(sd, sd_state, fmt);
+
+	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SINK);
+
+	*sink_fmt = fmt->format;
+	sink_fmt->width = clamp_t(u32, fmt->format.width, VISCSI2_MIN_WIDTH,
+				  VISCSI2_MAX_WIDTH);
+	sink_fmt->height = clamp_t(u32, fmt->format.height, VISCSI2_MIN_HEIGHT,
+				   VISCSI2_MAX_HEIGHT);
+	if (!fmt_for_mbus_code(sink_fmt->code))
+		sink_fmt->code = viscsi2_formats[0].code;
+	fmt->format = *sink_fmt;
+
+	/* Source pad should have the same format */
+	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SRC);
+	*src_fmt = *sink_fmt;
+
+	return 0;
+}
+
+static const struct media_entity_operations viscsi2_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_pad_ops viscsi2_pad_ops = {
+	.enum_mbus_code = viscsi2_enum_mbus_code,
+	.enum_frame_size = viscsi2_enum_frame_size,
+	.disable_streams = viscsi2_disable_streams,
+	.enable_streams = viscsi2_enable_streams,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = viscsi2_set_pad_format,
+};
+
+static const struct v4l2_subdev_ops viscsi2_subdev_ops = {
+	.pad = &viscsi2_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops viscsi2_internal_ops = {
+	.init_state = viscsi2_init_state,
+};
+
+static int viscsi2_notify_bound(struct v4l2_async_notifier *notifier,
+				struct v4l2_subdev *subdev,
+				struct v4l2_async_connection *asc)
+{
+	struct viscsi2 *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 | MEDIA_LNK_FL_IMMUTABLE);
+}
+
+static void viscsi2_notify_unbind(struct v4l2_async_notifier *notifier,
+				  struct v4l2_subdev *subdev,
+				  struct v4l2_async_connection *asc)
+{
+	struct viscsi2 *priv = notifier_to_csi2(notifier);
+
+	priv->remote = NULL;
+}
+
+static const struct v4l2_async_notifier_operations viscsi2_notify_ops = {
+	.bound = viscsi2_notify_bound,
+	.unbind = viscsi2_notify_unbind,
+};
+
+static int viscsi2_parse_dt(struct viscsi2 *priv)
+{
+	struct v4l2_async_connection *asc;
+	struct fwnode_handle *fwnode;
+	struct fwnode_handle *ep;
+	struct v4l2_fwnode_endpoint v4l2_ep = {
+		.bus_type = V4L2_MBUS_CSI2_DPHY,
+	};
+	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");
+		goto error_fwnode_handle_put;
+	}
+
+	priv->lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
+	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);
+		goto error_fwnode_handle_put;
+	}
+
+	fwnode = fwnode_graph_get_remote_endpoint(ep);
+	fwnode_handle_put(ep);
+
+	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
+	priv->notifier.ops = &viscsi2_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;
+
+error_fwnode_handle_put:
+	fwnode_handle_put(ep);
+	return -EINVAL;
+}
+
+static irqreturn_t viscsi2_irq(int irq, void *dev_id)
+{
+	struct viscsi2 *priv = dev_id;
+	u32 event;
+
+	event = viscsi2_read(priv, REG_CSI2RX_INT_ST_MAIN);
+	dev_err_ratelimited(priv->dev, "CSI2RX error 0x%x.\n", event);
+
+#ifdef CONFIG_DEBUG_FS
+	priv->debug_phy_fatal |=
+		viscsi2_read(priv, REG_CSI2RX_INT_ST_PHY_FATAL);
+	priv->debug_pkt_fatal |=
+		viscsi2_read(priv, REG_CSI2RX_INT_ST_PKT_FATAL);
+	priv->debug_frame_fatal |=
+		viscsi2_read(priv, REG_CSI2RX_INT_ST_FRAME_FATAL);
+	priv->debug_phy |= viscsi2_read(priv, REG_CSI2RX_INT_ST_PHY);
+	priv->debug_pkt |= viscsi2_read(priv, REG_CSI2RX_INT_ST_PKT);
+	priv->debug_line |= viscsi2_read(priv, REG_CSI2RX_INT_ST_LINE);
+#endif
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id viscsi2_of_table[] = {
+	{
+		.compatible = "toshiba,visconti5-csi2",
+	},
+	{ /* Sentinel */ }
+};
+
+static int viscsi2_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct viscsi2 *priv;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->running = false;
+
+	priv->dev = dev;
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+	ret = devm_request_irq(dev, irq, viscsi2_irq, 0, KBUILD_MODNAME, priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "irq request failed");
+
+	priv->irq = irq;
+
+	priv->clk_cfg = devm_clk_get(dev, "cfg");
+	if (IS_ERR(priv->clk_cfg))
+		return dev_err_probe(dev, PTR_ERR(priv->clk_cfg),
+				     "cannot get clock cfg");
+	priv->clk_apb = devm_clk_get(dev, "apb");
+	if (IS_ERR(priv->clk_apb))
+		return dev_err_probe(dev, PTR_ERR(priv->clk_apb),
+				     "cannot get clock apb");
+	priv->rst = devm_reset_control_get_exclusive_by_index(dev, 0);
+	if (IS_ERR(priv->rst))
+		return dev_err_probe(dev, PTR_ERR(priv->rst),
+				     "cannot get reset");
+
+	platform_set_drvdata(pdev, priv);
+
+	ret = viscsi2_parse_dt(priv);
+	if (ret)
+		return ret;
+
+	priv->subdev.dev = &pdev->dev;
+	v4l2_subdev_init(&priv->subdev, &viscsi2_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 = &viscsi2_internal_ops;
+	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	priv->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	priv->subdev.entity.ops = &viscsi2_entity_ops;
+
+	priv->pads[VISCSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	priv->pads[VISCSI2_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+
+	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;
+
+#ifdef CONFIG_DEBUG_FS
+	viscsi2_debug_init(priv);
+#endif
+
+	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 viscsi2_remove(struct platform_device *pdev)
+{
+	struct viscsi2 *priv = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_DEBUG_FS
+	viscsi2_debug_cleanup(priv);
+#endif
+
+	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 viscsi2_driver = {
+	.probe = viscsi2_probe,
+	.remove = viscsi2_remove,
+	.driver = {
+		.name = "visconti-csi2rx",
+		.of_match_table = viscsi2_of_table,
+	},
+};
+
+module_platform_driver(viscsi2_driver);
+
+MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
+MODULE_DESCRIPTION("Toshiba Visconti CSI-2 receiver driver");
+MODULE_LICENSE("Dual BSD/GPL");

-- 
2.34.1




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

* [PATCH v13 6/7] media: platform: visconti: Add streaming interface for ISP parameters and statistics
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (3 preceding siblings ...)
  2025-10-16  2:24 ` [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  2025-10-16  2:24 ` [PATCH v13 7/7] documentation: media: Add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa
  5 siblings, 0 replies; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

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

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

Changelog v13:
- wrap one line at 80 characters
- change banner comment style
- update comment style; spacing at the start and end, capitalize first letter
- remove redundant inline qualifier
- remove unused constants
- use system clock rate obtained from the framework, instead of constant value
- remove U suffix on numeric value
- remove members indicating status; they are moved to debugfs
- remove unused members from statistics interface
- fix v4l-compliance fail: v4l2-test-buffers.cpp(924): q.create_bufs(node, 1, &fmt) != EINVAL
- use ffs() instead of gen_grid_size()
- change signature of viif_apply_queued_parameter; int -> bool
- use ARRAY_SIZE macros for maximum loop iterations
- use scoped_guard() to acquire a lock
- use list_for_each_entry_safe() to modify list
- shorten the names of ISP guard functions.
---
 drivers/media/platform/toshiba/visconti/Makefile   |    2 +-
 drivers/media/platform/toshiba/visconti/viif.c     |   27 +-
 drivers/media/platform/toshiba/visconti/viif_isp.c |    5 +
 .../media/platform/toshiba/visconti/viif_params.c  | 2257 ++++++++++++++++++++
 .../media/platform/toshiba/visconti/viif_params.h  |   20 +
 .../media/platform/toshiba/visconti/viif_stats.c   |  320 +++
 .../media/platform/toshiba/visconti/viif_stats.h   |   16 +
 7 files changed, 2644 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
index e9fe874d6447..da493e21532d 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
+visconti-viif-objs = viif.o viif_capture.o viif_common.o viif_isp.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 16e8f108d996..04b4e3295645 100644
--- a/drivers/media/platform/toshiba/visconti/viif.c
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -24,7 +24,9 @@
 #include "viif_capture.h"
 #include "viif_common.h"
 #include "viif_isp.h"
+#include "viif_params.h"
 #include "viif_regs.h"
+#include "viif_stats.h"
 
 /*----------------------------------------------
  * Register Access
@@ -144,6 +146,9 @@ static irqreturn_t viif_vsync_irq_handler(int irq, void *dev_id)
 		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 */
@@ -533,13 +538,25 @@ static int visconti_viif_probe(struct platform_device *pdev)
 		goto error_isp_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;
 
 	ret = visconti_viif_subdev_notifier_register(viif_dev);
 	if (ret)
-		goto error_capture_unregister;
+		goto error_stats_unregister;
 
 #ifdef CONFIG_DEBUG_FS
 	viif_debug_init(viif_dev);
@@ -547,6 +564,10 @@ static int visconti_viif_probe(struct platform_device *pdev)
 
 	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_isp_unregister:
@@ -576,6 +597,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_isp_unregister(viif_dev);
 	media_device_unregister(&viif_dev->media_dev);
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
index 6ad4723a37cc..db00db79ab06 100644
--- a/drivers/media/platform/toshiba/visconti/viif_isp.c
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -15,6 +15,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() */
@@ -559,6 +560,9 @@ int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev)
 	/* Enable regbuf */
 	visconti_viif_isp_set_regbuf_auto_transmission(viif_dev);
 
+	/* L2 Undist: enable through mode as default */
+	visconti_viif_l2_undist_through(viif_dev);
+
 	return 0;
 }
 
@@ -612,6 +616,7 @@ static int visconti_viif_isp_enable_streams(struct v4l2_subdev *sd,
 	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..047ac5e74814
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.c
@@ -0,0 +1,2257 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2025 TOSHIBA CORPORATION
+ * (C) Copyright 2025 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_capture.h"
+#include "viif_common.h"
+#include "viif_isp.h"
+#include "viif_params.h"
+#include "viif_regs.h"
+
+/* ISP_L1_SET_HDRC */
+#define VIIF_L1_HDRC_RATIO_OFFSET 10
+#define VIIF_REGBUF_ACCESS_TIME	  15360
+#define VIIF_L1_DELAY_W_HDRC	  31
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST */
+#define VIIF_L2_UNDIST_POLY_NUM 11
+
+#define VIIF_PARAMS_REQ_BUFS_MIN 2
+#define VIIF_PARAMS_REQ_BUFS_MAX 8
+
+/*----------------------------------------------
+ * ISP parameter configuration
+ */
+static void viif_l1_set_input_mode(struct viif_device *viif_dev,
+				   const struct viif_l1_input_mode_config *arg)
+{
+	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)
+{
+	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;
+
+	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;
+
+	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)
+{
+	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 = 0;
+
+	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, table_m = 0, table_l = 0;
+	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);
+	}
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(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);
+}
+
+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 = 0;
+
+	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);
+}
+
+#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, table_gb = 0, table_r = 0, table_b = 0;
+	u32 val;
+
+	if (!arg->enable) {
+		guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+		guard(viif_isp)(viif_dev);
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_EN, 0);
+
+		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);
+	}
+
+	guard(spinlock_irqsave)(&viif_dev->regbuf_lock);
+	guard(viif_isp)(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 < ARRAY_SIZE(params); 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;
+
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 1);
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_SIZE,
+				   ffs(grid_param->lssc_grid_h_size));
+		viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_SIZE,
+				   ffs(grid_param->lssc_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 << 16) |
+	      (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 << 16) |
+	      (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 << 16) |
+	      (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 << 16) |
+	      (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);
+}
+
+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 == 64)
+		ygate_data = 0;
+	else if (param->awhb_ygate_data == 128)
+		ygate_data = 1;
+	else if (param->awhb_ygate_data == 256)
+		ygate_data = 2;
+	else
+		ygate_data = 3;
+
+	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, unsigned long sys_rate,
+			      const struct viif_img_clk *img_clk)
+{
+	u64 v1 = (u64)time_in_sysclk * img_clk->pixel_clock;
+	u64 v2 = (u64)img_clk->htotal_size * sys_rate;
+
+	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)) % 64) / 2;
+	viif_capture_write(viif_dev, REG_L1_HDRC_MAR_TOP, val);
+	val = ((viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH)) % 64) / 2;
+	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->clkrate,
+					       &viif_dev->img_clk) +
+			    VIIF_L1_DELAY_W_HDRC + 1;
+		val = viif_capture_read(viif_dev, REG_INT_M1_LINE) & 0xffffU;
+		val |= (sw_delay1 << 16);
+		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 != 128) {
+		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 {
+		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 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] << 2) |
+	       (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 = 0;
+
+	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] << 1) | (param->roi_mode[1] << 3);
+	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);
+}
+
+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] << 13) |
+		      roi->corrected_hsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_HSIZE(i),
+				   val);
+		val = (roi->corrected_wo_scale_vsize[i] << 12) |
+		      roi->corrected_vsize[i];
+		viif_capture_write(viif_dev, REG_L2_ROI_X_CORRECTED_VSIZE(i),
+				   val);
+	}
+}
+
+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 = 0;
+	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 << 16) | (l2_gamma->mode << 4) |
+	      (table_en != 0 ? 1 : 0);
+	viif_capture_write(viif_dev, REG_L2_POST_X_GAMMA_M(postid), val);
+}
+
+static void viif_l2_set_crop(struct viif_device *viif_dev, int pathid,
+			     const struct viif_l2_crop_config *l2_crop)
+{
+	struct cap_dev *cap_dev = (pathid == CAPTURE_PATH_MAIN_POST0) ?
+					  &viif_dev->cap_post0 :
+					  &viif_dev->cap_post1;
+
+	cap_dev->img_area.left = l2_crop->left;
+	cap_dev->img_area.top = l2_crop->top;
+}
+
+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_undist_config defval_l2_set_undist = {
+	.param = {
+		.through_mode = 1,
+		.roi_mode = {0, 0},
+		.grid_node_num_h = 0x10,
+		.grid_node_num_v = 0x10,
+	},
+};
+
+static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
+
+static const struct viif_l2_crop_config defval_l2_set_crop = { 0, 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);
+	viif_l2_set_undist(viif_dev, &defval_l2_set_undist);
+	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);
+	viif_l2_set_crop(viif_dev, CAPTURE_PATH_MAIN_POST0,
+			 &defval_l2_set_crop);
+	viif_l2_set_crop(viif_dev, CAPTURE_PATH_MAIN_POST1,
+			 &defval_l2_set_crop);
+}
+
+/*----------------------------------------------
+ * 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 bool 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 false;
+
+	/* 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);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_CROP_POST0)
+		viif_l2_set_crop(viif_dev, CAPTURE_PATH_MAIN_POST0,
+				 &new_params->l2_crop_post0);
+	if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_CROP_POST1)
+		viif_l2_set_crop(viif_dev, CAPTURE_PATH_MAIN_POST1,
+				 &new_params->l2_crop_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 true;
+}
+
+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[])
+{
+	if (*num_planes) {
+		if (*num_planes != 1)
+			return -EINVAL;
+		if (sizes[0] < sizeof(struct visconti_viif_isp_config))
+			return -EINVAL;
+	} else {
+		*num_planes = 1;
+		*num_buffers = clamp_t(u32, *num_buffers,
+				       VIIF_PARAMS_REQ_BUFS_MIN,
+				       VIIF_PARAMS_REQ_BUFS_MAX);
+		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);
+
+	scoped_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..a244459b6530
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2025 TOSHIBA CORPORATION
+ * (C) Copyright 2025 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);
+#endif /* __VIIF_PARAMS_H__ */
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..da20824e64a5
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2025 TOSHIBA CORPORATION
+ * (C) Copyright 2025 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"
+
+#define VIIF_STATS_REQ_BUFS_MIN 2
+#define VIIF_STATS_REQ_BUFS_MAX 8
+
+struct viif_buffer {
+	struct vb2_v4l2_buffer vb;
+	struct list_head queue;
+};
+
+static void viif_stats_read_isp_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);
+
+	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);
+
+	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);
+
+	viif_stats_read_isp_regs(&cur_stat_buf->isp_capture.l1_info, viif_dev);
+	cur_stat_buf->stat_type |= VISCONTI_VIIF_STAT_L1_INFO;
+
+	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[])
+{
+	if (*num_planes) {
+		if (*num_planes != 1)
+			return -EINVAL;
+		if (sizes[0] < sizeof(struct visconti_viif_isp_stat))
+			return -EINVAL;
+	} else {
+		*num_planes = 1;
+		*num_buffers = clamp_t(u32, *num_buffers,
+				       VIIF_STATS_REQ_BUFS_MIN,
+				       VIIF_STATS_REQ_BUFS_MAX);
+		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, *tmp;
+
+	guard(spinlock_irq)(&stats_dev->stats_lock);
+
+	list_for_each_entry_safe(buf, tmp, &stats_dev->stats_queue, 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..ca83d45e3b39
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2025 TOSHIBA CORPORATION
+ * (C) Copyright 2025 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.34.1




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

* [PATCH v13 7/7] documentation: media: Add documentation for Toshiba Visconti Video Input Interface driver
  2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
                   ` (4 preceding siblings ...)
  2025-10-16  2:24 ` [PATCH v13 6/7] media: platform: visconti: Add streaming interface for ISP parameters and statistics Yuji Ishikawa
@ 2025-10-16  2:24 ` Yuji Ishikawa
  5 siblings, 0 replies; 15+ messages in thread
From: Yuji Ishikawa @ 2025-10-16  2:24 UTC (permalink / raw)
  To: Nobuhiro Iwamatsu, Yuji Ishikawa, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

Add 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

Changelog v13:
- wrap one line at 80 characters
- add entries to MAINTAINERS flle
- update media subdevice diagram to remove resizer subdevices
- Clarify whether it is a line break around the 80-character mark or a paragraph transition.
- add detailed description for SLIC module.
- update description of HDRC: use of term "global and local tone mapping"
- update description of AWHB: algorithm of whitebalance is handled by hardware only
- what a keyword "AG" mean?: analog gain (general term for image sensors) / algorithm gain (VIIF specific term)
- PWL image have 14bit depth
- update illustration of preprocessing; most of the modules handle 12bit intermediate images
- update illustration of L2ISP
- add output format UYVY
- fix references to struct viif_l2_undist_config and viif_l2_roi_config
- add description of scaling and cropping
- add reference to viif_l2_crop_config
- update Capturing example
- add description of debugfs
---
 Documentation/admin-guide/media/v4l-drivers.rst    |   1 +
 Documentation/admin-guide/media/visconti-viif.dot  |  18 +
 Documentation/admin-guide/media/visconti-viif.rst  | 540 +++++++++++++++++++++
 .../userspace-api/media/v4l/meta-formats.rst       |   1 +
 .../media/v4l/metafmt-visconti-viif.rst            |  48 ++
 MAINTAINERS                                        |   2 +
 6 files changed, 610 insertions(+)

diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
index 3bac5165b134..b6b0b22a12a6 100644
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -33,5 +33,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..fb74c350b50d
--- /dev/null
+++ b/Documentation/admin-guide/media/visconti-viif.dot
@@ -0,0 +1,18 @@
+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
+        n00000001:port2 -> n0000000c
+        n00000001:port3 -> n00000010
+        n00000001:port5 -> n00000018
+        n00000008 [label="viif_capture_post0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+        n0000000c [label="viif_capture_post1\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
+        n00000010 [label="viif_capture_sub\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
+        n00000014 [label="viif_params\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
+        n00000014 -> n00000001:port4
+        n00000018 [label="viif_stats\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
+        n00000026 [label="{{<port0> 0} | visconti_csi2rx 1c008000.csi2rx\n/dev/v4l-subdev1 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+        n00000026:port1 -> n00000001:port0
+        n0000002b [label="{{} | imx219 1-0010\n/dev/v4l-subdev2 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
+        n0000002b:port0 -> n00000026:port0 [style=bold]
+}
diff --git a/Documentation/admin-guide/media/visconti-viif.rst b/Documentation/admin-guide/media/visconti-viif.rst
new file mode 100644
index 000000000000..fbe177b0709a
--- /dev/null
+++ b/Documentation/admin-guide/media/visconti-viif.rst
@@ -0,0 +1,540 @@
+.. 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_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 a
+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 statistics computed by the ISP are passed to userland via viif_stats node.
+
+L1 ISP provides following operations:
+
+- Input: accepts 8, 10, 12, 14bit bayer format
+    - Operation selector; see :c:type:`viif_l1_input_mode_config`
+        - HDR image / PWL (Piecewise 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
+        - see :c:type:`viif_l1_img_extraction_config`
+        - From a 24-bit input image, up to three 12-bit images with different
+          sensitivities (high, middle, low) are generated. Each preprocessing
+          operation is performed on the generated images. In preprocess,
+          parameters with the modifiers h, m, and l are used respectively.
+        - This driver does not skip SLIC operation. As a result, it does not
+          support DOL-HDR, in which multiple 12-bit images are directly
+          acquired from the sensor for preprocessing.
+    - 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`
+        - A 24-bit image is generated from the preprocessed 12-bit images.
+- 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 (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`
+        - The gain for the R and B components is adjusted so that the average U
+          and V components of the image become zero. This process is handled by
+          hardware and does not require feedback from external software.
+    - 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: algorithm 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 |--->|     |    +------------+    |     |
+  | 14bPWL |    |      |    |     |--->| preprocess |--->|     |
+  +--------+    +------+    +-----+    +------------+    +-----+
+
+  L1ISP::INPUT::preprocess
+
+  +-----+                +-----+
+  | 24b |    +------+    | 12b |
+  | RAW |--->| SLIC |--->| RAW |---+
+  | (0) |    +------+    |  x3 |   |
+  +-----+                +-----+   |
+                                   |
+     +-----------------------------+
+     |
+     |                                        +-----+                +-----+
+     |    +------+    +------+    +------+    | 12b |    +------+    | 24b |
+     +--->| ABPC |--->| PWHB |--->| RCNR |--->| RAW |--->| HDRS |--->| RAW |
+          +------+    +------+    +------+    |  x3 |    +------+    | (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::AlgorithmGain
+
+  statistics                     +----------------+    +------------------+
+  information ---> (user SW) --->| Algorithm 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_config`
+    - Scaling; see :c:type:`viif_l2_roi_config`
+    - Cropping; see :c:type:`viif_l2_roi_config`, :c:type:`viif_l2_crop_config`
+    - Gamma correction; see :c:type:`viif_l2_gamma_config`
+    - YUV2RGB
+- Output: RGB, YUV422, YUV444
+
+Below is the block diagram::
+
+  L2ISP
+
+  +-------+    +------------+    +--------------+
+  | Input |--->| YUV2RGB    |--->| Lens         |---+
+  | Image |    | Conversion |    | Undistortion |   |
+  +-------+    +------------+    +--------------+   |
+                                                    |
+  +-------------------------------------------------+
+  |
+  |    +---------+    +------------+    +------------+    +--------+    +--------+
+  +--->| Scaling |--->| Gamma      |--->| Colorspace |--->| Data   |--->| Output |
+  |    |         |    | Correction |    | Conversion |    | Packer |    | Image  |
+  |    +---------+    +------------+    +------------+    +--------+    +--------+
+  |
+  |    +---------+    +------------+    +------------+    +--------+    +--------+
+  +--->| Scaling |--->| Gamma      |--->| Colorspace |--->| Data   |--->| Output |
+       |         |    | Correction |    | Conversion |    | Packer |    | Image  |
+       +---------+    +------------+    +------------+    +--------+    +--------+
+
+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_ABGR32
+- V4L2_PIX_FMT_RGB24
+- V4L2_PIX_FMT_UYVY
+- V4L2_PIX_FMT_Y16
+- V4L2_PIX_FMT_YUV422M
+- V4L2_PIX_FMT_YUV444M
+
+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 statistics computed by the ISP.
+
+Following information is included:
+
+* statistics of auto white balance
+* average luminance information which can be used by auto exposure software
+  implementation.
+
+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.
+
+AG (algorithm gain) is a mechanism that synchronously adjusts the processing
+strength across multiple functional blocks. For specific usage details please
+refer to :c:type:`viif_l1_ag_mode_config`. The following is the list of
+functions affected by AG parameters.
+
+- ABPC/DPC
+- RCNR
+- LSSC
+- MPRO: color matrix correction
+- VPRO
+
+Scaling and cropping
+====================
+
+The L2 ISP provides an image transformation operation that integrates
+undistortion and scaling. Therefore, scaling and cropping cannot be represented
+using the COMPOSE and CROP rectangles commonly used in V4L2.
+
+This driver represents scaling and cropping using the following method.
+
+- Scaling is configured using :c:type:`viif_l2_roi_config`.
+    - The scaling ratio can be specified within the range of 0.5 to 2.0.
+    - The aspect ratio cannot be changed.
+    - In :c:type:`viif_l2_roi_config`, it is necessary to properly specify the
+      boundaries used in coordinate calculations for scaling and undistortion.
+    - The final image size is specified by corrected_hsize and corrected_vsize.
+- Cropping is configured using following information.
+    - The source image size for cropping is corrected_hsize and corrected_vsize.
+    - The top-left coordinate is set using :c:type:`viif_l2_crop_config`.
+    - The cropped size is specified by the format size of the corresponding ISP
+      source pad.
+
+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:
+
+- main path 0: 1920x1080, RGB picture
+- main path 1: 640x480, UYVY picture, cropping (0, 0, 640, 480)
+- sub path: 1920x1080 RAW picture
+
+.. code-block:: bash
+
+	# set the links
+	media-ctl -d platform:1c000000.viif -r
+	media-ctl -d platform:1c000000.viif -l '"imx219 1-0010":0 -> "visconti_csi2rx 1c008000.csi2rx":0 [1]'
+	media-ctl -d platform:1c000000.viif -l '"visconti_csi2rx 1c008000.csi2rx":1 -> "visconti-viif:isp":0 [1]'
+	media-ctl -d platform:1c000000.viif -l '"visconti-viif:isp":1 -> "viif_capture_post0":0 [1]'
+	media-ctl -d platform:1c000000.viif -l '"visconti-viif:isp":2 -> "viif_capture_post1":0 [1]'
+	media-ctl -d platform:1c000000.viif -l '"visconti-viif:isp":3 -> "viif_capture_sub":0 [1]'
+	media-ctl -d platform:1c000000.viif -l '"viif_params":0 -> "visconti-viif:isp":4 [1]'
+	media-ctl -d platform:1c000000.viif -l '"visconti-viif:isp":5 -> "viif_stats":0 [1]'
+
+	# set format for imx219
+	media-ctl -d platform:1c000000.viif --set-v4l2 '"imx219 1-0010":0 [fmt:SRGGB10_1X10/1920x1080]'
+
+	# set format for csi2rx
+	media-ctl -d platform:1c000000.viif --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
+	media-ctl -d platform:1c000000.viif --set-v4l2 '"visconti-viif:isp":0 [fmt:SRGGB10_1X10/1920x1080]'
+	media-ctl -d platform:1c000000.viif --set-v4l2 '"visconti-viif:isp":1 [fmt:fmt:YUV8_1X24/1920x1080]'
+	media-ctl -d platform:1c000000.viif --set-v4l2 '"visconti-viif:isp":2 [fmt:fmt:YUV8_1X24/640x480]'
+
+	# set format for main path0
+	v4l2-ctl -z platform:1c000000.viif -d viif_capture_post0 -v "width=1920,height=1080"
+	v4l2-ctl -z platform:1c000000.viif -d viif_capture_post0 -v "pixelformat=RGB3"
+
+	# set format for main path1
+	v4l2-ctl -z platform:1c000000.viif -d viif_capture_post1 -v "width=640,height=480"
+	v4l2-ctl -z platform:1c000000.viif -d viif_capture_post1 -v "pixelformat=UYVY"
+
+	# 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
+
+Debug filesystem
+================
+
+Some status information of CSI2 receiver and VIIF can be obtained via debugfs.
+The driver exposes following files.
+
+- /sys/kernel/debug/<device-name-for-csi2rx>/calibration_status
+    - This file contains some key-value pairs representing status of
+      calibration.
+    - Value can be either of DONE(=0), ERROR(=-11) or DONE(=-5).
+    - Keys are:
+        - 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
+- /sys/kernel/debug/<device-name-for-csi2rx>/err_status
+    - This file contains some key-value pairs representing CSI2 receiver
+      errors.
+    - Each bit of values indicates a specific error status
+    - Keys are:
+        - err_phy_fatal: D-PHY FATAL error.
+            - bit 0-3: Start of transmission error on DATA lane 0-3
+        - err_pkt_fatal: Packet FATAL error.
+            - bit 16: Header ECC contains 2 errors, unrecoverable.
+            - bit 0-3: Checksum error detected on virtual channel 0-3
+        - err_frame_fatal: Frame FATAL error.
+            - bit 16-19:
+              Last received Frame, in virtual channel 0-3, has at least one CRC
+              error.
+            - bit 8-11:
+              Incorrect Frame Sequence detected in virtual channel 0-3.
+            - bit 0-3:
+              Error matching Frame Start with Frame End for virtual channel 0-3.
+        - err_phy: D-PHY error.
+            - bit 16-19: Escape Entry Error on Data Lane 0-3.
+            - bit 0-3:
+              Start of Transmission Error on Data Lane 3 (synchronization can
+              still be achieved).
+        - err_pkt: Packet error.
+            - bit 16-19:
+              Header Error detected and corrected on virtual channel 0-3.
+            - bit 0-3:
+              Unrecognized or unimplemented data type detected in virtual
+              channel 0-3.
+        - err_line: Line error.
+            - bit 16-23: Error in the sequence of lines for vc0-7 and dt0-7.
+            - bit 0-7:
+              Error matching Line Start with Line End for vc0-7 and dt0-7.
+- /sys/kernel/debug/<device-name-for-viif>/reported_err_main
+    - This file contains integer value representing errors occurred in
+      viif_capture_post0 and viif_capture_post1.
+    - Each bit of the value indicates a specific error status
+        - 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
+- /sys/kernel/debug/<device-name-for-viif>/reported_err_sub
+    - This file contains integer value representing errors occurred in
+      viif_capture_sub.
+    - Each bit of the value indicates a specific error status
+        - bit 24: Vsync generator error
+        - bit  0: data transfer error
+
+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 0de80328c36b..b4ff1a7f403d 100644
--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
+++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
@@ -21,6 +21,7 @@ These formats are used for the :ref:`metadata` interface only.
     metafmt-rkisp1
     metafmt-uvc
     metafmt-uvc-msxu-1-5
+    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
diff --git a/MAINTAINERS b/MAINTAINERS
index cdd04f9a4459..f2475f07059f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25984,8 +25984,10 @@ M:	Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
 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-csi2.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
 

-- 
2.34.1




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

* Re: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
@ 2025-10-16  4:34   ` Frank Li
  2025-10-20  6:11     ` yuji2.ishikawa
  2025-10-16  6:38   ` Krzysztof Kozlowski
  1 sibling, 1 reply; 15+ messages in thread
From: Frank Li @ 2025-10-16  4:34 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Nobuhiro Iwamatsu, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, linux-media,
	devicetree, linux-arm-kernel, linux-kernel

On Thu, Oct 16, 2025 at 11:24:38AM +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>
> ---
> Changelog v12:
> - Newly add bindings for CSI2RX driver
>
> Changelog v13:
> - add entries to MAINTAINERS file.
> - update email address of Nobuhiro Iwamatsu in /maintainers
> - add Yuji Ishikawa to /maintainers
> - change /properties/compatible: toshiba,visconti5-csi2rx -> toshiba,visconti5-csi2
> - change bindings file name: toshiba,visconti5-csi2rx -> toshiba,visconti5-csi2
> - change node name in sample DTS: csi2rx -> csi
> - remove "|-" from /description
> - update /description
> - add definitions of clock and reset
> - update /properties/ports/properties/port@0/description for better comment
> - update /properties/ports/properties/port@0/$ref to specify full pathname
> - remove /properties/ports/properties/port@0/properties/endpoint/properties/data-lanes/description because the default text provides enough information.
> - update sample dts
> ---
>  .../bindings/media/toshiba,visconti5-csi2.yaml     | 125 +++++++++++++++++++++
>  MAINTAINERS                                        |   7 ++
>  2 files changed, 132 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
> new file mode 100644
> index 000000000000..21fb46de5b6e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
> @@ -0,0 +1,125 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> +
> +maintainers:
> +  - Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
> +  - Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> +
> +description:
> +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI CSI-2 video
> +  stream. The obtained video stream is used as input for the Visconti5 VIIF.
> +
> +properties:
> +  compatible:
> +    const: toshiba,visconti5-csi2
> +

...

> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/toshiba,tmpv770x.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        csi0: csi@1c008000 {

Needn't label csi0

> +            compatible = "toshiba,visconti5-csi2";
> +            reg = <0 0x1c008000 0 0x400>;
> +            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
> +            clocks = <&pismu TMPV770X_CLK_VIIFBS0_CFG>,
> +                     <&pismu TMPV770X_CLK_VIIFBS0_APB>;
> +            clock-names = "cfg", "apb";
> +            resets = <&pismu TMPV770X_RESET_VIIFBS0_APB>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;

need empty line here.
> +                port@0 {
> +                    reg = <0>;

empty line here

> +                    csi0_in: endpoint {
> +                        data-lanes = <1 2>;
> +                        remote-endpoint = <&imx219_out>;
> +                    };
> +                };

empty line here

Frank
> +                port@1 {
> +                    reg = <1>;
> +                    csi0_out: endpoint {
> +                        remote-endpoint = <&video0_in>;
> +                    };
> +                };
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 46126ce2f968..e4634a0aad74 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25979,6 +25979,13 @@ F:	Documentation/devicetree/bindings/media/i2c/toshiba,tc358743.txt
>  F:	drivers/media/i2c/tc358743*
>  F:	include/media/i2c/tc358743.h
>
> +TOSHIBA VISCONTI VIIF DRIVER
> +M:	Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
> +M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> +L:	linux-media@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
> +
>  TOSHIBA WMI HOTKEYS DRIVER
>  M:	Azael Avalos <coproscefalo@gmail.com>
>  L:	platform-driver-x86@vger.kernel.org
>
> --
> 2.34.1
>
>


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

* Re: [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2025-10-16  2:24 ` [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
@ 2025-10-16  4:45   ` Frank Li
  2025-10-20  6:13     ` yuji2.ishikawa
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Li @ 2025-10-16  4:45 UTC (permalink / raw)
  To: Yuji Ishikawa
  Cc: Nobuhiro Iwamatsu, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, linux-media,
	devicetree, linux-arm-kernel, linux-kernel

On Thu, Oct 16, 2025 at 11:24:41AM +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
>
> Changelog v13:
> - wrap one line at 80 characters
> - change banner comment style
> - update comment style; spacing at the start and end, capitalize first letter
> - add support for clock and reset framework
> - add debugfs to pass debug and status information
> - add entries to MAINTAINERS file
> - Kconfig: add a blank line just after License Identifier.
> - update references to header files
> - remove redundant inline qualifier
> - shorten function/variable names: visconti_csi2rx -> viscsi2
> - simplify dphy_write and dphy read operations
> - remove osc_freq_target from struct csi2rx_dphy_hs_info, which is always the same value.
> - add comment about MASK register's behavior (reversed polarity)
> - use v4l2_get_link_freq() instead of get_pixelclock()
> - set driver name according to module name: visconti_csi2rx_dev -> visconti-csi2rx
> - check error before setting priv->irq in probe()
> - check error at fmt_for_mbus_code()
> - add callback for ioctl(VIDIOC_ENUM_FRAMESIZES)
> - improve viscsi2_parse_dt() by assuming bus_type is CSI2_DPHY
> - use dev_err_ratelimited() for irq handler
> - bugfix on fmt_for_mbus_code(): in case unsupported mbus_code is given
> - add goto based error handling sequence to viscsi2_parse_dt()
> - specify default value of colorspace, ycbcr_enc, quantization and xfer_func of sink/src_fmt
> - specify sensor at enable_streams() using previously set ID, instead of checking remote pad every time
> - remove U suffix on numeric value
> - use unsigned int variable for loop index
> - remove redundant casting
> - use GENMASK instead of literal
> - remove unused constants
> - remove unused visconti_csi2rx_video_ops
> ---
>  MAINTAINERS                                        |   1 +
>  drivers/media/platform/Kconfig                     |   1 +
>  drivers/media/platform/Makefile                    |   1 +
>  drivers/media/platform/toshiba/Kconfig             |   6 +
>  drivers/media/platform/toshiba/Makefile            |   3 +
>  drivers/media/platform/toshiba/visconti/Kconfig    |  17 +
>  drivers/media/platform/toshiba/visconti/Makefile   |   8 +
>  .../media/platform/toshiba/visconti/csi2rx_drv.c   | 954 +++++++++++++++++++++
>  8 files changed, 991 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c17c7ddba5af..ce973791b367 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25986,6 +25986,7 @@ L:	linux-media@vger.kernel.org
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
>  F:	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> +F:	drivers/media/platform/toshiba/visconti/
>
>  TOSHIBA WMI HOTKEYS DRIVER
>  M:	Azael Avalos <coproscefalo@gmail.com>
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 9287faafdce5..d5265aa16c88 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -87,6 +87,7 @@ source "drivers/media/platform/st/Kconfig"
>  source "drivers/media/platform/sunxi/Kconfig"
>  source "drivers/media/platform/synopsys/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 6fd7db0541c7..09e67ecb9559 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -30,6 +30,7 @@ obj-y += st/
>  obj-y += sunxi/
>  obj-y += synopsys/
>  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..dd89a9a35704
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/Makefile
> @@ -0,0 +1,3 @@
> +# 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..aa0b63f9f008
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/Kconfig
> @@ -0,0 +1,17 @@
> +# 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..53d112432a86
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> @@ -0,0 +1,954 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/*
> + * Toshiba Visconti Video Capture Support
> + *
> + * (C) Copyright 2025 TOSHIBA CORPORATION
> + * (C) Copyright 2025 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/reset.h>
> +#include <linux/seq_file.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_DOUT	 GENMASK(15, 8)
> +
> +#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


Look like it is dwc CSI2RX controller. Can we work out a common dwc
CSI2RX driver to avoid every duplicate the same code

A attempt at
https://lore.kernel.org/imx/20250821-95_cam-v3-20-c9286fbb34b9@nxp.com/

The above is the base on stage's imx6. we try to find a path to workout
a common dwc csi2rx.

Frank



> +
> +/* DPHY register space */
> +enum dphy_testcode {
> +	DIG_TESTCODE_EXT = 0,
> +	DIG_SYS_0 = 0x001,
> +	DIG_SYS_1 = 0x002,
> +	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_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 VISCSI2_ERROR_MONITORS_NUM 8
> +
> +/**
> + * struct viscsi2_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 viscsi2_line_err_target {
> +	u32 vc[VISCSI2_ERROR_MONITORS_NUM];
> +	u32 dt[VISCSI2_ERROR_MONITORS_NUM];
> +};
> +
> +#define CSI2RX_MIN_DATA_RATE 80
> +#define CSI2RX_MAX_DATA_RATE 1500
> +
> +#define VISCSI2_PAD_SINK 0
> +#define VISCSI2_PAD_SRC	 1
> +#define VISCSI2_PAD_NUM	 2
> +
> +#define VISCSI2_DEF_WIDTH  1920
> +#define VISCSI2_DEF_HEIGHT 1080
> +#define VISCSI2_MIN_WIDTH  640
> +#define VISCSI2_MAX_WIDTH  3840
> +#define VISCSI2_MIN_HEIGHT 480
> +#define VISCSI2_MAX_HEIGHT 2160
> +
> +struct viscsi2 {
> +	struct device *dev;
> +	void __iomem *base;
> +
> +	struct v4l2_subdev subdev;
> +	struct media_pad pads[VISCSI2_PAD_NUM];
> +	struct v4l2_async_notifier notifier;
> +	struct v4l2_subdev *remote;
> +	unsigned int remote_pad;
> +
> +	unsigned int lanes;
> +
> +	unsigned int irq;
> +	struct clk *clk_apb;
> +	struct clk *clk_cfg;
> +	struct reset_control *rst;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	struct dentry *debugfs_dir;
> +	u32 debug_phy_fatal;
> +	u32 debug_pkt_fatal;
> +	u32 debug_frame_fatal;
> +	u32 debug_phy;
> +	u32 debug_pkt;
> +	u32 debug_line;
> +#endif
> +	bool running;
> +};
> +
> +static inline struct viscsi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
> +{
> +	return container_of(n, struct viscsi2, notifier);
> +}
> +
> +static inline struct viscsi2 *sd_to_csi2(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct viscsi2, subdev);
> +}
> +
> +static inline void viscsi2_write(struct viscsi2 *priv, u32 regid, u32 val)
> +{
> +	writel(val, priv->base + regid);
> +}
> +
> +static inline u32 viscsi2_read(struct viscsi2 *priv, u32 regid)
> +{
> +	return readl(priv->base + regid);
> +}
> +
> +static void viscsi2_set_dphy_param(struct viscsi2 *priv, u32 val)
> +{
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL1, val);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_1);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, BIT_TESTCTRL0_CLK_0);
> +}
> +
> +static void viscsi2_set_dphy_addr(struct viscsi2 *priv, u32 test_mode)
> +{
> +	/* Select testcode Ex space with top 4bits of test_mode */
> +	viscsi2_set_dphy_param(priv, BIT_TESTCTRL1_ADDR | DIG_TESTCODE_EXT);
> +	viscsi2_set_dphy_param(priv, FIELD_GET(0xf00, test_mode));
> +	viscsi2_set_dphy_param(priv,
> +			       BIT_TESTCTRL1_ADDR | FIELD_GET(0xff, test_mode));
> +}
> +
> +static void dphy_write(struct viscsi2 *priv, u32 test_mode, u8 test_in)
> +{
> +	viscsi2_set_dphy_addr(priv, test_mode);
> +	viscsi2_set_dphy_param(priv, test_in);
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static u8 dphy_read(struct viscsi2 *priv, u32 test_mode)
> +{
> +	u32 read_data;
> +
> +	viscsi2_set_dphy_addr(priv, test_mode);
> +	read_data = viscsi2_read(priv, REG_CSI2RX_PHY_TESTCTRL1);
> +	return FIELD_GET(MASK_TESTCTRL1_DOUT, read_data);
> +}
> +
> +static int viscsi2_read_calibration_status(struct viscsi2 *priv, u32 test_mode,
> +					   u32 mask_err, u32 mask_done)
> +{
> +	u32 read_data = (u32)dphy_read(priv, test_mode);
> +
> +	if (!(read_data & mask_done))
> +		return -EAGAIN;
> +
> +	if (read_data & mask_err)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +struct viscsi2_calibration_status_def {
> +	const char *name;
> +	u32 test_mode;
> +	u32 mask_err;
> +	u32 mask_done;
> +};
> +
> +static const struct viscsi2_calibration_status_def viscsi2_caldef[] = {
> +	{ "term_cal_with_rext", DIG_TERM_CAL_1, MASK_TERM_CAL_ERR,
> +	  MASK_TERM_CAL_DONE },
> +	{ "clock_lane_offset_cal", DIG_CLKLANE_OFFSET_CAL_0, MASK_CLK_CAL_ERR,
> +	  MASK_CLK_CAL_DONE },
> +	{ "data_lane0_offset_cal", DIG_LANE0_OFFSET_CAL_0, MASK_CAL_ERR,
> +	  MASK_CAL_DONE },
> +	{ "data_lane1_offset_cal", DIG_LANE1_OFFSET_CAL_0, MASK_CAL_ERR,
> +	  MASK_CAL_DONE },
> +	{ "data_lane2_offset_cal", DIG_LANE2_OFFSET_CAL_0, MASK_CAL_ERR,
> +	  MASK_CAL_DONE },
> +	{ "data_lane3_offset_cal", DIG_LANE3_OFFSET_CAL_0, MASK_CAL_ERR,
> +	  MASK_CAL_DONE },
> +	{ "data_lane0_ddl_tuning_cal", DIG_LANE0_DDL_0, MASK_DDL_ERR,
> +	  MASK_DDL_DONE },
> +	{ "data_lane1_ddl_tuning_cal", DIG_LANE1_DDL_0, MASK_DDL_ERR,
> +	  MASK_DDL_DONE },
> +	{ "data_lane2_ddl_tuning_cal", DIG_LANE2_DDL_0, MASK_DDL_ERR,
> +	  MASK_DDL_DONE },
> +	{ "data_lane3_ddl_tuning_cal", DIG_LANE3_DDL_0, MASK_DDL_ERR,
> +	  MASK_DDL_DONE },
> +};
> +
> +static int viscsi2_debug_calibration_status_show(struct seq_file *m, void *p)
> +{
> +	struct viscsi2 *priv = m->private;
> +	unsigned int i;
> +
> +	if (!priv->running)
> +		return 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(viscsi2_caldef); i++) {
> +		const struct viscsi2_calibration_status_def *cd =
> +			&viscsi2_caldef[i];
> +
> +		seq_printf(m, "%s: %d\n", cd->name,
> +			   viscsi2_read_calibration_status(priv, cd->test_mode,
> +							   cd->mask_err,
> +							   cd->mask_done));
> +	}
> +
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(viscsi2_debug_calibration_status);
> +
> +static int viscsi2_debug_err_status_show(struct seq_file *m, void *p)
> +{
> +	struct viscsi2 *priv = m->private;
> +
> +	seq_printf(m, "err_phy_fatal: 0x%08x\n", priv->debug_phy_fatal);
> +	seq_printf(m, "err_pkt_fatal: 0x%08x\n", priv->debug_pkt_fatal);
> +	seq_printf(m, "err_frame_fatal: 0x%08x\n", priv->debug_frame_fatal);
> +	seq_printf(m, "err_phy: 0x%08x\n", priv->debug_phy);
> +	seq_printf(m, "err_pkt: 0x%08x\n", priv->debug_pkt);
> +	seq_printf(m, "err_line: 0x%08x\n", priv->debug_line);
> +
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(viscsi2_debug_err_status);
> +
> +static void viscsi2_debug_init(struct viscsi2 *csi2)
> +{
> +	csi2->debugfs_dir = debugfs_create_dir(dev_name(csi2->dev), NULL);
> +	if (IS_ERR(csi2->debugfs_dir))
> +		return;
> +	debugfs_create_file("calibration_status", 0444, csi2->debugfs_dir, csi2,
> +			    &viscsi2_debug_calibration_status_fops);
> +	debugfs_create_file("err_status", 0444, csi2->debugfs_dir, csi2,
> +			    &viscsi2_debug_err_status_fops);
> +}
> +
> +static void viscsi2_debug_cleanup(struct viscsi2 *csi2)
> +{
> +	debugfs_remove_recursive(csi2->debugfs_dir);
> +}
> +#endif
> +
> +#define OSC_FREQ_TARGET 0x1cc
> +
> +struct viscsi2_dphy_hs_info {
> +	u32 rate;
> +	u32 hsfreqrange;
> +};
> +
> +static const struct viscsi2_dphy_hs_info dphy_hs_info[] = {
> +	{ 80, 0x0 },   { 85, 0x10 },   { 95, 0x20 },   { 105, 0x30 },
> +	{ 115, 0x1 },  { 125, 0x11 },  { 135, 0x21 },  { 145, 0x31 },
> +	{ 155, 0x2 },  { 165, 0x12 },  { 175, 0x22 },  { 185, 0x32 },
> +	{ 198, 0x3 },  { 213, 0x13 },  { 228, 0x23 },  { 243, 0x33 },
> +	{ 263, 0x4 },  { 288, 0x14 },  { 313, 0x25 },  { 338, 0x35 },
> +	{ 375, 0x5 },  { 425, 0x16 },  { 475, 0x26 },  { 525, 0x37 },
> +	{ 575, 0x7 },  { 625, 0x18 },  { 675, 0x28 },  { 725, 0x39 },
> +	{ 775, 0x9 },  { 825, 0x19 },  { 875, 0x29 },  { 925, 0x3a },
> +	{ 975, 0xa },  { 1025, 0x1a }, { 1075, 0x2a }, { 1125, 0x3b },
> +	{ 1175, 0xb }, { 1225, 0x1b }, { 1275, 0x2b }, { 1325, 0x3c },
> +	{ 1375, 0xc }, { 1425, 0x1c }, { 1475, 0x2c }
> +};
> +
> +static void get_dphy_hs_transfer_info(u32 dphy_rate, u32 *hsfreqrange)
> +{
> +	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;
> +			return;
> +		}
> +	}
> +
> +	/* Not found; return the largest entry */
> +	*hsfreqrange = dphy_hs_info[ARRAY_SIZE(dphy_hs_info) - 1].hsfreqrange;
> +}
> +
> +static void viscsi2_set_dphy_rate(struct viscsi2 *priv, u32 dphy_rate)
> +{
> +	u32 hsfreqrange;
> +
> +	get_dphy_hs_transfer_info(dphy_rate, &hsfreqrange);
> +
> +	dphy_write(priv, DIG_SYS_1, hsfreqrange);
> +	dphy_write(priv, DIG_SYS_0, SYS_0_HSFREQRANGE_OVR);
> +	dphy_write(priv, DIG_RX_STARTUP_OVR_5, STARTUP_OVR_5_BYPASS);
> +	dphy_write(priv, DIG_RX_STARTUP_OVR_4, STARTUP_OVR_4_CNTVAL);
> +	dphy_write(priv, DIG_CB_2, CB_2_LPRX_BIAS | CB_2_RESERVED);
> +	dphy_write(priv, DIG_SYS_7, SYS_7_DESKEW_POL | SYS_7_RESERVED);
> +	dphy_write(priv, DIG_CLKLANE_LANE_6, CLKLANE_RXHS_PULL_LONG);
> +	dphy_write(priv, DIG_RX_STARTUP_OVR_2,
> +		   FIELD_GET(0xff, OSC_FREQ_TARGET));
> +	dphy_write(priv, DIG_RX_STARTUP_OVR_3,
> +		   FIELD_GET(0xf00, OSC_FREQ_TARGET));
> +	dphy_write(priv, DIG_RX_STARTUP_OVR_4,
> +		   STARTUP_OVR_4_CNTVAL | STARTUP_OVR_4_DDL_EN);
> +}
> +
> +static int viscsi2_initialize(struct viscsi2 *priv, u32 num_lane, u32 dphy_rate,
> +			      const struct viscsi2_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 */
> +	viscsi2_write(priv, REG_CSI2RX_RESETN, 1);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> +	ndelay(15);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 0);
> +
> +	/* Configure D-PHY frequency range */
> +	viscsi2_set_dphy_rate(priv, dphy_rate);
> +
> +	/* 2nd phase of initialization */
> +	viscsi2_write(priv, REG_CSI2RX_NLANES, num_lane - 1);
> +	ndelay(5);
> +
> +	/* Release D-PHY from Reset */
> +	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 1);
> +	ndelay(5);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 1);
> +
> +	/* Configuration of line error target */
> +	val = (err_target->vc[3] << 30) | (err_target->dt[3] << 24) |
> +	      (err_target->vc[2] << 22) | (err_target->dt[2] << 16) |
> +	      (err_target->vc[1] << 14) | (err_target->dt[1] << 8) |
> +	      (err_target->vc[0] << 6) | (err_target->dt[0]);
> +	viscsi2_write(priv, REG_CSI2RX_DATA_IDS_1, val);
> +	val = (err_target->vc[7] << 30) | (err_target->dt[7] << 24) |
> +	      (err_target->vc[6] << 22) | (err_target->dt[6] << 16) |
> +	      (err_target->vc[5] << 14) | (err_target->dt[5] << 8) |
> +	      (err_target->vc[4] << 6) | (err_target->dt[4]);
> +	viscsi2_write(priv, REG_CSI2RX_DATA_IDS_2, val);
> +
> +	/* Configuration of mask */
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, MASK_PHY_FATAL_ALL);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, MASK_PKT_FATAL_ALL);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL,
> +		      MASK_FRAME_FATAL_ALL);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY, MASK_PHY_ERROR_ALL);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT, MASK_PKT_ERROR_ALL);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_LINE, MASK_LINE_ERROR_ALL);
> +
> +	return 0;
> +}
> +
> +struct viscsi2_format {
> +	u32 code;
> +	unsigned int bpp;
> +};
> +
> +static const struct viscsi2_format viscsi2_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 viscsi2_format *fmt_for_mbus_code(unsigned int mbus_code)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; ARRAY_SIZE(viscsi2_formats); i++) {
> +		if (viscsi2_formats[i].code == mbus_code)
> +			return &viscsi2_formats[i];
> +	}
> +	return NULL;
> +}
> +
> +static const struct viscsi2_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 viscsi2_start(struct viscsi2 *priv, struct v4l2_subdev_state *state)
> +{
> +	const struct v4l2_mbus_framefmt *sink_fmt;
> +	const struct viscsi2_format *cur_fmt;
> +	struct media_pad *src_pad;
> +	int cur_bpp, dphy_rate;
> +	s64 link_freq;
> +	int ret = 0;
> +
> +	/* Get bpp for current format */
> +	sink_fmt = v4l2_subdev_state_get_format(state, VISCSI2_PAD_SINK);
> +	cur_fmt = fmt_for_mbus_code(sink_fmt->code);
> +	if (!cur_fmt)
> +		return -EINVAL;
> +	cur_bpp = cur_fmt->bpp;
> +
> +	/* Get DPHY rate [unit: Mbps]; note that the signal is DDR */
> +	src_pad = &priv->remote->entity.pads[priv->remote_pad];
> +	link_freq = v4l2_get_link_freq(src_pad, cur_bpp, 2 * priv->lanes);
> +	if (link_freq < 0)
> +		return link_freq;
> +	dphy_rate = div_s64(link_freq, 500000);
> +
> +	clk_prepare_enable(priv->clk_apb);
> +	clk_prepare_enable(priv->clk_cfg);
> +	ndelay(15);
> +	reset_control_deassert(priv->rst);
> +
> +	ret = viscsi2_initialize(priv, priv->lanes, dphy_rate,
> +				 &err_target_vc0_alldt);
> +
> +	if (ret) {
> +		reset_control_assert(priv->rst);
> +		clk_disable_unprepare(priv->clk_cfg);
> +		clk_disable_unprepare(priv->clk_apb);
> +		return ret;
> +	}
> +
> +	priv->running = true;
> +	return 0;
> +}
> +
> +static void viscsi2_stop(struct viscsi2 *priv)
> +{
> +	priv->running = false;
> +
> +	/* Disable interrupt by clearing bits of MSK registers */
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY_FATAL, 0);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT_FATAL, 0);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL, 0);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PHY, 0);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_PKT, 0);
> +	viscsi2_write(priv, REG_CSI2RX_INT_MSK_LINE, 0);
> +	/* Make sure registers cleared */
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PHY_FATAL);
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PKT_FATAL);
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_FRAME_FATAL);
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PHY);
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_PKT);
> +	viscsi2_read(priv, REG_CSI2RX_INT_MSK_LINE);
> +	/* Wait for current handlers finish */
> +	synchronize_irq(priv->irq);
> +
> +	/* Shutdown hardware */
> +	viscsi2_write(priv, REG_CSI2RX_PHY_SHUTDOWNZ, 0);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_RSTZ, 0);
> +	viscsi2_write(priv, REG_CSI2RX_PHY_TESTCTRL0, 1);
> +	viscsi2_write(priv, REG_CSI2RX_RESETN, 0);
> +
> +	reset_control_assert(priv->rst);
> +	clk_disable_unprepare(priv->clk_cfg);
> +	clk_disable_unprepare(priv->clk_apb);
> +}
> +
> +static int viscsi2_enable_streams(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *state, u32 pad,
> +				  u64 streams_mask)
> +{
> +	struct viscsi2 *priv = sd_to_csi2(sd);
> +	int ret;
> +
> +	/* Enabling: turn on CSI2RX -> turn on sensor */
> +	ret = viscsi2_start(priv, state);
> +	if (ret)
> +		return ret;
> +
> +	/* Currently CSI2RX supports only stream0 in source pad */
> +	ret = v4l2_subdev_enable_streams(priv->remote, priv->remote_pad,
> +					 BIT(0));
> +	if (ret) {
> +		viscsi2_stop(priv);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int viscsi2_disable_streams(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *state, u32 pad,
> +				   u64 streams_mask)
> +{
> +	struct viscsi2 *priv = sd_to_csi2(sd);
> +
> +	/* Disabling: turn off sensor -> turn off CSI2RX */
> +	v4l2_subdev_disable_streams(priv->remote, priv->remote_pad, BIT(0));
> +	viscsi2_stop(priv);
> +
> +	return 0;
> +}
> +
> +static int viscsi2_enum_mbus_code(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_state *sd_state,
> +				  struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->pad == VISCSI2_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,
> +							VISCSI2_PAD_SINK);
> +		code->code = sink_fmt->code;
> +		return 0;
> +	}
> +
> +	if (code->index >= ARRAY_SIZE(viscsi2_formats))
> +		return -EINVAL;
> +	code->code = viscsi2_formats[code->index].code;
> +
> +	return 0;
> +}
> +
> +static int viscsi2_enum_frame_size(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *sd_state,
> +				   struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	if (fse->index > 0)
> +		return -EINVAL;
> +
> +	if (!fmt_for_mbus_code(fse->code))
> +		return -EINVAL;
> +
> +	fse->min_width = VISCSI2_MIN_WIDTH;
> +	fse->max_width = VISCSI2_MAX_WIDTH;
> +	fse->min_height = VISCSI2_MIN_HEIGHT;
> +	fse->max_height = VISCSI2_MAX_HEIGHT;
> +
> +	return 0;
> +}
> +
> +static int viscsi2_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, VISCSI2_PAD_SINK);
> +	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SRC);
> +
> +	sink_fmt->width = VISCSI2_DEF_WIDTH;
> +	sink_fmt->height = VISCSI2_DEF_HEIGHT;
> +	sink_fmt->field = V4L2_FIELD_NONE;
> +	sink_fmt->code = viscsi2_formats[0].code;
> +	sink_fmt->colorspace = V4L2_COLORSPACE_RAW;
> +	sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
> +	sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> +	sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE;
> +
> +	*src_fmt = *sink_fmt;
> +
> +	return 0;
> +}
> +
> +static int viscsi2_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 == VISCSI2_PAD_SRC)
> +		return v4l2_subdev_get_fmt(sd, sd_state, fmt);
> +
> +	sink_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SINK);
> +
> +	*sink_fmt = fmt->format;
> +	sink_fmt->width = clamp_t(u32, fmt->format.width, VISCSI2_MIN_WIDTH,
> +				  VISCSI2_MAX_WIDTH);
> +	sink_fmt->height = clamp_t(u32, fmt->format.height, VISCSI2_MIN_HEIGHT,
> +				   VISCSI2_MAX_HEIGHT);
> +	if (!fmt_for_mbus_code(sink_fmt->code))
> +		sink_fmt->code = viscsi2_formats[0].code;
> +	fmt->format = *sink_fmt;
> +
> +	/* Source pad should have the same format */
> +	src_fmt = v4l2_subdev_state_get_format(sd_state, VISCSI2_PAD_SRC);
> +	*src_fmt = *sink_fmt;
> +
> +	return 0;
> +}
> +
> +static const struct media_entity_operations viscsi2_entity_ops = {
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static const struct v4l2_subdev_pad_ops viscsi2_pad_ops = {
> +	.enum_mbus_code = viscsi2_enum_mbus_code,
> +	.enum_frame_size = viscsi2_enum_frame_size,
> +	.disable_streams = viscsi2_disable_streams,
> +	.enable_streams = viscsi2_enable_streams,
> +	.get_fmt = v4l2_subdev_get_fmt,
> +	.set_fmt = viscsi2_set_pad_format,
> +};
> +
> +static const struct v4l2_subdev_ops viscsi2_subdev_ops = {
> +	.pad = &viscsi2_pad_ops,
> +};
> +
> +static const struct v4l2_subdev_internal_ops viscsi2_internal_ops = {
> +	.init_state = viscsi2_init_state,
> +};
> +
> +static int viscsi2_notify_bound(struct v4l2_async_notifier *notifier,
> +				struct v4l2_subdev *subdev,
> +				struct v4l2_async_connection *asc)
> +{
> +	struct viscsi2 *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 | MEDIA_LNK_FL_IMMUTABLE);
> +}
> +
> +static void viscsi2_notify_unbind(struct v4l2_async_notifier *notifier,
> +				  struct v4l2_subdev *subdev,
> +				  struct v4l2_async_connection *asc)
> +{
> +	struct viscsi2 *priv = notifier_to_csi2(notifier);
> +
> +	priv->remote = NULL;
> +}
> +
> +static const struct v4l2_async_notifier_operations viscsi2_notify_ops = {
> +	.bound = viscsi2_notify_bound,
> +	.unbind = viscsi2_notify_unbind,
> +};
> +
> +static int viscsi2_parse_dt(struct viscsi2 *priv)
> +{
> +	struct v4l2_async_connection *asc;
> +	struct fwnode_handle *fwnode;
> +	struct fwnode_handle *ep;
> +	struct v4l2_fwnode_endpoint v4l2_ep = {
> +		.bus_type = V4L2_MBUS_CSI2_DPHY,
> +	};
> +	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");
> +		goto error_fwnode_handle_put;
> +	}
> +
> +	priv->lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
> +	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);
> +		goto error_fwnode_handle_put;
> +	}
> +
> +	fwnode = fwnode_graph_get_remote_endpoint(ep);
> +	fwnode_handle_put(ep);
> +
> +	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
> +	priv->notifier.ops = &viscsi2_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;
> +
> +error_fwnode_handle_put:
> +	fwnode_handle_put(ep);
> +	return -EINVAL;
> +}
> +
> +static irqreturn_t viscsi2_irq(int irq, void *dev_id)
> +{
> +	struct viscsi2 *priv = dev_id;
> +	u32 event;
> +
> +	event = viscsi2_read(priv, REG_CSI2RX_INT_ST_MAIN);
> +	dev_err_ratelimited(priv->dev, "CSI2RX error 0x%x.\n", event);
> +
> +#ifdef CONFIG_DEBUG_FS
> +	priv->debug_phy_fatal |=
> +		viscsi2_read(priv, REG_CSI2RX_INT_ST_PHY_FATAL);
> +	priv->debug_pkt_fatal |=
> +		viscsi2_read(priv, REG_CSI2RX_INT_ST_PKT_FATAL);
> +	priv->debug_frame_fatal |=
> +		viscsi2_read(priv, REG_CSI2RX_INT_ST_FRAME_FATAL);
> +	priv->debug_phy |= viscsi2_read(priv, REG_CSI2RX_INT_ST_PHY);
> +	priv->debug_pkt |= viscsi2_read(priv, REG_CSI2RX_INT_ST_PKT);
> +	priv->debug_line |= viscsi2_read(priv, REG_CSI2RX_INT_ST_LINE);
> +#endif
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct of_device_id viscsi2_of_table[] = {
> +	{
> +		.compatible = "toshiba,visconti5-csi2",
> +	},
> +	{ /* Sentinel */ }
> +};
> +
> +static int viscsi2_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct viscsi2 *priv;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->running = false;
> +
> +	priv->dev = dev;
> +
> +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +	ret = devm_request_irq(dev, irq, viscsi2_irq, 0, KBUILD_MODNAME, priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "irq request failed");
> +
> +	priv->irq = irq;
> +
> +	priv->clk_cfg = devm_clk_get(dev, "cfg");
> +	if (IS_ERR(priv->clk_cfg))
> +		return dev_err_probe(dev, PTR_ERR(priv->clk_cfg),
> +				     "cannot get clock cfg");
> +	priv->clk_apb = devm_clk_get(dev, "apb");
> +	if (IS_ERR(priv->clk_apb))
> +		return dev_err_probe(dev, PTR_ERR(priv->clk_apb),
> +				     "cannot get clock apb");
> +	priv->rst = devm_reset_control_get_exclusive_by_index(dev, 0);
> +	if (IS_ERR(priv->rst))
> +		return dev_err_probe(dev, PTR_ERR(priv->rst),
> +				     "cannot get reset");
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	ret = viscsi2_parse_dt(priv);
> +	if (ret)
> +		return ret;
> +
> +	priv->subdev.dev = &pdev->dev;
> +	v4l2_subdev_init(&priv->subdev, &viscsi2_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 = &viscsi2_internal_ops;
> +	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	priv->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> +	priv->subdev.entity.ops = &viscsi2_entity_ops;
> +
> +	priv->pads[VISCSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	priv->pads[VISCSI2_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
> +
> +	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;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	viscsi2_debug_init(priv);
> +#endif
> +
> +	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 viscsi2_remove(struct platform_device *pdev)
> +{
> +	struct viscsi2 *priv = platform_get_drvdata(pdev);
> +
> +#ifdef CONFIG_DEBUG_FS
> +	viscsi2_debug_cleanup(priv);
> +#endif
> +
> +	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 viscsi2_driver = {
> +	.probe = viscsi2_probe,
> +	.remove = viscsi2_remove,
> +	.driver = {
> +		.name = "visconti-csi2rx",
> +		.of_match_table = viscsi2_of_table,
> +	},
> +};
> +
> +module_platform_driver(viscsi2_driver);
> +
> +MODULE_AUTHOR("Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>");
> +MODULE_DESCRIPTION("Toshiba Visconti CSI-2 receiver driver");
> +MODULE_LICENSE("Dual BSD/GPL");
>
> --
> 2.34.1
>
>


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

* Re: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
  2025-10-16  4:34   ` Frank Li
@ 2025-10-16  6:38   ` Krzysztof Kozlowski
  2025-10-20  6:16     ` yuji2.ishikawa
  1 sibling, 1 reply; 15+ messages in thread
From: Krzysztof Kozlowski @ 2025-10-16  6:38 UTC (permalink / raw)
  To: Yuji Ishikawa, Nobuhiro Iwamatsu, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

On 16/10/2025 04:24, Yuji Ishikawa wrote:
> Adds the Device Tree binding documentation that allows to describe

"Add".

https://elixir.bootlin.com/linux/v6.16/source/Documentation/process/submitting-patches.rst#L94


> the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.


...

> +examples:
> +  - |
> +    #include <dt-bindings/clock/toshiba,tmpv770x.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +        #address-cells = <2>;
> +        #size-cells = <2>;
> +
> +        csi0: csi@1c008000 {

I don't understand why the label appeared. It is not used and it wasn't
here before. I did not ask to add label, but I only asked to fix the
node name to match generic names rule.

Drop the label. With these fixes:

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>


Best regards,
Krzysztof


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

* Re: [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface
  2025-10-16  2:24 ` [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
@ 2025-10-16  6:39   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2025-10-16  6:39 UTC (permalink / raw)
  To: Yuji Ishikawa, Nobuhiro Iwamatsu, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

On 16/10/2025 04:24, 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: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


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

* RE: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-10-16  4:34   ` Frank Li
@ 2025-10-20  6:11     ` yuji2.ishikawa
  0 siblings, 0 replies; 15+ messages in thread
From: yuji2.ishikawa @ 2025-10-20  6:11 UTC (permalink / raw)
  To: Frank.li
  Cc: nobuhiro.iwamatsu.x90, mchehab, robh, krzk+dt, conor+dt, p.zabel,
	linux-media, devicetree, linux-arm-kernel, linux-kernel

Hello Frank

Thank you for review comments.

> -----Original Message-----
> From: Frank Li <Frank.li@nxp.com>
> Sent: Thursday, October 16, 2025 1:35 PM
> To: ishikawa yuji(石川 悠司 □AIDC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: iwamatsu nobuhiro(岩松 信洋 □DITC○CPT)
> <nobuhiro.iwamatsu.x90@mail.toshiba>; Mauro Carvalho Chehab
> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Philipp Zabel
> <p.zabel@pengutronix.de>; linux-media@vger.kernel.org;
> devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti MIPI CSI-2 Receiver
> 
> On Thu, Oct 16, 2025 at 11:24:38AM +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>
> > ---
> > Changelog v12:
> > - Newly add bindings for CSI2RX driver
> >
> > Changelog v13:
> > - add entries to MAINTAINERS file.
> > - update email address of Nobuhiro Iwamatsu in /maintainers
> > - add Yuji Ishikawa to /maintainers
> > - change /properties/compatible: toshiba,visconti5-csi2rx ->
> > toshiba,visconti5-csi2
> > - change bindings file name: toshiba,visconti5-csi2rx ->
> > toshiba,visconti5-csi2
> > - change node name in sample DTS: csi2rx -> csi
> > - remove "|-" from /description
> > - update /description
> > - add definitions of clock and reset
> > - update /properties/ports/properties/port@0/description for better
> > comment
> > - update /properties/ports/properties/port@0/$ref to specify full
> > pathname
> > - remove
> /properties/ports/properties/port@0/properties/endpoint/properties/data-la
> nes/description because the default text provides enough information.
> > - update sample dts
> > ---
> >  .../bindings/media/toshiba,visconti5-csi2.yaml     | 125
> +++++++++++++++++++++
> >  MAINTAINERS                                        |   7 ++
> >  2 files changed, 132 insertions(+)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
> > b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.yaml
> > new file mode 100644
> > index 000000000000..21fb46de5b6e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.y
> > +++ aml
> > @@ -0,0 +1,125 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/toshiba,visconti5-csi2.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Toshiba Visconti5 SoC MIPI CSI-2 receiver
> > +
> > +maintainers:
> > +  - Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
> > +  - Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > +
> > +description:
> > +  Toshiba Visconti5 SoC MIPI CSI-2 receiver device receives MIPI
> > +CSI-2 video
> > +  stream. The obtained video stream is used as input for the Visconti5 VIIF.
> > +
> > +properties:
> > +  compatible:
> > +    const: toshiba,visconti5-csi2
> > +
> 
> ...
> 
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/clock/toshiba,tmpv770x.h>
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    soc {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        csi0: csi@1c008000 {
> 
> Needn't label csi0
> 

I'll drop the label.

> > +            compatible = "toshiba,visconti5-csi2";
> > +            reg = <0 0x1c008000 0 0x400>;
> > +            interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
> > +            clocks = <&pismu TMPV770X_CLK_VIIFBS0_CFG>,
> > +                     <&pismu TMPV770X_CLK_VIIFBS0_APB>;
> > +            clock-names = "cfg", "apb";
> > +            resets = <&pismu TMPV770X_RESET_VIIFBS0_APB>;
> > +
> > +            ports {
> > +                #address-cells = <1>;
> > +                #size-cells = <0>;
> 
> need empty line here.

I'll add empty line before blocks.

> > +                port@0 {
> > +                    reg = <0>;
> 
> empty line here
> 
> > +                    csi0_in: endpoint {
> > +                        data-lanes = <1 2>;
> > +                        remote-endpoint = <&imx219_out>;
> > +                    };
> > +                };
> 
> empty line here
> 
> Frank
> > +                port@1 {
> > +                    reg = <1>;
> > +                    csi0_out: endpoint {
> > +                        remote-endpoint = <&video0_in>;
> > +                    };
> > +                };
> > +            };
> > +        };
> > +    };
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > 46126ce2f968..e4634a0aad74 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -25979,6 +25979,13 @@ F:
> 	Documentation/devicetree/bindings/media/i2c/toshiba,tc358743.txt
> >  F:	drivers/media/i2c/tc358743*
> >  F:	include/media/i2c/tc358743.h
> >
> > +TOSHIBA VISCONTI VIIF DRIVER
> > +M:	Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
> > +M:	Yuji Ishikawa <yuji2.ishikawa@toshiba.co.jp>
> > +L:	linux-media@vger.kernel.org
> > +S:	Maintained
> > +F:
> 	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.ya
> ml
> > +
> >  TOSHIBA WMI HOTKEYS DRIVER
> >  M:	Azael Avalos <coproscefalo@gmail.com>
> >  L:	platform-driver-x86@vger.kernel.org
> >
> > --
> > 2.34.1
> >
> >

Regards,

Yuji Ishikawa



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

* RE: [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2025-10-16  4:45   ` Frank Li
@ 2025-10-20  6:13     ` yuji2.ishikawa
  2025-10-20 16:05       ` Frank Li
  0 siblings, 1 reply; 15+ messages in thread
From: yuji2.ishikawa @ 2025-10-20  6:13 UTC (permalink / raw)
  To: Frank.li
  Cc: nobuhiro.iwamatsu.x90, mchehab, robh, krzk+dt, conor+dt, p.zabel,
	linux-media, devicetree, linux-arm-kernel, linux-kernel

Hello Frank,

Thank you for review comments.

> -----Original Message-----
> From: Frank Li <Frank.li@nxp.com>
> Sent: Thursday, October 16, 2025 1:45 PM
> To: ishikawa yuji(石川 悠司 □AIDC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>
> Cc: iwamatsu nobuhiro(岩松 信洋 □DITC○CPT)
> <nobuhiro.iwamatsu.x90@mail.toshiba>; Mauro Carvalho Chehab
> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Philipp Zabel
> <p.zabel@pengutronix.de>; linux-media@vger.kernel.org;
> devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti
> CSI-2 Receiver driver
> 
> On Thu, Oct 16, 2025 at 11:24:41AM +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
> >
> > Changelog v13:
> > - wrap one line at 80 characters
> > - change banner comment style
> > - update comment style; spacing at the start and end, capitalize first
> > letter
> > - add support for clock and reset framework
> > - add debugfs to pass debug and status information
> > - add entries to MAINTAINERS file
> > - Kconfig: add a blank line just after License Identifier.
> > - update references to header files
> > - remove redundant inline qualifier
> > - shorten function/variable names: visconti_csi2rx -> viscsi2
> > - simplify dphy_write and dphy read operations
> > - remove osc_freq_target from struct csi2rx_dphy_hs_info, which is always
> the same value.
> > - add comment about MASK register's behavior (reversed polarity)
> > - use v4l2_get_link_freq() instead of get_pixelclock()
> > - set driver name according to module name: visconti_csi2rx_dev ->
> > visconti-csi2rx
> > - check error before setting priv->irq in probe()
> > - check error at fmt_for_mbus_code()
> > - add callback for ioctl(VIDIOC_ENUM_FRAMESIZES)
> > - improve viscsi2_parse_dt() by assuming bus_type is CSI2_DPHY
> > - use dev_err_ratelimited() for irq handler
> > - bugfix on fmt_for_mbus_code(): in case unsupported mbus_code is
> > given
> > - add goto based error handling sequence to viscsi2_parse_dt()
> > - specify default value of colorspace, ycbcr_enc, quantization and
> > xfer_func of sink/src_fmt
> > - specify sensor at enable_streams() using previously set ID, instead
> > of checking remote pad every time
> > - remove U suffix on numeric value
> > - use unsigned int variable for loop index
> > - remove redundant casting
> > - use GENMASK instead of literal
> > - remove unused constants
> > - remove unused visconti_csi2rx_video_ops
> > ---
> >  MAINTAINERS                                        |   1 +
> >  drivers/media/platform/Kconfig                     |   1 +
> >  drivers/media/platform/Makefile                    |   1 +
> >  drivers/media/platform/toshiba/Kconfig             |   6 +
> >  drivers/media/platform/toshiba/Makefile            |   3 +
> >  drivers/media/platform/toshiba/visconti/Kconfig    |  17 +
> >  drivers/media/platform/toshiba/visconti/Makefile   |   8 +
> >  .../media/platform/toshiba/visconti/csi2rx_drv.c   | 954
> +++++++++++++++++++++
> >  8 files changed, 991 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > c17c7ddba5af..ce973791b367 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -25986,6 +25986,7 @@ L:	linux-media@vger.kernel.org
> >  S:	Maintained
> >  F:
> 	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.ya
> ml
> >  F:
> 	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yam
> l
> > +F:	drivers/media/platform/toshiba/visconti/
> >
> >  TOSHIBA WMI HOTKEYS DRIVER
> >  M:	Azael Avalos <coproscefalo@gmail.com>
> > diff --git a/drivers/media/platform/Kconfig
> > b/drivers/media/platform/Kconfig index 9287faafdce5..d5265aa16c88
> > 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -87,6 +87,7 @@ source "drivers/media/platform/st/Kconfig"
> >  source "drivers/media/platform/sunxi/Kconfig"
> >  source "drivers/media/platform/synopsys/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 6fd7db0541c7..09e67ecb9559
> > 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -30,6 +30,7 @@ obj-y += st/
> >  obj-y += sunxi/
> >  obj-y += synopsys/
> >  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..dd89a9a35704
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/Makefile
> > @@ -0,0 +1,3 @@
> > +# 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..aa0b63f9f008
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/Kconfig
> > @@ -0,0 +1,17 @@
> > +# 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..53d112432a86
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> > @@ -0,0 +1,954 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> > +/*
> > + * Toshiba Visconti Video Capture Support
> > + *
> > + * (C) Copyright 2025 TOSHIBA CORPORATION
> > + * (C) Copyright 2025 Toshiba Electronic Devices & Storage
> > +Corporation  */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/property.h>
> > +#include <linux/reset.h>
> > +#include <linux/seq_file.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_DOUT	 GENMASK(15, 8)
> > +
> > +#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
> 
> 
> Look like it is dwc CSI2RX controller. Can we work out a common dwc CSI2RX
> driver to avoid every duplicate the same code
> 
> A attempt at
> https://lore.kernel.org/imx/20250821-95_cam-v3-20-c9286fbb34b9@nxp.com
> /
> 
> The above is the base on stage's imx6. we try to find a path to workout a
> common dwc csi2rx.
> 
> Frank
> 

Yes, it is DWC CSI2RX controller.
It's an interesting idea to have a common dwc driver.
Let me check if CSI2RX and PHY drivers work well with Visconti's hardware.
Please let me know the base repository to apply patches.

Regards,
Yuji Ishikawa



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

* RE: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver
  2025-10-16  6:38   ` Krzysztof Kozlowski
@ 2025-10-20  6:16     ` yuji2.ishikawa
  0 siblings, 0 replies; 15+ messages in thread
From: yuji2.ishikawa @ 2025-10-20  6:16 UTC (permalink / raw)
  To: krzk, nobuhiro.iwamatsu.x90, mchehab, robh, krzk+dt, conor+dt,
	p.zabel
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel

Hello Krzysztof

Thank you for review comments.

> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Thursday, October 16, 2025 3:38 PM
> To: ishikawa yuji(石川 悠司 □AIDC○EA開)
> <yuji2.ishikawa@toshiba.co.jp>; iwamatsu nobuhiro(岩松 信洋 □DITC○
> CPT) <nobuhiro.iwamatsu.x90@mail.toshiba>; Mauro Carvalho Chehab
> <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Philipp Zabel
> <p.zabel@pengutronix.de>
> Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add
> Toshiba Visconti MIPI CSI-2 Receiver
> 
> On 16/10/2025 04:24, Yuji Ishikawa wrote:
> > Adds the Device Tree binding documentation that allows to describe
> 
> "Add".
> 
> https://elixir.bootlin.com/linux/v6.16/source/Documentation/process/submit
> ting-patches.rst#L94
> 

I'll fix commit messages.

> 
> > the MIPI CSI-2 Receiver found in Toshiba Visconti SoCs.
> 
> 
> ...
> 
> > +examples:
> > +  - |
> > +    #include <dt-bindings/clock/toshiba,tmpv770x.h>
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +    soc {
> > +        #address-cells = <2>;
> > +        #size-cells = <2>;
> > +
> > +        csi0: csi@1c008000 {
> 
> I don't understand why the label appeared. It is not used and it wasn't here
> before. I did not ask to add label, but I only asked to fix the node name to match
> generic names rule.
> 
> Drop the label. With these fixes:
> 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> 

I'll remove the label.

> 
> Best regards,
> Krzysztof

Regards,
Yuji Ishikawa

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

* Re: [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver
  2025-10-20  6:13     ` yuji2.ishikawa
@ 2025-10-20 16:05       ` Frank Li
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Li @ 2025-10-20 16:05 UTC (permalink / raw)
  To: yuji2.ishikawa
  Cc: nobuhiro.iwamatsu.x90, mchehab, robh, krzk+dt, conor+dt, p.zabel,
	linux-media, devicetree, linux-arm-kernel, linux-kernel

On Mon, Oct 20, 2025 at 06:13:37AM +0000, yuji2.ishikawa@toshiba.co.jp wrote:
> Hello Frank,
>
> Thank you for review comments.
>
> > -----Original Message-----
> > From: Frank Li <Frank.li@nxp.com>
> > Sent: Thursday, October 16, 2025 1:45 PM
> > To: ishikawa yuji(石川 悠司 □AIDC○EA開)
> > <yuji2.ishikawa@toshiba.co.jp>
> > Cc: iwamatsu nobuhiro(岩松 信洋 □DITC○CPT)
> > <nobuhiro.iwamatsu.x90@mail.toshiba>; Mauro Carvalho Chehab
> > <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> > <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Philipp Zabel
> > <p.zabel@pengutronix.de>; linux-media@vger.kernel.org;
> > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti
> > CSI-2 Receiver driver
> >
> > On Thu, Oct 16, 2025 at 11:24:41AM +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
> > >
> > > Changelog v13:
> > > - wrap one line at 80 characters
> > > - change banner comment style
> > > - update comment style; spacing at the start and end, capitalize first
> > > letter
> > > - add support for clock and reset framework
> > > - add debugfs to pass debug and status information
> > > - add entries to MAINTAINERS file
> > > - Kconfig: add a blank line just after License Identifier.
> > > - update references to header files
> > > - remove redundant inline qualifier
> > > - shorten function/variable names: visconti_csi2rx -> viscsi2
> > > - simplify dphy_write and dphy read operations
> > > - remove osc_freq_target from struct csi2rx_dphy_hs_info, which is always
> > the same value.
> > > - add comment about MASK register's behavior (reversed polarity)
> > > - use v4l2_get_link_freq() instead of get_pixelclock()
> > > - set driver name according to module name: visconti_csi2rx_dev ->
> > > visconti-csi2rx
> > > - check error before setting priv->irq in probe()
> > > - check error at fmt_for_mbus_code()
> > > - add callback for ioctl(VIDIOC_ENUM_FRAMESIZES)
> > > - improve viscsi2_parse_dt() by assuming bus_type is CSI2_DPHY
> > > - use dev_err_ratelimited() for irq handler
> > > - bugfix on fmt_for_mbus_code(): in case unsupported mbus_code is
> > > given
> > > - add goto based error handling sequence to viscsi2_parse_dt()
> > > - specify default value of colorspace, ycbcr_enc, quantization and
> > > xfer_func of sink/src_fmt
> > > - specify sensor at enable_streams() using previously set ID, instead
> > > of checking remote pad every time
> > > - remove U suffix on numeric value
> > > - use unsigned int variable for loop index
> > > - remove redundant casting
> > > - use GENMASK instead of literal
> > > - remove unused constants
> > > - remove unused visconti_csi2rx_video_ops
> > > ---
> > >  MAINTAINERS                                        |   1 +
> > >  drivers/media/platform/Kconfig                     |   1 +
> > >  drivers/media/platform/Makefile                    |   1 +
> > >  drivers/media/platform/toshiba/Kconfig             |   6 +
> > >  drivers/media/platform/toshiba/Makefile            |   3 +
> > >  drivers/media/platform/toshiba/visconti/Kconfig    |  17 +
> > >  drivers/media/platform/toshiba/visconti/Makefile   |   8 +
> > >  .../media/platform/toshiba/visconti/csi2rx_drv.c   | 954
> > +++++++++++++++++++++
> > >  8 files changed, 991 insertions(+)
> > >
> > > diff --git a/MAINTAINERS b/MAINTAINERS index
> > > c17c7ddba5af..ce973791b367 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -25986,6 +25986,7 @@ L:	linux-media@vger.kernel.org
> > >  S:	Maintained
> > >  F:
> > 	Documentation/devicetree/bindings/media/toshiba,visconti5-csi2.ya
> > ml
> > >  F:
> > 	Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yam
> > l
> > > +F:	drivers/media/platform/toshiba/visconti/
> > >
> > >  TOSHIBA WMI HOTKEYS DRIVER
> > >  M:	Azael Avalos <coproscefalo@gmail.com>
> > > diff --git a/drivers/media/platform/Kconfig
> > > b/drivers/media/platform/Kconfig index 9287faafdce5..d5265aa16c88
> > > 100644
> > > --- a/drivers/media/platform/Kconfig
> > > +++ b/drivers/media/platform/Kconfig
> > > @@ -87,6 +87,7 @@ source "drivers/media/platform/st/Kconfig"
> > >  source "drivers/media/platform/sunxi/Kconfig"
> > >  source "drivers/media/platform/synopsys/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 6fd7db0541c7..09e67ecb9559
> > > 100644
> > > --- a/drivers/media/platform/Makefile
> > > +++ b/drivers/media/platform/Makefile
> > > @@ -30,6 +30,7 @@ obj-y += st/
> > >  obj-y += sunxi/
> > >  obj-y += synopsys/
> > >  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..dd89a9a35704
> > > --- /dev/null
> > > +++ b/drivers/media/platform/toshiba/Makefile
> > > @@ -0,0 +1,3 @@
> > > +# 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..aa0b63f9f008
> > > --- /dev/null
> > > +++ b/drivers/media/platform/toshiba/visconti/Kconfig
> > > @@ -0,0 +1,17 @@
> > > +# 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..53d112432a86
> > > --- /dev/null
> > > +++ b/drivers/media/platform/toshiba/visconti/csi2rx_drv.c
> > > @@ -0,0 +1,954 @@
> > > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> > > +/*
> > > + * Toshiba Visconti Video Capture Support
> > > + *
> > > + * (C) Copyright 2025 TOSHIBA CORPORATION
> > > + * (C) Copyright 2025 Toshiba Electronic Devices & Storage
> > > +Corporation  */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/debugfs.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/device.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/module.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/property.h>
> > > +#include <linux/reset.h>
> > > +#include <linux/seq_file.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_DOUT	 GENMASK(15, 8)
> > > +
> > > +#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
> >
> >
> > Look like it is dwc CSI2RX controller. Can we work out a common dwc CSI2RX
> > driver to avoid every duplicate the same code
> >
> > A attempt at
> > https://lore.kernel.org/imx/20250821-95_cam-v3-20-c9286fbb34b9@nxp.com
> > /
> >
> > The above is the base on stage's imx6. we try to find a path to workout a
> > common dwc csi2rx.
> >
> > Frank
> >
>
> Yes, it is DWC CSI2RX controller.
> It's an interesting idea to have a common dwc driver.
> Let me check if CSI2RX and PHY drivers work well with Visconti's hardware.
> Please let me know the base repository to apply patches.

It's base next-20250821.

https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tag/?h=next-20250821

Frank
>
> Regards,
> Yuji Ishikawa
>


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

end of thread, other threads:[~2025-10-20 16:06 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-16  2:24 [PATCH v13 0/7] Add Toshiba Visconti Video Input Interface driver Yuji Ishikawa
2025-10-16  2:24 ` [PATCH v13 1/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti MIPI CSI-2 Receiver Yuji Ishikawa
2025-10-16  4:34   ` Frank Li
2025-10-20  6:11     ` yuji2.ishikawa
2025-10-16  6:38   ` Krzysztof Kozlowski
2025-10-20  6:16     ` yuji2.ishikawa
2025-10-16  2:24 ` [PATCH v13 2/7] dt-bindings: media: platform: visconti: Add Toshiba Visconti Video Input Interface Yuji Ishikawa
2025-10-16  6:39   ` Krzysztof Kozlowski
2025-10-16  2:24 ` [PATCH v13 3/7] media: uapi: Add visconti viif meta buffer formats Yuji Ishikawa
2025-10-16  2:24 ` [PATCH v13 4/7] media: platform: visconti: Add Toshiba Visconti CSI-2 Receiver driver Yuji Ishikawa
2025-10-16  4:45   ` Frank Li
2025-10-20  6:13     ` yuji2.ishikawa
2025-10-20 16:05       ` Frank Li
2025-10-16  2:24 ` [PATCH v13 6/7] media: platform: visconti: Add streaming interface for ISP parameters and statistics Yuji Ishikawa
2025-10-16  2:24 ` [PATCH v13 7/7] documentation: media: Add documentation for Toshiba Visconti Video Input Interface driver Yuji Ishikawa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox