devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU)
@ 2025-02-21 15:55 Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
                   ` (17 more replies)
  0 siblings, 18 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

Dear All,

In preparation of supporting the CRU/CSI2 IPs found into the Renesas RZ/G3E
SoC, this series adds driver/dt-bindings support.
This adds also some minor fixes into rzg2l-csi2 and rzg2l-core drivers.

The series was tested in an out of tree branch with the following hw pipeline:

ov5645 image sensor (Coral Camera) -> rzg3e CSI2 -> rzg3e CRU
imx219 image sensor (Pi PiNoir Camera Module V2.1) -> rzg3e CSI2 -> rzg3e CRU

base commit: d4b0fd87ff0d (tag: next-20250221, linux-next/master)

------
Some logs:

root@smarc-rzg3e:~# media-ctl -p
Media controller API version 6.14.0

Media device information
------------------------
driver          rzg2l_cru
model           renesas,r9a09g047-cru
serial
bus info        platform:16000000.video
hw revision     0x0
driver version  6.14.0

Device topology
- entity 1: csi-16000400.csi2 (2 pads, 2 links, 0 routes)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        pad0: Sink
                [stream:0 fmt:UYVY8_1X16/320x240 field:none colorspace:srgb]
                <- "ov5645 0-003c":0 [ENABLED,IMMUTABLE]
        pad1: Source
                [stream:0 fmt:UYVY8_1X16/320x240 field:none colorspace:srgb]
                -> "cru-ip-16000000.video":0 [ENABLED,IMMUTABLE]

- entity 4: ov5645 0-003c (1 pad, 1 link, 0 routes)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev1
        pad0: Source
                [stream:0 fmt:UYVY8_1X16/1920x1080 field:none colorspace:srgb
                 crop:(0,0)/1920x1080]
                -> "csi-16000400.csi2":0 [ENABLED,IMMUTABLE]

- entity 8: cru-ip-16000000.video (2 pads, 2 links, 0 routes)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev2
        pad0: Sink
                [stream:0 fmt:UYVY8_1X16/320x240 field:none colorspace:srgb]
                <- "csi-16000400.csi2":1 [ENABLED,IMMUTABLE]
        pad1: Source
                [stream:0 fmt:UYVY8_1X16/320x240 field:none colorspace:srgb]
                -> "CRU output":0 [ENABLED,IMMUTABLE]

- entity 17: CRU output (1 pad, 1 link)
             type Node subtype V4L flags 0
             device node name /dev/video0
        pad0: Sink
                <- "cru-ip-16000000.video":1 [ENABLED,IMMUTABLE]

root@smarc-rzg3e:~# v4l2-compliance -d /dev/v4l-subdev0
v4l2-compliance 1.26.1-5142, 64 bits, 64-bit time_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38

Compliance test for device /dev/v4l-subdev0:

Driver Info:
        Driver version   : 6.14.0
        Capabil[  101.574758] csi-16000400.csi2: =================  START STATUS  =================
ities     : 0x00[  101.583166] csi-16000400.csi2: ==================  END STATUS  ==================
000000

Required ioctls:
        test VIDIOC_SUDBEV_QUERYCAP: OK
        test invalid ioctls: OK

Allow for multiple opens:
        test second /dev/v4l-subdev0 open: OK
        test VIDIOC_SUBDEV_QUERYCAP: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
        test VIDIOC_QUERYCTRL: OK (Not Supported)
        test VIDIOC_G/S_CTRL: OK (Not Supported)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 0 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test CREATE_BUFS maximum buffers: OK
        test VIDIOC_EXPBUF: OK (Not Supported)
        test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev0: 44, Succeeded: 44, Failed: 0, Warnings: 0

root@smarc-rzg3e:~# v4l2-compliance -d /dev/v4l-subdev1
v4l2-compliance 1.26.1-5142, 64 [  125.542264] ov5645 0-003c: =================  START STATUS  =================
bits, 64-bit tim[  125.550585] ov5645 0-003c: ==================  END STATUS  ==================
e_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38

Compliance test for device /dev/v4l-subdev1:

Driver Info:
        Driver version   : 6.14.0
        Capabilities     : 0x00000000

Required ioctls:
        test VIDIOC_SUDBEV_QUERYCAP: OK
        test invalid ioctls: OK

Allow for multiple opens:
        test second /dev/v4l-subdev1 open: OK
        test VIDIOC_SUBDEV_QUERYCAP: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
        test VIDIOC_QUERYCTRL: OK
        test VIDIOC_G/S_CTRL: OK
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 12 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test CREATE_BUFS maximum buffers: OK
        test VIDIOC_EXPBUF: OK (Not Supported)
        test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev1: 44, Succeeded: 44, Failed: 0, Warnings: 0

root@smarc-rzg3e:~# v4l2-compliance -d /dev/v4l-subdev2
v4l2-compliance 1.26.1-5142, 64 [  139.054132] cru-ip-16000000.video: =================  START STATUS  =================
bits, 64-bit tim[  139.062922] cru-ip-16000000.video: ==================  END STATUS  ==================
e_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38

Compliance test for rzg2l_cru device /dev/v4l-subdev2:

Driver Info:
        Driver version   : 6.14.0
        Capabilities     : 0x00000000
Media Driver Info:
        Driver name      : rzg2l_cru
        Model            : renesas,r9a09g047-cru
        Serial           :
        Bus info         : platform:16000000.video
        Media version    : 6.14.0
        Hardware revision: 0x00000000 (0)
        Driver version   : 6.14.0
Interface Info:
        ID               : 0x0300000f
        Type             : V4L Sub-Device
Entity Info:
        ID               : 0x00000008 (8)
        Name             : cru-ip-16000000.video
        Function         : Video Pixel Formatter
        Pad 0x01000009   : 0: Sink, Must Connect
          Link 0x02000015: from remote pad 0x1000003 of entity 'csi-16000400.csi2' (Video Interface Bridge): Data, Enabled, Immutable
        Pad 0x0100000a   : 1: Source, Must Connect
          Link 0x02000017: to remote pad 0x1000012 of entity 'CRU output' (V4L2 I/O): Data, Enabled, Immutable

Required ioctls:
        test MC information (see 'Media Driver Info' above): OK
        test VIDIOC_SUDBEV_QUERYCAP: OK
        test invalid ioctls: OK

Allow for multiple opens:
        test second /dev/v4l-subdev2 open: OK
        test VIDIOC_SUBDEV_QUERYCAP: OK
        test for unlimited opens: OK

Debug ioctls:
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device ioctls (Sink Pad 0):
        Try Stream 0
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        Active Stream 0
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Sub-Device ioctls (Source Pad 1):
        Try Stream 0
        test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Try VIDIOC_SUBDEV_G/S_FMT: OK
        test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        Active Stream 0
        test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
        test Active VIDIOC_SUBDEV_G/S_FMT: OK
        test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
        test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)

Control ioctls:
        test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
        test VIDIOC_QUERYCTRL: OK (Not Supported)
        test VIDIOC_G/S_CTRL: OK (Not Supported)
        test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
        test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
        test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
        Standard Controls: 0 Private Controls: 0

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK (Not Supported)
        test VIDIOC_TRY_FMT: OK (Not Supported)
        test VIDIOC_S_FMT: OK (Not Supported)
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

Codec ioctls:
        test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
        test VIDIOC_G_ENC_INDEX: OK (Not Supported)
        test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
        test CREATE_BUFS maximum buffers: OK
        test VIDIOC_EXPBUF: OK (Not Supported)
        test Requests: OK (Not Supported)

Total for rzg2l_cru device /dev/v4l-subdev2: 59, Succeeded: 59, Failed: 0, Warnings: 0

Thanks & Regards,
Tommaso

Lad Prabhakar (14):
  media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  media: rzg2l-cru: csi2: Use local variable for struct device in
    rzg2l_csi2_probe()
  media: rzg2l-cru: rzg2l-core: Use local variable for struct device in
    rzg2l_cru_probe()
  media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling
  media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC
  media: rzg2l-cru: csi2: Add support for RZ/V2H(P) SoC
  media: rzg2l-cru: Add register mapping support
  media: rzg2l-cru: Pass resolution limits via OF data
  media: rzg2l-cru: Add image_conv offset to OF data
  media: rzg2l-cru: Add IRQ handler to OF data
  media: rzg2l-cru: Add function pointers to enable and disable
    interrupts
  media: rzg2l-cru: Add function pointer to check if FIFO is empty
  media: rzg2l-cru: Add function pointer to configure CSI
  media: rzg2l-cru: Add support for RZ/G3E SoC

Tommaso Merciai (4):
  media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2
    block
  media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC
  media: rzg2l-cru: csi2: Use devm_pm_runtime_enable()
  media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable()

 .../bindings/media/renesas,rzg2l-cru.yaml     |  65 ++++-
 .../bindings/media/renesas,rzg2l-csi2.yaml    |  62 ++++-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 149 ++++++++--
 .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  90 ++++--
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  44 ++-
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 156 +++++++++--
 .../platform/renesas/rzg2l-cru/rzg2l-ip.c     |  13 +-
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 259 ++++++++++++++++--
 8 files changed, 707 insertions(+), 131 deletions(-)

-- 
2.34.1


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

* [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:08   ` Laurent Pinchart
  2025-02-24 17:25   ` Rob Herring (Arm)
  2025-02-21 15:55 ` [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block Tommaso Merciai
                   ` (16 subsequent siblings)
  17 siblings, 2 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
found on the Renesas RZ/G2L SoC, with the following differences:
- A different D-PHY
- Additional registers for the MIPI CSI-2 link
- Only two clocks

Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
SoC.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Dropped empty line as suggested by LPinchart
 - Fixed minItems into else conditional block as suggested by RHerring

 .../bindings/media/renesas,rzg2l-csi2.yaml    | 59 ++++++++++++++-----
 1 file changed, 44 insertions(+), 15 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
index 7faa12fecd5b..1d7784e8af16 100644
--- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
+++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
@@ -17,12 +17,14 @@ description:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - renesas,r9a07g043-csi2       # RZ/G2UL
-          - renesas,r9a07g044-csi2       # RZ/G2{L,LC}
-          - renesas,r9a07g054-csi2       # RZ/V2L
-      - const: renesas,rzg2l-csi2
+    oneOf:
+      - items:
+          - enum:
+              - renesas,r9a07g043-csi2 # RZ/G2UL
+              - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
+              - renesas,r9a07g054-csi2 # RZ/V2L
+          - const: renesas,rzg2l-csi2
+      - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
 
   reg:
     maxItems: 1
@@ -31,16 +33,24 @@ properties:
     maxItems: 1
 
   clocks:
-    items:
-      - description: Internal clock for connecting CRU and MIPI
-      - description: CRU Main clock
-      - description: CRU Register access clock
+    oneOf:
+      - items:
+          - description: Internal clock for connecting CRU and MIPI
+          - description: CRU Main clock
+          - description: CRU Register access clock
+      - items:
+          - description: CRU Main clock
+          - description: CRU Register access clock
 
   clock-names:
-    items:
-      - const: system
-      - const: video
-      - const: apb
+    oneOf:
+      - items:
+          - const: system
+          - const: video
+          - const: apb
+      - items:
+          - const: video
+          - const: apb
 
   power-domains:
     maxItems: 1
@@ -48,7 +58,7 @@ properties:
   resets:
     items:
       - description: CRU_PRESETN reset terminal
-      - description: CRU_CMN_RSTB reset terminal
+      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
 
   reset-names:
     items:
@@ -101,6 +111,25 @@ required:
   - reset-names
   - ports
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: renesas,r9a09g057-csi2
+    then:
+      properties:
+        clocks:
+          maxItems: 2
+        clock-names:
+          maxItems: 2
+    else:
+      properties:
+        clocks:
+          minItems: 3
+        clock-names:
+          minItems: 3
+
 additionalProperties: false
 
 examples:
-- 
2.34.1


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

* [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:10   ` Laurent Pinchart
  2025-02-23 21:11   ` Lad, Prabhakar
  2025-02-21 15:55 ` [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC Tommaso Merciai
                   ` (15 subsequent siblings)
  17 siblings, 2 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

Document the CSI-2 block which is part of CRU found in Renesas RZ/G3E
SoC.

The CSI-2 block on the RZ/G3E SoC is identical to one found on the
RZ/V2H(P) SoC.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../devicetree/bindings/media/renesas,rzg2l-csi2.yaml          | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
index 1d7784e8af16..9b7ed86ef14b 100644
--- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
+++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
@@ -24,6 +24,9 @@ properties:
               - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
               - renesas,r9a07g054-csi2 # RZ/V2L
           - const: renesas,rzg2l-csi2
+      - items:
+          - const: renesas,r9a09g047-csi2 # RZ/G3E
+          - const: renesas,r9a09g057-csi2
       - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
 
   reg:
-- 
2.34.1


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

* [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-24 17:27   ` Rob Herring (Arm)
  2025-02-21 15:55 ` [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe() Tommaso Merciai
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

The CRU block found on the Renesas RZ/G3E ("R9A09G047") SoC has five
interrupts:

 - image_conv:    image_conv irq
 - axi_mst_err:   AXI master error level irq
 - vd_addr_wend:  Video data AXI master addr 0 write end irq
 - sd_addr_wend:  Statistics data AXI master addr 0 write end irq
 - vsd_addr_wend: Video statistics data AXI master addr 0 write end irq

This IP has only one input port 'port@1' similar to the RZ/G2UL CRU.

Document the CRU block found on the Renesas RZ/G3E ("R9A09G047") SoC.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Use oneOf for interrupts and interrupt-names
 - Handle interrupts and interrupt names base on soc variants.

 .../bindings/media/renesas,rzg2l-cru.yaml     | 65 +++++++++++++++----
 1 file changed, 54 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml
index bc1245127025..47e18690fa57 100644
--- a/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml
+++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-cru.yaml
@@ -17,24 +17,43 @@ description:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - renesas,r9a07g043-cru       # RZ/G2UL
-          - renesas,r9a07g044-cru       # RZ/G2{L,LC}
-          - renesas,r9a07g054-cru       # RZ/V2L
-      - const: renesas,rzg2l-cru
+    oneOf:
+      - items:
+          - enum:
+              - renesas,r9a07g043-cru       # RZ/G2UL
+              - renesas,r9a07g044-cru       # RZ/G2{L,LC}
+              - renesas,r9a07g054-cru       # RZ/V2L
+          - const: renesas,rzg2l-cru
+      - const: renesas,r9a09g047-cru        # RZ/G3E
 
   reg:
     maxItems: 1
 
   interrupts:
-    maxItems: 3
+    oneOf:
+      - items:
+          - description: CRU Interrupt for image_conv
+          - description: CRU Interrupt for image_conv_err
+          - description: CRU AXI master error interrupt
+      - items:
+          - description: CRU Interrupt for image_conv
+          - description: CRU AXI master error interrupt
+          - description: CRU Video Data AXI Master Address 0 Write End interrupt
+          - description: CRU Statistics data AXI master addr 0 write end interrupt
+          - description: CRU Video statistics data AXI master addr 0 write end interrupt
 
   interrupt-names:
-    items:
-      - const: image_conv
-      - const: image_conv_err
-      - const: axi_mst_err
+    oneOf:
+      - items:
+          - const: image_conv
+          - const: image_conv_err
+          - const: axi_mst_err
+      - items:
+          - const: image_conv
+          - const: axi_mst_err
+          - const: vd_addr_wend
+          - const: sd_addr_wend
+          - const: vsd_addr_wend
 
   clocks:
     items:
@@ -109,6 +128,10 @@ allOf:
               - renesas,r9a07g054-cru
     then:
       properties:
+        interrupts:
+          maxItems: 3
+        interrupt-names:
+          maxItems: 3
         ports:
           required:
             - port@0
@@ -122,10 +145,30 @@ allOf:
               - renesas,r9a07g043-cru
     then:
       properties:
+        interrupts:
+          maxItems: 3
+        interrupt-names:
+          maxItems: 3
         ports:
           properties:
             port@0: false
+          required:
+            - port@1
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: renesas,r9a09g047-cru
+    then:
+      properties:
+        interrupts:
+          minItems: 5
+        interrupt-names:
+          minItems: 5
+        ports:
+          properties:
+            port@0: false
           required:
             - port@1
 
-- 
2.34.1


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

* [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe()
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (2 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:13   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable() Tommaso Merciai
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Use a local variable for the struct device pointers. This increases code
readability with shortened lines.

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Fixed commit msg and commit body as suggested by LPinchart
 - Collected tags

 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 31 ++++++++++---------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 881e910dce02..948f1917b830 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -764,10 +764,11 @@ static const struct media_entity_operations rzg2l_csi2_entity_ops = {
 
 static int rzg2l_csi2_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct rzg2l_csi2 *csi2;
 	int ret;
 
-	csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
+	csi2 = devm_kzalloc(dev, sizeof(*csi2), GFP_KERNEL);
 	if (!csi2)
 		return -ENOMEM;
 
@@ -775,28 +776,28 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	if (IS_ERR(csi2->base))
 		return PTR_ERR(csi2->base);
 
-	csi2->cmn_rstb = devm_reset_control_get_exclusive(&pdev->dev, "cmn-rstb");
+	csi2->cmn_rstb = devm_reset_control_get_exclusive(dev, "cmn-rstb");
 	if (IS_ERR(csi2->cmn_rstb))
-		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->cmn_rstb),
+		return dev_err_probe(dev, PTR_ERR(csi2->cmn_rstb),
 				     "Failed to get cpg cmn-rstb\n");
 
-	csi2->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn");
+	csi2->presetn = devm_reset_control_get_shared(dev, "presetn");
 	if (IS_ERR(csi2->presetn))
-		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->presetn),
+		return dev_err_probe(dev, PTR_ERR(csi2->presetn),
 				     "Failed to get cpg presetn\n");
 
-	csi2->sysclk = devm_clk_get(&pdev->dev, "system");
+	csi2->sysclk = devm_clk_get(dev, "system");
 	if (IS_ERR(csi2->sysclk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk),
+		return dev_err_probe(dev, PTR_ERR(csi2->sysclk),
 				     "Failed to get system clk\n");
 
-	csi2->vclk = devm_clk_get(&pdev->dev, "video");
+	csi2->vclk = devm_clk_get(dev, "video");
 	if (IS_ERR(csi2->vclk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->vclk),
+		return dev_err_probe(dev, PTR_ERR(csi2->vclk),
 				     "Failed to get video clock\n");
 	csi2->vclk_rate = clk_get_rate(csi2->vclk);
 
-	csi2->dev = &pdev->dev;
+	csi2->dev = dev;
 
 	platform_set_drvdata(pdev, csi2);
 
@@ -804,18 +805,18 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	pm_runtime_enable(&pdev->dev);
+	pm_runtime_enable(dev);
 
 	ret = rzg2l_validate_csi2_lanes(csi2);
 	if (ret)
 		goto error_pm;
 
-	csi2->subdev.dev = &pdev->dev;
+	csi2->subdev.dev = dev;
 	v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
 	csi2->subdev.internal_ops = &rzg2l_csi2_internal_ops;
-	v4l2_set_subdevdata(&csi2->subdev, &pdev->dev);
+	v4l2_set_subdevdata(&csi2->subdev, dev);
 	snprintf(csi2->subdev.name, sizeof(csi2->subdev.name),
-		 "csi-%s", dev_name(&pdev->dev));
+		 "csi-%s", dev_name(dev));
 	csi2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
@@ -852,7 +853,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	v4l2_async_nf_cleanup(&csi2->notifier);
 	media_entity_cleanup(&csi2->subdev.entity);
 error_pm:
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
 
 	return ret;
 }
-- 
2.34.1


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

* [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable()
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (3 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe() Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 21:13   ` Lad, Prabhakar
  2025-02-21 15:55 ` [PATCH v2 06/18] media: rzg2l-cru: rzg2l-core: Use local variable for struct device in rzg2l_cru_probe() Tommaso Merciai
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Laurent Pinchart,
	Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Use newly added devm_pm_runtime_enable() into rzg2l_csi2_probe() and
drop error path accordingly. Drop also unnecessary pm_runtime_disable()
from rzg2l_csi2_remove().

Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Collected tags

 drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 948f1917b830..4ccf7c5ea58b 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -805,11 +805,13 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
 
 	ret = rzg2l_validate_csi2_lanes(csi2);
 	if (ret)
-		goto error_pm;
+		return ret;
 
 	csi2->subdev.dev = dev;
 	v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
@@ -834,7 +836,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads),
 				     csi2->pads);
 	if (ret)
-		goto error_pm;
+		return ret;
 
 	ret = v4l2_subdev_init_finalize(&csi2->subdev);
 	if (ret < 0)
@@ -852,8 +854,6 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	v4l2_async_nf_unregister(&csi2->notifier);
 	v4l2_async_nf_cleanup(&csi2->notifier);
 	media_entity_cleanup(&csi2->subdev.entity);
-error_pm:
-	pm_runtime_disable(dev);
 
 	return ret;
 }
@@ -867,7 +867,6 @@ static void rzg2l_csi2_remove(struct platform_device *pdev)
 	v4l2_async_unregister_subdev(&csi2->subdev);
 	v4l2_subdev_cleanup(&csi2->subdev);
 	media_entity_cleanup(&csi2->subdev.entity);
-	pm_runtime_disable(&pdev->dev);
 }
 
 static int rzg2l_csi2_pm_runtime_suspend(struct device *dev)
-- 
2.34.1


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

* [PATCH v2 06/18] media: rzg2l-cru: rzg2l-core: Use local variable for struct device in rzg2l_cru_probe()
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (4 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable() Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable() Tommaso Merciai
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Laurent Pinchart, Tommaso Merciai,
	Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Geert Uytterhoeven, Magnus Damm,
	Hans Verkuil, Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Use a local variable for the struct device pointers. This increases code
readability with shortened lines.

Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Fixed commit msg and commit body as suggested by LPinchart
 - Collected tags

 .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 29 ++++++++++---------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 89be584a4988..70fed0ce45ea 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -240,10 +240,11 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
 
 static int rzg2l_cru_probe(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct rzg2l_cru_dev *cru;
 	int irq, ret;
 
-	cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL);
+	cru = devm_kzalloc(dev, sizeof(*cru), GFP_KERNEL);
 	if (!cru)
 		return -ENOMEM;
 
@@ -251,32 +252,32 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 	if (IS_ERR(cru->base))
 		return PTR_ERR(cru->base);
 
-	cru->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn");
+	cru->presetn = devm_reset_control_get_shared(dev, "presetn");
 	if (IS_ERR(cru->presetn))
-		return dev_err_probe(&pdev->dev, PTR_ERR(cru->presetn),
+		return dev_err_probe(dev, PTR_ERR(cru->presetn),
 				     "Failed to get cpg presetn\n");
 
-	cru->aresetn = devm_reset_control_get_exclusive(&pdev->dev, "aresetn");
+	cru->aresetn = devm_reset_control_get_exclusive(dev, "aresetn");
 	if (IS_ERR(cru->aresetn))
-		return dev_err_probe(&pdev->dev, PTR_ERR(cru->aresetn),
+		return dev_err_probe(dev, PTR_ERR(cru->aresetn),
 				     "Failed to get cpg aresetn\n");
 
-	cru->vclk = devm_clk_get(&pdev->dev, "video");
+	cru->vclk = devm_clk_get(dev, "video");
 	if (IS_ERR(cru->vclk))
-		return dev_err_probe(&pdev->dev, PTR_ERR(cru->vclk),
+		return dev_err_probe(dev, PTR_ERR(cru->vclk),
 				     "Failed to get video clock\n");
 
-	cru->dev = &pdev->dev;
-	cru->info = of_device_get_match_data(&pdev->dev);
+	cru->dev = dev;
+	cru->info = of_device_get_match_data(dev);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 		return irq;
 
-	ret = devm_request_irq(&pdev->dev, irq, rzg2l_cru_irq, 0,
+	ret = devm_request_irq(dev, irq, rzg2l_cru_irq, 0,
 			       KBUILD_MODNAME, cru);
 	if (ret)
-		return dev_err_probe(&pdev->dev, ret, "failed to request irq\n");
+		return dev_err_probe(dev, ret, "failed to request irq\n");
 
 	platform_set_drvdata(pdev, cru);
 
@@ -285,8 +286,8 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 		return ret;
 
 	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
-	pm_suspend_ignore_children(&pdev->dev, true);
-	pm_runtime_enable(&pdev->dev);
+	pm_suspend_ignore_children(dev, true);
+	pm_runtime_enable(dev);
 
 	ret = rzg2l_cru_media_init(cru);
 	if (ret)
@@ -296,7 +297,7 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 
 error_dma_unregister:
 	rzg2l_cru_dma_unregister(cru);
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
 
 	return ret;
 }
-- 
2.34.1


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

* [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable()
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (5 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 06/18] media: rzg2l-cru: rzg2l-core: Use local variable for struct device in rzg2l_cru_probe() Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:14   ` Laurent Pinchart
  2025-02-23 21:14   ` Lad, Prabhakar
  2025-02-21 15:55 ` [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling Tommaso Merciai
                   ` (10 subsequent siblings)
  17 siblings, 2 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Use newly added devm_pm_runtime_enable() into rzg2l_cru_probe() and
drop unnecessary pm_runtime_disable() from rzg2l_cru_probe() and
rzg2l_csi2_remove().

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
Changes since v1:
 - Fixed DMA leak as suggested by LPinchart
 - Collected tags

 drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 70fed0ce45ea..eed9d2bd0841 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -287,7 +287,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 
 	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
 	pm_suspend_ignore_children(dev, true);
-	pm_runtime_enable(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		goto error_dma_unregister;
 
 	ret = rzg2l_cru_media_init(cru);
 	if (ret)
@@ -297,7 +299,6 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 
 error_dma_unregister:
 	rzg2l_cru_dma_unregister(cru);
-	pm_runtime_disable(dev);
 
 	return ret;
 }
@@ -306,8 +307,6 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
 {
 	struct rzg2l_cru_dev *cru = platform_get_drvdata(pdev);
 
-	pm_runtime_disable(&pdev->dev);
-
 	v4l2_async_nf_unregister(&cru->notifier);
 	v4l2_async_nf_cleanup(&cru->notifier);
 
-- 
2.34.1


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

* [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (6 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable() Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:17   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC Tommaso Merciai
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

In preparation for adding support for the RZ/V2H(P) SoC, where the D-PHY
differs from the existing RZ/G2L implementation, introduce a new
rzg2l_csi2_info structure. This structure provides function pointers for
SoC-specific D-PHY enable and disable operations.

Modify rzg2l_csi2_dphy_setting() to use these function pointers instead of
calling rzg2l_csi2_dphy_enable() and rzg2l_csi2_dphy_disable() directly.
Update the device match table to store the appropriate function pointers
for each compatible SoC.

This change prepares the driver for future extensions without affecting
the current functionality for RZ/G2L.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 24 ++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 4ccf7c5ea58b..3a4e720ba732 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -107,6 +107,7 @@ struct rzg2l_csi2 {
 	void __iomem *base;
 	struct reset_control *presetn;
 	struct reset_control *cmn_rstb;
+	const struct rzg2l_csi2_info *info;
 	struct clk *sysclk;
 	struct clk *vclk;
 	unsigned long vclk_rate;
@@ -123,6 +124,11 @@ struct rzg2l_csi2 {
 	bool dphy_enabled;
 };
 
+struct rzg2l_csi2_info {
+	int (*dphy_enable)(struct rzg2l_csi2 *csi2);
+	int (*dphy_disable)(struct rzg2l_csi2 *csi2);
+};
+
 struct rzg2l_csi2_timings {
 	u32 t_init;
 	u32 tclk_miss;
@@ -360,9 +366,9 @@ static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on)
 	struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
 
 	if (on)
-		return rzg2l_csi2_dphy_enable(csi2);
+		return csi2->info->dphy_enable(csi2);
 
-	return rzg2l_csi2_dphy_disable(csi2);
+	return csi2->info->dphy_disable(csi2);
 }
 
 static int rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
@@ -772,6 +778,10 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 	if (!csi2)
 		return -ENOMEM;
 
+	csi2->info = of_device_get_match_data(dev);
+	if (!csi2->info)
+		return dev_err_probe(dev, -EINVAL, "Failed to get OF match data\n");
+
 	csi2->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(csi2->base))
 		return PTR_ERR(csi2->base);
@@ -890,8 +900,16 @@ static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
 		       rzg2l_csi2_pm_runtime_resume, NULL)
 };
 
+static const struct rzg2l_csi2_info rzg2l_csi2_info = {
+	.dphy_enable = rzg2l_csi2_dphy_enable,
+	.dphy_disable = rzg2l_csi2_dphy_disable,
+};
+
 static const struct of_device_id rzg2l_csi2_of_table[] = {
-	{ .compatible = "renesas,rzg2l-csi2", },
+	{
+		.compatible = "renesas,rzg2l-csi2",
+		.data = &rzg2l_csi2_info,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table);
-- 
2.34.1


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

* [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (7 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:19   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support " Tommaso Merciai
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The RZ/V2H(P) SoC does not provide a `system` clock for the CSI-2
interface. To accommodate this, use `devm_clk_get_optional()` instead
of `devm_clk_get()` when retrieving the clock.

This patch is in preparation for adding support for RZ/V2H(P) SoC.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 3a4e720ba732..771fa35558be 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -796,7 +796,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, PTR_ERR(csi2->presetn),
 				     "Failed to get cpg presetn\n");
 
-	csi2->sysclk = devm_clk_get(dev, "system");
+	csi2->sysclk = devm_clk_get_optional(dev, "system");
 	if (IS_ERR(csi2->sysclk))
 		return dev_err_probe(dev, PTR_ERR(csi2->sysclk),
 				     "Failed to get system clk\n");
-- 
2.34.1


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

* [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support for RZ/V2H(P) SoC
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (8 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 18:24   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support Tommaso Merciai
                   ` (7 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The D-PHY on the RZ/V2H(P) SoC is different from the D-PHY on the RZ/G2L
SoC. To handle this difference, function pointers for D-PHY enable/disable
have been added, and the `struct rzg2l_csi2_info` pointer is passed as OF
data.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 771fa35558be..cd452c84f101 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -85,6 +85,15 @@
 					 CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(1) | \
 					 CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(1))
 
+/* DPHY registers on RZ/V2H(P) SoC */
+#define CRUm_S_TIMCTL			0x41c
+#define CRUm_S_TIMCTL_S_HSSETTLECTL(x)	((x) << 8)
+
+#define CRUm_S_DPHYCTL_MSB		0x434
+#define CRUm_S_DPHYCTL_MSB_DESKEW	BIT(1)
+
+#define CRUm_SWAPCTL			0x438
+
 #define VSRSTS_RETRIES			20
 
 #define RZG2L_CSI2_MIN_WIDTH		320
@@ -139,6 +148,30 @@ struct rzg2l_csi2_timings {
 	u32 max_hsfreq;
 };
 
+struct rzv2h_csi2_s_hssettlectl {
+	unsigned int hsfreq;
+	u16 s_hssettlectl;
+};
+
+static const struct rzv2h_csi2_s_hssettlectl rzv2h_s_hssettlectl[] = {
+	{   90,  1 }, {  130,  2 }, {  180,  3 },
+	{  220,  4 }, {  270,  5 }, {  310,  6 },
+	{  360,  7 }, {  400,  8 }, {  450,  9 },
+	{  490, 10 }, {  540, 11 }, {  580, 12 },
+	{  630, 13 }, {  670, 14 }, {  720, 15 },
+	{  760, 16 }, {  810, 17 }, {  850, 18 },
+	{  900, 19 }, {  940, 20 }, {  990, 21 },
+	{ 1030, 22 }, { 1080, 23 }, { 1120, 24 },
+	{ 1170, 25 }, { 1220, 26 }, { 1260, 27 },
+	{ 1310, 28 }, { 1350, 29 }, { 1400, 30 },
+	{ 1440, 31 }, { 1490, 32 }, { 1530, 33 },
+	{ 1580, 34 }, { 1620, 35 }, { 1670, 36 },
+	{ 1710, 37 }, { 1760, 38 }, { 1800, 39 },
+	{ 1850, 40 }, { 1890, 41 }, { 1940, 42 },
+	{ 1980, 43 }, { 2030, 44 }, { 2070, 45 },
+	{ 2100, 46 },
+};
+
 static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = {
 	{
 		.max_hsfreq = 80,
@@ -427,6 +460,58 @@ static int rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
 	return 0;
 }
 
+static int rzv2h_csi2_dphy_disable(struct rzg2l_csi2 *csi2)
+{
+	int ret;
+
+	/* Reset the CRU (D-PHY) */
+	ret = reset_control_assert(csi2->cmn_rstb);
+	if (ret)
+		return ret;
+
+	csi2->dphy_enabled = false;
+
+	return 0;
+}
+
+static int rzv2h_csi2_dphy_enable(struct rzg2l_csi2 *csi2)
+{
+	unsigned int i;
+	u16 hssettle;
+	int mbps;
+
+	mbps = rzg2l_csi2_calc_mbps(csi2);
+	if (mbps < 0)
+		return mbps;
+
+	csi2->hsfreq = mbps;
+
+	rzg2l_csi2_write(csi2, CRUm_SWAPCTL, 0);
+
+	for (i = 0; i < ARRAY_SIZE(rzv2h_s_hssettlectl); i++) {
+		if (csi2->hsfreq <= rzv2h_s_hssettlectl[i].hsfreq)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(rzv2h_s_hssettlectl))
+		return -EINVAL;
+
+	hssettle = rzv2h_s_hssettlectl[i].s_hssettlectl;
+	rzg2l_csi2_write(csi2, CRUm_S_TIMCTL,
+			 CRUm_S_TIMCTL_S_HSSETTLECTL(hssettle));
+
+	if (csi2->hsfreq > 1500)
+		rzg2l_csi2_set(csi2, CRUm_S_DPHYCTL_MSB,
+			       CRUm_S_DPHYCTL_MSB_DESKEW);
+	else
+		rzg2l_csi2_clr(csi2, CRUm_S_DPHYCTL_MSB,
+			       CRUm_S_DPHYCTL_MSB_DESKEW);
+
+	csi2->dphy_enabled = true;
+
+	return 0;
+}
+
 static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on)
 {
 	struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
@@ -900,12 +985,21 @@ static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
 		       rzg2l_csi2_pm_runtime_resume, NULL)
 };
 
+static const struct rzg2l_csi2_info rzv2h_csi2_info = {
+	.dphy_enable = rzv2h_csi2_dphy_enable,
+	.dphy_disable = rzv2h_csi2_dphy_disable,
+};
+
 static const struct rzg2l_csi2_info rzg2l_csi2_info = {
 	.dphy_enable = rzg2l_csi2_dphy_enable,
 	.dphy_disable = rzg2l_csi2_dphy_disable,
 };
 
 static const struct of_device_id rzg2l_csi2_of_table[] = {
+	{
+		.compatible = "renesas,r9a09g057-csi2",
+		.data = &rzv2h_csi2_info,
+	},
 	{
 		.compatible = "renesas,rzg2l-csi2",
 		.data = &rzg2l_csi2_info,
-- 
2.34.1


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

* [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (9 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support " Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 19:52   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data Tommaso Merciai
                   ` (6 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Prepare for adding support for RZ/G3E and RZ/V2HP SoCs, which have a
CRU-IP that is mostly identical to RZ/G2L but with different register
offsets and additional registers. Introduce a flexible register mapping
mechanism to handle these variations.

Define the `rzg2l_cru_info` structure to store register mappings and
pass it as part of the OF match data. Update the read/write functions
to use indexed register offsets from `rzg2l_cru_info`, ensuring
compatibility across different SoC variants.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 46 ++++++++++++-
 .../renesas/rzg2l-cru/rzg2l-cru-regs.h        | 65 ++++++++++---------
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 12 ++--
 4 files changed, 92 insertions(+), 35 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index eed9d2bd0841..abc2a979833a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -22,6 +22,7 @@
 #include <media/v4l2-mc.h>
 
 #include "rzg2l-cru.h"
+#include "rzg2l-cru-regs.h"
 
 static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
 {
@@ -269,6 +270,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 
 	cru->dev = dev;
 	cru->info = of_device_get_match_data(dev);
+	if (!cru->info)
+		return dev_err_probe(dev, -EINVAL,
+				     "Failed to get OF match data\n");
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -317,8 +321,48 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
 	rzg2l_cru_dma_unregister(cru);
 }
 
+static const u16 rzg2l_cru_regs[] = {
+	[CRUnCTRL] = 0x0,
+	[CRUnIE] = 0x4,
+	[CRUnINTS] = 0x8,
+	[CRUnRST] = 0xc,
+	[AMnMB1ADDRL] = 0x100,
+	[AMnMB1ADDRH] = 0x104,
+	[AMnMB2ADDRL] = 0x108,
+	[AMnMB2ADDRH] = 0x10c,
+	[AMnMB3ADDRL] = 0x110,
+	[AMnMB3ADDRH] = 0x114,
+	[AMnMB4ADDRL] = 0x118,
+	[AMnMB4ADDRH] = 0x11c,
+	[AMnMB5ADDRL] = 0x120,
+	[AMnMB5ADDRH] = 0x124,
+	[AMnMB6ADDRL] = 0x128,
+	[AMnMB6ADDRH] = 0x12c,
+	[AMnMB7ADDRL] = 0x130,
+	[AMnMB7ADDRH] = 0x134,
+	[AMnMB8ADDRL] = 0x138,
+	[AMnMB8ADDRH] = 0x13c,
+	[AMnMBVALID] = 0x148,
+	[AMnMBS] = 0x14c,
+	[AMnAXIATTR] = 0x158,
+	[AMnFIFOPNTR] = 0x168,
+	[AMnAXISTP] = 0x174,
+	[AMnAXISTPACK] = 0x178,
+	[ICnEN] = 0x200,
+	[ICnMC] = 0x208,
+	[ICnMS] = 0x254,
+	[ICnDMR] = 0x26c,
+};
+
+static const struct rzg2l_cru_info rzgl2_cru_info = {
+	.regs = rzg2l_cru_regs,
+};
+
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
-	{ .compatible = "renesas,rzg2l-cru", },
+	{
+		.compatible = "renesas,rzg2l-cru",
+		.data = &rzgl2_cru_info,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
index 1c9f22118a5d..82920db7134e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -10,71 +10,76 @@
 
 /* HW CRU Registers Definition */
 
-/* CRU Control Register */
-#define CRUnCTRL			0x0
 #define CRUnCTRL_VINSEL(x)		((x) << 0)
 
-/* CRU Interrupt Enable Register */
-#define CRUnIE				0x4
 #define CRUnIE_EFE			BIT(17)
 
-/* CRU Interrupt Status Register */
-#define CRUnINTS			0x8
 #define CRUnINTS_SFS			BIT(16)
 
-/* CRU Reset Register */
-#define CRUnRST				0xc
 #define CRUnRST_VRESETN			BIT(0)
 
 /* Memory Bank Base Address (Lower) Register for CRU Image Data */
-#define AMnMBxADDRL(x)			(0x100 + ((x) * 8))
+#define AMnMBxADDRL(base, x)		((base) + (x) * 2)
 
 /* Memory Bank Base Address (Higher) Register for CRU Image Data */
-#define AMnMBxADDRH(x)			(0x104 + ((x) * 8))
+#define AMnMBxADDRH(base, x)		AMnMBxADDRL(base, x)
 
-/* Memory Bank Enable Register for CRU Image Data */
-#define AMnMBVALID			0x148
 #define AMnMBVALID_MBVALID(x)		GENMASK(x, 0)
 
-/* Memory Bank Status Register for CRU Image Data */
-#define AMnMBS				0x14c
 #define AMnMBS_MBSTS			0x7
 
-/* AXI Master Transfer Setting Register for CRU Image Data */
-#define AMnAXIATTR			0x158
 #define AMnAXIATTR_AXILEN_MASK		GENMASK(3, 0)
 #define AMnAXIATTR_AXILEN		(0xf)
 
-/* AXI Master FIFO Pointer Register for CRU Image Data */
-#define AMnFIFOPNTR			0x168
 #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
 #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
 
-/* AXI Master Transfer Stop Register for CRU Image Data */
-#define AMnAXISTP			0x174
 #define AMnAXISTP_AXI_STOP		BIT(0)
 
-/* AXI Master Transfer Stop Status Register for CRU Image Data */
-#define AMnAXISTPACK			0x178
 #define AMnAXISTPACK_AXI_STOP_ACK	BIT(0)
 
-/* CRU Image Processing Enable Register */
-#define ICnEN				0x200
 #define ICnEN_ICEN			BIT(0)
 
-/* CRU Image Processing Main Control Register */
-#define ICnMC				0x208
 #define ICnMC_CSCTHR			BIT(5)
 #define ICnMC_INF(x)			((x) << 16)
 #define ICnMC_VCSEL(x)			((x) << 22)
 #define ICnMC_INF_MASK			GENMASK(21, 16)
 
-/* CRU Module Status Register */
-#define ICnMS				0x254
 #define ICnMS_IA			BIT(2)
 
-/* CRU Data Output Mode Register */
-#define ICnDMR				0x26c
 #define ICnDMR_YCMODE_UYVY		(1 << 4)
 
+enum rzg2l_cru_common_regs {
+	CRUnCTRL,	/* CRU Control */
+	CRUnIE,		/* CRU Interrupt Enable */
+	CRUnINTS,	/* CRU Interrupt Status */
+	CRUnRST, 	/* CRU Reset */
+	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
+	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
+	AMnMB2ADDRL,    /* Bank 2 Address (Lower) for CRU Image Data */
+	AMnMB2ADDRH,    /* Bank 2 Address (Higher) for CRU Image Data */
+	AMnMB3ADDRL,    /* Bank 3 Address (Lower) for CRU Image Data */
+	AMnMB3ADDRH,    /* Bank 3 Address (Higher) for CRU Image Data */
+	AMnMB4ADDRL,    /* Bank 4 Address (Lower) for CRU Image Data */
+	AMnMB4ADDRH,    /* Bank 4 Address (Higher) for CRU Image Data */
+	AMnMB5ADDRL,    /* Bank 5 Address (Lower) for CRU Image Data */
+	AMnMB5ADDRH,    /* Bank 5 Address (Higher) for CRU Image Data */
+	AMnMB6ADDRL,    /* Bank 6 Address (Lower) for CRU Image Data */
+	AMnMB6ADDRH,    /* Bank 6 Address (Higher) for CRU Image Data */
+	AMnMB7ADDRL,    /* Bank 7 Address (Lower) for CRU Image Data */
+	AMnMB7ADDRH,    /* Bank 7 Address (Higher) for CRU Image Data */
+	AMnMB8ADDRL,    /* Bank 8 Address (Lower) for CRU Image Data */
+	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
+	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
+	AMnMBS,		/* Memory Bank Status for CRU Image Data */
+	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
+	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
+	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
+	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
+	ICnEN,		/* CRU Image Processing Enable */
+	ICnMC,		/* CRU Image Processing Main Control */
+	ICnMS,		/* CRU Module Status */
+	ICnDMR,		/* CRU Data Output Mode */
+};
+
 #endif /* __RZG2L_CRU_REGS_H__ */
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 8b898ce05b84..00c3f7458e20 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -80,6 +80,10 @@ struct rzg2l_cru_ip_format {
 	bool yuv;
 };
 
+struct rzg2l_cru_info {
+	const u16 *regs;
+};
+
 /**
  * struct rzg2l_cru_dev - Renesas CRU device structure
  * @dev:		(OF) device
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index cd69c8a686d3..f25fd9b35c55 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -44,12 +44,16 @@ struct rzg2l_cru_buffer {
  */
 static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
 {
-	iowrite32(value, cru->base + offset);
+	const u16 *regs = cru->info->regs;
+
+	iowrite32(value, cru->base + regs[offset]);
 }
 
 static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
 {
-	return ioread32(cru->base + offset);
+	const u16 *regs = cru->info->regs;
+
+	return ioread32(cru->base + regs[offset]);
 }
 
 /* Need to hold qlock before calling */
@@ -132,8 +136,8 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
 		return;
 
 	/* Currently, we just use the buffer in 32 bits address */
-	rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
-	rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
+	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
+	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
 }
 
 /*
-- 
2.34.1


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

* [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (10 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 19:54   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 13/18] media: rzg2l-cru: Add image_conv offset to " Tommaso Merciai
                   ` (5 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Pass `max_width` and `max_height` as part of the OF data to facilitate the
addition of support for RZ/G3E and RZ/V2H(P) SoCs. These SoCs have a
maximum resolution of 4096x4096 as compared to 2800x4095 on RZ/G2L SoC.
This change prepares the driver for easier integration of these SoCs by
defining the resolution limits in the `rzg2l_cru_info` structure.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../media/platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 ++
 .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++--
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c | 13 +++++++++----
 .../media/platform/renesas/rzg2l-cru/rzg2l-video.c  |  5 +++--
 4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index abc2a979833a..19f93b7fe6fb 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -355,6 +355,8 @@ static const u16 rzg2l_cru_regs[] = {
 };
 
 static const struct rzg2l_cru_info rzgl2_cru_info = {
+	.max_width = 2800,
+	.max_height = 4095,
 	.regs = rzg2l_cru_regs,
 };
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 00c3f7458e20..6a621073948a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -27,9 +27,7 @@
 #define RZG2L_CRU_CSI2_VCHANNEL		4
 
 #define RZG2L_CRU_MIN_INPUT_WIDTH	320
-#define RZG2L_CRU_MAX_INPUT_WIDTH	2800
 #define RZG2L_CRU_MIN_INPUT_HEIGHT	240
-#define RZG2L_CRU_MAX_INPUT_HEIGHT	4095
 
 enum rzg2l_csi2_pads {
 	RZG2L_CRU_IP_SINK = 0,
@@ -81,6 +79,8 @@ struct rzg2l_cru_ip_format {
 };
 
 struct rzg2l_cru_info {
+	unsigned int max_width;
+	unsigned int max_height;
 	const u16 *regs;
 };
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
index 76a2b451f1da..7836c7cd53dc 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
@@ -148,6 +148,8 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
 				   struct v4l2_subdev_state *state,
 				   struct v4l2_subdev_format *fmt)
 {
+	struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
+	const struct rzg2l_cru_info *info = cru->info;
 	struct v4l2_mbus_framefmt *src_format;
 	struct v4l2_mbus_framefmt *sink_format;
 
@@ -170,9 +172,9 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
 	sink_format->ycbcr_enc = fmt->format.ycbcr_enc;
 	sink_format->quantization = fmt->format.quantization;
 	sink_format->width = clamp_t(u32, fmt->format.width,
-				     RZG2L_CRU_MIN_INPUT_WIDTH, RZG2L_CRU_MAX_INPUT_WIDTH);
+				     RZG2L_CRU_MIN_INPUT_WIDTH, info->max_width);
 	sink_format->height = clamp_t(u32, fmt->format.height,
-				      RZG2L_CRU_MIN_INPUT_HEIGHT, RZG2L_CRU_MAX_INPUT_HEIGHT);
+				      RZG2L_CRU_MIN_INPUT_HEIGHT, info->max_height);
 
 	fmt->format = *sink_format;
 
@@ -197,6 +199,9 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
 					struct v4l2_subdev_state *state,
 					struct v4l2_subdev_frame_size_enum *fse)
 {
+	struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
+	const struct rzg2l_cru_info *info = cru->info;
+
 	if (fse->index != 0)
 		return -EINVAL;
 
@@ -205,8 +210,8 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
 
 	fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
 	fse->min_height = RZG2L_CRU_MIN_INPUT_HEIGHT;
-	fse->max_width = RZG2L_CRU_MAX_INPUT_WIDTH;
-	fse->max_height = RZG2L_CRU_MAX_INPUT_HEIGHT;
+	fse->max_width = info->max_width;
+	fse->max_height = info->max_height;
 
 	return 0;
 }
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index f25fd9b35c55..9e5e79c6ca98 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -690,6 +690,7 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
 static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
 				   struct v4l2_pix_format *pix)
 {
+	const struct rzg2l_cru_info *info = cru->info;
 	const struct rzg2l_cru_ip_format *fmt;
 
 	fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
@@ -712,8 +713,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
 	}
 
 	/* Limit to CRU capabilities */
-	v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1,
-			      &pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0);
+	v4l_bound_align_image(&pix->width, 320, info->max_width, 1,
+			      &pix->height, 240, info->max_height, 2, 0);
 
 	pix->bytesperline = pix->width * fmt->bpp;
 	pix->sizeimage = pix->bytesperline * pix->height;
-- 
2.34.1


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

* [PATCH v2 13/18] media: rzg2l-cru: Add image_conv offset to OF data
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (11 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler " Tommaso Merciai
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, Sakari Ailus, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add `image_conv` field to the `rzg2l_cru_info` structure to store the
register offset for image conversion control. RZ/G2L uses `ICnMC`, while
RZ/G3E and RZ/V2H(P) use `ICnIPMC_C0`.

Update `rzg2l_cru_initialize_image_conv()` and `rzg2l_cru_csi2_setup()`
to use this `image_conv` offset from the OF data, facilitating future
support for RZ/G3E and RZ/V2H(P) SoCs.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../media/platform/renesas/rzg2l-cru/rzg2l-core.c  |  1 +
 .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h   |  1 +
 .../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 14 ++++++++------
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 19f93b7fe6fb..7e94ae803967 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -357,6 +357,7 @@ static const u16 rzg2l_cru_regs[] = {
 static const struct rzg2l_cru_info rzgl2_cru_info = {
 	.max_width = 2800,
 	.max_height = 4095,
+	.image_conv = ICnMC,
 	.regs = rzg2l_cru_regs,
 };
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 6a621073948a..ca156772b949 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -81,6 +81,7 @@ struct rzg2l_cru_ip_format {
 struct rzg2l_cru_info {
 	unsigned int max_width;
 	unsigned int max_height;
+	u16 image_conv;
 	const u16 *regs;
 };
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 9e5e79c6ca98..022da19dd88a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -200,20 +200,22 @@ static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
 				 const struct rzg2l_cru_ip_format *ip_fmt,
 				 u8 csi_vc)
 {
+	const struct rzg2l_cru_info *info = cru->info;
 	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
 
-	icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK);
+	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
 
 	/* Set virtual channel CSI2 */
 	icnmc |= ICnMC_VCSEL(csi_vc);
 
-	rzg2l_cru_write(cru, ICnMC, icnmc);
+	rzg2l_cru_write(cru, info->image_conv, icnmc);
 }
 
 static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
 					   struct v4l2_mbus_framefmt *ip_sd_fmt,
 					   u8 csi_vc)
 {
+	const struct rzg2l_cru_info *info = cru->info;
 	const struct rzg2l_cru_ip_format *cru_video_fmt;
 	const struct rzg2l_cru_ip_format *cru_ip_fmt;
 
@@ -230,11 +232,11 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
 
 	/* If input and output use same colorspace, do bypass mode */
 	if (cru_ip_fmt->yuv == cru_video_fmt->yuv)
-		rzg2l_cru_write(cru, ICnMC,
-				rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR);
+		rzg2l_cru_write(cru, info->image_conv,
+				rzg2l_cru_read(cru, info->image_conv) | ICnMC_CSCTHR);
 	else
-		rzg2l_cru_write(cru, ICnMC,
-				rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR));
+		rzg2l_cru_write(cru, info->image_conv,
+				rzg2l_cru_read(cru, info->image_conv) & (~ICnMC_CSCTHR));
 
 	/* Set output data format */
 	rzg2l_cru_write(cru, ICnDMR, cru_video_fmt->icndmr);
-- 
2.34.1


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

* [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler to OF data
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (12 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 13/18] media: rzg2l-cru: Add image_conv offset to " Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 19:55   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts Tommaso Merciai
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add `irq_handler` to the `rzg2l_cru_info` structure and pass it as part of
the OF data. This prepares for supporting RZ/G3E and RZ/V2H(P) SoCs, which
require a different IRQ handler. Update the IRQ request code to use the
handler from the OF data.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 3 ++-
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h  | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 7e94ae803967..510e55496e8e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -278,7 +278,7 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
-	ret = devm_request_irq(dev, irq, rzg2l_cru_irq, 0,
+	ret = devm_request_irq(dev, irq, cru->info->irq_handler, 0,
 			       KBUILD_MODNAME, cru);
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to request irq\n");
@@ -359,6 +359,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
 	.max_height = 4095,
 	.image_conv = ICnMC,
 	.regs = rzg2l_cru_regs,
+	.irq_handler = rzg2l_cru_irq,
 };
 
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index ca156772b949..32bea35c8c1f 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -83,6 +83,7 @@ struct rzg2l_cru_info {
 	unsigned int max_height;
 	u16 image_conv;
 	const u16 *regs;
+	irqreturn_t (*irq_handler)(int irq, void *data);
 };
 
 /**
-- 
2.34.1


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

* [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (13 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler " Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 19:56   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty Tommaso Merciai
                   ` (2 subsequent siblings)
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, Sakari Ailus, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add `enable_interrupts` and `disable_interrupts` function pointers to the
`rzg2l_cru_info` structure and pass them as part of the OF data. This
prepares for supporting RZ/G3E and RZ/V2H(P) SoCs, which require different
interrupt configurations.

Implement `rzg2l_cru_enable_interrupts()` and
`rzg2l_cru_disable_interrupts()` functions and update the code to use them
instead of directly writing to interrupt registers.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 ++
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  7 +++++++
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 19 ++++++++++++++-----
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 510e55496e8e..302f792cb415 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -360,6 +360,8 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
 	.image_conv = ICnMC,
 	.regs = rzg2l_cru_regs,
 	.irq_handler = rzg2l_cru_irq,
+	.enable_interrupts = rzg2l_cru_enable_interrupts,
+	.disable_interrupts = rzg2l_cru_disable_interrupts,
 };
 
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 32bea35c8c1f..3f694044d8cd 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -34,6 +34,8 @@ enum rzg2l_csi2_pads {
 	RZG2L_CRU_IP_SOURCE,
 };
 
+struct rzg2l_cru_dev;
+
 /**
  * enum rzg2l_cru_dma_state - DMA states
  * @RZG2L_CRU_DMA_STOPPED:   No operation in progress
@@ -84,6 +86,8 @@ struct rzg2l_cru_info {
 	u16 image_conv;
 	const u16 *regs;
 	irqreturn_t (*irq_handler)(int irq, void *data);
+	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
+	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
 };
 
 /**
@@ -178,4 +182,7 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code);
 const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format);
 const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
 
+void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
+
 #endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 022da19dd88a..5ffa3173af62 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -254,8 +254,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
 	spin_lock_irqsave(&cru->qlock, flags);
 
 	/* Disable and clear the interrupt */
-	rzg2l_cru_write(cru, CRUnIE, 0);
-	rzg2l_cru_write(cru, CRUnINTS, 0x001F0F0F);
+	cru->info->disable_interrupts(cru);
 
 	/* Stop the operation of image conversion */
 	rzg2l_cru_write(cru, ICnEN, 0);
@@ -347,6 +346,17 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
 	return fd.entry[0].bus.csi2.vc;
 }
 
+void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
+{
+	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
+}
+
+void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
+{
+	rzg2l_cru_write(cru, CRUnIE, 0);
+	rzg2l_cru_write(cru, CRUnINTS, 0x001f000f);
+}
+
 int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 {
 	struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
@@ -368,8 +378,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 	rzg2l_cru_write(cru, CRUnRST, CRUnRST_VRESETN);
 
 	/* Disable and clear the interrupt before using */
-	rzg2l_cru_write(cru, CRUnIE, 0);
-	rzg2l_cru_write(cru, CRUnINTS, 0x001f000f);
+	cru->info->disable_interrupts(cru);
 
 	/* Initialize the AXI master */
 	rzg2l_cru_initialize_axi(cru);
@@ -382,7 +391,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 	}
 
 	/* Enable interrupt */
-	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
+	cru->info->enable_interrupts(cru);
 
 	/* Enable image processing reception */
 	rzg2l_cru_write(cru, ICnEN, ICnEN_ICEN);
-- 
2.34.1


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

* [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (14 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 20:00   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI Tommaso Merciai
  2025-02-21 15:55 ` [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC Tommaso Merciai
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, Sakari Ailus, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add a `fifo_empty` function pointer to the `rzg2l_cru_info` structure and
pass it as part of the OF data. On RZ/G3E and RZ/V2H(P) SoCs, checking if
the FIFO is empty requires a different register configuration.

Implement `rzg2l_fifo_empty()` and update the code to use it from the
function pointer.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  1 +
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  3 +++
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 23 +++++++++++++------
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 302f792cb415..e4fb3e12d6bf 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -362,6 +362,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
 	.irq_handler = rzg2l_cru_irq,
 	.enable_interrupts = rzg2l_cru_enable_interrupts,
 	.disable_interrupts = rzg2l_cru_disable_interrupts,
+	.fifo_empty = rzg2l_fifo_empty,
 };
 
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 3f694044d8cd..2e17bfef43ce 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -88,6 +88,7 @@ struct rzg2l_cru_info {
 	irqreturn_t (*irq_handler)(int irq, void *data);
 	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
 	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
+	bool (*fifo_empty)(struct rzg2l_cru_dev *cru);
 };
 
 /**
@@ -185,4 +186,6 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
 void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
 
+bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
+
 #endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 5ffa3173af62..7cc83486ce03 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -244,9 +244,23 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
 	return 0;
 }
 
-void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
+bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
 {
 	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
+
+	amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
+
+	amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR;
+	amnfifopntr_r_y =
+		(amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16;
+	if (amnfifopntr_w == amnfifopntr_r_y)
+		return true;
+
+	return false;
+}
+
+void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
+{
 	unsigned int retries = 0;
 	unsigned long flags;
 	u32 icnms;
@@ -274,12 +288,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
 
 	/* Wait until the FIFO becomes empty */
 	for (retries = 5; retries > 0; retries--) {
-		amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
-
-		amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR;
-		amnfifopntr_r_y =
-			(amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16;
-		if (amnfifopntr_w == amnfifopntr_r_y)
+		if (cru->info->fifo_empty(cru))
 			break;
 
 		usleep_range(10, 20);
-- 
2.34.1


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

* [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (15 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 20:03   ` Laurent Pinchart
  2025-02-21 15:55 ` [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC Tommaso Merciai
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add a `csi_setup` function pointer to the `rzg2l_cru_info` structure and
pass it as part of the OF data. On RZ/G3E and RZ/V2H(P) SoCs, additional
register configurations are required compared to the RZ/G2L SoC.

Modify `rzg2l_cru_csi2_setup()` to be referenced through this function
pointer and update the code to use it accordingly.

This change is in preparation for adding support for RZ/G3E and RZ/V2H(P)
SoCs.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c  | 1 +
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h   | 6 ++++++
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 8 ++++----
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index e4fb3e12d6bf..3ae0cd83af16 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -363,6 +363,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
 	.enable_interrupts = rzg2l_cru_enable_interrupts,
 	.disable_interrupts = rzg2l_cru_disable_interrupts,
 	.fifo_empty = rzg2l_fifo_empty,
+	.csi_setup = rzg2l_cru_csi2_setup,
 };
 
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 2e17bfef43ce..ccaba5220f1c 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -89,6 +89,9 @@ struct rzg2l_cru_info {
 	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
 	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
 	bool (*fifo_empty)(struct rzg2l_cru_dev *cru);
+	void (*csi_setup)(struct rzg2l_cru_dev *cru,
+			  const struct rzg2l_cru_ip_format *ip_fmt,
+			  u8 csi_vc);
 };
 
 /**
@@ -187,5 +190,8 @@ void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
 
 bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
+void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+			  const struct rzg2l_cru_ip_format *ip_fmt,
+			  u8 csi_vc);
 
 #endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 7cc83486ce03..637c9c9f9ba8 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -196,9 +196,9 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
 	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
 }
 
-static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
-				 const struct rzg2l_cru_ip_format *ip_fmt,
-				 u8 csi_vc)
+void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+			  const struct rzg2l_cru_ip_format *ip_fmt,
+			  u8 csi_vc)
 {
 	const struct rzg2l_cru_info *info = cru->info;
 	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
@@ -220,7 +220,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
 	const struct rzg2l_cru_ip_format *cru_ip_fmt;
 
 	cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code);
-	rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc);
+	info->csi_setup(cru, cru_ip_fmt, csi_vc);
 
 	/* Output format */
 	cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);
-- 
2.34.1


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

* [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
                   ` (16 preceding siblings ...)
  2025-02-21 15:55 ` [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI Tommaso Merciai
@ 2025-02-21 15:55 ` Tommaso Merciai
  2025-02-23 20:32   ` Laurent Pinchart
  17 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-21 15:55 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Tommaso Merciai, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
the Renesas RZ/G2L SoC, with the following differences:

- Additional registers rzg3e_cru_regs.
- A different irq handler rzg3e_cru_irq.
- A different rzg3e_cru_csi2_setup.
- A different max input width.

Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
and RZ/G3E and related RZ/G3E functions:

 - rzg3e_cru_enable_interrupts()
 - rzg3e_cru_enable_interrupts()
 - rz3e_fifo_empty()
 - rzg3e_cru_csi2_setup()
 - rzg3e_cru_get_current_slot()

Add then support for the RZ/G3E SoC CRU block with the new compatible
string "renesas,r9a09g047-cru".

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
 .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
 4 files changed, 282 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 3ae0cd83af16..075a3aa8af29 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
 		return ret;
 
 	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
+	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
+					    sizeof(struct rzg2l_cru_mem_bank),
+					    GFP_KERNEL);
+	if (!cru->mem_banks)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to init mem banks\n");
+
 	pm_suspend_ignore_children(dev, true);
 	ret = devm_pm_runtime_enable(dev);
 	if (ret)
@@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
 	rzg2l_cru_dma_unregister(cru);
 }
 
+static const u16 rzg3e_cru_regs[] = {
+	[CRUnCTRL] = 0x0,
+	[CRUnIE] = 0x4,
+	[CRUnIE2] = 0x8,
+	[CRUnINTS] = 0xc,
+	[CRUnINTS2] = 0x10,
+	[CRUnRST] = 0x18,
+	[AMnMB1ADDRL] = 0x40,
+	[AMnMB1ADDRH] = 0x44,
+	[AMnMB2ADDRL] = 0x48,
+	[AMnMB2ADDRH] = 0x4c,
+	[AMnMB3ADDRL] = 0x50,
+	[AMnMB3ADDRH] = 0x54,
+	[AMnMB4ADDRL] = 0x58,
+	[AMnMB4ADDRH] = 0x5c,
+	[AMnMB5ADDRL] = 0x60,
+	[AMnMB5ADDRH] = 0x64,
+	[AMnMB6ADDRL] = 0x68,
+	[AMnMB6ADDRH] = 0x6c,
+	[AMnMB7ADDRL] = 0x70,
+	[AMnMB7ADDRH] = 0x74,
+	[AMnMB8ADDRL] = 0x78,
+	[AMnMB8ADDRH] = 0x7c,
+	[AMnMBVALID] = 0x88,
+	[AMnMADRSL] = 0x8c,
+	[AMnMADRSH] = 0x90,
+	[AMnAXIATTR] = 0xec,
+	[AMnFIFOPNTR] = 0xf8,
+	[AMnAXISTP] = 0x110,
+	[AMnAXISTPACK] = 0x114,
+	[AMnIS] = 0x128,
+	[ICnEN] = 0x1f0,
+	[ICnSVCNUM] = 0x1f8,
+	[ICnSVC] = 0x1fc,
+	[ICnIPMC_C0] = 0x200,
+	[ICnMS] = 0x2d8,
+	[ICnDMR] = 0x304,
+};
+
+static const struct rzg2l_cru_info rzg3e_cru_info = {
+	.max_width = 4095,
+	.max_height = 4095,
+	.image_conv = ICnIPMC_C0,
+	.stride = 128,
+	.regs = rzg3e_cru_regs,
+	.irq_handler = rzg3e_cru_irq,
+	.enable_interrupts = rzg3e_cru_enable_interrupts,
+	.disable_interrupts = rzg3e_cru_disable_interrupts,
+	.fifo_empty = rz3e_fifo_empty,
+	.csi_setup = rzg3e_cru_csi2_setup,
+};
+
 static const u16 rzg2l_cru_regs[] = {
 	[CRUnCTRL] = 0x0,
 	[CRUnIE] = 0x4,
@@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
 };
 
 static const struct of_device_id rzg2l_cru_of_id_table[] = {
+	{
+		.compatible = "renesas,r9a09g047-cru",
+		.data = &rzg3e_cru_info,
+	},
 	{
 		.compatible = "renesas,rzg2l-cru",
 		.data = &rzgl2_cru_info,
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
index 82920db7134e..1646d1e2953c 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -14,8 +14,13 @@
 
 #define CRUnIE_EFE			BIT(17)
 
+#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
+#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
+
 #define CRUnINTS_SFS			BIT(16)
 
+#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
+
 #define CRUnRST_VRESETN			BIT(0)
 
 /* Memory Bank Base Address (Lower) Register for CRU Image Data */
@@ -32,7 +37,14 @@
 #define AMnAXIATTR_AXILEN		(0xf)
 
 #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
+#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
+#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
 #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
+#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
+#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
+
+#define AMnIS_IS_MASK			GENMASK(14, 7)
+#define AMnIS_IS(x)			((x) << 7)
 
 #define AMnAXISTP_AXI_STOP		BIT(0)
 
@@ -40,6 +52,11 @@
 
 #define ICnEN_ICEN			BIT(0)
 
+#define ICnSVC_SVC0(x)			(x)
+#define ICnSVC_SVC1(x)			((x) << 4)
+#define ICnSVC_SVC2(x)			((x) << 8)
+#define ICnSVC_SVC3(x)			((x) << 12)
+
 #define ICnMC_CSCTHR			BIT(5)
 #define ICnMC_INF(x)			((x) << 16)
 #define ICnMC_VCSEL(x)			((x) << 22)
@@ -52,7 +69,9 @@
 enum rzg2l_cru_common_regs {
 	CRUnCTRL,	/* CRU Control */
 	CRUnIE,		/* CRU Interrupt Enable */
+	CRUnIE2,	/* CRU Interrupt Enable(2) */
 	CRUnINTS,	/* CRU Interrupt Status */
+	CRUnINTS2,	/* CRU Interrupt Status(2) */
 	CRUnRST, 	/* CRU Reset */
 	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
 	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
@@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
 	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
 	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
 	AMnMBS,		/* Memory Bank Status for CRU Image Data */
+	AMnMADRSL,	/* VD Memory Address Lower Status Register */
+	AMnMADRSH,	/* VD Memory Address Higher Status Register */
 	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
 	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
 	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
 	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
+	AMnIS,		/* Image Stride Setting Register */
 	ICnEN,		/* CRU Image Processing Enable */
+	ICnSVCNUM,	/* CRU SVC Number Register */
+	ICnSVC,		/* CRU VC Select Register */
 	ICnMC,		/* CRU Image Processing Main Control */
+	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
 	ICnMS,		/* CRU Module Status */
 	ICnDMR,		/* CRU Data Output Mode */
 };
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index ccaba5220f1c..3301379c132c 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -84,6 +84,7 @@ struct rzg2l_cru_info {
 	unsigned int max_width;
 	unsigned int max_height;
 	u16 image_conv;
+	u16 stride;
 	const u16 *regs;
 	irqreturn_t (*irq_handler)(int irq, void *data);
 	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
@@ -94,6 +95,11 @@ struct rzg2l_cru_info {
 			  u8 csi_vc);
 };
 
+struct rzg2l_cru_mem_bank {
+	dma_addr_t addrl;
+	dma_addr_t addrh;
+};
+
 /**
  * struct rzg2l_cru_dev - Renesas CRU device structure
  * @dev:		(OF) device
@@ -108,6 +114,8 @@ struct rzg2l_cru_info {
  * @vdev:		V4L2 video device associated with CRU
  * @v4l2_dev:		V4L2 device
  * @num_buf:		Holds the current number of buffers enabled
+ * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
+ * @mem_banks:		Memory addresses where current video data is written.
  * @notifier:		V4L2 asynchronous subdevs notifier
  *
  * @ip:			Image processing subdev info
@@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
 	struct v4l2_device v4l2_dev;
 	u8 num_buf;
 
+	u8 svc_channel;
+	struct rzg2l_cru_mem_bank *mem_banks;
+
 	struct v4l2_async_notifier notifier;
 
 	struct rzg2l_cru_ip ip;
@@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
 int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
 irqreturn_t rzg2l_cru_irq(int irq, void *data);
+irqreturn_t rzg3e_cru_irq(int irq, void *data);
 
 const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
 
@@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
 
 void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
+void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
+void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
 
 bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
+bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
 			  const struct rzg2l_cru_ip_format *ip_fmt,
 			  u8 csi_vc);
+void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+			  const struct rzg2l_cru_ip_format *ip_fmt,
+			  u8 csi_vc);
 
 #endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 637c9c9f9ba8..efd70c13704e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
 	/* Currently, we just use the buffer in 32 bits address */
 	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
 	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
+
+	cru->mem_banks[slot].addrl = lower_32_bits(addr);
+	cru->mem_banks[slot].addrh = upper_32_bits(addr);
 }
 
 /*
@@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
 	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
 }
 
-static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
+static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
 {
 	unsigned int slot;
 	u32 amnaxiattr;
@@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
 	for (slot = 0; slot < cru->num_buf; slot++)
 		rzg2l_cru_fill_hw_slot(cru, slot);
 
+	if (cru->info->stride) {
+		u32 stride = cru->format.bytesperline;
+		u32 amnis;
+
+		if (stride % cru->info->stride) {
+			dev_err(cru->dev,
+				"Bytesperline must be multiple of %u bytes\n",
+				cru->info->stride);
+			return -EINVAL;
+		}
+		stride = stride / cru->info->stride;
+		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
+		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
+	}
+
 	/* Set AXI burst max length to recommended setting */
 	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
 	amnaxiattr |= AMnAXIATTR_AXILEN;
 	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
+
+	return 0;
+}
+
+void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+			  const struct rzg2l_cru_ip_format *ip_fmt,
+			  u8 csi_vc)
+{
+	const struct rzg2l_cru_info *info = cru->info;
+	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
+
+	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
+
+	/* Set virtual channel CSI2 */
+	icnmc |= ICnMC_VCSEL(csi_vc);
+
+	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
+	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
+			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
+	rzg2l_cru_write(cru, info->image_conv, icnmc);
 }
 
 void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
@@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
 	return 0;
 }
 
+bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
+{
+	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
+
+	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
+	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
+	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
+	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
+		return true;
+
+	return false;
+}
+
 bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
 {
 	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
@@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
 	return fd.entry[0].bus.csi2.vc;
 }
 
+void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
+{
+	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
+	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
+}
+
+void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
+{
+	rzg2l_cru_write(cru, CRUnIE, 0);
+	rzg2l_cru_write(cru, CRUnIE2, 0);
+	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
+	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
+}
+
 void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
 {
 	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
@@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 	if (ret < 0)
 		return ret;
 	csi_vc = ret;
+	cru->svc_channel = csi_vc;
 
 	spin_lock_irqsave(&cru->qlock, flags);
 
@@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 	cru->info->disable_interrupts(cru);
 
 	/* Initialize the AXI master */
-	rzg2l_cru_initialize_axi(cru);
+	ret = rzg2l_cru_initialize_axi(cru);
+	if (ret) {
+		spin_unlock_irqrestore(&cru->qlock, flags);
+		return ret;
+	}
 
 	/* Initialize image convert */
 	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
@@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
 	return IRQ_RETVAL(handled);
 }
 
+static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
+{
+	dma_addr_t amnmadrs;
+	unsigned int slot;
+
+	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
+	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
+
+	for (slot = 0; slot < cru->num_buf; slot++) {
+		dma_addr_t buf_addr;
+
+		buf_addr = cru->mem_banks[slot].addrh << 32 |
+			cru->mem_banks[slot].addrl;
+
+		/* Ensure amnmadrs is within this buffer range */
+		if (amnmadrs >= buf_addr &&
+		    amnmadrs < buf_addr + cru->format.sizeimage) {
+			return slot;
+		}
+	}
+
+	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
+	return -EINVAL;
+}
+
+irqreturn_t rzg3e_cru_irq(int irq, void *data)
+{
+	struct rzg2l_cru_dev *cru = data;
+	unsigned int handled = 0;
+	unsigned long flags;
+	unsigned int slot;
+	u32 irq_status;
+
+	spin_lock_irqsave(&cru->qlock, flags);
+	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
+	if (!(irq_status))
+		goto done;
+
+	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
+
+	handled = 1;
+
+	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
+
+	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
+	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
+		dev_dbg(cru->dev, "IRQ while state stopped\n");
+		goto done;
+	}
+
+	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
+		if (irq_status & CRUnINTS2_FSxS(0) ||
+		    irq_status & CRUnINTS2_FSxS(1) ||
+		    irq_status & CRUnINTS2_FSxS(2) ||
+		    irq_status & CRUnINTS2_FSxS(3))
+			dev_dbg(cru->dev, "IRQ while state stopping\n");
+		goto done;
+	}
+
+	slot = rzg3e_cru_get_current_slot(cru);
+	if (slot < 0)
+		goto done;
+
+	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
+
+	cru->mem_banks[slot].addrl = 0;
+	cru->mem_banks[slot].addrh = 0;
+
+	/*
+	 * To hand buffers back in a known order to userspace start
+	 * to capture first from slot 0.
+	 */
+	if (cru->state == RZG2L_CRU_DMA_STARTING) {
+		if (slot != 0) {
+			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
+			goto done;
+		}
+		dev_dbg(cru->dev, "Capture start synced!\n");
+		cru->state = RZG2L_CRU_DMA_RUNNING;
+	}
+
+	/* Capture frame */
+	if (cru->queue_buf[slot]) {
+		cru->queue_buf[slot]->field = cru->format.field;
+		cru->queue_buf[slot]->sequence = cru->sequence;
+		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
+		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
+				VB2_BUF_STATE_DONE);
+		cru->queue_buf[slot] = NULL;
+	} else {
+		/* Scratch buffer was used, dropping frame. */
+		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
+	}
+
+	cru->sequence++;
+
+	/* Prepare for next frame */
+	rzg2l_cru_fill_hw_slot(cru, slot);
+
+done:
+	spin_unlock_irqrestore(&cru->qlock, flags);
+	return IRQ_RETVAL(handled);
+}
+
 static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
 {
 	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
-- 
2.34.1


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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
@ 2025-02-23 18:08   ` Laurent Pinchart
  2025-02-23 21:00     ` Lad, Prabhakar
  2025-02-24  9:00     ` Geert Uytterhoeven
  2025-02-24 17:25   ` Rob Herring (Arm)
  1 sibling, 2 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:08 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> found on the Renesas RZ/G2L SoC, with the following differences:
> - A different D-PHY
> - Additional registers for the MIPI CSI-2 link
> - Only two clocks
> 
> Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> SoC.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> Changes since v1:
>  - Dropped empty line as suggested by LPinchart
>  - Fixed minItems into else conditional block as suggested by RHerring
> 
>  .../bindings/media/renesas,rzg2l-csi2.yaml    | 59 ++++++++++++++-----
>  1 file changed, 44 insertions(+), 15 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> index 7faa12fecd5b..1d7784e8af16 100644
> --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> @@ -17,12 +17,14 @@ description:
>  
>  properties:
>    compatible:
> -    items:
> -      - enum:
> -          - renesas,r9a07g043-csi2       # RZ/G2UL
> -          - renesas,r9a07g044-csi2       # RZ/G2{L,LC}
> -          - renesas,r9a07g054-csi2       # RZ/V2L
> -      - const: renesas,rzg2l-csi2
> +    oneOf:
> +      - items:
> +          - enum:
> +              - renesas,r9a07g043-csi2 # RZ/G2UL
> +              - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
> +              - renesas,r9a07g054-csi2 # RZ/V2L
> +          - const: renesas,rzg2l-csi2
> +      - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
>  
>    reg:
>      maxItems: 1
> @@ -31,16 +33,24 @@ properties:
>      maxItems: 1
>  
>    clocks:
> -    items:
> -      - description: Internal clock for connecting CRU and MIPI
> -      - description: CRU Main clock
> -      - description: CRU Register access clock
> +    oneOf:
> +      - items:
> +          - description: Internal clock for connecting CRU and MIPI
> +          - description: CRU Main clock
> +          - description: CRU Register access clock
> +      - items:
> +          - description: CRU Main clock
> +          - description: CRU Register access clock
>  
>    clock-names:
> -    items:
> -      - const: system
> -      - const: video
> -      - const: apb
> +    oneOf:
> +      - items:
> +          - const: system
> +          - const: video
> +          - const: apb
> +      - items:
> +          - const: video
> +          - const: apb
>  
>    power-domains:
>      maxItems: 1
> @@ -48,7 +58,7 @@ properties:
>    resets:
>      items:
>        - description: CRU_PRESETN reset terminal
> -      - description: CRU_CMN_RSTB reset terminal
> +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset

I'd mention which SoCs these apply to:

      - description:
          CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY reset (RZ/V2H)

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

>  
>    reset-names:
>      items:
> @@ -101,6 +111,25 @@ required:
>    - reset-names
>    - ports
>  
> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: renesas,r9a09g057-csi2
> +    then:
> +      properties:
> +        clocks:
> +          maxItems: 2
> +        clock-names:
> +          maxItems: 2
> +    else:
> +      properties:
> +        clocks:
> +          minItems: 3
> +        clock-names:
> +          minItems: 3
> +
>  additionalProperties: false
>  
>  examples:

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block
  2025-02-21 15:55 ` [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block Tommaso Merciai
@ 2025-02-23 18:10   ` Laurent Pinchart
  2025-02-23 21:11   ` Lad, Prabhakar
  1 sibling, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:10 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:16PM +0100, Tommaso Merciai wrote:
> Document the CSI-2 block which is part of CRU found in Renesas RZ/G3E
> SoC.
> 
> The CSI-2 block on the RZ/G3E SoC is identical to one found on the
> RZ/V2H(P) SoC.
> 
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../devicetree/bindings/media/renesas,rzg2l-csi2.yaml          | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> index 1d7784e8af16..9b7ed86ef14b 100644
> --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> @@ -24,6 +24,9 @@ properties:
>                - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
>                - renesas,r9a07g054-csi2 # RZ/V2L
>            - const: renesas,rzg2l-csi2
> +      - items:
> +          - const: renesas,r9a09g047-csi2 # RZ/G3E
> +          - const: renesas,r9a09g057-csi2

If you follow my suggestion on 01/18, the description of the second
reset entry needs to be updated.

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

>        - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
>  
>    reg:

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe()
  2025-02-21 15:55 ` [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe() Tommaso Merciai
@ 2025-02-23 18:13   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:13 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
	Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:18PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Use a local variable for the struct device pointers. This increases code
> readability with shortened lines.
> 
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

> ---
> Changes since v1:
>  - Fixed commit msg and commit body as suggested by LPinchart
>  - Collected tags
> 
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 31 ++++++++++---------
>  1 file changed, 16 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 881e910dce02..948f1917b830 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -764,10 +764,11 @@ static const struct media_entity_operations rzg2l_csi2_entity_ops = {
>  
>  static int rzg2l_csi2_probe(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
>  	struct rzg2l_csi2 *csi2;
>  	int ret;
>  
> -	csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
> +	csi2 = devm_kzalloc(dev, sizeof(*csi2), GFP_KERNEL);
>  	if (!csi2)
>  		return -ENOMEM;
>  
> @@ -775,28 +776,28 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>  	if (IS_ERR(csi2->base))
>  		return PTR_ERR(csi2->base);
>  
> -	csi2->cmn_rstb = devm_reset_control_get_exclusive(&pdev->dev, "cmn-rstb");
> +	csi2->cmn_rstb = devm_reset_control_get_exclusive(dev, "cmn-rstb");
>  	if (IS_ERR(csi2->cmn_rstb))
> -		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->cmn_rstb),
> +		return dev_err_probe(dev, PTR_ERR(csi2->cmn_rstb),
>  				     "Failed to get cpg cmn-rstb\n");
>  
> -	csi2->presetn = devm_reset_control_get_shared(&pdev->dev, "presetn");
> +	csi2->presetn = devm_reset_control_get_shared(dev, "presetn");
>  	if (IS_ERR(csi2->presetn))
> -		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->presetn),
> +		return dev_err_probe(dev, PTR_ERR(csi2->presetn),
>  				     "Failed to get cpg presetn\n");
>  
> -	csi2->sysclk = devm_clk_get(&pdev->dev, "system");
> +	csi2->sysclk = devm_clk_get(dev, "system");
>  	if (IS_ERR(csi2->sysclk))
> -		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk),
> +		return dev_err_probe(dev, PTR_ERR(csi2->sysclk),
>  				     "Failed to get system clk\n");
>  
> -	csi2->vclk = devm_clk_get(&pdev->dev, "video");
> +	csi2->vclk = devm_clk_get(dev, "video");
>  	if (IS_ERR(csi2->vclk))
> -		return dev_err_probe(&pdev->dev, PTR_ERR(csi2->vclk),
> +		return dev_err_probe(dev, PTR_ERR(csi2->vclk),
>  				     "Failed to get video clock\n");
>  	csi2->vclk_rate = clk_get_rate(csi2->vclk);
>  
> -	csi2->dev = &pdev->dev;
> +	csi2->dev = dev;
>  
>  	platform_set_drvdata(pdev, csi2);
>  
> @@ -804,18 +805,18 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	pm_runtime_enable(&pdev->dev);
> +	pm_runtime_enable(dev);
>  
>  	ret = rzg2l_validate_csi2_lanes(csi2);
>  	if (ret)
>  		goto error_pm;
>  
> -	csi2->subdev.dev = &pdev->dev;
> +	csi2->subdev.dev = dev;
>  	v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
>  	csi2->subdev.internal_ops = &rzg2l_csi2_internal_ops;
> -	v4l2_set_subdevdata(&csi2->subdev, &pdev->dev);
> +	v4l2_set_subdevdata(&csi2->subdev, dev);
>  	snprintf(csi2->subdev.name, sizeof(csi2->subdev.name),
> -		 "csi-%s", dev_name(&pdev->dev));
> +		 "csi-%s", dev_name(dev));
>  	csi2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
>  
>  	csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> @@ -852,7 +853,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>  	v4l2_async_nf_cleanup(&csi2->notifier);
>  	media_entity_cleanup(&csi2->subdev.entity);
>  error_pm:
> -	pm_runtime_disable(&pdev->dev);
> +	pm_runtime_disable(dev);
>  
>  	return ret;
>  }

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable()
  2025-02-21 15:55 ` [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable() Tommaso Merciai
@ 2025-02-23 18:14   ` Laurent Pinchart
  2025-02-23 21:14   ` Lad, Prabhakar
  1 sibling, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:14 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:21PM +0100, Tommaso Merciai wrote:
> Use newly added devm_pm_runtime_enable() into rzg2l_cru_probe() and
> drop unnecessary pm_runtime_disable() from rzg2l_cru_probe() and
> rzg2l_csi2_remove().
> 
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

> ---
> Changes since v1:
>  - Fixed DMA leak as suggested by LPinchart
>  - Collected tags
> 
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 70fed0ce45ea..eed9d2bd0841 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -287,7 +287,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>  
>  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
>  	pm_suspend_ignore_children(dev, true);
> -	pm_runtime_enable(dev);
> +	ret = devm_pm_runtime_enable(dev);
> +	if (ret)
> +		goto error_dma_unregister;
>  
>  	ret = rzg2l_cru_media_init(cru);
>  	if (ret)
> @@ -297,7 +299,6 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>  
>  error_dma_unregister:
>  	rzg2l_cru_dma_unregister(cru);
> -	pm_runtime_disable(dev);
>  
>  	return ret;
>  }
> @@ -306,8 +307,6 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
>  {
>  	struct rzg2l_cru_dev *cru = platform_get_drvdata(pdev);
>  
> -	pm_runtime_disable(&pdev->dev);
> -
>  	v4l2_async_nf_unregister(&cru->notifier);
>  	v4l2_async_nf_cleanup(&cru->notifier);
>  

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling
  2025-02-21 15:55 ` [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling Tommaso Merciai
@ 2025-02-23 18:17   ` Laurent Pinchart
  2025-02-23 21:21     ` Lad, Prabhakar
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:17 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:22PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> In preparation for adding support for the RZ/V2H(P) SoC, where the D-PHY
> differs from the existing RZ/G2L implementation, introduce a new
> rzg2l_csi2_info structure. This structure provides function pointers for
> SoC-specific D-PHY enable and disable operations.
> 
> Modify rzg2l_csi2_dphy_setting() to use these function pointers instead of
> calling rzg2l_csi2_dphy_enable() and rzg2l_csi2_dphy_disable() directly.
> Update the device match table to store the appropriate function pointers
> for each compatible SoC.
> 
> This change prepares the driver for future extensions without affecting
> the current functionality for RZ/G2L.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 24 ++++++++++++++++---
>  1 file changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 4ccf7c5ea58b..3a4e720ba732 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -107,6 +107,7 @@ struct rzg2l_csi2 {
>  	void __iomem *base;
>  	struct reset_control *presetn;
>  	struct reset_control *cmn_rstb;
> +	const struct rzg2l_csi2_info *info;
>  	struct clk *sysclk;
>  	struct clk *vclk;
>  	unsigned long vclk_rate;
> @@ -123,6 +124,11 @@ struct rzg2l_csi2 {
>  	bool dphy_enabled;
>  };
>  
> +struct rzg2l_csi2_info {
> +	int (*dphy_enable)(struct rzg2l_csi2 *csi2);
> +	int (*dphy_disable)(struct rzg2l_csi2 *csi2);
> +};

Unless you'll need to add non-function fields later, I'd name the
structure rzg2l_csi2_phy_ops.

> +
>  struct rzg2l_csi2_timings {
>  	u32 t_init;
>  	u32 tclk_miss;
> @@ -360,9 +366,9 @@ static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on)
>  	struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
>  
>  	if (on)
> -		return rzg2l_csi2_dphy_enable(csi2);
> +		return csi2->info->dphy_enable(csi2);
>  
> -	return rzg2l_csi2_dphy_disable(csi2);
> +	return csi2->info->dphy_disable(csi2);
>  }
>  
>  static int rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
> @@ -772,6 +778,10 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>  	if (!csi2)
>  		return -ENOMEM;
>  
> +	csi2->info = of_device_get_match_data(dev);
> +	if (!csi2->info)
> +		return dev_err_probe(dev, -EINVAL, "Failed to get OF match data\n");
> +
>  	csi2->base = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(csi2->base))
>  		return PTR_ERR(csi2->base);
> @@ -890,8 +900,16 @@ static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
>  		       rzg2l_csi2_pm_runtime_resume, NULL)
>  };
>  
> +static const struct rzg2l_csi2_info rzg2l_csi2_info = {
> +	.dphy_enable = rzg2l_csi2_dphy_enable,
> +	.dphy_disable = rzg2l_csi2_dphy_disable,
> +};

I'd recommend moving this just below the definition of the
rzg2l_csi2_dphy_enable() function.

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

> +
>  static const struct of_device_id rzg2l_csi2_of_table[] = {
> -	{ .compatible = "renesas,rzg2l-csi2", },
> +	{
> +		.compatible = "renesas,rzg2l-csi2",
> +		.data = &rzg2l_csi2_info,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC
  2025-02-21 15:55 ` [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC Tommaso Merciai
@ 2025-02-23 18:19   ` Laurent Pinchart
  2025-02-23 20:57     ` Lad, Prabhakar
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:19 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:23PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The RZ/V2H(P) SoC does not provide a `system` clock for the CSI-2
> interface. To accommodate this, use `devm_clk_get_optional()` instead
> of `devm_clk_get()` when retrieving the clock.

The clock shouldn't be optional. On all SoCs but V2H it should remain
mandatory, and on V2H you shouldn't call clk_get() at all.

I'd recommend adding a flag to the rzg2l_csi2_info structure.

> This patch is in preparation for adding support for RZ/V2H(P) SoC.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 3a4e720ba732..771fa35558be 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -796,7 +796,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>  		return dev_err_probe(dev, PTR_ERR(csi2->presetn),
>  				     "Failed to get cpg presetn\n");
>  
> -	csi2->sysclk = devm_clk_get(dev, "system");
> +	csi2->sysclk = devm_clk_get_optional(dev, "system");
>  	if (IS_ERR(csi2->sysclk))
>  		return dev_err_probe(dev, PTR_ERR(csi2->sysclk),
>  				     "Failed to get system clk\n");

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support for RZ/V2H(P) SoC
  2025-02-21 15:55 ` [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support " Tommaso Merciai
@ 2025-02-23 18:24   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 18:24 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
	Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:24PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The D-PHY on the RZ/V2H(P) SoC is different from the D-PHY on the RZ/G2L
> SoC. To handle this difference, function pointers for D-PHY enable/disable
> have been added, and the `struct rzg2l_csi2_info` pointer is passed as OF
> data.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 94 +++++++++++++++++++
>  1 file changed, 94 insertions(+)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 771fa35558be..cd452c84f101 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -85,6 +85,15 @@
>  					 CSIDPHYSKW0_UTIL_DL2_SKW_ADJ(1) | \
>  					 CSIDPHYSKW0_UTIL_DL3_SKW_ADJ(1))
>  
> +/* DPHY registers on RZ/V2H(P) SoC */
> +#define CRUm_S_TIMCTL			0x41c
> +#define CRUm_S_TIMCTL_S_HSSETTLECTL(x)	((x) << 8)
> +
> +#define CRUm_S_DPHYCTL_MSB		0x434
> +#define CRUm_S_DPHYCTL_MSB_DESKEW	BIT(1)
> +
> +#define CRUm_SWAPCTL			0x438
> +
>  #define VSRSTS_RETRIES			20
>  
>  #define RZG2L_CSI2_MIN_WIDTH		320
> @@ -139,6 +148,30 @@ struct rzg2l_csi2_timings {
>  	u32 max_hsfreq;
>  };
>  
> +struct rzv2h_csi2_s_hssettlectl {
> +	unsigned int hsfreq;
> +	u16 s_hssettlectl;
> +};
> +
> +static const struct rzv2h_csi2_s_hssettlectl rzv2h_s_hssettlectl[] = {
> +	{   90,  1 }, {  130,  2 }, {  180,  3 },
> +	{  220,  4 }, {  270,  5 }, {  310,  6 },
> +	{  360,  7 }, {  400,  8 }, {  450,  9 },
> +	{  490, 10 }, {  540, 11 }, {  580, 12 },
> +	{  630, 13 }, {  670, 14 }, {  720, 15 },
> +	{  760, 16 }, {  810, 17 }, {  850, 18 },
> +	{  900, 19 }, {  940, 20 }, {  990, 21 },
> +	{ 1030, 22 }, { 1080, 23 }, { 1120, 24 },
> +	{ 1170, 25 }, { 1220, 26 }, { 1260, 27 },
> +	{ 1310, 28 }, { 1350, 29 }, { 1400, 30 },
> +	{ 1440, 31 }, { 1490, 32 }, { 1530, 33 },
> +	{ 1580, 34 }, { 1620, 35 }, { 1670, 36 },
> +	{ 1710, 37 }, { 1760, 38 }, { 1800, 39 },
> +	{ 1850, 40 }, { 1890, 41 }, { 1940, 42 },
> +	{ 1980, 43 }, { 2030, 44 }, { 2070, 45 },
> +	{ 2100, 46 },
> +};
> +
>  static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = {
>  	{
>  		.max_hsfreq = 80,
> @@ -427,6 +460,58 @@ static int rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
>  	return 0;
>  }
>  
> +static int rzv2h_csi2_dphy_disable(struct rzg2l_csi2 *csi2)
> +{
> +	int ret;
> +
> +	/* Reset the CRU (D-PHY) */
> +	ret = reset_control_assert(csi2->cmn_rstb);
> +	if (ret)
> +		return ret;
> +
> +	csi2->dphy_enabled = false;
> +
> +	return 0;
> +}
> +
> +static int rzv2h_csi2_dphy_enable(struct rzg2l_csi2 *csi2)
> +{
> +	unsigned int i;
> +	u16 hssettle;
> +	int mbps;
> +
> +	mbps = rzg2l_csi2_calc_mbps(csi2);
> +	if (mbps < 0)
> +		return mbps;
> +
> +	csi2->hsfreq = mbps;
> +
> +	rzg2l_csi2_write(csi2, CRUm_SWAPCTL, 0);
> +

Maybe move this after the error check below to avoid writing any
register if an error occurs.

> +	for (i = 0; i < ARRAY_SIZE(rzv2h_s_hssettlectl); i++) {
> +		if (csi2->hsfreq <= rzv2h_s_hssettlectl[i].hsfreq)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(rzv2h_s_hssettlectl))
> +		return -EINVAL;
> +
> +	hssettle = rzv2h_s_hssettlectl[i].s_hssettlectl;
> +	rzg2l_csi2_write(csi2, CRUm_S_TIMCTL,
> +			 CRUm_S_TIMCTL_S_HSSETTLECTL(hssettle));
> +
> +	if (csi2->hsfreq > 1500)
> +		rzg2l_csi2_set(csi2, CRUm_S_DPHYCTL_MSB,
> +			       CRUm_S_DPHYCTL_MSB_DESKEW);
> +	else
> +		rzg2l_csi2_clr(csi2, CRUm_S_DPHYCTL_MSB,
> +			       CRUm_S_DPHYCTL_MSB_DESKEW);
> +
> +	csi2->dphy_enabled = true;
> +
> +	return 0;
> +}
> +
>  static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on)
>  {
>  	struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
> @@ -900,12 +985,21 @@ static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
>  		       rzg2l_csi2_pm_runtime_resume, NULL)
>  };
>  
> +static const struct rzg2l_csi2_info rzv2h_csi2_info = {
> +	.dphy_enable = rzv2h_csi2_dphy_enable,
> +	.dphy_disable = rzv2h_csi2_dphy_disable,
> +};

Move this just after rzv2h_csi2_dphy_enable().

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

> +
>  static const struct rzg2l_csi2_info rzg2l_csi2_info = {
>  	.dphy_enable = rzg2l_csi2_dphy_enable,
>  	.dphy_disable = rzg2l_csi2_dphy_disable,
>  };
>  
>  static const struct of_device_id rzg2l_csi2_of_table[] = {
> +	{
> +		.compatible = "renesas,r9a09g057-csi2",
> +		.data = &rzv2h_csi2_info,
> +	},
>  	{
>  		.compatible = "renesas,rzg2l-csi2",
>  		.data = &rzg2l_csi2_info,

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support
  2025-02-21 15:55 ` [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support Tommaso Merciai
@ 2025-02-23 19:52   ` Laurent Pinchart
  2025-02-24 13:46     ` Tommaso Merciai
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 19:52 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:25PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Prepare for adding support for RZ/G3E and RZ/V2HP SoCs, which have a
> CRU-IP that is mostly identical to RZ/G2L but with different register
> offsets and additional registers. Introduce a flexible register mapping
> mechanism to handle these variations.
> 
> Define the `rzg2l_cru_info` structure to store register mappings and
> pass it as part of the OF match data. Update the read/write functions
> to use indexed register offsets from `rzg2l_cru_info`, ensuring
> compatibility across different SoC variants.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 46 ++++++++++++-
>  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        | 65 ++++++++++---------
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 12 ++--
>  4 files changed, 92 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index eed9d2bd0841..abc2a979833a 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -22,6 +22,7 @@
>  #include <media/v4l2-mc.h>
>  
>  #include "rzg2l-cru.h"
> +#include "rzg2l-cru-regs.h"
>  
>  static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
>  {
> @@ -269,6 +270,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>  
>  	cru->dev = dev;
>  	cru->info = of_device_get_match_data(dev);
> +	if (!cru->info)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "Failed to get OF match data\n");
>  
>  	irq = platform_get_irq(pdev, 0);
>  	if (irq < 0)
> @@ -317,8 +321,48 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
>  	rzg2l_cru_dma_unregister(cru);
>  }
>  
> +static const u16 rzg2l_cru_regs[] = {
> +	[CRUnCTRL] = 0x0,
> +	[CRUnIE] = 0x4,
> +	[CRUnINTS] = 0x8,
> +	[CRUnRST] = 0xc,
> +	[AMnMB1ADDRL] = 0x100,
> +	[AMnMB1ADDRH] = 0x104,
> +	[AMnMB2ADDRL] = 0x108,
> +	[AMnMB2ADDRH] = 0x10c,
> +	[AMnMB3ADDRL] = 0x110,
> +	[AMnMB3ADDRH] = 0x114,
> +	[AMnMB4ADDRL] = 0x118,
> +	[AMnMB4ADDRH] = 0x11c,
> +	[AMnMB5ADDRL] = 0x120,
> +	[AMnMB5ADDRH] = 0x124,
> +	[AMnMB6ADDRL] = 0x128,
> +	[AMnMB6ADDRH] = 0x12c,
> +	[AMnMB7ADDRL] = 0x130,
> +	[AMnMB7ADDRH] = 0x134,
> +	[AMnMB8ADDRL] = 0x138,
> +	[AMnMB8ADDRH] = 0x13c,
> +	[AMnMBVALID] = 0x148,
> +	[AMnMBS] = 0x14c,
> +	[AMnAXIATTR] = 0x158,
> +	[AMnFIFOPNTR] = 0x168,
> +	[AMnAXISTP] = 0x174,
> +	[AMnAXISTPACK] = 0x178,
> +	[ICnEN] = 0x200,
> +	[ICnMC] = 0x208,
> +	[ICnMS] = 0x254,
> +	[ICnDMR] = 0x26c,
> +};
> +
> +static const struct rzg2l_cru_info rzgl2_cru_info = {
> +	.regs = rzg2l_cru_regs,
> +};
> +
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> -	{ .compatible = "renesas,rzg2l-cru", },
> +	{
> +		.compatible = "renesas,rzg2l-cru",
> +		.data = &rzgl2_cru_info,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> index 1c9f22118a5d..82920db7134e 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> @@ -10,71 +10,76 @@
>  
>  /* HW CRU Registers Definition */
>  
> -/* CRU Control Register */
> -#define CRUnCTRL			0x0
>  #define CRUnCTRL_VINSEL(x)		((x) << 0)
>  
> -/* CRU Interrupt Enable Register */
> -#define CRUnIE				0x4
>  #define CRUnIE_EFE			BIT(17)
>  
> -/* CRU Interrupt Status Register */
> -#define CRUnINTS			0x8
>  #define CRUnINTS_SFS			BIT(16)
>  
> -/* CRU Reset Register */
> -#define CRUnRST				0xc
>  #define CRUnRST_VRESETN			BIT(0)
>  
>  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> -#define AMnMBxADDRL(x)			(0x100 + ((x) * 8))
> +#define AMnMBxADDRL(base, x)		((base) + (x) * 2)
>  
>  /* Memory Bank Base Address (Higher) Register for CRU Image Data */
> -#define AMnMBxADDRH(x)			(0x104 + ((x) * 8))
> +#define AMnMBxADDRH(base, x)		AMnMBxADDRL(base, x)
>  
> -/* Memory Bank Enable Register for CRU Image Data */
> -#define AMnMBVALID			0x148
>  #define AMnMBVALID_MBVALID(x)		GENMASK(x, 0)
>  
> -/* Memory Bank Status Register for CRU Image Data */
> -#define AMnMBS				0x14c
>  #define AMnMBS_MBSTS			0x7
>  
> -/* AXI Master Transfer Setting Register for CRU Image Data */
> -#define AMnAXIATTR			0x158
>  #define AMnAXIATTR_AXILEN_MASK		GENMASK(3, 0)
>  #define AMnAXIATTR_AXILEN		(0xf)
>  
> -/* AXI Master FIFO Pointer Register for CRU Image Data */
> -#define AMnFIFOPNTR			0x168
>  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
>  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
>  
> -/* AXI Master Transfer Stop Register for CRU Image Data */
> -#define AMnAXISTP			0x174
>  #define AMnAXISTP_AXI_STOP		BIT(0)
>  
> -/* AXI Master Transfer Stop Status Register for CRU Image Data */
> -#define AMnAXISTPACK			0x178
>  #define AMnAXISTPACK_AXI_STOP_ACK	BIT(0)
>  
> -/* CRU Image Processing Enable Register */
> -#define ICnEN				0x200
>  #define ICnEN_ICEN			BIT(0)
>  
> -/* CRU Image Processing Main Control Register */
> -#define ICnMC				0x208
>  #define ICnMC_CSCTHR			BIT(5)
>  #define ICnMC_INF(x)			((x) << 16)
>  #define ICnMC_VCSEL(x)			((x) << 22)
>  #define ICnMC_INF_MASK			GENMASK(21, 16)
>  
> -/* CRU Module Status Register */
> -#define ICnMS				0x254
>  #define ICnMS_IA			BIT(2)
>  
> -/* CRU Data Output Mode Register */
> -#define ICnDMR				0x26c
>  #define ICnDMR_YCMODE_UYVY		(1 << 4)
>  
> +enum rzg2l_cru_common_regs {
> +	CRUnCTRL,	/* CRU Control */
> +	CRUnIE,		/* CRU Interrupt Enable */
> +	CRUnINTS,	/* CRU Interrupt Status */
> +	CRUnRST, 	/* CRU Reset */
> +	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> +	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> +	AMnMB2ADDRL,    /* Bank 2 Address (Lower) for CRU Image Data */
> +	AMnMB2ADDRH,    /* Bank 2 Address (Higher) for CRU Image Data */
> +	AMnMB3ADDRL,    /* Bank 3 Address (Lower) for CRU Image Data */
> +	AMnMB3ADDRH,    /* Bank 3 Address (Higher) for CRU Image Data */
> +	AMnMB4ADDRL,    /* Bank 4 Address (Lower) for CRU Image Data */
> +	AMnMB4ADDRH,    /* Bank 4 Address (Higher) for CRU Image Data */
> +	AMnMB5ADDRL,    /* Bank 5 Address (Lower) for CRU Image Data */
> +	AMnMB5ADDRH,    /* Bank 5 Address (Higher) for CRU Image Data */
> +	AMnMB6ADDRL,    /* Bank 6 Address (Lower) for CRU Image Data */
> +	AMnMB6ADDRH,    /* Bank 6 Address (Higher) for CRU Image Data */
> +	AMnMB7ADDRL,    /* Bank 7 Address (Lower) for CRU Image Data */
> +	AMnMB7ADDRH,    /* Bank 7 Address (Higher) for CRU Image Data */
> +	AMnMB8ADDRL,    /* Bank 8 Address (Lower) for CRU Image Data */
> +	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> +	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> +	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> +	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> +	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> +	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> +	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> +	ICnEN,		/* CRU Image Processing Enable */
> +	ICnMC,		/* CRU Image Processing Main Control */
> +	ICnMS,		/* CRU Module Status */
> +	ICnDMR,		/* CRU Data Output Mode */
> +};
> +
>  #endif /* __RZG2L_CRU_REGS_H__ */
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 8b898ce05b84..00c3f7458e20 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -80,6 +80,10 @@ struct rzg2l_cru_ip_format {
>  	bool yuv;
>  };
>  
> +struct rzg2l_cru_info {
> +	const u16 *regs;
> +};
> +
>  /**
>   * struct rzg2l_cru_dev - Renesas CRU device structure
>   * @dev:		(OF) device
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index cd69c8a686d3..f25fd9b35c55 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -44,12 +44,16 @@ struct rzg2l_cru_buffer {
>   */
>  static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
>  {
> -	iowrite32(value, cru->base + offset);
> +	const u16 *regs = cru->info->regs;
> +
> +	iowrite32(value, cru->base + regs[offset]);

Should out-of-bound accesses be checked ? Ideally that should be done at
build time, but in some cases that may be hard. Maybe rzg2l_cru_write()
and rzg2l_cru_read() could implement compile-time checks, and
__rzg2l_cru_write() and __rzg2l_cru_read() could be used for the cases
where checks are not possible at compile time (for AMnMBxADDRL and
AMnMBxADDRH as far as I can see).

>  }
>  
>  static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
>  {
> -	return ioread32(cru->base + offset);
> +	const u16 *regs = cru->info->regs;
> +
> +	return ioread32(cru->base + regs[offset]);
>  }
>  
>  /* Need to hold qlock before calling */
> @@ -132,8 +136,8 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
>  		return;
>  
>  	/* Currently, we just use the buffer in 32 bits address */
> -	rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
> -	rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
> +	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> +	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);

This seems fairly error-prone. The first argument doesn't seem to be
needed.

>  }
>  
>  /*

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data
  2025-02-21 15:55 ` [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data Tommaso Merciai
@ 2025-02-23 19:54   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 19:54 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:26PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Pass `max_width` and `max_height` as part of the OF data to facilitate the
> addition of support for RZ/G3E and RZ/V2H(P) SoCs. These SoCs have a
> maximum resolution of 4096x4096 as compared to 2800x4095 on RZ/G2L SoC.
> This change prepares the driver for easier integration of these SoCs by
> defining the resolution limits in the `rzg2l_cru_info` structure.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

> ---
>  .../media/platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 ++
>  .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++--
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c | 13 +++++++++----
>  .../media/platform/renesas/rzg2l-cru/rzg2l-video.c  |  5 +++--
>  4 files changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index abc2a979833a..19f93b7fe6fb 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -355,6 +355,8 @@ static const u16 rzg2l_cru_regs[] = {
>  };
>  
>  static const struct rzg2l_cru_info rzgl2_cru_info = {
> +	.max_width = 2800,
> +	.max_height = 4095,
>  	.regs = rzg2l_cru_regs,
>  };
>  
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 00c3f7458e20..6a621073948a 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -27,9 +27,7 @@
>  #define RZG2L_CRU_CSI2_VCHANNEL		4
>  
>  #define RZG2L_CRU_MIN_INPUT_WIDTH	320
> -#define RZG2L_CRU_MAX_INPUT_WIDTH	2800
>  #define RZG2L_CRU_MIN_INPUT_HEIGHT	240
> -#define RZG2L_CRU_MAX_INPUT_HEIGHT	4095
>  
>  enum rzg2l_csi2_pads {
>  	RZG2L_CRU_IP_SINK = 0,
> @@ -81,6 +79,8 @@ struct rzg2l_cru_ip_format {
>  };
>  
>  struct rzg2l_cru_info {
> +	unsigned int max_width;
> +	unsigned int max_height;
>  	const u16 *regs;
>  };
>  
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
> index 76a2b451f1da..7836c7cd53dc 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
> @@ -148,6 +148,8 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
>  				   struct v4l2_subdev_state *state,
>  				   struct v4l2_subdev_format *fmt)
>  {
> +	struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
> +	const struct rzg2l_cru_info *info = cru->info;
>  	struct v4l2_mbus_framefmt *src_format;
>  	struct v4l2_mbus_framefmt *sink_format;
>  
> @@ -170,9 +172,9 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
>  	sink_format->ycbcr_enc = fmt->format.ycbcr_enc;
>  	sink_format->quantization = fmt->format.quantization;
>  	sink_format->width = clamp_t(u32, fmt->format.width,
> -				     RZG2L_CRU_MIN_INPUT_WIDTH, RZG2L_CRU_MAX_INPUT_WIDTH);
> +				     RZG2L_CRU_MIN_INPUT_WIDTH, info->max_width);
>  	sink_format->height = clamp_t(u32, fmt->format.height,
> -				      RZG2L_CRU_MIN_INPUT_HEIGHT, RZG2L_CRU_MAX_INPUT_HEIGHT);
> +				      RZG2L_CRU_MIN_INPUT_HEIGHT, info->max_height);
>  
>  	fmt->format = *sink_format;
>  
> @@ -197,6 +199,9 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
>  					struct v4l2_subdev_state *state,
>  					struct v4l2_subdev_frame_size_enum *fse)
>  {
> +	struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
> +	const struct rzg2l_cru_info *info = cru->info;
> +
>  	if (fse->index != 0)
>  		return -EINVAL;
>  
> @@ -205,8 +210,8 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
>  
>  	fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
>  	fse->min_height = RZG2L_CRU_MIN_INPUT_HEIGHT;
> -	fse->max_width = RZG2L_CRU_MAX_INPUT_WIDTH;
> -	fse->max_height = RZG2L_CRU_MAX_INPUT_HEIGHT;
> +	fse->max_width = info->max_width;
> +	fse->max_height = info->max_height;
>  
>  	return 0;
>  }
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index f25fd9b35c55..9e5e79c6ca98 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -690,6 +690,7 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
>  static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
>  				   struct v4l2_pix_format *pix)
>  {
> +	const struct rzg2l_cru_info *info = cru->info;
>  	const struct rzg2l_cru_ip_format *fmt;
>  
>  	fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
> @@ -712,8 +713,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
>  	}
>  
>  	/* Limit to CRU capabilities */
> -	v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1,
> -			      &pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0);
> +	v4l_bound_align_image(&pix->width, 320, info->max_width, 1,
> +			      &pix->height, 240, info->max_height, 2, 0);
>  
>  	pix->bytesperline = pix->width * fmt->bpp;
>  	pix->sizeimage = pix->bytesperline * pix->height;

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler to OF data
  2025-02-21 15:55 ` [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler " Tommaso Merciai
@ 2025-02-23 19:55   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 19:55 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:28PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Add `irq_handler` to the `rzg2l_cru_info` structure and pass it as part of
> the OF data. This prepares for supporting RZ/G3E and RZ/V2H(P) SoCs, which
> require a different IRQ handler. Update the IRQ request code to use the
> handler from the OF data.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 3 ++-
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h  | 1 +
>  2 files changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 7e94ae803967..510e55496e8e 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -278,7 +278,7 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>  	if (irq < 0)
>  		return irq;
>  
> -	ret = devm_request_irq(dev, irq, rzg2l_cru_irq, 0,
> +	ret = devm_request_irq(dev, irq, cru->info->irq_handler, 0,
>  			       KBUILD_MODNAME, cru);
>  	if (ret)
>  		return dev_err_probe(dev, ret, "failed to request irq\n");
> @@ -359,6 +359,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
>  	.max_height = 4095,
>  	.image_conv = ICnMC,
>  	.regs = rzg2l_cru_regs,
> +	.irq_handler = rzg2l_cru_irq,
>  };
>  
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index ca156772b949..32bea35c8c1f 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -83,6 +83,7 @@ struct rzg2l_cru_info {
>  	unsigned int max_height;
>  	u16 image_conv;
>  	const u16 *regs;
> +	irqreturn_t (*irq_handler)(int irq, void *data);
>  };
>  
>  /**

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts
  2025-02-21 15:55 ` [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts Tommaso Merciai
@ 2025-02-23 19:56   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 19:56 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, Sakari Ailus,
	devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:29PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Add `enable_interrupts` and `disable_interrupts` function pointers to the
> `rzg2l_cru_info` structure and pass them as part of the OF data. This
> prepares for supporting RZ/G3E and RZ/V2H(P) SoCs, which require different
> interrupt configurations.
> 
> Implement `rzg2l_cru_enable_interrupts()` and
> `rzg2l_cru_disable_interrupts()` functions and update the code to use them
> instead of directly writing to interrupt registers.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

You could squash this with 14/18 though.

> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 ++
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  7 +++++++
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 19 ++++++++++++++-----
>  3 files changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 510e55496e8e..302f792cb415 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -360,6 +360,8 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
>  	.image_conv = ICnMC,
>  	.regs = rzg2l_cru_regs,
>  	.irq_handler = rzg2l_cru_irq,
> +	.enable_interrupts = rzg2l_cru_enable_interrupts,
> +	.disable_interrupts = rzg2l_cru_disable_interrupts,
>  };
>  
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 32bea35c8c1f..3f694044d8cd 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -34,6 +34,8 @@ enum rzg2l_csi2_pads {
>  	RZG2L_CRU_IP_SOURCE,
>  };
>  
> +struct rzg2l_cru_dev;
> +
>  /**
>   * enum rzg2l_cru_dma_state - DMA states
>   * @RZG2L_CRU_DMA_STOPPED:   No operation in progress
> @@ -84,6 +86,8 @@ struct rzg2l_cru_info {
>  	u16 image_conv;
>  	const u16 *regs;
>  	irqreturn_t (*irq_handler)(int irq, void *data);
> +	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> +	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
>  };
>  
>  /**
> @@ -178,4 +182,7 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code);
>  const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format);
>  const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
>  
> +void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> +void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> +
>  #endif
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 022da19dd88a..5ffa3173af62 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -254,8 +254,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
>  	spin_lock_irqsave(&cru->qlock, flags);
>  
>  	/* Disable and clear the interrupt */
> -	rzg2l_cru_write(cru, CRUnIE, 0);
> -	rzg2l_cru_write(cru, CRUnINTS, 0x001F0F0F);
> +	cru->info->disable_interrupts(cru);
>  
>  	/* Stop the operation of image conversion */
>  	rzg2l_cru_write(cru, ICnEN, 0);
> @@ -347,6 +346,17 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
>  	return fd.entry[0].bus.csi2.vc;
>  }
>  
> +void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> +{
> +	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> +}
> +
> +void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> +{
> +	rzg2l_cru_write(cru, CRUnIE, 0);
> +	rzg2l_cru_write(cru, CRUnINTS, 0x001f000f);
> +}
> +
>  int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  {
>  	struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
> @@ -368,8 +378,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  	rzg2l_cru_write(cru, CRUnRST, CRUnRST_VRESETN);
>  
>  	/* Disable and clear the interrupt before using */
> -	rzg2l_cru_write(cru, CRUnIE, 0);
> -	rzg2l_cru_write(cru, CRUnINTS, 0x001f000f);
> +	cru->info->disable_interrupts(cru);
>  
>  	/* Initialize the AXI master */
>  	rzg2l_cru_initialize_axi(cru);
> @@ -382,7 +391,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  	}
>  
>  	/* Enable interrupt */
> -	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> +	cru->info->enable_interrupts(cru);
>  
>  	/* Enable image processing reception */
>  	rzg2l_cru_write(cru, ICnEN, ICnEN_ICEN);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty
  2025-02-21 15:55 ` [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty Tommaso Merciai
@ 2025-02-23 20:00   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 20:00 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, Sakari Ailus,
	devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:30PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Add a `fifo_empty` function pointer to the `rzg2l_cru_info` structure and
> pass it as part of the OF data. On RZ/G3E and RZ/V2H(P) SoCs, checking if
> the FIFO is empty requires a different register configuration.
> 
> Implement `rzg2l_fifo_empty()` and update the code to use it from the
> function pointer.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  1 +
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  3 +++
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 23 +++++++++++++------
>  3 files changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 302f792cb415..e4fb3e12d6bf 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -362,6 +362,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
>  	.irq_handler = rzg2l_cru_irq,
>  	.enable_interrupts = rzg2l_cru_enable_interrupts,
>  	.disable_interrupts = rzg2l_cru_disable_interrupts,
> +	.fifo_empty = rzg2l_fifo_empty,
>  };
>  
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 3f694044d8cd..2e17bfef43ce 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -88,6 +88,7 @@ struct rzg2l_cru_info {
>  	irqreturn_t (*irq_handler)(int irq, void *data);
>  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
>  	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
> +	bool (*fifo_empty)(struct rzg2l_cru_dev *cru);
>  };
>  
>  /**
> @@ -185,4 +186,6 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
>  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
>  
> +bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> +
>  #endif
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 5ffa3173af62..7cc83486ce03 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -244,9 +244,23 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
>  	return 0;
>  }
>  
> -void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
> +bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
>  {
>  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> +
> +	amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> +
> +	amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR;
> +	amnfifopntr_r_y =
> +		(amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16;
> +	if (amnfifopntr_w == amnfifopntr_r_y)
> +		return true;
> +
> +	return false;

Maybe

	return amnfifopntr_w == amnfifopntr_r_y;

> +}

I wonder if this function, along with rzg2l_cru_enable_interrupts() and
rzg2l_cru_disable_interrupts(), should be moved to rzg2l-core.c. Either
way,

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

> +
> +void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
> +{
>  	unsigned int retries = 0;
>  	unsigned long flags;
>  	u32 icnms;
> @@ -274,12 +288,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
>  
>  	/* Wait until the FIFO becomes empty */
>  	for (retries = 5; retries > 0; retries--) {
> -		amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> -
> -		amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR;
> -		amnfifopntr_r_y =
> -			(amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16;
> -		if (amnfifopntr_w == amnfifopntr_r_y)
> +		if (cru->info->fifo_empty(cru))
>  			break;
>  
>  		usleep_range(10, 20);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI
  2025-02-21 15:55 ` [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI Tommaso Merciai
@ 2025-02-23 20:03   ` Laurent Pinchart
  0 siblings, 0 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 20:03 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:31PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> Add a `csi_setup` function pointer to the `rzg2l_cru_info` structure and
> pass it as part of the OF data. On RZ/G3E and RZ/V2H(P) SoCs, additional
> register configurations are required compared to the RZ/G2L SoC.
> 
> Modify `rzg2l_cru_csi2_setup()` to be referenced through this function
> pointer and update the code to use it accordingly.
> 
> This change is in preparation for adding support for RZ/G3E and RZ/V2H(P)
> SoCs.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

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

> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c  | 1 +
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h   | 6 ++++++
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 8 ++++----
>  3 files changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index e4fb3e12d6bf..3ae0cd83af16 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -363,6 +363,7 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
>  	.enable_interrupts = rzg2l_cru_enable_interrupts,
>  	.disable_interrupts = rzg2l_cru_disable_interrupts,
>  	.fifo_empty = rzg2l_fifo_empty,
> +	.csi_setup = rzg2l_cru_csi2_setup,
>  };
>  
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 2e17bfef43ce..ccaba5220f1c 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -89,6 +89,9 @@ struct rzg2l_cru_info {
>  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
>  	void (*disable_interrupts)(struct rzg2l_cru_dev *cru);
>  	bool (*fifo_empty)(struct rzg2l_cru_dev *cru);
> +	void (*csi_setup)(struct rzg2l_cru_dev *cru,
> +			  const struct rzg2l_cru_ip_format *ip_fmt,
> +			  u8 csi_vc);
>  };
>  
>  /**
> @@ -187,5 +190,8 @@ void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
>  
>  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> +void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> +			  const struct rzg2l_cru_ip_format *ip_fmt,
> +			  u8 csi_vc);
>  
>  #endif
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 7cc83486ce03..637c9c9f9ba8 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -196,9 +196,9 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
>  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
>  }
>  
> -static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> -				 const struct rzg2l_cru_ip_format *ip_fmt,
> -				 u8 csi_vc)
> +void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> +			  const struct rzg2l_cru_ip_format *ip_fmt,
> +			  u8 csi_vc)
>  {
>  	const struct rzg2l_cru_info *info = cru->info;
>  	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> @@ -220,7 +220,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
>  	const struct rzg2l_cru_ip_format *cru_ip_fmt;
>  
>  	cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code);
> -	rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc);
> +	info->csi_setup(cru, cru_ip_fmt, csi_vc);
>  
>  	/* Output format */
>  	cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-21 15:55 ` [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC Tommaso Merciai
@ 2025-02-23 20:32   ` Laurent Pinchart
  2025-02-24 18:15     ` Tommaso Merciai
  2025-02-25 10:52     ` Tommaso Merciai
  0 siblings, 2 replies; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-23 20:32 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> the Renesas RZ/G2L SoC, with the following differences:
> 
> - Additional registers rzg3e_cru_regs.
> - A different irq handler rzg3e_cru_irq.
> - A different rzg3e_cru_csi2_setup.
> - A different max input width.
> 
> Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> and RZ/G3E and related RZ/G3E functions:
> 
>  - rzg3e_cru_enable_interrupts()
>  - rzg3e_cru_enable_interrupts()
>  - rz3e_fifo_empty()
>  - rzg3e_cru_csi2_setup()
>  - rzg3e_cru_get_current_slot()
> 
> Add then support for the RZ/G3E SoC CRU block with the new compatible
> string "renesas,r9a09g047-cru".
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
>  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
>  4 files changed, 282 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 3ae0cd83af16..075a3aa8af29 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> +					    sizeof(struct rzg2l_cru_mem_bank),
> +					    GFP_KERNEL);
> +	if (!cru->mem_banks)
> +		return dev_err_probe(dev, -ENOMEM,
> +				     "Failed to init mem banks\n");
> +
>  	pm_suspend_ignore_children(dev, true);
>  	ret = devm_pm_runtime_enable(dev);
>  	if (ret)
> @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
>  	rzg2l_cru_dma_unregister(cru);
>  }
>  
> +static const u16 rzg3e_cru_regs[] = {
> +	[CRUnCTRL] = 0x0,
> +	[CRUnIE] = 0x4,
> +	[CRUnIE2] = 0x8,
> +	[CRUnINTS] = 0xc,
> +	[CRUnINTS2] = 0x10,
> +	[CRUnRST] = 0x18,
> +	[AMnMB1ADDRL] = 0x40,
> +	[AMnMB1ADDRH] = 0x44,
> +	[AMnMB2ADDRL] = 0x48,
> +	[AMnMB2ADDRH] = 0x4c,
> +	[AMnMB3ADDRL] = 0x50,
> +	[AMnMB3ADDRH] = 0x54,
> +	[AMnMB4ADDRL] = 0x58,
> +	[AMnMB4ADDRH] = 0x5c,
> +	[AMnMB5ADDRL] = 0x60,
> +	[AMnMB5ADDRH] = 0x64,
> +	[AMnMB6ADDRL] = 0x68,
> +	[AMnMB6ADDRH] = 0x6c,
> +	[AMnMB7ADDRL] = 0x70,
> +	[AMnMB7ADDRH] = 0x74,
> +	[AMnMB8ADDRL] = 0x78,
> +	[AMnMB8ADDRH] = 0x7c,
> +	[AMnMBVALID] = 0x88,
> +	[AMnMADRSL] = 0x8c,
> +	[AMnMADRSH] = 0x90,
> +	[AMnAXIATTR] = 0xec,
> +	[AMnFIFOPNTR] = 0xf8,
> +	[AMnAXISTP] = 0x110,
> +	[AMnAXISTPACK] = 0x114,
> +	[AMnIS] = 0x128,
> +	[ICnEN] = 0x1f0,
> +	[ICnSVCNUM] = 0x1f8,
> +	[ICnSVC] = 0x1fc,
> +	[ICnIPMC_C0] = 0x200,
> +	[ICnMS] = 0x2d8,
> +	[ICnDMR] = 0x304,
> +};
> +
> +static const struct rzg2l_cru_info rzg3e_cru_info = {
> +	.max_width = 4095,
> +	.max_height = 4095,
> +	.image_conv = ICnIPMC_C0,
> +	.stride = 128,
> +	.regs = rzg3e_cru_regs,
> +	.irq_handler = rzg3e_cru_irq,
> +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> +	.fifo_empty = rz3e_fifo_empty,
> +	.csi_setup = rzg3e_cru_csi2_setup,
> +};
> +
>  static const u16 rzg2l_cru_regs[] = {
>  	[CRUnCTRL] = 0x0,
>  	[CRUnIE] = 0x4,
> @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
>  };
>  
>  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> +	{
> +		.compatible = "renesas,r9a09g047-cru",
> +		.data = &rzg3e_cru_info,
> +	},
>  	{
>  		.compatible = "renesas,rzg2l-cru",
>  		.data = &rzgl2_cru_info,
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> index 82920db7134e..1646d1e2953c 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> @@ -14,8 +14,13 @@
>  
>  #define CRUnIE_EFE			BIT(17)
>  
> +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> +
>  #define CRUnINTS_SFS			BIT(16)
>  
> +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> +
>  #define CRUnRST_VRESETN			BIT(0)
>  
>  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> @@ -32,7 +37,14 @@
>  #define AMnAXIATTR_AXILEN		(0xf)
>  
>  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
>  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> +
> +#define AMnIS_IS_MASK			GENMASK(14, 7)
> +#define AMnIS_IS(x)			((x) << 7)
>  
>  #define AMnAXISTP_AXI_STOP		BIT(0)
>  
> @@ -40,6 +52,11 @@
>  
>  #define ICnEN_ICEN			BIT(0)
>  
> +#define ICnSVC_SVC0(x)			(x)
> +#define ICnSVC_SVC1(x)			((x) << 4)
> +#define ICnSVC_SVC2(x)			((x) << 8)
> +#define ICnSVC_SVC3(x)			((x) << 12)
> +
>  #define ICnMC_CSCTHR			BIT(5)
>  #define ICnMC_INF(x)			((x) << 16)
>  #define ICnMC_VCSEL(x)			((x) << 22)
> @@ -52,7 +69,9 @@
>  enum rzg2l_cru_common_regs {
>  	CRUnCTRL,	/* CRU Control */
>  	CRUnIE,		/* CRU Interrupt Enable */
> +	CRUnIE2,	/* CRU Interrupt Enable(2) */
>  	CRUnINTS,	/* CRU Interrupt Status */
> +	CRUnINTS2,	/* CRU Interrupt Status(2) */
>  	CRUnRST, 	/* CRU Reset */
>  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
>  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
>  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
>  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
>  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
>  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
>  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
>  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
>  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> +	AMnIS,		/* Image Stride Setting Register */
>  	ICnEN,		/* CRU Image Processing Enable */
> +	ICnSVCNUM,	/* CRU SVC Number Register */
> +	ICnSVC,		/* CRU VC Select Register */
>  	ICnMC,		/* CRU Image Processing Main Control */
> +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
>  	ICnMS,		/* CRU Module Status */
>  	ICnDMR,		/* CRU Data Output Mode */
>  };
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index ccaba5220f1c..3301379c132c 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
>  	unsigned int max_width;
>  	unsigned int max_height;
>  	u16 image_conv;
> +	u16 stride;
>  	const u16 *regs;
>  	irqreturn_t (*irq_handler)(int irq, void *data);
>  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
>  			  u8 csi_vc);
>  };
>  
> +struct rzg2l_cru_mem_bank {
> +	dma_addr_t addrl;
> +	dma_addr_t addrh;
> +};
> +
>  /**
>   * struct rzg2l_cru_dev - Renesas CRU device structure
>   * @dev:		(OF) device
> @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
>   * @vdev:		V4L2 video device associated with CRU
>   * @v4l2_dev:		V4L2 device
>   * @num_buf:		Holds the current number of buffers enabled
> + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> + * @mem_banks:		Memory addresses where current video data is written.
>   * @notifier:		V4L2 asynchronous subdevs notifier
>   *
>   * @ip:			Image processing subdev info
> @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
>  	struct v4l2_device v4l2_dev;
>  	u8 num_buf;
>  
> +	u8 svc_channel;
> +	struct rzg2l_cru_mem_bank *mem_banks;
> +
>  	struct v4l2_async_notifier notifier;
>  
>  	struct rzg2l_cru_ip ip;
> @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
>  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
>  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> +irqreturn_t rzg3e_cru_irq(int irq, void *data);
>  
>  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
>  
> @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
>  
>  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
>  
>  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
>  			  const struct rzg2l_cru_ip_format *ip_fmt,
>  			  u8 csi_vc);
> +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> +			  const struct rzg2l_cru_ip_format *ip_fmt,
> +			  u8 csi_vc);
>  
>  #endif
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 637c9c9f9ba8..efd70c13704e 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
>  	/* Currently, we just use the buffer in 32 bits address */

Should this be fixed ?

>  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
>  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> +
> +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> +	cru->mem_banks[slot].addrh = upper_32_bits(addr);

Here you stplit the dma_addr_t in two fields, storing the low and high
parts separately (but still in dma_addr_t variables), and below you
recombine those two fields to recreate the full address. That doesn't
seem needed.

>  }
>  
>  /*
> @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
>  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
>  }
>  
> -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
>  {
>  	unsigned int slot;
>  	u32 amnaxiattr;
> @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
>  	for (slot = 0; slot < cru->num_buf; slot++)
>  		rzg2l_cru_fill_hw_slot(cru, slot);
>  
> +	if (cru->info->stride) {

I'd name this field stride_align or something similar.

> +		u32 stride = cru->format.bytesperline;
> +		u32 amnis;
> +
> +		if (stride % cru->info->stride) {
> +			dev_err(cru->dev,
> +				"Bytesperline must be multiple of %u bytes\n",
> +				cru->info->stride);
> +			return -EINVAL;
> +		}

This needs to be caught at set format time, and the stride must be
adjusted then.

> +		stride = stride / cru->info->stride;

		stride /= cru->info->stride;

> +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> +	}
> +
>  	/* Set AXI burst max length to recommended setting */
>  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
>  	amnaxiattr |= AMnAXIATTR_AXILEN;
>  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> +
> +	return 0;
> +}
> +
> +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> +			  const struct rzg2l_cru_ip_format *ip_fmt,
> +			  u8 csi_vc)
> +{
> +	const struct rzg2l_cru_info *info = cru->info;
> +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> +
> +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> +
> +	/* Set virtual channel CSI2 */
> +	icnmc |= ICnMC_VCSEL(csi_vc);
> +
> +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);

As far as I can tell, csi_vc and cru->svc_channel hold the same value.
You can drop ths svc_channel field.

> +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> +	rzg2l_cru_write(cru, info->image_conv, icnmc);
>  }
>  
>  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
>  	return 0;
>  }
>  
> +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> +{
> +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> +
> +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> +		return true;
> +
> +	return false;
> +}
> +
>  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
>  {
>  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
>  	return fd.entry[0].bus.csi2.vc;
>  }
>  
> +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> +{
> +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> +}
> +
> +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> +{
> +	rzg2l_cru_write(cru, CRUnIE, 0);
> +	rzg2l_cru_write(cru, CRUnIE2, 0);
> +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> +}
> +
>  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
>  {
>  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  	if (ret < 0)
>  		return ret;
>  	csi_vc = ret;
> +	cru->svc_channel = csi_vc;
>  
>  	spin_lock_irqsave(&cru->qlock, flags);
>  
> @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  	cru->info->disable_interrupts(cru);
>  
>  	/* Initialize the AXI master */
> -	rzg2l_cru_initialize_axi(cru);
> +	ret = rzg2l_cru_initialize_axi(cru);
> +	if (ret) {
> +		spin_unlock_irqrestore(&cru->qlock, flags);
> +		return ret;
> +	}

This will go away once you remove the error check from
rzg2l_cru_initialize_axi(), which should then remain a void function.

There's another function returning an error here,
rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
separate patch).

>  
>  	/* Initialize image convert */
>  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
>  	return IRQ_RETVAL(handled);
>  }
>  
> +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> +{
> +	dma_addr_t amnmadrs;
> +	unsigned int slot;
> +
> +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);

What if the two registers are read on a frame boundary ?

> +
> +	for (slot = 0; slot < cru->num_buf; slot++) {
> +		dma_addr_t buf_addr;
> +
> +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> +			cru->mem_banks[slot].addrl;
> +
> +		/* Ensure amnmadrs is within this buffer range */
> +		if (amnmadrs >= buf_addr &&
> +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> +			return slot;
> +		}
> +	}
> +
> +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> +	return -EINVAL;
> +}
> +
> +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> +{
> +	struct rzg2l_cru_dev *cru = data;
> +	unsigned int handled = 0;
> +	unsigned long flags;
> +	unsigned int slot;
> +	u32 irq_status;
> +
> +	spin_lock_irqsave(&cru->qlock, flags);
> +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> +	if (!(irq_status))
> +		goto done;
> +
> +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> +
> +	handled = 1;
> +
> +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> +
> +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> +		goto done;
> +	}
> +
> +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> +		if (irq_status & CRUnINTS2_FSxS(0) ||
> +		    irq_status & CRUnINTS2_FSxS(1) ||
> +		    irq_status & CRUnINTS2_FSxS(2) ||
> +		    irq_status & CRUnINTS2_FSxS(3))
> +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> +		goto done;
> +	}
> +
> +	slot = rzg3e_cru_get_current_slot(cru);
> +	if (slot < 0)
> +		goto done;
> +
> +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> +
> +	cru->mem_banks[slot].addrl = 0;
> +	cru->mem_banks[slot].addrh = 0;
> +
> +	/*
> +	 * To hand buffers back in a known order to userspace start
> +	 * to capture first from slot 0.
> +	 */
> +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> +		if (slot != 0) {
> +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> +			goto done;
> +		}
> +		dev_dbg(cru->dev, "Capture start synced!\n");
> +		cru->state = RZG2L_CRU_DMA_RUNNING;
> +	}
> +
> +	/* Capture frame */
> +	if (cru->queue_buf[slot]) {
> +		cru->queue_buf[slot]->field = cru->format.field;
> +		cru->queue_buf[slot]->sequence = cru->sequence;
> +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> +				VB2_BUF_STATE_DONE);
> +		cru->queue_buf[slot] = NULL;
> +	} else {
> +		/* Scratch buffer was used, dropping frame. */
> +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> +	}
> +
> +	cru->sequence++;
> +
> +	/* Prepare for next frame */
> +	rzg2l_cru_fill_hw_slot(cru, slot);
> +
> +done:
> +	spin_unlock_irqrestore(&cru->qlock, flags);
> +	return IRQ_RETVAL(handled);
> +}
> +
>  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
>  {
>  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC
  2025-02-23 18:19   ` Laurent Pinchart
@ 2025-02-23 20:57     ` Lad, Prabhakar
  0 siblings, 0 replies; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 20:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tommaso Merciai, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Hi Laurent,

Thank you for the review.

On Sun, Feb 23, 2025 at 6:20 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Tommaso,
>
> Thank you for the patch.
>
> On Fri, Feb 21, 2025 at 04:55:23PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > The RZ/V2H(P) SoC does not provide a `system` clock for the CSI-2
> > interface. To accommodate this, use `devm_clk_get_optional()` instead
> > of `devm_clk_get()` when retrieving the clock.
>
> The clock shouldn't be optional. On all SoCs but V2H it should remain
> mandatory, and on V2H you shouldn't call clk_get() at all.
>
> I'd recommend adding a flag to the rzg2l_csi2_info structure.
>
Agreed, in this case dtbs_check will not catch this issue if we pass
"video" and "apb" clocks.

Cheers,
Prabhakar

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-23 18:08   ` Laurent Pinchart
@ 2025-02-23 21:00     ` Lad, Prabhakar
  2025-02-24  8:07       ` Tommaso Merciai
  2025-02-24  9:00     ` Geert Uytterhoeven
  1 sibling, 1 reply; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 21:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tommaso Merciai, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

HI Laurent,

Thank you for the review.

On Sun, Feb 23, 2025 at 6:09 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Tommaso,
>
> Thank you for the patch.
>
> On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> > found on the Renesas RZ/G2L SoC, with the following differences:
> > - A different D-PHY
> > - Additional registers for the MIPI CSI-2 link
> > - Only two clocks
> >
> > Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> > SoC.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> > Changes since v1:
> >  - Dropped empty line as suggested by LPinchart
> >  - Fixed minItems into else conditional block as suggested by RHerring
> >
> >  .../bindings/media/renesas,rzg2l-csi2.yaml    | 59 ++++++++++++++-----
> >  1 file changed, 44 insertions(+), 15 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > index 7faa12fecd5b..1d7784e8af16 100644
> > --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > @@ -17,12 +17,14 @@ description:
> >
> >  properties:
> >    compatible:
> > -    items:
> > -      - enum:
> > -          - renesas,r9a07g043-csi2       # RZ/G2UL
> > -          - renesas,r9a07g044-csi2       # RZ/G2{L,LC}
> > -          - renesas,r9a07g054-csi2       # RZ/V2L
> > -      - const: renesas,rzg2l-csi2
> > +    oneOf:
> > +      - items:
> > +          - enum:
> > +              - renesas,r9a07g043-csi2 # RZ/G2UL
> > +              - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
> > +              - renesas,r9a07g054-csi2 # RZ/V2L
> > +          - const: renesas,rzg2l-csi2
> > +      - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
> >
> >    reg:
> >      maxItems: 1
> > @@ -31,16 +33,24 @@ properties:
> >      maxItems: 1
> >
> >    clocks:
> > -    items:
> > -      - description: Internal clock for connecting CRU and MIPI
> > -      - description: CRU Main clock
> > -      - description: CRU Register access clock
> > +    oneOf:
> > +      - items:
> > +          - description: Internal clock for connecting CRU and MIPI
> > +          - description: CRU Main clock
> > +          - description: CRU Register access clock
> > +      - items:
> > +          - description: CRU Main clock
> > +          - description: CRU Register access clock
> >
> >    clock-names:
> > -    items:
> > -      - const: system
> > -      - const: video
> > -      - const: apb
> > +    oneOf:
> > +      - items:
> > +          - const: system
> > +          - const: video
> > +          - const: apb
> > +      - items:
> > +          - const: video
> > +          - const: apb
> >
> >    power-domains:
> >      maxItems: 1
> > @@ -48,7 +58,7 @@ properties:
> >    resets:
> >      items:
> >        - description: CRU_PRESETN reset terminal
> > -      - description: CRU_CMN_RSTB reset terminal
> > +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
>
> I'd mention which SoCs these apply to:
>
>       - description:
>           CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY reset (RZ/V2H)
>
Maybe RZ/V2H(P).

Cheers,
Prabhakar

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

* Re: [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block
  2025-02-21 15:55 ` [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block Tommaso Merciai
  2025-02-23 18:10   ` Laurent Pinchart
@ 2025-02-23 21:11   ` Lad, Prabhakar
  2025-02-24  8:11     ` Tommaso Merciai
  1 sibling, 1 reply; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 21:11 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree, linux-kernel

Hi Tommaso,

Thank you for the patch.

On Fri, Feb 21, 2025 at 4:04 PM Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
>
> Document the CSI-2 block which is part of CRU found in Renesas RZ/G3E
> SoC.
>
> The CSI-2 block on the RZ/G3E SoC is identical to one found on the
> RZ/V2H(P) SoC.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../devicetree/bindings/media/renesas,rzg2l-csi2.yaml          | 3 +++
>  1 file changed, 3 insertions(+)
>
As pointed by Laurent, with below added to resets description,

- description:
      CRU_CMN_RSTB reset terminal (except for RZ/V2H(P) and RZ/G3E) or
      D-PHY reset (for RZ/V2H(P) and RZ/G3E).

Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Cheers,
Prabhakar


> diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> index 1d7784e8af16..9b7ed86ef14b 100644
> --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> @@ -24,6 +24,9 @@ properties:
>                - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
>                - renesas,r9a07g054-csi2 # RZ/V2L
>            - const: renesas,rzg2l-csi2
> +      - items:
> +          - const: renesas,r9a09g047-csi2 # RZ/G3E
> +          - const: renesas,r9a09g057-csi2
>        - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
>
>    reg:
> --
> 2.34.1
>
>

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

* Re: [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable()
  2025-02-21 15:55 ` [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable() Tommaso Merciai
@ 2025-02-23 21:13   ` Lad, Prabhakar
  0 siblings, 0 replies; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 21:13 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Laurent Pinchart, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

On Fri, Feb 21, 2025 at 4:05 PM Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
>
> Use newly added devm_pm_runtime_enable() into rzg2l_csi2_probe() and
> drop error path accordingly. Drop also unnecessary pm_runtime_disable()
> from rzg2l_csi2_remove().
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> Changes since v1:
>  - Collected tags
>
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Cheers,
Prabhakar

> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 948f1917b830..4ccf7c5ea58b 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -805,11 +805,13 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>         if (ret)
>                 return ret;
>
> -       pm_runtime_enable(dev);
> +       ret = devm_pm_runtime_enable(dev);
> +       if (ret)
> +               return ret;
>
>         ret = rzg2l_validate_csi2_lanes(csi2);
>         if (ret)
> -               goto error_pm;
> +               return ret;
>
>         csi2->subdev.dev = dev;
>         v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
> @@ -834,7 +836,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>         ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads),
>                                      csi2->pads);
>         if (ret)
> -               goto error_pm;
> +               return ret;
>
>         ret = v4l2_subdev_init_finalize(&csi2->subdev);
>         if (ret < 0)
> @@ -852,8 +854,6 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
>         v4l2_async_nf_unregister(&csi2->notifier);
>         v4l2_async_nf_cleanup(&csi2->notifier);
>         media_entity_cleanup(&csi2->subdev.entity);
> -error_pm:
> -       pm_runtime_disable(dev);
>
>         return ret;
>  }
> @@ -867,7 +867,6 @@ static void rzg2l_csi2_remove(struct platform_device *pdev)
>         v4l2_async_unregister_subdev(&csi2->subdev);
>         v4l2_subdev_cleanup(&csi2->subdev);
>         media_entity_cleanup(&csi2->subdev.entity);
> -       pm_runtime_disable(&pdev->dev);
>  }
>
>  static int rzg2l_csi2_pm_runtime_suspend(struct device *dev)
> --
> 2.34.1
>
>

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

* Re: [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable()
  2025-02-21 15:55 ` [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable() Tommaso Merciai
  2025-02-23 18:14   ` Laurent Pinchart
@ 2025-02-23 21:14   ` Lad, Prabhakar
  1 sibling, 0 replies; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 21:14 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Laurent Pinchart, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

On Fri, Feb 21, 2025 at 4:06 PM Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
>
> Use newly added devm_pm_runtime_enable() into rzg2l_cru_probe() and
> drop unnecessary pm_runtime_disable() from rzg2l_cru_probe() and
> rzg2l_csi2_remove().
>
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> Changes since v1:
>  - Fixed DMA leak as suggested by LPinchart
>  - Collected tags
>
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Cheers,
Prabhakar

> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 70fed0ce45ea..eed9d2bd0841 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -287,7 +287,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>
>         cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
>         pm_suspend_ignore_children(dev, true);
> -       pm_runtime_enable(dev);
> +       ret = devm_pm_runtime_enable(dev);
> +       if (ret)
> +               goto error_dma_unregister;
>
>         ret = rzg2l_cru_media_init(cru);
>         if (ret)
> @@ -297,7 +299,6 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
>
>  error_dma_unregister:
>         rzg2l_cru_dma_unregister(cru);
> -       pm_runtime_disable(dev);
>
>         return ret;
>  }
> @@ -306,8 +307,6 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
>  {
>         struct rzg2l_cru_dev *cru = platform_get_drvdata(pdev);
>
> -       pm_runtime_disable(&pdev->dev);
> -
>         v4l2_async_nf_unregister(&cru->notifier);
>         v4l2_async_nf_cleanup(&cru->notifier);
>
> --
> 2.34.1
>
>

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

* Re: [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling
  2025-02-23 18:17   ` Laurent Pinchart
@ 2025-02-23 21:21     ` Lad, Prabhakar
  0 siblings, 0 replies; 56+ messages in thread
From: Lad, Prabhakar @ 2025-02-23 21:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tommaso Merciai, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, Hans Verkuil,
	Uwe Kleine-König, devicetree, linux-kernel

Hi Laurent,

Thank you for the review.

On Sun, Feb 23, 2025 at 6:18 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Tommaso,
>
> Thank you for the patch.
>
> On Fri, Feb 21, 2025 at 04:55:22PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > In preparation for adding support for the RZ/V2H(P) SoC, where the D-PHY
> > differs from the existing RZ/G2L implementation, introduce a new
> > rzg2l_csi2_info structure. This structure provides function pointers for
> > SoC-specific D-PHY enable and disable operations.
> >
> > Modify rzg2l_csi2_dphy_setting() to use these function pointers instead of
> > calling rzg2l_csi2_dphy_enable() and rzg2l_csi2_dphy_disable() directly.
> > Update the device match table to store the appropriate function pointers
> > for each compatible SoC.
> >
> > This change prepares the driver for future extensions without affecting
> > the current functionality for RZ/G2L.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 24 ++++++++++++++++---
> >  1 file changed, 21 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> > index 4ccf7c5ea58b..3a4e720ba732 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> > @@ -107,6 +107,7 @@ struct rzg2l_csi2 {
> >       void __iomem *base;
> >       struct reset_control *presetn;
> >       struct reset_control *cmn_rstb;
> > +     const struct rzg2l_csi2_info *info;
> >       struct clk *sysclk;
> >       struct clk *vclk;
> >       unsigned long vclk_rate;
> > @@ -123,6 +124,11 @@ struct rzg2l_csi2 {
> >       bool dphy_enabled;
> >  };
> >
> > +struct rzg2l_csi2_info {
> > +     int (*dphy_enable)(struct rzg2l_csi2 *csi2);
> > +     int (*dphy_disable)(struct rzg2l_csi2 *csi2);
> > +};
>
> Unless you'll need to add non-function fields later, I'd name the
> structure rzg2l_csi2_phy_ops.
>
As based on the feedback on patch 09/18 I will keep the struct name as is.

> > +
> >  struct rzg2l_csi2_timings {
> >       u32 t_init;
> >       u32 tclk_miss;
> > @@ -360,9 +366,9 @@ static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on)
> >       struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
> >
> >       if (on)
> > -             return rzg2l_csi2_dphy_enable(csi2);
> > +             return csi2->info->dphy_enable(csi2);
> >
> > -     return rzg2l_csi2_dphy_disable(csi2);
> > +     return csi2->info->dphy_disable(csi2);
> >  }
> >
> >  static int rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
> > @@ -772,6 +778,10 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
> >       if (!csi2)
> >               return -ENOMEM;
> >
> > +     csi2->info = of_device_get_match_data(dev);
> > +     if (!csi2->info)
> > +             return dev_err_probe(dev, -EINVAL, "Failed to get OF match data\n");
> > +
> >       csi2->base = devm_platform_ioremap_resource(pdev, 0);
> >       if (IS_ERR(csi2->base))
> >               return PTR_ERR(csi2->base);
> > @@ -890,8 +900,16 @@ static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
> >                      rzg2l_csi2_pm_runtime_resume, NULL)
> >  };
> >
> > +static const struct rzg2l_csi2_info rzg2l_csi2_info = {
> > +     .dphy_enable = rzg2l_csi2_dphy_enable,
> > +     .dphy_disable = rzg2l_csi2_dphy_disable,
> > +};
>
> I'd recommend moving this just below the definition of the
> rzg2l_csi2_dphy_enable() function.
>
Ok.

> Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>
> > +
> >  static const struct of_device_id rzg2l_csi2_of_table[] = {
> > -     { .compatible = "renesas,rzg2l-csi2", },
> > +     {
> > +             .compatible = "renesas,rzg2l-csi2",
> > +             .data = &rzg2l_csi2_info,
> > +     },
> >       { /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table);
>
> --
> Regards,
>
> Laurent Pinchart
>
Chers,
Prabhakar

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-23 21:00     ` Lad, Prabhakar
@ 2025-02-24  8:07       ` Tommaso Merciai
  0 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-24  8:07 UTC (permalink / raw)
  To: Lad, Prabhakar
  Cc: Laurent Pinchart, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

Hi Laurent, Prabhakar,

Thanks for your review.

On Sun, Feb 23, 2025 at 09:00:48PM +0000, Lad, Prabhakar wrote:
> HI Laurent,
> 
> Thank you for the review.
> 
> On Sun, Feb 23, 2025 at 6:09 PM Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Hi Tommaso,
> >
> > Thank you for the patch.
> >
> > On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > >
> > > The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> > > found on the Renesas RZ/G2L SoC, with the following differences:
> > > - A different D-PHY
> > > - Additional registers for the MIPI CSI-2 link
> > > - Only two clocks
> > >
> > > Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> > > SoC.
> > >
> > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > ---
> > > Changes since v1:
> > >  - Dropped empty line as suggested by LPinchart
> > >  - Fixed minItems into else conditional block as suggested by RHerring
> > >
> > >  .../bindings/media/renesas,rzg2l-csi2.yaml    | 59 ++++++++++++++-----
> > >  1 file changed, 44 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > > index 7faa12fecd5b..1d7784e8af16 100644
> > > --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > > @@ -17,12 +17,14 @@ description:
> > >
> > >  properties:
> > >    compatible:
> > > -    items:
> > > -      - enum:
> > > -          - renesas,r9a07g043-csi2       # RZ/G2UL
> > > -          - renesas,r9a07g044-csi2       # RZ/G2{L,LC}
> > > -          - renesas,r9a07g054-csi2       # RZ/V2L
> > > -      - const: renesas,rzg2l-csi2
> > > +    oneOf:
> > > +      - items:
> > > +          - enum:
> > > +              - renesas,r9a07g043-csi2 # RZ/G2UL
> > > +              - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
> > > +              - renesas,r9a07g054-csi2 # RZ/V2L
> > > +          - const: renesas,rzg2l-csi2
> > > +      - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
> > >
> > >    reg:
> > >      maxItems: 1
> > > @@ -31,16 +33,24 @@ properties:
> > >      maxItems: 1
> > >
> > >    clocks:
> > > -    items:
> > > -      - description: Internal clock for connecting CRU and MIPI
> > > -      - description: CRU Main clock
> > > -      - description: CRU Register access clock
> > > +    oneOf:
> > > +      - items:
> > > +          - description: Internal clock for connecting CRU and MIPI
> > > +          - description: CRU Main clock
> > > +          - description: CRU Register access clock
> > > +      - items:
> > > +          - description: CRU Main clock
> > > +          - description: CRU Register access clock
> > >
> > >    clock-names:
> > > -    items:
> > > -      - const: system
> > > -      - const: video
> > > -      - const: apb
> > > +    oneOf:
> > > +      - items:
> > > +          - const: system
> > > +          - const: video
> > > +          - const: apb
> > > +      - items:
> > > +          - const: video
> > > +          - const: apb
> > >
> > >    power-domains:
> > >      maxItems: 1
> > > @@ -48,7 +58,7 @@ properties:
> > >    resets:
> > >      items:
> > >        - description: CRU_PRESETN reset terminal
> > > -      - description: CRU_CMN_RSTB reset terminal
> > > +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
> >
> > I'd mention which SoCs these apply to:
> >
> >       - description:
> >           CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY reset (RZ/V2H)
> >
> Maybe RZ/V2H(P).

Will fix this in v3 using:

	- description:
          CRU_CMN_RSTB reset terminal (all but RZ/V2H(P)) or D-PHY reset (RZ/V2H(P))

Thanks & Regards,
Tommaso

> 
> Cheers,
> Prabhakar

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

* Re: [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block
  2025-02-23 21:11   ` Lad, Prabhakar
@ 2025-02-24  8:11     ` Tommaso Merciai
  0 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-24  8:11 UTC (permalink / raw)
  To: Lad, Prabhakar
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree, linux-kernel

Hi Laurent, Prabhakar,

Thanks for the review.

On Sun, Feb 23, 2025 at 09:11:47PM +0000, Lad, Prabhakar wrote:
> Hi Tommaso,
> 
> Thank you for the patch.
> 
> On Fri, Feb 21, 2025 at 4:04 PM Tommaso Merciai
> <tommaso.merciai.xr@bp.renesas.com> wrote:
> >
> > Document the CSI-2 block which is part of CRU found in Renesas RZ/G3E
> > SoC.
> >
> > The CSI-2 block on the RZ/G3E SoC is identical to one found on the
> > RZ/V2H(P) SoC.
> >
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> >  .../devicetree/bindings/media/renesas,rzg2l-csi2.yaml          | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> As pointed by Laurent, with below added to resets description,
> 
> - description:
>       CRU_CMN_RSTB reset terminal (except for RZ/V2H(P) and RZ/G3E) or
>       D-PHY reset (for RZ/V2H(P) and RZ/G3E).
> 
> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Will apply this in v3.
Thanks.


Regards,
Tommaso

> 
> Cheers,
> Prabhakar
> 
> 
> > diff --git a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > index 1d7784e8af16..9b7ed86ef14b 100644
> > --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > @@ -24,6 +24,9 @@ properties:
> >                - renesas,r9a07g044-csi2 # RZ/G2{L,LC}
> >                - renesas,r9a07g054-csi2 # RZ/V2L
> >            - const: renesas,rzg2l-csi2
> > +      - items:
> > +          - const: renesas,r9a09g047-csi2 # RZ/G3E
> > +          - const: renesas,r9a09g057-csi2
> >        - const: renesas,r9a09g057-csi2 # RZ/V2H(P)
> >
> >    reg:
> > --
> > 2.34.1
> >
> >

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-23 18:08   ` Laurent Pinchart
  2025-02-23 21:00     ` Lad, Prabhakar
@ 2025-02-24  9:00     ` Geert Uytterhoeven
  2025-02-24  9:05       ` Geert Uytterhoeven
  1 sibling, 1 reply; 56+ messages in thread
From: Geert Uytterhoeven @ 2025-02-24  9:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tommaso Merciai, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

Hi all,

On Sun, 23 Feb 2025 at 19:09, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> > found on the Renesas RZ/G2L SoC, with the following differences:
> > - A different D-PHY
> > - Additional registers for the MIPI CSI-2 link
> > - Only two clocks
> >
> > Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> > SoC.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

> > --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml

> > @@ -48,7 +58,7 @@ properties:
> >    resets:
> >      items:
> >        - description: CRU_PRESETN reset terminal
> > -      - description: CRU_CMN_RSTB reset terminal
> > +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
>
> I'd mention which SoCs these apply to:
>
>       - description:
>           CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY reset (RZ/V2H)

Note that RZ/G3E uses the same naming, so be prepared for more churn...

However, I am confused...

1. According to Section 35.3.1 "Starting Reception for the MIPI CSI-2
   Input" (RZ/G2L Rev. 1.45) CPG_RST_CRU.CRU_CMN_RSTB _is_ the
   D-PHY reset.

2. The CRU has three (not two) resets on all:
     - CRU_PRESETN,
     - CRU_ARESETN,
     - CRU_CMN_RSTB (RZ/G2L, RZ/V2L, and RZ/G2UL) or
       CRU_S_RESETN (RZ/V2H and RZ/G3E).

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-24  9:00     ` Geert Uytterhoeven
@ 2025-02-24  9:05       ` Geert Uytterhoeven
  2025-02-24  9:09         ` Biju Das
  0 siblings, 1 reply; 56+ messages in thread
From: Geert Uytterhoeven @ 2025-02-24  9:05 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Tommaso Merciai, tomm.merciai, linux-renesas-soc, linux-media,
	biju.das.jz, prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm, devicetree, linux-kernel

On Mon, 24 Feb 2025 at 10:00, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Sun, 23 Feb 2025 at 19:09, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> > On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > >
> > > The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> > > found on the Renesas RZ/G2L SoC, with the following differences:
> > > - A different D-PHY
> > > - Additional registers for the MIPI CSI-2 link
> > > - Only two clocks
> > >
> > > Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> > > SoC.
> > >
> > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
>
> > > --- a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
>
> > > @@ -48,7 +58,7 @@ properties:
> > >    resets:
> > >      items:
> > >        - description: CRU_PRESETN reset terminal
> > > -      - description: CRU_CMN_RSTB reset terminal
> > > +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
> >
> > I'd mention which SoCs these apply to:
> >
> >       - description:
> >           CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY reset (RZ/V2H)
>
> Note that RZ/G3E uses the same naming, so be prepared for more churn...
>
> However, I am confused...
>
> 1. According to Section 35.3.1 "Starting Reception for the MIPI CSI-2
>    Input" (RZ/G2L Rev. 1.45) CPG_RST_CRU.CRU_CMN_RSTB _is_ the
>    D-PHY reset.

This is still valid.

> 2. The CRU has three (not two) resets on all:
>      - CRU_PRESETN,
>      - CRU_ARESETN,
>      - CRU_CMN_RSTB (RZ/G2L, RZ/V2L, and RZ/G2UL) or
>        CRU_S_RESETN (RZ/V2H and RZ/G3E).

Sorry, I missed this binding is about the CSI-2, not the CRU.
So the third interrupt is really about the CSI-2 PHY.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* RE: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-24  9:05       ` Geert Uytterhoeven
@ 2025-02-24  9:09         ` Biju Das
  2025-02-24  9:21           ` Geert Uytterhoeven
  0 siblings, 1 reply; 56+ messages in thread
From: Biju Das @ 2025-02-24  9:09 UTC (permalink / raw)
  To: Geert Uytterhoeven, laurent.pinchart
  Cc: Tommaso Merciai, Tommaso Merciai,
	linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org,
	Prabhakar Mahadev Lad, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org

Hi Geert,

> -----Original Message-----
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Sent: 24 February 2025 09:05
> Subject: Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
> 
> On Mon, 24 Feb 2025 at 10:00, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Sun, 23 Feb 2025 at 19:09, Laurent Pinchart
> > <laurent.pinchart@ideasonboard.com> wrote:
> > > On Fri, Feb 21, 2025 at 04:55:15PM +0100, Tommaso Merciai wrote:
> > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > >
> > > > The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to
> > > > the one found on the Renesas RZ/G2L SoC, with the following differences:
> > > > - A different D-PHY
> > > > - Additional registers for the MIPI CSI-2 link
> > > > - Only two clocks
> > > >
> > > > Add a new compatible string, `renesas,r9a09g057-csi2`, for the
> > > > RZ/V2H(P) SoC.
> > > >
> > > > Signed-off-by: Lad Prabhakar
> > > > <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> >
> > > > ---
> > > > a/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.yaml
> > > > +++ b/Documentation/devicetree/bindings/media/renesas,rzg2l-csi2.y
> > > > +++ aml
> >
> > > > @@ -48,7 +58,7 @@ properties:
> > > >    resets:
> > > >      items:
> > > >        - description: CRU_PRESETN reset terminal
> > > > -      - description: CRU_CMN_RSTB reset terminal
> > > > +      - description: CRU_CMN_RSTB reset terminal or D-PHY reset
> > >
> > > I'd mention which SoCs these apply to:
> > >
> > >       - description:
> > >           CRU_CMN_RSTB reset terminal (all but RZ/V2H) or D-PHY
> > > reset (RZ/V2H)
> >
> > Note that RZ/G3E uses the same naming, so be prepared for more churn...
> >
> > However, I am confused...
> >
> > 1. According to Section 35.3.1 "Starting Reception for the MIPI CSI-2
> >    Input" (RZ/G2L Rev. 1.45) CPG_RST_CRU.CRU_CMN_RSTB _is_ the
> >    D-PHY reset.
> 
> This is still valid.
> 
> > 2. The CRU has three (not two) resets on all:
> >      - CRU_PRESETN,
> >      - CRU_ARESETN,
> >      - CRU_CMN_RSTB (RZ/G2L, RZ/V2L, and RZ/G2UL) or
> >        CRU_S_RESETN (RZ/V2H and RZ/G3E).
> 
> Sorry, I missed this binding is about the CSI-2, not the CRU.
> So the third interrupt is really about the CSI-2 PHY.

You mean typo, interrupt->reset??

Cheers,
Biju

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-24  9:09         ` Biju Das
@ 2025-02-24  9:21           ` Geert Uytterhoeven
  0 siblings, 0 replies; 56+ messages in thread
From: Geert Uytterhoeven @ 2025-02-24  9:21 UTC (permalink / raw)
  To: Biju Das
  Cc: laurent.pinchart, Tommaso Merciai, Tommaso Merciai,
	linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org,
	Prabhakar Mahadev Lad, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org

Hi Biju,

On Mon, 24 Feb 2025 at 10:09, Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > From: Geert Uytterhoeven <geert@linux-m68k.org>
> > On Mon, 24 Feb 2025 at 10:00, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > > 2. The CRU has three (not two) resets on all:
> > >      - CRU_PRESETN,
> > >      - CRU_ARESETN,
> > >      - CRU_CMN_RSTB (RZ/G2L, RZ/V2L, and RZ/G2UL) or
> > >        CRU_S_RESETN (RZ/V2H and RZ/G3E).
> >
> > Sorry, I missed this binding is about the CSI-2, not the CRU.
> > So the third interrupt is really about the CSI-2 PHY.
>
> You mean typo, interrupt->reset??

Yes (doh, coffee for real!)

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support
  2025-02-23 19:52   ` Laurent Pinchart
@ 2025-02-24 13:46     ` Tommaso Merciai
  2025-02-24 18:44       ` Laurent Pinchart
  0 siblings, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-24 13:46 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Laurent,
Thank you for the review.

On Sun, Feb 23, 2025 at 09:52:32PM +0200, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> Thank you for the patch.
> 
> On Fri, Feb 21, 2025 at 04:55:25PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > 
> > Prepare for adding support for RZ/G3E and RZ/V2HP SoCs, which have a
> > CRU-IP that is mostly identical to RZ/G2L but with different register
> > offsets and additional registers. Introduce a flexible register mapping
> > mechanism to handle these variations.
> > 
> > Define the `rzg2l_cru_info` structure to store register mappings and
> > pass it as part of the OF match data. Update the read/write functions
> > to use indexed register offsets from `rzg2l_cru_info`, ensuring
> > compatibility across different SoC variants.
> > 
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 46 ++++++++++++-
> >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        | 65 ++++++++++---------
> >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++
> >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 12 ++--
> >  4 files changed, 92 insertions(+), 35 deletions(-)
> > 
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > index eed9d2bd0841..abc2a979833a 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > @@ -22,6 +22,7 @@
> >  #include <media/v4l2-mc.h>
> >  
> >  #include "rzg2l-cru.h"
> > +#include "rzg2l-cru-regs.h"
> >  
> >  static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
> >  {
> > @@ -269,6 +270,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> >  
> >  	cru->dev = dev;
> >  	cru->info = of_device_get_match_data(dev);
> > +	if (!cru->info)
> > +		return dev_err_probe(dev, -EINVAL,
> > +				     "Failed to get OF match data\n");
> >  
> >  	irq = platform_get_irq(pdev, 0);
> >  	if (irq < 0)
> > @@ -317,8 +321,48 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> >  	rzg2l_cru_dma_unregister(cru);
> >  }
> >  
> > +static const u16 rzg2l_cru_regs[] = {
> > +	[CRUnCTRL] = 0x0,
> > +	[CRUnIE] = 0x4,
> > +	[CRUnINTS] = 0x8,
> > +	[CRUnRST] = 0xc,
> > +	[AMnMB1ADDRL] = 0x100,
> > +	[AMnMB1ADDRH] = 0x104,
> > +	[AMnMB2ADDRL] = 0x108,
> > +	[AMnMB2ADDRH] = 0x10c,
> > +	[AMnMB3ADDRL] = 0x110,
> > +	[AMnMB3ADDRH] = 0x114,
> > +	[AMnMB4ADDRL] = 0x118,
> > +	[AMnMB4ADDRH] = 0x11c,
> > +	[AMnMB5ADDRL] = 0x120,
> > +	[AMnMB5ADDRH] = 0x124,
> > +	[AMnMB6ADDRL] = 0x128,
> > +	[AMnMB6ADDRH] = 0x12c,
> > +	[AMnMB7ADDRL] = 0x130,
> > +	[AMnMB7ADDRH] = 0x134,
> > +	[AMnMB8ADDRL] = 0x138,
> > +	[AMnMB8ADDRH] = 0x13c,
> > +	[AMnMBVALID] = 0x148,
> > +	[AMnMBS] = 0x14c,
> > +	[AMnAXIATTR] = 0x158,
> > +	[AMnFIFOPNTR] = 0x168,
> > +	[AMnAXISTP] = 0x174,
> > +	[AMnAXISTPACK] = 0x178,
> > +	[ICnEN] = 0x200,
> > +	[ICnMC] = 0x208,
> > +	[ICnMS] = 0x254,
> > +	[ICnDMR] = 0x26c,
> > +};
> > +
> > +static const struct rzg2l_cru_info rzgl2_cru_info = {
> > +	.regs = rzg2l_cru_regs,
> > +};
> > +
> >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > -	{ .compatible = "renesas,rzg2l-cru", },
> > +	{
> > +		.compatible = "renesas,rzg2l-cru",
> > +		.data = &rzgl2_cru_info,
> > +	},
> >  	{ /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > index 1c9f22118a5d..82920db7134e 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > @@ -10,71 +10,76 @@
> >  
> >  /* HW CRU Registers Definition */
> >  
> > -/* CRU Control Register */
> > -#define CRUnCTRL			0x0
> >  #define CRUnCTRL_VINSEL(x)		((x) << 0)
> >  
> > -/* CRU Interrupt Enable Register */
> > -#define CRUnIE				0x4
> >  #define CRUnIE_EFE			BIT(17)
> >  
> > -/* CRU Interrupt Status Register */
> > -#define CRUnINTS			0x8
> >  #define CRUnINTS_SFS			BIT(16)
> >  
> > -/* CRU Reset Register */
> > -#define CRUnRST				0xc
> >  #define CRUnRST_VRESETN			BIT(0)
> >  
> >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > -#define AMnMBxADDRL(x)			(0x100 + ((x) * 8))
> > +#define AMnMBxADDRL(base, x)		((base) + (x) * 2)
> >  
> >  /* Memory Bank Base Address (Higher) Register for CRU Image Data */
> > -#define AMnMBxADDRH(x)			(0x104 + ((x) * 8))
> > +#define AMnMBxADDRH(base, x)		AMnMBxADDRL(base, x)
> >  
> > -/* Memory Bank Enable Register for CRU Image Data */
> > -#define AMnMBVALID			0x148
> >  #define AMnMBVALID_MBVALID(x)		GENMASK(x, 0)
> >  
> > -/* Memory Bank Status Register for CRU Image Data */
> > -#define AMnMBS				0x14c
> >  #define AMnMBS_MBSTS			0x7
> >  
> > -/* AXI Master Transfer Setting Register for CRU Image Data */
> > -#define AMnAXIATTR			0x158
> >  #define AMnAXIATTR_AXILEN_MASK		GENMASK(3, 0)
> >  #define AMnAXIATTR_AXILEN		(0xf)
> >  
> > -/* AXI Master FIFO Pointer Register for CRU Image Data */
> > -#define AMnFIFOPNTR			0x168
> >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> >  
> > -/* AXI Master Transfer Stop Register for CRU Image Data */
> > -#define AMnAXISTP			0x174
> >  #define AMnAXISTP_AXI_STOP		BIT(0)
> >  
> > -/* AXI Master Transfer Stop Status Register for CRU Image Data */
> > -#define AMnAXISTPACK			0x178
> >  #define AMnAXISTPACK_AXI_STOP_ACK	BIT(0)
> >  
> > -/* CRU Image Processing Enable Register */
> > -#define ICnEN				0x200
> >  #define ICnEN_ICEN			BIT(0)
> >  
> > -/* CRU Image Processing Main Control Register */
> > -#define ICnMC				0x208
> >  #define ICnMC_CSCTHR			BIT(5)
> >  #define ICnMC_INF(x)			((x) << 16)
> >  #define ICnMC_VCSEL(x)			((x) << 22)
> >  #define ICnMC_INF_MASK			GENMASK(21, 16)
> >  
> > -/* CRU Module Status Register */
> > -#define ICnMS				0x254
> >  #define ICnMS_IA			BIT(2)
> >  
> > -/* CRU Data Output Mode Register */
> > -#define ICnDMR				0x26c
> >  #define ICnDMR_YCMODE_UYVY		(1 << 4)
> >  
> > +enum rzg2l_cru_common_regs {
> > +	CRUnCTRL,	/* CRU Control */
> > +	CRUnIE,		/* CRU Interrupt Enable */
> > +	CRUnINTS,	/* CRU Interrupt Status */
> > +	CRUnRST, 	/* CRU Reset */
> > +	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > +	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > +	AMnMB2ADDRL,    /* Bank 2 Address (Lower) for CRU Image Data */
> > +	AMnMB2ADDRH,    /* Bank 2 Address (Higher) for CRU Image Data */
> > +	AMnMB3ADDRL,    /* Bank 3 Address (Lower) for CRU Image Data */
> > +	AMnMB3ADDRH,    /* Bank 3 Address (Higher) for CRU Image Data */
> > +	AMnMB4ADDRL,    /* Bank 4 Address (Lower) for CRU Image Data */
> > +	AMnMB4ADDRH,    /* Bank 4 Address (Higher) for CRU Image Data */
> > +	AMnMB5ADDRL,    /* Bank 5 Address (Lower) for CRU Image Data */
> > +	AMnMB5ADDRH,    /* Bank 5 Address (Higher) for CRU Image Data */
> > +	AMnMB6ADDRL,    /* Bank 6 Address (Lower) for CRU Image Data */
> > +	AMnMB6ADDRH,    /* Bank 6 Address (Higher) for CRU Image Data */
> > +	AMnMB7ADDRL,    /* Bank 7 Address (Lower) for CRU Image Data */
> > +	AMnMB7ADDRH,    /* Bank 7 Address (Higher) for CRU Image Data */
> > +	AMnMB8ADDRL,    /* Bank 8 Address (Lower) for CRU Image Data */
> > +	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > +	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > +	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > +	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > +	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > +	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > +	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > +	ICnEN,		/* CRU Image Processing Enable */
> > +	ICnMC,		/* CRU Image Processing Main Control */
> > +	ICnMS,		/* CRU Module Status */
> > +	ICnDMR,		/* CRU Data Output Mode */
> > +};
> > +
> >  #endif /* __RZG2L_CRU_REGS_H__ */
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > index 8b898ce05b84..00c3f7458e20 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > @@ -80,6 +80,10 @@ struct rzg2l_cru_ip_format {
> >  	bool yuv;
> >  };
> >  
> > +struct rzg2l_cru_info {
> > +	const u16 *regs;
> > +};
> > +
> >  /**
> >   * struct rzg2l_cru_dev - Renesas CRU device structure
> >   * @dev:		(OF) device
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > index cd69c8a686d3..f25fd9b35c55 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > @@ -44,12 +44,16 @@ struct rzg2l_cru_buffer {
> >   */
> >  static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> >  {
> > -	iowrite32(value, cru->base + offset);
> > +	const u16 *regs = cru->info->regs;
> > +
> > +	iowrite32(value, cru->base + regs[offset]);
> 
> Should out-of-bound accesses be checked ? Ideally that should be done at
> build time, but in some cases that may be hard. Maybe rzg2l_cru_write()
> and rzg2l_cru_read() could implement compile-time checks, and
> __rzg2l_cru_write() and __rzg2l_cru_read() could be used for the cases
> where checks are not possible at compile time (for AMnMBxADDRL and
> AMnMBxADDRH as far as I can see).

What about using:

static void __rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
{
	const u16 *regs = cru->info->regs;

	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
		return;

	iowrite32(value, cru->base + regs[offset]);
}

static u32 __rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
{
	const u16 *regs = cru->info->regs;

	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
		return 0;

	return ioread32(cru->base + regs[offset]);
}

static inline void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
{
	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
	__rzg2l_cru_write(cru, offset, value);
}

static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
{
	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
	return __rzg2l_cru_read(cru, offset);
}

And use rzg2l_cru_write, rzg2l_cru_read where check can be done at build
time, and __read/__write functions where check can be only done at
runtime.

> 
> >  }
> >  
> >  static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> >  {
> > -	return ioread32(cru->base + offset);
> > +	const u16 *regs = cru->info->regs;
> > +
> > +	return ioread32(cru->base + regs[offset]);
> >  }
> >  
> >  /* Need to hold qlock before calling */
> > @@ -132,8 +136,8 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> >  		return;
> >  
> >  	/* Currently, we just use the buffer in 32 bits address */
> > -	rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
> > -	rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
> > +	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > +	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> 
> This seems fairly error-prone. The first argument doesn't seem to be
> needed.

Sorry I don't completely got this.
Please correct me if I'm wrong.

I think cru argument is needed here has AMnMBxADDRH macro is returning an
index of rzg2l_cru_regs[] and not the real address.


Btw with the changes above here we can use:

	__rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
	__rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);

That is checking for out-of-bound accesses at runtime.

What do you think?
Thanks in advance.


Regards,
Tommaso

> 
> >  }
> >  
> >  /*
> 
> -- 
> Regards,
> 
> Laurent Pinchart

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

* Re: [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC
  2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
  2025-02-23 18:08   ` Laurent Pinchart
@ 2025-02-24 17:25   ` Rob Herring (Arm)
  1 sibling, 0 replies; 56+ messages in thread
From: Rob Herring (Arm) @ 2025-02-24 17:25 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: devicetree, prabhakar.mahadev-lad.rj, biju.das.jz,
	Geert Uytterhoeven, Magnus Damm, Krzysztof Kozlowski,
	Conor Dooley, linux-kernel, tomm.merciai, linux-renesas-soc,
	Mauro Carvalho Chehab, linux-media


On Fri, 21 Feb 2025 16:55:15 +0100, Tommaso Merciai wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> 
> The MIPI CSI-2 block on the Renesas RZ/V2H(P) SoC is similar to the one
> found on the Renesas RZ/G2L SoC, with the following differences:
> - A different D-PHY
> - Additional registers for the MIPI CSI-2 link
> - Only two clocks
> 
> Add a new compatible string, `renesas,r9a09g057-csi2`, for the RZ/V2H(P)
> SoC.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> Changes since v1:
>  - Dropped empty line as suggested by LPinchart
>  - Fixed minItems into else conditional block as suggested by RHerring
> 
>  .../bindings/media/renesas,rzg2l-csi2.yaml    | 59 ++++++++++++++-----
>  1 file changed, 44 insertions(+), 15 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


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

* Re: [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC
  2025-02-21 15:55 ` [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC Tommaso Merciai
@ 2025-02-24 17:27   ` Rob Herring (Arm)
  0 siblings, 0 replies; 56+ messages in thread
From: Rob Herring (Arm) @ 2025-02-24 17:27 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: devicetree, biju.das.jz, prabhakar.mahadev-lad.rj, linux-kernel,
	tomm.merciai, linux-renesas-soc, Krzysztof Kozlowski, Magnus Damm,
	Conor Dooley, Geert Uytterhoeven, Mauro Carvalho Chehab,
	linux-media


On Fri, 21 Feb 2025 16:55:17 +0100, Tommaso Merciai wrote:
> The CRU block found on the Renesas RZ/G3E ("R9A09G047") SoC has five
> interrupts:
> 
>  - image_conv:    image_conv irq
>  - axi_mst_err:   AXI master error level irq
>  - vd_addr_wend:  Video data AXI master addr 0 write end irq
>  - sd_addr_wend:  Statistics data AXI master addr 0 write end irq
>  - vsd_addr_wend: Video statistics data AXI master addr 0 write end irq
> 
> This IP has only one input port 'port@1' similar to the RZ/G2UL CRU.
> 
> Document the CRU block found on the Renesas RZ/G3E ("R9A09G047") SoC.
> 
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> Changes since v1:
>  - Use oneOf for interrupts and interrupt-names
>  - Handle interrupts and interrupt names base on soc variants.
> 
>  .../bindings/media/renesas,rzg2l-cru.yaml     | 65 +++++++++++++++----
>  1 file changed, 54 insertions(+), 11 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-23 20:32   ` Laurent Pinchart
@ 2025-02-24 18:15     ` Tommaso Merciai
  2025-02-24 18:38       ` Laurent Pinchart
  2025-02-25 10:52     ` Tommaso Merciai
  1 sibling, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-24 18:15 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Laurent,

Thank you for the review

On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> Thank you for the patch.
> 
> On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > 
> > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > the Renesas RZ/G2L SoC, with the following differences:
> > 
> > - Additional registers rzg3e_cru_regs.
> > - A different irq handler rzg3e_cru_irq.
> > - A different rzg3e_cru_csi2_setup.
> > - A different max input width.
> > 
> > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > and RZ/G3E and related RZ/G3E functions:
> > 
> >  - rzg3e_cru_enable_interrupts()
> >  - rzg3e_cru_enable_interrupts()
> >  - rz3e_fifo_empty()
> >  - rzg3e_cru_csi2_setup()
> >  - rzg3e_cru_get_current_slot()
> > 
> > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > string "renesas,r9a09g047-cru".
> > 
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> >  4 files changed, 282 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > index 3ae0cd83af16..075a3aa8af29 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> >  		return ret;
> >  
> >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > +					    sizeof(struct rzg2l_cru_mem_bank),
> > +					    GFP_KERNEL);
> > +	if (!cru->mem_banks)
> > +		return dev_err_probe(dev, -ENOMEM,
> > +				     "Failed to init mem banks\n");
> > +
> >  	pm_suspend_ignore_children(dev, true);
> >  	ret = devm_pm_runtime_enable(dev);
> >  	if (ret)
> > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> >  	rzg2l_cru_dma_unregister(cru);
> >  }
> >  
> > +static const u16 rzg3e_cru_regs[] = {
> > +	[CRUnCTRL] = 0x0,
> > +	[CRUnIE] = 0x4,
> > +	[CRUnIE2] = 0x8,
> > +	[CRUnINTS] = 0xc,
> > +	[CRUnINTS2] = 0x10,
> > +	[CRUnRST] = 0x18,
> > +	[AMnMB1ADDRL] = 0x40,
> > +	[AMnMB1ADDRH] = 0x44,
> > +	[AMnMB2ADDRL] = 0x48,
> > +	[AMnMB2ADDRH] = 0x4c,
> > +	[AMnMB3ADDRL] = 0x50,
> > +	[AMnMB3ADDRH] = 0x54,
> > +	[AMnMB4ADDRL] = 0x58,
> > +	[AMnMB4ADDRH] = 0x5c,
> > +	[AMnMB5ADDRL] = 0x60,
> > +	[AMnMB5ADDRH] = 0x64,
> > +	[AMnMB6ADDRL] = 0x68,
> > +	[AMnMB6ADDRH] = 0x6c,
> > +	[AMnMB7ADDRL] = 0x70,
> > +	[AMnMB7ADDRH] = 0x74,
> > +	[AMnMB8ADDRL] = 0x78,
> > +	[AMnMB8ADDRH] = 0x7c,
> > +	[AMnMBVALID] = 0x88,
> > +	[AMnMADRSL] = 0x8c,
> > +	[AMnMADRSH] = 0x90,
> > +	[AMnAXIATTR] = 0xec,
> > +	[AMnFIFOPNTR] = 0xf8,
> > +	[AMnAXISTP] = 0x110,
> > +	[AMnAXISTPACK] = 0x114,
> > +	[AMnIS] = 0x128,
> > +	[ICnEN] = 0x1f0,
> > +	[ICnSVCNUM] = 0x1f8,
> > +	[ICnSVC] = 0x1fc,
> > +	[ICnIPMC_C0] = 0x200,
> > +	[ICnMS] = 0x2d8,
> > +	[ICnDMR] = 0x304,
> > +};
> > +
> > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > +	.max_width = 4095,
> > +	.max_height = 4095,
> > +	.image_conv = ICnIPMC_C0,
> > +	.stride = 128,
> > +	.regs = rzg3e_cru_regs,
> > +	.irq_handler = rzg3e_cru_irq,
> > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > +	.fifo_empty = rz3e_fifo_empty,
> > +	.csi_setup = rzg3e_cru_csi2_setup,
> > +};
> > +
> >  static const u16 rzg2l_cru_regs[] = {
> >  	[CRUnCTRL] = 0x0,
> >  	[CRUnIE] = 0x4,
> > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> >  };
> >  
> >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > +	{
> > +		.compatible = "renesas,r9a09g047-cru",
> > +		.data = &rzg3e_cru_info,
> > +	},
> >  	{
> >  		.compatible = "renesas,rzg2l-cru",
> >  		.data = &rzgl2_cru_info,
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > index 82920db7134e..1646d1e2953c 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > @@ -14,8 +14,13 @@
> >  
> >  #define CRUnIE_EFE			BIT(17)
> >  
> > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > +
> >  #define CRUnINTS_SFS			BIT(16)
> >  
> > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > +
> >  #define CRUnRST_VRESETN			BIT(0)
> >  
> >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > @@ -32,7 +37,14 @@
> >  #define AMnAXIATTR_AXILEN		(0xf)
> >  
> >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > +
> > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > +#define AMnIS_IS(x)			((x) << 7)
> >  
> >  #define AMnAXISTP_AXI_STOP		BIT(0)
> >  
> > @@ -40,6 +52,11 @@
> >  
> >  #define ICnEN_ICEN			BIT(0)
> >  
> > +#define ICnSVC_SVC0(x)			(x)
> > +#define ICnSVC_SVC1(x)			((x) << 4)
> > +#define ICnSVC_SVC2(x)			((x) << 8)
> > +#define ICnSVC_SVC3(x)			((x) << 12)
> > +
> >  #define ICnMC_CSCTHR			BIT(5)
> >  #define ICnMC_INF(x)			((x) << 16)
> >  #define ICnMC_VCSEL(x)			((x) << 22)
> > @@ -52,7 +69,9 @@
> >  enum rzg2l_cru_common_regs {
> >  	CRUnCTRL,	/* CRU Control */
> >  	CRUnIE,		/* CRU Interrupt Enable */
> > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> >  	CRUnINTS,	/* CRU Interrupt Status */
> > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> >  	CRUnRST, 	/* CRU Reset */
> >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > +	AMnIS,		/* Image Stride Setting Register */
> >  	ICnEN,		/* CRU Image Processing Enable */
> > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > +	ICnSVC,		/* CRU VC Select Register */
> >  	ICnMC,		/* CRU Image Processing Main Control */
> > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> >  	ICnMS,		/* CRU Module Status */
> >  	ICnDMR,		/* CRU Data Output Mode */
> >  };
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > index ccaba5220f1c..3301379c132c 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> >  	unsigned int max_width;
> >  	unsigned int max_height;
> >  	u16 image_conv;
> > +	u16 stride;
> >  	const u16 *regs;
> >  	irqreturn_t (*irq_handler)(int irq, void *data);
> >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> >  			  u8 csi_vc);
> >  };
> >  
> > +struct rzg2l_cru_mem_bank {
> > +	dma_addr_t addrl;
> > +	dma_addr_t addrh;
> > +};
> > +
> >  /**
> >   * struct rzg2l_cru_dev - Renesas CRU device structure
> >   * @dev:		(OF) device
> > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> >   * @vdev:		V4L2 video device associated with CRU
> >   * @v4l2_dev:		V4L2 device
> >   * @num_buf:		Holds the current number of buffers enabled
> > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > + * @mem_banks:		Memory addresses where current video data is written.
> >   * @notifier:		V4L2 asynchronous subdevs notifier
> >   *
> >   * @ip:			Image processing subdev info
> > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> >  	struct v4l2_device v4l2_dev;
> >  	u8 num_buf;
> >  
> > +	u8 svc_channel;
> > +	struct rzg2l_cru_mem_bank *mem_banks;
> > +
> >  	struct v4l2_async_notifier notifier;
> >  
> >  	struct rzg2l_cru_ip ip;
> > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> >  
> >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> >  
> > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> >  
> >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> >  
> >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> >  			  u8 csi_vc);
> > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > +			  u8 csi_vc);
> >  
> >  #endif
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > index 637c9c9f9ba8..efd70c13704e 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> >  	/* Currently, we just use the buffer in 32 bits address */
> 
> Should this be fixed ?
> 
> >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > +
> > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> 
> Here you stplit the dma_addr_t in two fields, storing the low and high
> parts separately (but still in dma_addr_t variables), and below you
> recombine those two fields to recreate the full address. That doesn't
> seem needed.

We can use:

struct rzg2l_cru_mem_bank {
	dma_addr_t addr;
};

cru->mem_banks[slot].addr = addr;
Instead of using low and high.

Then accordingly update the rzg3e_cru_get_current_slot()

> 
> >  }
> >  
> >  /*
> > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> >  }
> >  
> > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> >  {
> >  	unsigned int slot;
> >  	u32 amnaxiattr;
> > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> >  	for (slot = 0; slot < cru->num_buf; slot++)
> >  		rzg2l_cru_fill_hw_slot(cru, slot);
> >  
> > +	if (cru->info->stride) {
> 
> I'd name this field stride_align or something similar.

Agreed on stride_align.
Will update this in v3.

> 
> > +		u32 stride = cru->format.bytesperline;
> > +		u32 amnis;
> > +
> > +		if (stride % cru->info->stride) {
> > +			dev_err(cru->dev,
> > +				"Bytesperline must be multiple of %u bytes\n",
> > +				cru->info->stride);
> > +			return -EINVAL;
> > +		}
> 
> This needs to be caught at set format time, and the stride must be
> adjusted then.

What about doing this into the rzg2l_cru_format_align() function?
Somenthing like:

	if (info->stride_align) {
		u32 stride = pix->width * fmt->bpp;

		if (stride % info->stride_align) {
			dev_warn(cru->dev,
				"Bytesperline (%u) is not aligned to %u bytes, adjusting it\n",
				stride, info->stride_align);

			stride = ALIGN_DOWN(stride, info->stride_align);
			pix->width = stride / fmt->bpp;
		}
	}

	/* Limit to CRU capabilities */
	v4l_bound_align_image(&pix->width, 320, info->max_width, 1,
			      &pix->height, 240, info->max_height, 2, 0);

	pix->bytesperline = pix->width * fmt->bpp;
	pix->sizeimage = pix->bytesperline * pix->height;


> 
> > +		stride = stride / cru->info->stride;
> 
> 		stride /= cru->info->stride;
> 
> > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > +	}
> > +
> >  	/* Set AXI burst max length to recommended setting */
> >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > +
> > +	return 0;
> > +}
> > +
> > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > +			  u8 csi_vc)
> > +{
> > +	const struct rzg2l_cru_info *info = cru->info;
> > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > +
> > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > +
> > +	/* Set virtual channel CSI2 */
> > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > +
> > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> 
> As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> You can drop ths svc_channel field.


Agreed here I can directly use:

rzg2l_cru_write(cru, ICnSVCNUM, csi_vc);

Thanks

> 
> > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> >  }
> >  
> >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> >  	return 0;
> >  }
> >  
> > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > +{
> > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > +
> > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> >  {
> >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> >  	return fd.entry[0].bus.csi2.vc;
> >  }
> >  
> > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > +{
> > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > +}
> > +
> > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > +{
> > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > +}
> > +
> >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> >  {
> >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> >  	if (ret < 0)
> >  		return ret;
> >  	csi_vc = ret;
> > +	cru->svc_channel = csi_vc;
> >  
> >  	spin_lock_irqsave(&cru->qlock, flags);
> >  
> > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> >  	cru->info->disable_interrupts(cru);
> >  
> >  	/* Initialize the AXI master */
> > -	rzg2l_cru_initialize_axi(cru);
> > +	ret = rzg2l_cru_initialize_axi(cru);
> > +	if (ret) {
> > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > +		return ret;
> > +	}
> 
> This will go away once you remove the error check from
> rzg2l_cru_initialize_axi(), which should then remain a void function.

Ooks, thanks.

> 
> There's another function returning an error here,
> rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> separate patch).
> 
> >  
> >  	/* Initialize image convert */
> >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> >  	return IRQ_RETVAL(handled);
> >  }
> >  
> > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > +{
> > +	dma_addr_t amnmadrs;
> > +	unsigned int slot;
> > +
> > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> 
> What if the two registers are read on a frame boundary ?

Nice point.

You are suggesting here to read the AMnMADRSL and AMnMADRSH with a single
ioread64 starting from AMnMADRSL right?

> 
> > +
> > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > +		dma_addr_t buf_addr;
> > +
> > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > +			cru->mem_banks[slot].addrl;
> > +
> > +		/* Ensure amnmadrs is within this buffer range */
> > +		if (amnmadrs >= buf_addr &&
> > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > +			return slot;
> > +		}

Here with the upper changes I can use:

	for (slot = 0; slot < cru->num_buf; slot++) {

		/* Ensure amnmadrs is within this buffer range */
		if (amnmadrs >= cru->mem_banks[slot].addr &&
		    amnmadrs < cru->mem_banks[slot].addr +
		    cru->format.sizeimage) {
			return slot;
		}
	}


> > +	}
> > +
> > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > +	return -EINVAL;
> > +}
> > +
> > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > +{
> > +	struct rzg2l_cru_dev *cru = data;
> > +	unsigned int handled = 0;
> > +	unsigned long flags;
> > +	unsigned int slot;
> > +	u32 irq_status;
> > +
> > +	spin_lock_irqsave(&cru->qlock, flags);
> > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > +	if (!(irq_status))
> > +		goto done;
> > +
> > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > +
> > +	handled = 1;
> > +
> > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > +
> > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > +		goto done;
> > +	}
> > +
> > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > +		    irq_status & CRUnINTS2_FSxS(3))
> > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > +		goto done;
> > +	}
> > +
> > +	slot = rzg3e_cru_get_current_slot(cru);
> > +	if (slot < 0)
> > +		goto done;
> > +
> > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > +
> > +	cru->mem_banks[slot].addrl = 0;
> > +	cru->mem_banks[slot].addrh = 0;
> > +
> > +	/*
> > +	 * To hand buffers back in a known order to userspace start
> > +	 * to capture first from slot 0.
> > +	 */
> > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > +		if (slot != 0) {
> > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > +			goto done;
> > +		}
> > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > +	}
> > +
> > +	/* Capture frame */
> > +	if (cru->queue_buf[slot]) {
> > +		cru->queue_buf[slot]->field = cru->format.field;
> > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > +				VB2_BUF_STATE_DONE);
> > +		cru->queue_buf[slot] = NULL;
> > +	} else {
> > +		/* Scratch buffer was used, dropping frame. */
> > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > +	}
> > +
> > +	cru->sequence++;
> > +
> > +	/* Prepare for next frame */
> > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > +
> > +done:
> > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > +	return IRQ_RETVAL(handled);
> > +}
> > +
> >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> >  {
> >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Thanks & Regards,
Tommaso


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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-24 18:15     ` Tommaso Merciai
@ 2025-02-24 18:38       ` Laurent Pinchart
  2025-02-25 11:28         ` Tommaso Merciai
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-24 18:38 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

On Mon, Feb 24, 2025 at 07:15:31PM +0100, Tommaso Merciai wrote:
> On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> > On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > 
> > > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > > the Renesas RZ/G2L SoC, with the following differences:
> > > 
> > > - Additional registers rzg3e_cru_regs.
> > > - A different irq handler rzg3e_cru_irq.
> > > - A different rzg3e_cru_csi2_setup.
> > > - A different max input width.
> > > 
> > > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > > and RZ/G3E and related RZ/G3E functions:
> > > 
> > >  - rzg3e_cru_enable_interrupts()
> > >  - rzg3e_cru_enable_interrupts()
> > >  - rz3e_fifo_empty()
> > >  - rzg3e_cru_csi2_setup()
> > >  - rzg3e_cru_get_current_slot()
> > > 
> > > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > > string "renesas,r9a09g047-cru".
> > > 
> > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > ---
> > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> > >  4 files changed, 282 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > index 3ae0cd83af16..075a3aa8af29 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > >  		return ret;
> > >  
> > >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > > +					    sizeof(struct rzg2l_cru_mem_bank),
> > > +					    GFP_KERNEL);
> > > +	if (!cru->mem_banks)
> > > +		return dev_err_probe(dev, -ENOMEM,
> > > +				     "Failed to init mem banks\n");
> > > +
> > >  	pm_suspend_ignore_children(dev, true);
> > >  	ret = devm_pm_runtime_enable(dev);
> > >  	if (ret)
> > > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > >  	rzg2l_cru_dma_unregister(cru);
> > >  }
> > >  
> > > +static const u16 rzg3e_cru_regs[] = {
> > > +	[CRUnCTRL] = 0x0,
> > > +	[CRUnIE] = 0x4,
> > > +	[CRUnIE2] = 0x8,
> > > +	[CRUnINTS] = 0xc,
> > > +	[CRUnINTS2] = 0x10,
> > > +	[CRUnRST] = 0x18,
> > > +	[AMnMB1ADDRL] = 0x40,
> > > +	[AMnMB1ADDRH] = 0x44,
> > > +	[AMnMB2ADDRL] = 0x48,
> > > +	[AMnMB2ADDRH] = 0x4c,
> > > +	[AMnMB3ADDRL] = 0x50,
> > > +	[AMnMB3ADDRH] = 0x54,
> > > +	[AMnMB4ADDRL] = 0x58,
> > > +	[AMnMB4ADDRH] = 0x5c,
> > > +	[AMnMB5ADDRL] = 0x60,
> > > +	[AMnMB5ADDRH] = 0x64,
> > > +	[AMnMB6ADDRL] = 0x68,
> > > +	[AMnMB6ADDRH] = 0x6c,
> > > +	[AMnMB7ADDRL] = 0x70,
> > > +	[AMnMB7ADDRH] = 0x74,
> > > +	[AMnMB8ADDRL] = 0x78,
> > > +	[AMnMB8ADDRH] = 0x7c,
> > > +	[AMnMBVALID] = 0x88,
> > > +	[AMnMADRSL] = 0x8c,
> > > +	[AMnMADRSH] = 0x90,
> > > +	[AMnAXIATTR] = 0xec,
> > > +	[AMnFIFOPNTR] = 0xf8,
> > > +	[AMnAXISTP] = 0x110,
> > > +	[AMnAXISTPACK] = 0x114,
> > > +	[AMnIS] = 0x128,
> > > +	[ICnEN] = 0x1f0,
> > > +	[ICnSVCNUM] = 0x1f8,
> > > +	[ICnSVC] = 0x1fc,
> > > +	[ICnIPMC_C0] = 0x200,
> > > +	[ICnMS] = 0x2d8,
> > > +	[ICnDMR] = 0x304,
> > > +};
> > > +
> > > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > > +	.max_width = 4095,
> > > +	.max_height = 4095,
> > > +	.image_conv = ICnIPMC_C0,
> > > +	.stride = 128,
> > > +	.regs = rzg3e_cru_regs,
> > > +	.irq_handler = rzg3e_cru_irq,
> > > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > > +	.fifo_empty = rz3e_fifo_empty,
> > > +	.csi_setup = rzg3e_cru_csi2_setup,
> > > +};
> > > +
> > >  static const u16 rzg2l_cru_regs[] = {
> > >  	[CRUnCTRL] = 0x0,
> > >  	[CRUnIE] = 0x4,
> > > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> > >  };
> > >  
> > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > +	{
> > > +		.compatible = "renesas,r9a09g047-cru",
> > > +		.data = &rzg3e_cru_info,
> > > +	},
> > >  	{
> > >  		.compatible = "renesas,rzg2l-cru",
> > >  		.data = &rzgl2_cru_info,
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > index 82920db7134e..1646d1e2953c 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > @@ -14,8 +14,13 @@
> > >  
> > >  #define CRUnIE_EFE			BIT(17)
> > >  
> > > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > > +
> > >  #define CRUnINTS_SFS			BIT(16)
> > >  
> > > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > > +
> > >  #define CRUnRST_VRESETN			BIT(0)
> > >  
> > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > @@ -32,7 +37,14 @@
> > >  #define AMnAXIATTR_AXILEN		(0xf)
> > >  
> > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > > +
> > > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > > +#define AMnIS_IS(x)			((x) << 7)
> > >  
> > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > >  
> > > @@ -40,6 +52,11 @@
> > >  
> > >  #define ICnEN_ICEN			BIT(0)
> > >  
> > > +#define ICnSVC_SVC0(x)			(x)
> > > +#define ICnSVC_SVC1(x)			((x) << 4)
> > > +#define ICnSVC_SVC2(x)			((x) << 8)
> > > +#define ICnSVC_SVC3(x)			((x) << 12)
> > > +
> > >  #define ICnMC_CSCTHR			BIT(5)
> > >  #define ICnMC_INF(x)			((x) << 16)
> > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > > @@ -52,7 +69,9 @@
> > >  enum rzg2l_cru_common_regs {
> > >  	CRUnCTRL,	/* CRU Control */
> > >  	CRUnIE,		/* CRU Interrupt Enable */
> > > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> > >  	CRUnINTS,	/* CRU Interrupt Status */
> > > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> > >  	CRUnRST, 	/* CRU Reset */
> > >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> > >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> > >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > +	AMnIS,		/* Image Stride Setting Register */
> > >  	ICnEN,		/* CRU Image Processing Enable */
> > > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > > +	ICnSVC,		/* CRU VC Select Register */
> > >  	ICnMC,		/* CRU Image Processing Main Control */
> > > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> > >  	ICnMS,		/* CRU Module Status */
> > >  	ICnDMR,		/* CRU Data Output Mode */
> > >  };
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > index ccaba5220f1c..3301379c132c 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> > >  	unsigned int max_width;
> > >  	unsigned int max_height;
> > >  	u16 image_conv;
> > > +	u16 stride;
> > >  	const u16 *regs;
> > >  	irqreturn_t (*irq_handler)(int irq, void *data);
> > >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> > >  			  u8 csi_vc);
> > >  };
> > >  
> > > +struct rzg2l_cru_mem_bank {
> > > +	dma_addr_t addrl;
> > > +	dma_addr_t addrh;
> > > +};
> > > +
> > >  /**
> > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > >   * @dev:		(OF) device
> > > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> > >   * @vdev:		V4L2 video device associated with CRU
> > >   * @v4l2_dev:		V4L2 device
> > >   * @num_buf:		Holds the current number of buffers enabled
> > > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > > + * @mem_banks:		Memory addresses where current video data is written.
> > >   * @notifier:		V4L2 asynchronous subdevs notifier
> > >   *
> > >   * @ip:			Image processing subdev info
> > > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> > >  	struct v4l2_device v4l2_dev;
> > >  	u8 num_buf;
> > >  
> > > +	u8 svc_channel;
> > > +	struct rzg2l_cru_mem_bank *mem_banks;
> > > +
> > >  	struct v4l2_async_notifier notifier;
> > >  
> > >  	struct rzg2l_cru_ip ip;
> > > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> > >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> > >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> > >  
> > >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> > >  
> > > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> > >  
> > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > >  
> > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> > >  			  u8 csi_vc);
> > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > +			  u8 csi_vc);
> > >  
> > >  #endif
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > index 637c9c9f9ba8..efd70c13704e 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > >  	/* Currently, we just use the buffer in 32 bits address */
> > 
> > Should this be fixed ?
> > 
> > >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > > +
> > > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> > 
> > Here you stplit the dma_addr_t in two fields, storing the low and high
> > parts separately (but still in dma_addr_t variables), and below you
> > recombine those two fields to recreate the full address. That doesn't
> > seem needed.
> 
> We can use:
> 
> struct rzg2l_cru_mem_bank {
> 	dma_addr_t addr;
> };

Drop rzg2l_cru_mem_bank and just use dma_addr_t.

> cru->mem_banks[slot].addr = addr;
> Instead of using low and high.
> 
> Then accordingly update the rzg3e_cru_get_current_slot()
> 
> > >  }
> > >  
> > >  /*
> > > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> > >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> > >  }
> > >  
> > > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	unsigned int slot;
> > >  	u32 amnaxiattr;
> > > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > >  	for (slot = 0; slot < cru->num_buf; slot++)
> > >  		rzg2l_cru_fill_hw_slot(cru, slot);
> > >  
> > > +	if (cru->info->stride) {
> > 
> > I'd name this field stride_align or something similar.
> 
> Agreed on stride_align.
> Will update this in v3.
> 
> > > +		u32 stride = cru->format.bytesperline;
> > > +		u32 amnis;
> > > +
> > > +		if (stride % cru->info->stride) {
> > > +			dev_err(cru->dev,
> > > +				"Bytesperline must be multiple of %u bytes\n",
> > > +				cru->info->stride);
> > > +			return -EINVAL;
> > > +		}
> > 
> > This needs to be caught at set format time, and the stride must be
> > adjusted then.
> 
> What about doing this into the rzg2l_cru_format_align() function?
> Somenthing like:
> 
> 	if (info->stride_align) {
> 		u32 stride = pix->width * fmt->bpp;

		u32 stride = clamp(pix->bytesperline, pix->width * fmt->bpp,
				   RZG2L_CRU_MAX_STRIDE);

to honour the userspace request and to avoid overflows.


RZG2L_CRU_MAX_STRIDE may need to be turned into an info field. That may
be slightly over-engineered though, unless you expect other versions of
the CRU with different stride alignments, maybe an info->has_stride
field would be enough, you can then use macros for the stride alignement
and maximum value.

> 
> 		if (stride % info->stride_align) {
> 			dev_warn(cru->dev,
> 				"Bytesperline (%u) is not aligned to %u bytes, adjusting it\n",
> 				stride, info->stride_align);

Drop the warning, we shouldn't allow userspace to flood the kernel log.

> 
> 			stride = ALIGN_DOWN(stride, info->stride_align);

Align up, not down. ALIGN() requires the alignment to be a power of two,
use round_up() if that's not a guarantee.

> 			pix->width = stride / fmt->bpp;

No, width doesn't change based on the stride. Only bytesperline does.
Drop this whole conditional block, and just do

		pix->bytesperline = round_up(stride, info->stride_align);
	} else {
		pix->bytesperline = pix->width * fmt->bpp;
	}

> 		}
> 	}
> 
> 	/* Limit to CRU capabilities */
> 	v4l_bound_align_image(&pix->width, 320, info->max_width, 1,
> 			      &pix->height, 240, info->max_height, 2, 0);
> 
> 	pix->bytesperline = pix->width * fmt->bpp;

Drop this line.

> 	pix->sizeimage = pix->bytesperline * pix->height;
> 
> 
> > 
> > > +		stride = stride / cru->info->stride;
> > 
> > 		stride /= cru->info->stride;
> > 
> > > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > > +	}
> > > +
> > >  	/* Set AXI burst max length to recommended setting */
> > >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> > >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> > >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > +			  u8 csi_vc)
> > > +{
> > > +	const struct rzg2l_cru_info *info = cru->info;
> > > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > > +
> > > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > > +
> > > +	/* Set virtual channel CSI2 */
> > > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > > +
> > > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> > 
> > As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> > You can drop ths svc_channel field.
> 
> Agreed here I can directly use:
> 
> rzg2l_cru_write(cru, ICnSVCNUM, csi_vc);
> 
> Thanks
> 
> > > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> > >  }
> > >  
> > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> > >  	return 0;
> > >  }
> > >  
> > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > > +
> > > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > > +		return true;
> > > +
> > > +	return false;
> > > +}
> > > +
> > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> > >  	return fd.entry[0].bus.csi2.vc;
> > >  }
> > >  
> > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > > +}
> > > +
> > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > +}
> > > +
> > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > >  	if (ret < 0)
> > >  		return ret;
> > >  	csi_vc = ret;
> > > +	cru->svc_channel = csi_vc;
> > >  
> > >  	spin_lock_irqsave(&cru->qlock, flags);
> > >  
> > > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > >  	cru->info->disable_interrupts(cru);
> > >  
> > >  	/* Initialize the AXI master */
> > > -	rzg2l_cru_initialize_axi(cru);
> > > +	ret = rzg2l_cru_initialize_axi(cru);
> > > +	if (ret) {
> > > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > > +		return ret;
> > > +	}
> > 
> > This will go away once you remove the error check from
> > rzg2l_cru_initialize_axi(), which should then remain a void function.
> 
> Ooks, thanks.
> 
> > There's another function returning an error here,
> > rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> > separate patch).
> > 
> > >  
> > >  	/* Initialize image convert */
> > >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> > >  	return IRQ_RETVAL(handled);
> > >  }
> > >  
> > > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	dma_addr_t amnmadrs;
> > > +	unsigned int slot;
> > > +
> > > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> > 
> > What if the two registers are read on a frame boundary ?
> 
> Nice point.
> 
> You are suggesting here to read the AMnMADRSL and AMnMADRSH with a single
> ioread64 starting from AMnMADRSL right?

Is that guaranteed to be atomic ? I wouldn't count on that if the
APB/AHB interface to registers is 32-bit wide.

> > > +
> > > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > > +		dma_addr_t buf_addr;
> > > +
> > > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > > +			cru->mem_banks[slot].addrl;
> > > +
> > > +		/* Ensure amnmadrs is within this buffer range */
> > > +		if (amnmadrs >= buf_addr &&
> > > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > > +			return slot;
> > > +		}
> 
> Here with the upper changes I can use:
> 
> 	for (slot = 0; slot < cru->num_buf; slot++) {
> 
> 		/* Ensure amnmadrs is within this buffer range */
> 		if (amnmadrs >= cru->mem_banks[slot].addr &&
> 		    amnmadrs < cru->mem_banks[slot].addr +
> 		    cru->format.sizeimage) {
> 			return slot;
> 		}
> 	}
> 
> > > +	}
> > > +
> > > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > > +	return -EINVAL;
> > > +}
> > > +
> > > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > > +{
> > > +	struct rzg2l_cru_dev *cru = data;
> > > +	unsigned int handled = 0;
> > > +	unsigned long flags;
> > > +	unsigned int slot;
> > > +	u32 irq_status;
> > > +
> > > +	spin_lock_irqsave(&cru->qlock, flags);
> > > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > > +	if (!(irq_status))
> > > +		goto done;
> > > +
> > > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > > +
> > > +	handled = 1;
> > > +
> > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > +
> > > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > > +		goto done;
> > > +	}
> > > +
> > > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > > +		    irq_status & CRUnINTS2_FSxS(3))
> > > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > > +		goto done;
> > > +	}
> > > +
> > > +	slot = rzg3e_cru_get_current_slot(cru);
> > > +	if (slot < 0)
> > > +		goto done;
> > > +
> > > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > > +
> > > +	cru->mem_banks[slot].addrl = 0;
> > > +	cru->mem_banks[slot].addrh = 0;
> > > +
> > > +	/*
> > > +	 * To hand buffers back in a known order to userspace start
> > > +	 * to capture first from slot 0.
> > > +	 */
> > > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > > +		if (slot != 0) {
> > > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > > +			goto done;
> > > +		}
> > > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > > +	}
> > > +
> > > +	/* Capture frame */
> > > +	if (cru->queue_buf[slot]) {
> > > +		cru->queue_buf[slot]->field = cru->format.field;
> > > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > > +				VB2_BUF_STATE_DONE);
> > > +		cru->queue_buf[slot] = NULL;
> > > +	} else {
> > > +		/* Scratch buffer was used, dropping frame. */
> > > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > > +	}
> > > +
> > > +	cru->sequence++;
> > > +
> > > +	/* Prepare for next frame */
> > > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > > +
> > > +done:
> > > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > > +	return IRQ_RETVAL(handled);
> > > +}
> > > +
> > >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> > >  {
> > >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support
  2025-02-24 13:46     ` Tommaso Merciai
@ 2025-02-24 18:44       ` Laurent Pinchart
  2025-02-25 11:21         ` Tommaso Merciai
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-24 18:44 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

On Mon, Feb 24, 2025 at 02:46:24PM +0100, Tommaso Merciai wrote:
> On Sun, Feb 23, 2025 at 09:52:32PM +0200, Laurent Pinchart wrote:
> > On Fri, Feb 21, 2025 at 04:55:25PM +0100, Tommaso Merciai wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > 
> > > Prepare for adding support for RZ/G3E and RZ/V2HP SoCs, which have a
> > > CRU-IP that is mostly identical to RZ/G2L but with different register
> > > offsets and additional registers. Introduce a flexible register mapping
> > > mechanism to handle these variations.
> > > 
> > > Define the `rzg2l_cru_info` structure to store register mappings and
> > > pass it as part of the OF match data. Update the read/write functions
> > > to use indexed register offsets from `rzg2l_cru_info`, ensuring
> > > compatibility across different SoC variants.
> > > 
> > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > ---
> > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 46 ++++++++++++-
> > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        | 65 ++++++++++---------
> > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++
> > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 12 ++--
> > >  4 files changed, 92 insertions(+), 35 deletions(-)
> > > 
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > index eed9d2bd0841..abc2a979833a 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > @@ -22,6 +22,7 @@
> > >  #include <media/v4l2-mc.h>
> > >  
> > >  #include "rzg2l-cru.h"
> > > +#include "rzg2l-cru-regs.h"
> > >  
> > >  static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
> > >  {
> > > @@ -269,6 +270,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > >  
> > >  	cru->dev = dev;
> > >  	cru->info = of_device_get_match_data(dev);
> > > +	if (!cru->info)
> > > +		return dev_err_probe(dev, -EINVAL,
> > > +				     "Failed to get OF match data\n");
> > >  
> > >  	irq = platform_get_irq(pdev, 0);
> > >  	if (irq < 0)
> > > @@ -317,8 +321,48 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > >  	rzg2l_cru_dma_unregister(cru);
> > >  }
> > >  
> > > +static const u16 rzg2l_cru_regs[] = {
> > > +	[CRUnCTRL] = 0x0,
> > > +	[CRUnIE] = 0x4,
> > > +	[CRUnINTS] = 0x8,
> > > +	[CRUnRST] = 0xc,
> > > +	[AMnMB1ADDRL] = 0x100,
> > > +	[AMnMB1ADDRH] = 0x104,
> > > +	[AMnMB2ADDRL] = 0x108,
> > > +	[AMnMB2ADDRH] = 0x10c,
> > > +	[AMnMB3ADDRL] = 0x110,
> > > +	[AMnMB3ADDRH] = 0x114,
> > > +	[AMnMB4ADDRL] = 0x118,
> > > +	[AMnMB4ADDRH] = 0x11c,
> > > +	[AMnMB5ADDRL] = 0x120,
> > > +	[AMnMB5ADDRH] = 0x124,
> > > +	[AMnMB6ADDRL] = 0x128,
> > > +	[AMnMB6ADDRH] = 0x12c,
> > > +	[AMnMB7ADDRL] = 0x130,
> > > +	[AMnMB7ADDRH] = 0x134,
> > > +	[AMnMB8ADDRL] = 0x138,
> > > +	[AMnMB8ADDRH] = 0x13c,
> > > +	[AMnMBVALID] = 0x148,
> > > +	[AMnMBS] = 0x14c,
> > > +	[AMnAXIATTR] = 0x158,
> > > +	[AMnFIFOPNTR] = 0x168,
> > > +	[AMnAXISTP] = 0x174,
> > > +	[AMnAXISTPACK] = 0x178,
> > > +	[ICnEN] = 0x200,
> > > +	[ICnMC] = 0x208,
> > > +	[ICnMS] = 0x254,
> > > +	[ICnDMR] = 0x26c,
> > > +};
> > > +
> > > +static const struct rzg2l_cru_info rzgl2_cru_info = {
> > > +	.regs = rzg2l_cru_regs,
> > > +};
> > > +
> > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > -	{ .compatible = "renesas,rzg2l-cru", },
> > > +	{
> > > +		.compatible = "renesas,rzg2l-cru",
> > > +		.data = &rzgl2_cru_info,
> > > +	},
> > >  	{ /* sentinel */ }
> > >  };
> > >  MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > index 1c9f22118a5d..82920db7134e 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > @@ -10,71 +10,76 @@
> > >  
> > >  /* HW CRU Registers Definition */
> > >  
> > > -/* CRU Control Register */
> > > -#define CRUnCTRL			0x0
> > >  #define CRUnCTRL_VINSEL(x)		((x) << 0)
> > >  
> > > -/* CRU Interrupt Enable Register */
> > > -#define CRUnIE				0x4
> > >  #define CRUnIE_EFE			BIT(17)
> > >  
> > > -/* CRU Interrupt Status Register */
> > > -#define CRUnINTS			0x8
> > >  #define CRUnINTS_SFS			BIT(16)
> > >  
> > > -/* CRU Reset Register */
> > > -#define CRUnRST				0xc
> > >  #define CRUnRST_VRESETN			BIT(0)
> > >  
> > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > -#define AMnMBxADDRL(x)			(0x100 + ((x) * 8))
> > > +#define AMnMBxADDRL(base, x)		((base) + (x) * 2)
> > >  
> > >  /* Memory Bank Base Address (Higher) Register for CRU Image Data */
> > > -#define AMnMBxADDRH(x)			(0x104 + ((x) * 8))
> > > +#define AMnMBxADDRH(base, x)		AMnMBxADDRL(base, x)
> > >  
> > > -/* Memory Bank Enable Register for CRU Image Data */
> > > -#define AMnMBVALID			0x148
> > >  #define AMnMBVALID_MBVALID(x)		GENMASK(x, 0)
> > >  
> > > -/* Memory Bank Status Register for CRU Image Data */
> > > -#define AMnMBS				0x14c
> > >  #define AMnMBS_MBSTS			0x7
> > >  
> > > -/* AXI Master Transfer Setting Register for CRU Image Data */
> > > -#define AMnAXIATTR			0x158
> > >  #define AMnAXIATTR_AXILEN_MASK		GENMASK(3, 0)
> > >  #define AMnAXIATTR_AXILEN		(0xf)
> > >  
> > > -/* AXI Master FIFO Pointer Register for CRU Image Data */
> > > -#define AMnFIFOPNTR			0x168
> > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > >  
> > > -/* AXI Master Transfer Stop Register for CRU Image Data */
> > > -#define AMnAXISTP			0x174
> > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > >  
> > > -/* AXI Master Transfer Stop Status Register for CRU Image Data */
> > > -#define AMnAXISTPACK			0x178
> > >  #define AMnAXISTPACK_AXI_STOP_ACK	BIT(0)
> > >  
> > > -/* CRU Image Processing Enable Register */
> > > -#define ICnEN				0x200
> > >  #define ICnEN_ICEN			BIT(0)
> > >  
> > > -/* CRU Image Processing Main Control Register */
> > > -#define ICnMC				0x208
> > >  #define ICnMC_CSCTHR			BIT(5)
> > >  #define ICnMC_INF(x)			((x) << 16)
> > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > >  #define ICnMC_INF_MASK			GENMASK(21, 16)
> > >  
> > > -/* CRU Module Status Register */
> > > -#define ICnMS				0x254
> > >  #define ICnMS_IA			BIT(2)
> > >  
> > > -/* CRU Data Output Mode Register */
> > > -#define ICnDMR				0x26c
> > >  #define ICnDMR_YCMODE_UYVY		(1 << 4)
> > >  
> > > +enum rzg2l_cru_common_regs {
> > > +	CRUnCTRL,	/* CRU Control */
> > > +	CRUnIE,		/* CRU Interrupt Enable */
> > > +	CRUnINTS,	/* CRU Interrupt Status */
> > > +	CRUnRST, 	/* CRU Reset */
> > > +	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > > +	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > +	AMnMB2ADDRL,    /* Bank 2 Address (Lower) for CRU Image Data */
> > > +	AMnMB2ADDRH,    /* Bank 2 Address (Higher) for CRU Image Data */
> > > +	AMnMB3ADDRL,    /* Bank 3 Address (Lower) for CRU Image Data */
> > > +	AMnMB3ADDRH,    /* Bank 3 Address (Higher) for CRU Image Data */
> > > +	AMnMB4ADDRL,    /* Bank 4 Address (Lower) for CRU Image Data */
> > > +	AMnMB4ADDRH,    /* Bank 4 Address (Higher) for CRU Image Data */
> > > +	AMnMB5ADDRL,    /* Bank 5 Address (Lower) for CRU Image Data */
> > > +	AMnMB5ADDRH,    /* Bank 5 Address (Higher) for CRU Image Data */
> > > +	AMnMB6ADDRL,    /* Bank 6 Address (Lower) for CRU Image Data */
> > > +	AMnMB6ADDRH,    /* Bank 6 Address (Higher) for CRU Image Data */
> > > +	AMnMB7ADDRL,    /* Bank 7 Address (Lower) for CRU Image Data */
> > > +	AMnMB7ADDRH,    /* Bank 7 Address (Higher) for CRU Image Data */
> > > +	AMnMB8ADDRL,    /* Bank 8 Address (Lower) for CRU Image Data */
> > > +	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > > +	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > > +	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > +	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > > +	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > > +	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > > +	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > +	ICnEN,		/* CRU Image Processing Enable */
> > > +	ICnMC,		/* CRU Image Processing Main Control */
> > > +	ICnMS,		/* CRU Module Status */
> > > +	ICnDMR,		/* CRU Data Output Mode */
> > > +};
> > > +
> > >  #endif /* __RZG2L_CRU_REGS_H__ */
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > index 8b898ce05b84..00c3f7458e20 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > @@ -80,6 +80,10 @@ struct rzg2l_cru_ip_format {
> > >  	bool yuv;
> > >  };
> > >  
> > > +struct rzg2l_cru_info {
> > > +	const u16 *regs;
> > > +};
> > > +
> > >  /**
> > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > >   * @dev:		(OF) device
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > index cd69c8a686d3..f25fd9b35c55 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > @@ -44,12 +44,16 @@ struct rzg2l_cru_buffer {
> > >   */
> > >  static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> > >  {
> > > -	iowrite32(value, cru->base + offset);
> > > +	const u16 *regs = cru->info->regs;
> > > +
> > > +	iowrite32(value, cru->base + regs[offset]);
> > 
> > Should out-of-bound accesses be checked ? Ideally that should be done at
> > build time, but in some cases that may be hard. Maybe rzg2l_cru_write()
> > and rzg2l_cru_read() could implement compile-time checks, and
> > __rzg2l_cru_write() and __rzg2l_cru_read() could be used for the cases
> > where checks are not possible at compile time (for AMnMBxADDRL and
> > AMnMBxADDRH as far as I can see).
> 
> What about using:
> 
> static void __rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> {
> 	const u16 *regs = cru->info->regs;
> 
> 	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
> 	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
> 		return;
> 
> 	iowrite32(value, cru->base + regs[offset]);
> }
> 
> static u32 __rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> {
> 	const u16 *regs = cru->info->regs;
> 
> 	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
> 	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
> 		return 0;
> 
> 	return ioread32(cru->base + regs[offset]);
> }
> 
> static inline void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> {
> 	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
> 	__rzg2l_cru_write(cru, offset, value);

If there's already a check at compile time, we shouldn't incur a
performance impact at runtime. I'd do

	iowrite32(value, cru->base + cru->info->regs[offset]);

here. Same below.

> }
> 
> static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> {
> 	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
> 	return __rzg2l_cru_read(cru, offset);
> }
> 
> And use rzg2l_cru_write, rzg2l_cru_read where check can be done at build
> time, and __read/__write functions where check can be only done at
> runtime.

Is there a way we could use a common macro (e.g. rzg2l_cru_write()) and
use __builtin_constant_p() to dispatch to __rzg2l_cru_write_constant()
or __rzg2l_cru_write() ?

> > >  }
> > >  
> > >  static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> > >  {
> > > -	return ioread32(cru->base + offset);
> > > +	const u16 *regs = cru->info->regs;
> > > +
> > > +	return ioread32(cru->base + regs[offset]);
> > >  }
> > >  
> > >  /* Need to hold qlock before calling */
> > > @@ -132,8 +136,8 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > >  		return;
> > >  
> > >  	/* Currently, we just use the buffer in 32 bits address */
> > > -	rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
> > > -	rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
> > > +	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > > +	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > 
> > This seems fairly error-prone. The first argument doesn't seem to be
> > needed.
> 
> Sorry I don't completely got this.
> Please correct me if I'm wrong.
> 
> I think cru argument is needed here has AMnMBxADDRH macro is returning an
> index of rzg2l_cru_regs[] and not the real address.

I meant the first argument to the AMnMBxADDRL() and AMnMBxADDRH(),
sorry. Can it ever be something else than AMnMB1ADDRL or AMnMB1ADDRH
respectively ?

> Btw with the changes above here we can use:
> 
> 	__rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> 	__rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> 
> That is checking for out-of-bound accesses at runtime.
> 
> What do you think?
> Thanks in advance.
> 
> > >  }
> > >  
> > >  /*

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-23 20:32   ` Laurent Pinchart
  2025-02-24 18:15     ` Tommaso Merciai
@ 2025-02-25 10:52     ` Tommaso Merciai
  2025-02-25 11:23       ` Laurent Pinchart
  1 sibling, 1 reply; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-25 10:52 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Laurent,

Thanks for your review.
Back on some previous comments.

On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> Hi Tommaso,
> 
> Thank you for the patch.
> 
> On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > 
> > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > the Renesas RZ/G2L SoC, with the following differences:
> > 
> > - Additional registers rzg3e_cru_regs.
> > - A different irq handler rzg3e_cru_irq.
> > - A different rzg3e_cru_csi2_setup.
> > - A different max input width.
> > 
> > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > and RZ/G3E and related RZ/G3E functions:
> > 
> >  - rzg3e_cru_enable_interrupts()
> >  - rzg3e_cru_enable_interrupts()
> >  - rz3e_fifo_empty()
> >  - rzg3e_cru_csi2_setup()
> >  - rzg3e_cru_get_current_slot()
> > 
> > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > string "renesas,r9a09g047-cru".
> > 
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> >  4 files changed, 282 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > index 3ae0cd83af16..075a3aa8af29 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> >  		return ret;
> >  
> >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > +					    sizeof(struct rzg2l_cru_mem_bank),
> > +					    GFP_KERNEL);
> > +	if (!cru->mem_banks)
> > +		return dev_err_probe(dev, -ENOMEM,
> > +				     "Failed to init mem banks\n");
> > +
> >  	pm_suspend_ignore_children(dev, true);
> >  	ret = devm_pm_runtime_enable(dev);
> >  	if (ret)
> > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> >  	rzg2l_cru_dma_unregister(cru);
> >  }
> >  
> > +static const u16 rzg3e_cru_regs[] = {
> > +	[CRUnCTRL] = 0x0,
> > +	[CRUnIE] = 0x4,
> > +	[CRUnIE2] = 0x8,
> > +	[CRUnINTS] = 0xc,
> > +	[CRUnINTS2] = 0x10,
> > +	[CRUnRST] = 0x18,
> > +	[AMnMB1ADDRL] = 0x40,
> > +	[AMnMB1ADDRH] = 0x44,
> > +	[AMnMB2ADDRL] = 0x48,
> > +	[AMnMB2ADDRH] = 0x4c,
> > +	[AMnMB3ADDRL] = 0x50,
> > +	[AMnMB3ADDRH] = 0x54,
> > +	[AMnMB4ADDRL] = 0x58,
> > +	[AMnMB4ADDRH] = 0x5c,
> > +	[AMnMB5ADDRL] = 0x60,
> > +	[AMnMB5ADDRH] = 0x64,
> > +	[AMnMB6ADDRL] = 0x68,
> > +	[AMnMB6ADDRH] = 0x6c,
> > +	[AMnMB7ADDRL] = 0x70,
> > +	[AMnMB7ADDRH] = 0x74,
> > +	[AMnMB8ADDRL] = 0x78,
> > +	[AMnMB8ADDRH] = 0x7c,
> > +	[AMnMBVALID] = 0x88,
> > +	[AMnMADRSL] = 0x8c,
> > +	[AMnMADRSH] = 0x90,
> > +	[AMnAXIATTR] = 0xec,
> > +	[AMnFIFOPNTR] = 0xf8,
> > +	[AMnAXISTP] = 0x110,
> > +	[AMnAXISTPACK] = 0x114,
> > +	[AMnIS] = 0x128,
> > +	[ICnEN] = 0x1f0,
> > +	[ICnSVCNUM] = 0x1f8,
> > +	[ICnSVC] = 0x1fc,
> > +	[ICnIPMC_C0] = 0x200,
> > +	[ICnMS] = 0x2d8,
> > +	[ICnDMR] = 0x304,
> > +};
> > +
> > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > +	.max_width = 4095,
> > +	.max_height = 4095,
> > +	.image_conv = ICnIPMC_C0,
> > +	.stride = 128,
> > +	.regs = rzg3e_cru_regs,
> > +	.irq_handler = rzg3e_cru_irq,
> > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > +	.fifo_empty = rz3e_fifo_empty,
> > +	.csi_setup = rzg3e_cru_csi2_setup,
> > +};
> > +
> >  static const u16 rzg2l_cru_regs[] = {
> >  	[CRUnCTRL] = 0x0,
> >  	[CRUnIE] = 0x4,
> > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> >  };
> >  
> >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > +	{
> > +		.compatible = "renesas,r9a09g047-cru",
> > +		.data = &rzg3e_cru_info,
> > +	},
> >  	{
> >  		.compatible = "renesas,rzg2l-cru",
> >  		.data = &rzgl2_cru_info,
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > index 82920db7134e..1646d1e2953c 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > @@ -14,8 +14,13 @@
> >  
> >  #define CRUnIE_EFE			BIT(17)
> >  
> > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > +
> >  #define CRUnINTS_SFS			BIT(16)
> >  
> > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > +
> >  #define CRUnRST_VRESETN			BIT(0)
> >  
> >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > @@ -32,7 +37,14 @@
> >  #define AMnAXIATTR_AXILEN		(0xf)
> >  
> >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > +
> > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > +#define AMnIS_IS(x)			((x) << 7)
> >  
> >  #define AMnAXISTP_AXI_STOP		BIT(0)
> >  
> > @@ -40,6 +52,11 @@
> >  
> >  #define ICnEN_ICEN			BIT(0)
> >  
> > +#define ICnSVC_SVC0(x)			(x)
> > +#define ICnSVC_SVC1(x)			((x) << 4)
> > +#define ICnSVC_SVC2(x)			((x) << 8)
> > +#define ICnSVC_SVC3(x)			((x) << 12)
> > +
> >  #define ICnMC_CSCTHR			BIT(5)
> >  #define ICnMC_INF(x)			((x) << 16)
> >  #define ICnMC_VCSEL(x)			((x) << 22)
> > @@ -52,7 +69,9 @@
> >  enum rzg2l_cru_common_regs {
> >  	CRUnCTRL,	/* CRU Control */
> >  	CRUnIE,		/* CRU Interrupt Enable */
> > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> >  	CRUnINTS,	/* CRU Interrupt Status */
> > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> >  	CRUnRST, 	/* CRU Reset */
> >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > +	AMnIS,		/* Image Stride Setting Register */
> >  	ICnEN,		/* CRU Image Processing Enable */
> > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > +	ICnSVC,		/* CRU VC Select Register */
> >  	ICnMC,		/* CRU Image Processing Main Control */
> > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> >  	ICnMS,		/* CRU Module Status */
> >  	ICnDMR,		/* CRU Data Output Mode */
> >  };
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > index ccaba5220f1c..3301379c132c 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> >  	unsigned int max_width;
> >  	unsigned int max_height;
> >  	u16 image_conv;
> > +	u16 stride;
> >  	const u16 *regs;
> >  	irqreturn_t (*irq_handler)(int irq, void *data);
> >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> >  			  u8 csi_vc);
> >  };
> >  
> > +struct rzg2l_cru_mem_bank {
> > +	dma_addr_t addrl;
> > +	dma_addr_t addrh;
> > +};
> > +
> >  /**
> >   * struct rzg2l_cru_dev - Renesas CRU device structure
> >   * @dev:		(OF) device
> > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> >   * @vdev:		V4L2 video device associated with CRU
> >   * @v4l2_dev:		V4L2 device
> >   * @num_buf:		Holds the current number of buffers enabled
> > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > + * @mem_banks:		Memory addresses where current video data is written.
> >   * @notifier:		V4L2 asynchronous subdevs notifier
> >   *
> >   * @ip:			Image processing subdev info
> > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> >  	struct v4l2_device v4l2_dev;
> >  	u8 num_buf;
> >  
> > +	u8 svc_channel;
> > +	struct rzg2l_cru_mem_bank *mem_banks;
> > +
> >  	struct v4l2_async_notifier notifier;
> >  
> >  	struct rzg2l_cru_ip ip;
> > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> >  
> >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> >  
> > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> >  
> >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> >  
> >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> >  			  u8 csi_vc);
> > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > +			  u8 csi_vc);
> >  
> >  #endif
> > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > index 637c9c9f9ba8..efd70c13704e 100644
> > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> >  	/* Currently, we just use the buffer in 32 bits address */
> 
> Should this be fixed ?

This feature support is in the pipeline and we shall start looking into once the
initial support for RZ/G3E and RZ/V2H gets in.

> 
> >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > +
> > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> 
> Here you stplit the dma_addr_t in two fields, storing the low and high
> parts separately (but still in dma_addr_t variables), and below you
> recombine those two fields to recreate the full address. That doesn't
> seem needed.
> 
> >  }
> >  
> >  /*
> > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> >  }
> >  
> > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> >  {
> >  	unsigned int slot;
> >  	u32 amnaxiattr;
> > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> >  	for (slot = 0; slot < cru->num_buf; slot++)
> >  		rzg2l_cru_fill_hw_slot(cru, slot);
> >  
> > +	if (cru->info->stride) {
> 
> I'd name this field stride_align or something similar.
> 
> > +		u32 stride = cru->format.bytesperline;
> > +		u32 amnis;
> > +
> > +		if (stride % cru->info->stride) {
> > +			dev_err(cru->dev,
> > +				"Bytesperline must be multiple of %u bytes\n",
> > +				cru->info->stride);
> > +			return -EINVAL;
> > +		}
> 
> This needs to be caught at set format time, and the stride must be
> adjusted then.
> 
> > +		stride = stride / cru->info->stride;
> 
> 		stride /= cru->info->stride;
> 
> > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > +	}
> > +
> >  	/* Set AXI burst max length to recommended setting */
> >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > +
> > +	return 0;
> > +}
> > +
> > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > +			  u8 csi_vc)
> > +{
> > +	const struct rzg2l_cru_info *info = cru->info;
> > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > +
> > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > +
> > +	/* Set virtual channel CSI2 */
> > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > +
> > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> 
> As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> You can drop ths svc_channel field.
> 
> > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> >  }
> >  
> >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> >  	return 0;
> >  }
> >  
> > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > +{
> > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > +
> > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> >  {
> >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> >  	return fd.entry[0].bus.csi2.vc;
> >  }
> >  
> > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > +{
> > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > +}
> > +
> > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > +{
> > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > +}
> > +
> >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> >  {
> >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> >  	if (ret < 0)
> >  		return ret;
> >  	csi_vc = ret;
> > +	cru->svc_channel = csi_vc;
> >  
> >  	spin_lock_irqsave(&cru->qlock, flags);
> >  
> > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> >  	cru->info->disable_interrupts(cru);
> >  
> >  	/* Initialize the AXI master */
> > -	rzg2l_cru_initialize_axi(cru);
> > +	ret = rzg2l_cru_initialize_axi(cru);
> > +	if (ret) {
> > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > +		return ret;
> > +	}
> 
> This will go away once you remove the error check from
> rzg2l_cru_initialize_axi(), which should then remain a void function.
> 
> There's another function returning an error here,
> rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> separate patch).
> 
> >  
> >  	/* Initialize image convert */
> >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> >  	return IRQ_RETVAL(handled);
> >  }
> >  
> > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > +{
> > +	dma_addr_t amnmadrs;
> > +	unsigned int slot;
> > +
> > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> 
> What if the two registers are read on a frame boundary ?

The reference manual says:

AMnMADRSL:
 Note: When this register is read, AMnMADRSH of the higher-order address also latches the
 address.
 Note: Be sure to read AMnMADRSH after AMnMADRSL has been read.

AMnMADRSH:
 Note: When the AMnMADRSL register is read, the higher address AMnMADRSH also latches the
 address.
 Note: Be sure to lead AMnMADRSH after AMnMADRSL lead.

Then I think we are safe from this perspective.

> 
> > +
> > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > +		dma_addr_t buf_addr;
> > +
> > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > +			cru->mem_banks[slot].addrl;
> > +
> > +		/* Ensure amnmadrs is within this buffer range */
> > +		if (amnmadrs >= buf_addr &&
> > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > +			return slot;
> > +		}
> > +	}
> > +
> > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > +	return -EINVAL;
> > +}
> > +
> > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > +{
> > +	struct rzg2l_cru_dev *cru = data;
> > +	unsigned int handled = 0;
> > +	unsigned long flags;
> > +	unsigned int slot;
> > +	u32 irq_status;
> > +
> > +	spin_lock_irqsave(&cru->qlock, flags);
> > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > +	if (!(irq_status))
> > +		goto done;
> > +
> > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > +
> > +	handled = 1;
> > +
> > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > +
> > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > +		goto done;
> > +	}
> > +
> > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > +		    irq_status & CRUnINTS2_FSxS(3))
> > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > +		goto done;
> > +	}
> > +
> > +	slot = rzg3e_cru_get_current_slot(cru);
> > +	if (slot < 0)
> > +		goto done;
> > +
> > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > +
> > +	cru->mem_banks[slot].addrl = 0;
> > +	cru->mem_banks[slot].addrh = 0;
> > +
> > +	/*
> > +	 * To hand buffers back in a known order to userspace start
> > +	 * to capture first from slot 0.
> > +	 */
> > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > +		if (slot != 0) {
> > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > +			goto done;
> > +		}
> > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > +	}
> > +
> > +	/* Capture frame */
> > +	if (cru->queue_buf[slot]) {
> > +		cru->queue_buf[slot]->field = cru->format.field;
> > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > +				VB2_BUF_STATE_DONE);
> > +		cru->queue_buf[slot] = NULL;
> > +	} else {
> > +		/* Scratch buffer was used, dropping frame. */
> > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > +	}
> > +
> > +	cru->sequence++;
> > +
> > +	/* Prepare for next frame */
> > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > +
> > +done:
> > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > +	return IRQ_RETVAL(handled);
> > +}
> > +
> >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> >  {
> >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Thanks & Regards,
Tommaso

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

* Re: [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support
  2025-02-24 18:44       ` Laurent Pinchart
@ 2025-02-25 11:21         ` Tommaso Merciai
  0 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-25 11:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

On Mon, Feb 24, 2025 at 08:44:16PM +0200, Laurent Pinchart wrote:
> On Mon, Feb 24, 2025 at 02:46:24PM +0100, Tommaso Merciai wrote:
> > On Sun, Feb 23, 2025 at 09:52:32PM +0200, Laurent Pinchart wrote:
> > > On Fri, Feb 21, 2025 at 04:55:25PM +0100, Tommaso Merciai wrote:
> > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > 
> > > > Prepare for adding support for RZ/G3E and RZ/V2HP SoCs, which have a
> > > > CRU-IP that is mostly identical to RZ/G2L but with different register
> > > > offsets and additional registers. Introduce a flexible register mapping
> > > > mechanism to handle these variations.
> > > > 
> > > > Define the `rzg2l_cru_info` structure to store register mappings and
> > > > pass it as part of the OF match data. Update the read/write functions
> > > > to use indexed register offsets from `rzg2l_cru_info`, ensuring
> > > > compatibility across different SoC variants.
> > > > 
> > > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > > ---
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 46 ++++++++++++-
> > > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        | 65 ++++++++++---------
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  4 ++
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 12 ++--
> > > >  4 files changed, 92 insertions(+), 35 deletions(-)
> > > > 
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > index eed9d2bd0841..abc2a979833a 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > @@ -22,6 +22,7 @@
> > > >  #include <media/v4l2-mc.h>
> > > >  
> > > >  #include "rzg2l-cru.h"
> > > > +#include "rzg2l-cru-regs.h"
> > > >  
> > > >  static inline struct rzg2l_cru_dev *notifier_to_cru(struct v4l2_async_notifier *n)
> > > >  {
> > > > @@ -269,6 +270,9 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > > >  
> > > >  	cru->dev = dev;
> > > >  	cru->info = of_device_get_match_data(dev);
> > > > +	if (!cru->info)
> > > > +		return dev_err_probe(dev, -EINVAL,
> > > > +				     "Failed to get OF match data\n");
> > > >  
> > > >  	irq = platform_get_irq(pdev, 0);
> > > >  	if (irq < 0)
> > > > @@ -317,8 +321,48 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > > >  	rzg2l_cru_dma_unregister(cru);
> > > >  }
> > > >  
> > > > +static const u16 rzg2l_cru_regs[] = {
> > > > +	[CRUnCTRL] = 0x0,
> > > > +	[CRUnIE] = 0x4,
> > > > +	[CRUnINTS] = 0x8,
> > > > +	[CRUnRST] = 0xc,
> > > > +	[AMnMB1ADDRL] = 0x100,
> > > > +	[AMnMB1ADDRH] = 0x104,
> > > > +	[AMnMB2ADDRL] = 0x108,
> > > > +	[AMnMB2ADDRH] = 0x10c,
> > > > +	[AMnMB3ADDRL] = 0x110,
> > > > +	[AMnMB3ADDRH] = 0x114,
> > > > +	[AMnMB4ADDRL] = 0x118,
> > > > +	[AMnMB4ADDRH] = 0x11c,
> > > > +	[AMnMB5ADDRL] = 0x120,
> > > > +	[AMnMB5ADDRH] = 0x124,
> > > > +	[AMnMB6ADDRL] = 0x128,
> > > > +	[AMnMB6ADDRH] = 0x12c,
> > > > +	[AMnMB7ADDRL] = 0x130,
> > > > +	[AMnMB7ADDRH] = 0x134,
> > > > +	[AMnMB8ADDRL] = 0x138,
> > > > +	[AMnMB8ADDRH] = 0x13c,
> > > > +	[AMnMBVALID] = 0x148,
> > > > +	[AMnMBS] = 0x14c,
> > > > +	[AMnAXIATTR] = 0x158,
> > > > +	[AMnFIFOPNTR] = 0x168,
> > > > +	[AMnAXISTP] = 0x174,
> > > > +	[AMnAXISTPACK] = 0x178,
> > > > +	[ICnEN] = 0x200,
> > > > +	[ICnMC] = 0x208,
> > > > +	[ICnMS] = 0x254,
> > > > +	[ICnDMR] = 0x26c,
> > > > +};
> > > > +
> > > > +static const struct rzg2l_cru_info rzgl2_cru_info = {
> > > > +	.regs = rzg2l_cru_regs,
> > > > +};
> > > > +
> > > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > > -	{ .compatible = "renesas,rzg2l-cru", },
> > > > +	{
> > > > +		.compatible = "renesas,rzg2l-cru",
> > > > +		.data = &rzgl2_cru_info,
> > > > +	},
> > > >  	{ /* sentinel */ }
> > > >  };
> > > >  MODULE_DEVICE_TABLE(of, rzg2l_cru_of_id_table);
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > index 1c9f22118a5d..82920db7134e 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > @@ -10,71 +10,76 @@
> > > >  
> > > >  /* HW CRU Registers Definition */
> > > >  
> > > > -/* CRU Control Register */
> > > > -#define CRUnCTRL			0x0
> > > >  #define CRUnCTRL_VINSEL(x)		((x) << 0)
> > > >  
> > > > -/* CRU Interrupt Enable Register */
> > > > -#define CRUnIE				0x4
> > > >  #define CRUnIE_EFE			BIT(17)
> > > >  
> > > > -/* CRU Interrupt Status Register */
> > > > -#define CRUnINTS			0x8
> > > >  #define CRUnINTS_SFS			BIT(16)
> > > >  
> > > > -/* CRU Reset Register */
> > > > -#define CRUnRST				0xc
> > > >  #define CRUnRST_VRESETN			BIT(0)
> > > >  
> > > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > > -#define AMnMBxADDRL(x)			(0x100 + ((x) * 8))
> > > > +#define AMnMBxADDRL(base, x)		((base) + (x) * 2)
> > > >  
> > > >  /* Memory Bank Base Address (Higher) Register for CRU Image Data */
> > > > -#define AMnMBxADDRH(x)			(0x104 + ((x) * 8))
> > > > +#define AMnMBxADDRH(base, x)		AMnMBxADDRL(base, x)
> > > >  
> > > > -/* Memory Bank Enable Register for CRU Image Data */
> > > > -#define AMnMBVALID			0x148
> > > >  #define AMnMBVALID_MBVALID(x)		GENMASK(x, 0)
> > > >  
> > > > -/* Memory Bank Status Register for CRU Image Data */
> > > > -#define AMnMBS				0x14c
> > > >  #define AMnMBS_MBSTS			0x7
> > > >  
> > > > -/* AXI Master Transfer Setting Register for CRU Image Data */
> > > > -#define AMnAXIATTR			0x158
> > > >  #define AMnAXIATTR_AXILEN_MASK		GENMASK(3, 0)
> > > >  #define AMnAXIATTR_AXILEN		(0xf)
> > > >  
> > > > -/* AXI Master FIFO Pointer Register for CRU Image Data */
> > > > -#define AMnFIFOPNTR			0x168
> > > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > > >  
> > > > -/* AXI Master Transfer Stop Register for CRU Image Data */
> > > > -#define AMnAXISTP			0x174
> > > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > > >  
> > > > -/* AXI Master Transfer Stop Status Register for CRU Image Data */
> > > > -#define AMnAXISTPACK			0x178
> > > >  #define AMnAXISTPACK_AXI_STOP_ACK	BIT(0)
> > > >  
> > > > -/* CRU Image Processing Enable Register */
> > > > -#define ICnEN				0x200
> > > >  #define ICnEN_ICEN			BIT(0)
> > > >  
> > > > -/* CRU Image Processing Main Control Register */
> > > > -#define ICnMC				0x208
> > > >  #define ICnMC_CSCTHR			BIT(5)
> > > >  #define ICnMC_INF(x)			((x) << 16)
> > > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > > >  #define ICnMC_INF_MASK			GENMASK(21, 16)
> > > >  
> > > > -/* CRU Module Status Register */
> > > > -#define ICnMS				0x254
> > > >  #define ICnMS_IA			BIT(2)
> > > >  
> > > > -/* CRU Data Output Mode Register */
> > > > -#define ICnDMR				0x26c
> > > >  #define ICnDMR_YCMODE_UYVY		(1 << 4)
> > > >  
> > > > +enum rzg2l_cru_common_regs {
> > > > +	CRUnCTRL,	/* CRU Control */
> > > > +	CRUnIE,		/* CRU Interrupt Enable */
> > > > +	CRUnINTS,	/* CRU Interrupt Status */
> > > > +	CRUnRST, 	/* CRU Reset */
> > > > +	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > > > +	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > > +	AMnMB2ADDRL,    /* Bank 2 Address (Lower) for CRU Image Data */
> > > > +	AMnMB2ADDRH,    /* Bank 2 Address (Higher) for CRU Image Data */
> > > > +	AMnMB3ADDRL,    /* Bank 3 Address (Lower) for CRU Image Data */
> > > > +	AMnMB3ADDRH,    /* Bank 3 Address (Higher) for CRU Image Data */
> > > > +	AMnMB4ADDRL,    /* Bank 4 Address (Lower) for CRU Image Data */
> > > > +	AMnMB4ADDRH,    /* Bank 4 Address (Higher) for CRU Image Data */
> > > > +	AMnMB5ADDRL,    /* Bank 5 Address (Lower) for CRU Image Data */
> > > > +	AMnMB5ADDRH,    /* Bank 5 Address (Higher) for CRU Image Data */
> > > > +	AMnMB6ADDRL,    /* Bank 6 Address (Lower) for CRU Image Data */
> > > > +	AMnMB6ADDRH,    /* Bank 6 Address (Higher) for CRU Image Data */
> > > > +	AMnMB7ADDRL,    /* Bank 7 Address (Lower) for CRU Image Data */
> > > > +	AMnMB7ADDRH,    /* Bank 7 Address (Higher) for CRU Image Data */
> > > > +	AMnMB8ADDRL,    /* Bank 8 Address (Lower) for CRU Image Data */
> > > > +	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > > > +	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > > > +	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > > +	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > > > +	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > > > +	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > > > +	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > > +	ICnEN,		/* CRU Image Processing Enable */
> > > > +	ICnMC,		/* CRU Image Processing Main Control */
> > > > +	ICnMS,		/* CRU Module Status */
> > > > +	ICnDMR,		/* CRU Data Output Mode */
> > > > +};
> > > > +
> > > >  #endif /* __RZG2L_CRU_REGS_H__ */
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > index 8b898ce05b84..00c3f7458e20 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > @@ -80,6 +80,10 @@ struct rzg2l_cru_ip_format {
> > > >  	bool yuv;
> > > >  };
> > > >  
> > > > +struct rzg2l_cru_info {
> > > > +	const u16 *regs;
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > > >   * @dev:		(OF) device
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > index cd69c8a686d3..f25fd9b35c55 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > @@ -44,12 +44,16 @@ struct rzg2l_cru_buffer {
> > > >   */
> > > >  static void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> > > >  {
> > > > -	iowrite32(value, cru->base + offset);
> > > > +	const u16 *regs = cru->info->regs;
> > > > +
> > > > +	iowrite32(value, cru->base + regs[offset]);
> > > 
> > > Should out-of-bound accesses be checked ? Ideally that should be done at
> > > build time, but in some cases that may be hard. Maybe rzg2l_cru_write()
> > > and rzg2l_cru_read() could implement compile-time checks, and
> > > __rzg2l_cru_write() and __rzg2l_cru_read() could be used for the cases
> > > where checks are not possible at compile time (for AMnMBxADDRL and
> > > AMnMBxADDRH as far as I can see).
> > 
> > What about using:
> > 
> > static void __rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> > {
> > 	const u16 *regs = cru->info->regs;
> > 
> > 	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
> > 	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
> > 		return;
> > 
> > 	iowrite32(value, cru->base + regs[offset]);
> > }
> > 
> > static u32 __rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> > {
> > 	const u16 *regs = cru->info->regs;
> > 
> > 	if (WARN_ON(offset >= RZG2L_CRU_MAX_REG) ||
> > 	    WARN_ON(offset != CRUnCTRL && regs[offset] == 0))
> > 		return 0;
> > 
> > 	return ioread32(cru->base + regs[offset]);
> > }
> > 
> > static inline void rzg2l_cru_write(struct rzg2l_cru_dev *cru, u32 offset, u32 value)
> > {
> > 	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
> > 	__rzg2l_cru_write(cru, offset, value);
> 
> If there's already a check at compile time, we shouldn't incur a
> performance impact at runtime. I'd do
> 
> 	iowrite32(value, cru->base + cru->info->regs[offset]);
> 
> here. Same below.

Got it, thank.
Will update that in v3.

> 
> > }
> > 
> > static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> > {
> > 	BUILD_BUG_ON(offset >= RZG2L_CRU_MAX_REG);
> > 	return __rzg2l_cru_read(cru, offset);
> > }
> > 
> > And use rzg2l_cru_write, rzg2l_cru_read where check can be done at build
> > time, and __read/__write functions where check can be only done at
> > runtime.
> 
> Is there a way we could use a common macro (e.g. rzg2l_cru_write()) and
> use __builtin_constant_p() to dispatch to __rzg2l_cru_write_constant()
> or __rzg2l_cru_write() ?

As you suggested I'm going to use:

#define rzg2l_cru_write(cru, offset, value) \
	(__builtin_constant_p(offset) ? \
	 __rzg2l_cru_write_constant(cru, offset, value) : \
	 __rzg2l_cru_write(cru, offset, value))

#define rzg2l_cru_read(cru, offset) \
	 (__builtin_constant_p(offset) ? \
	  __rzg2l_cru_read_constant(cru, offset) : \
	  __rzg2l_cru_read(cru, offset))

In v3, thanks.

> 
> > > >  }
> > > >  
> > > >  static u32 rzg2l_cru_read(struct rzg2l_cru_dev *cru, u32 offset)
> > > >  {
> > > > -	return ioread32(cru->base + offset);
> > > > +	const u16 *regs = cru->info->regs;
> > > > +
> > > > +	return ioread32(cru->base + regs[offset]);
> > > >  }
> > > >  
> > > >  /* Need to hold qlock before calling */
> > > > @@ -132,8 +136,8 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > > >  		return;
> > > >  
> > > >  	/* Currently, we just use the buffer in 32 bits address */
> > > > -	rzg2l_cru_write(cru, AMnMBxADDRL(slot), addr);
> > > > -	rzg2l_cru_write(cru, AMnMBxADDRH(slot), 0);
> > > > +	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > > > +	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > > 
> > > This seems fairly error-prone. The first argument doesn't seem to be
> > > needed.
> > 
> > Sorry I don't completely got this.
> > Please correct me if I'm wrong.
> > 
> > I think cru argument is needed here has AMnMBxADDRH macro is returning an
> > index of rzg2l_cru_regs[] and not the real address.
> 
> I meant the first argument to the AMnMBxADDRL() and AMnMBxADDRH(),
> sorry. Can it ever be something else than AMnMB1ADDRL or AMnMB1ADDRH
> respectively ?

Agree we can just use:

#define AMnMBxADDRL(x)			(AMnMB1ADDRL + (x) * 2)
#define AMnMBxADDRH(x)			(AMnMB1ADDRH + (x) * 2)

Will use this in v3.
Thanks.

> 
> > Btw with the changes above here we can use:
> > 
> > 	__rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > 	__rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > 
> > That is checking for out-of-bound accesses at runtime.
> > 
> > What do you think?
> > Thanks in advance.
> > 
> > > >  }
> > > >  
> > > >  /*
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Regards,
Tommaso

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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-25 10:52     ` Tommaso Merciai
@ 2025-02-25 11:23       ` Laurent Pinchart
  2025-02-25 11:30         ` Tommaso Merciai
  0 siblings, 1 reply; 56+ messages in thread
From: Laurent Pinchart @ 2025-02-25 11:23 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

On Tue, Feb 25, 2025 at 11:52:54AM +0100, Tommaso Merciai wrote:
> Hi Laurent,
> 
> Thanks for your review.
> Back on some previous comments.
> 
> On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> > Hi Tommaso,
> > 
> > Thank you for the patch.
> > 
> > On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > 
> > > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > > the Renesas RZ/G2L SoC, with the following differences:
> > > 
> > > - Additional registers rzg3e_cru_regs.
> > > - A different irq handler rzg3e_cru_irq.
> > > - A different rzg3e_cru_csi2_setup.
> > > - A different max input width.
> > > 
> > > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > > and RZ/G3E and related RZ/G3E functions:
> > > 
> > >  - rzg3e_cru_enable_interrupts()
> > >  - rzg3e_cru_enable_interrupts()
> > >  - rz3e_fifo_empty()
> > >  - rzg3e_cru_csi2_setup()
> > >  - rzg3e_cru_get_current_slot()
> > > 
> > > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > > string "renesas,r9a09g047-cru".
> > > 
> > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > ---
> > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> > >  4 files changed, 282 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > index 3ae0cd83af16..075a3aa8af29 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > >  		return ret;
> > >  
> > >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > > +					    sizeof(struct rzg2l_cru_mem_bank),
> > > +					    GFP_KERNEL);
> > > +	if (!cru->mem_banks)
> > > +		return dev_err_probe(dev, -ENOMEM,
> > > +				     "Failed to init mem banks\n");
> > > +
> > >  	pm_suspend_ignore_children(dev, true);
> > >  	ret = devm_pm_runtime_enable(dev);
> > >  	if (ret)
> > > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > >  	rzg2l_cru_dma_unregister(cru);
> > >  }
> > >  
> > > +static const u16 rzg3e_cru_regs[] = {
> > > +	[CRUnCTRL] = 0x0,
> > > +	[CRUnIE] = 0x4,
> > > +	[CRUnIE2] = 0x8,
> > > +	[CRUnINTS] = 0xc,
> > > +	[CRUnINTS2] = 0x10,
> > > +	[CRUnRST] = 0x18,
> > > +	[AMnMB1ADDRL] = 0x40,
> > > +	[AMnMB1ADDRH] = 0x44,
> > > +	[AMnMB2ADDRL] = 0x48,
> > > +	[AMnMB2ADDRH] = 0x4c,
> > > +	[AMnMB3ADDRL] = 0x50,
> > > +	[AMnMB3ADDRH] = 0x54,
> > > +	[AMnMB4ADDRL] = 0x58,
> > > +	[AMnMB4ADDRH] = 0x5c,
> > > +	[AMnMB5ADDRL] = 0x60,
> > > +	[AMnMB5ADDRH] = 0x64,
> > > +	[AMnMB6ADDRL] = 0x68,
> > > +	[AMnMB6ADDRH] = 0x6c,
> > > +	[AMnMB7ADDRL] = 0x70,
> > > +	[AMnMB7ADDRH] = 0x74,
> > > +	[AMnMB8ADDRL] = 0x78,
> > > +	[AMnMB8ADDRH] = 0x7c,
> > > +	[AMnMBVALID] = 0x88,
> > > +	[AMnMADRSL] = 0x8c,
> > > +	[AMnMADRSH] = 0x90,
> > > +	[AMnAXIATTR] = 0xec,
> > > +	[AMnFIFOPNTR] = 0xf8,
> > > +	[AMnAXISTP] = 0x110,
> > > +	[AMnAXISTPACK] = 0x114,
> > > +	[AMnIS] = 0x128,
> > > +	[ICnEN] = 0x1f0,
> > > +	[ICnSVCNUM] = 0x1f8,
> > > +	[ICnSVC] = 0x1fc,
> > > +	[ICnIPMC_C0] = 0x200,
> > > +	[ICnMS] = 0x2d8,
> > > +	[ICnDMR] = 0x304,
> > > +};
> > > +
> > > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > > +	.max_width = 4095,
> > > +	.max_height = 4095,
> > > +	.image_conv = ICnIPMC_C0,
> > > +	.stride = 128,
> > > +	.regs = rzg3e_cru_regs,
> > > +	.irq_handler = rzg3e_cru_irq,
> > > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > > +	.fifo_empty = rz3e_fifo_empty,
> > > +	.csi_setup = rzg3e_cru_csi2_setup,
> > > +};
> > > +
> > >  static const u16 rzg2l_cru_regs[] = {
> > >  	[CRUnCTRL] = 0x0,
> > >  	[CRUnIE] = 0x4,
> > > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> > >  };
> > >  
> > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > +	{
> > > +		.compatible = "renesas,r9a09g047-cru",
> > > +		.data = &rzg3e_cru_info,
> > > +	},
> > >  	{
> > >  		.compatible = "renesas,rzg2l-cru",
> > >  		.data = &rzgl2_cru_info,
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > index 82920db7134e..1646d1e2953c 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > @@ -14,8 +14,13 @@
> > >  
> > >  #define CRUnIE_EFE			BIT(17)
> > >  
> > > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > > +
> > >  #define CRUnINTS_SFS			BIT(16)
> > >  
> > > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > > +
> > >  #define CRUnRST_VRESETN			BIT(0)
> > >  
> > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > @@ -32,7 +37,14 @@
> > >  #define AMnAXIATTR_AXILEN		(0xf)
> > >  
> > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > > +
> > > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > > +#define AMnIS_IS(x)			((x) << 7)
> > >  
> > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > >  
> > > @@ -40,6 +52,11 @@
> > >  
> > >  #define ICnEN_ICEN			BIT(0)
> > >  
> > > +#define ICnSVC_SVC0(x)			(x)
> > > +#define ICnSVC_SVC1(x)			((x) << 4)
> > > +#define ICnSVC_SVC2(x)			((x) << 8)
> > > +#define ICnSVC_SVC3(x)			((x) << 12)
> > > +
> > >  #define ICnMC_CSCTHR			BIT(5)
> > >  #define ICnMC_INF(x)			((x) << 16)
> > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > > @@ -52,7 +69,9 @@
> > >  enum rzg2l_cru_common_regs {
> > >  	CRUnCTRL,	/* CRU Control */
> > >  	CRUnIE,		/* CRU Interrupt Enable */
> > > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> > >  	CRUnINTS,	/* CRU Interrupt Status */
> > > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> > >  	CRUnRST, 	/* CRU Reset */
> > >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> > >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> > >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > +	AMnIS,		/* Image Stride Setting Register */
> > >  	ICnEN,		/* CRU Image Processing Enable */
> > > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > > +	ICnSVC,		/* CRU VC Select Register */
> > >  	ICnMC,		/* CRU Image Processing Main Control */
> > > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> > >  	ICnMS,		/* CRU Module Status */
> > >  	ICnDMR,		/* CRU Data Output Mode */
> > >  };
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > index ccaba5220f1c..3301379c132c 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> > >  	unsigned int max_width;
> > >  	unsigned int max_height;
> > >  	u16 image_conv;
> > > +	u16 stride;
> > >  	const u16 *regs;
> > >  	irqreturn_t (*irq_handler)(int irq, void *data);
> > >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> > >  			  u8 csi_vc);
> > >  };
> > >  
> > > +struct rzg2l_cru_mem_bank {
> > > +	dma_addr_t addrl;
> > > +	dma_addr_t addrh;
> > > +};
> > > +
> > >  /**
> > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > >   * @dev:		(OF) device
> > > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> > >   * @vdev:		V4L2 video device associated with CRU
> > >   * @v4l2_dev:		V4L2 device
> > >   * @num_buf:		Holds the current number of buffers enabled
> > > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > > + * @mem_banks:		Memory addresses where current video data is written.
> > >   * @notifier:		V4L2 asynchronous subdevs notifier
> > >   *
> > >   * @ip:			Image processing subdev info
> > > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> > >  	struct v4l2_device v4l2_dev;
> > >  	u8 num_buf;
> > >  
> > > +	u8 svc_channel;
> > > +	struct rzg2l_cru_mem_bank *mem_banks;
> > > +
> > >  	struct v4l2_async_notifier notifier;
> > >  
> > >  	struct rzg2l_cru_ip ip;
> > > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> > >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> > >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> > >  
> > >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> > >  
> > > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> > >  
> > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > >  
> > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> > >  			  u8 csi_vc);
> > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > +			  u8 csi_vc);
> > >  
> > >  #endif
> > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > index 637c9c9f9ba8..efd70c13704e 100644
> > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > >  	/* Currently, we just use the buffer in 32 bits address */
> > 
> > Should this be fixed ?
> 
> This feature support is in the pipeline and we shall start looking into once the
> initial support for RZ/G3E and RZ/V2H gets in.
> 
> > 
> > >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > > +
> > > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> > 
> > Here you stplit the dma_addr_t in two fields, storing the low and high
> > parts separately (but still in dma_addr_t variables), and below you
> > recombine those two fields to recreate the full address. That doesn't
> > seem needed.
> > 
> > >  }
> > >  
> > >  /*
> > > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> > >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> > >  }
> > >  
> > > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	unsigned int slot;
> > >  	u32 amnaxiattr;
> > > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > >  	for (slot = 0; slot < cru->num_buf; slot++)
> > >  		rzg2l_cru_fill_hw_slot(cru, slot);
> > >  
> > > +	if (cru->info->stride) {
> > 
> > I'd name this field stride_align or something similar.
> > 
> > > +		u32 stride = cru->format.bytesperline;
> > > +		u32 amnis;
> > > +
> > > +		if (stride % cru->info->stride) {
> > > +			dev_err(cru->dev,
> > > +				"Bytesperline must be multiple of %u bytes\n",
> > > +				cru->info->stride);
> > > +			return -EINVAL;
> > > +		}
> > 
> > This needs to be caught at set format time, and the stride must be
> > adjusted then.
> > 
> > > +		stride = stride / cru->info->stride;
> > 
> > 		stride /= cru->info->stride;
> > 
> > > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > > +	}
> > > +
> > >  	/* Set AXI burst max length to recommended setting */
> > >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> > >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> > >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > +			  u8 csi_vc)
> > > +{
> > > +	const struct rzg2l_cru_info *info = cru->info;
> > > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > > +
> > > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > > +
> > > +	/* Set virtual channel CSI2 */
> > > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > > +
> > > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> > 
> > As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> > You can drop ths svc_channel field.
> > 
> > > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> > >  }
> > >  
> > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> > >  	return 0;
> > >  }
> > >  
> > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > > +
> > > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > > +		return true;
> > > +
> > > +	return false;
> > > +}
> > > +
> > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> > >  	return fd.entry[0].bus.csi2.vc;
> > >  }
> > >  
> > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > > +}
> > > +
> > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > +}
> > > +
> > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > >  {
> > >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > >  	if (ret < 0)
> > >  		return ret;
> > >  	csi_vc = ret;
> > > +	cru->svc_channel = csi_vc;
> > >  
> > >  	spin_lock_irqsave(&cru->qlock, flags);
> > >  
> > > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > >  	cru->info->disable_interrupts(cru);
> > >  
> > >  	/* Initialize the AXI master */
> > > -	rzg2l_cru_initialize_axi(cru);
> > > +	ret = rzg2l_cru_initialize_axi(cru);
> > > +	if (ret) {
> > > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > > +		return ret;
> > > +	}
> > 
> > This will go away once you remove the error check from
> > rzg2l_cru_initialize_axi(), which should then remain a void function.
> > 
> > There's another function returning an error here,
> > rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> > separate patch).
> > 
> > >  
> > >  	/* Initialize image convert */
> > >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> > >  	return IRQ_RETVAL(handled);
> > >  }
> > >  
> > > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > > +{
> > > +	dma_addr_t amnmadrs;
> > > +	unsigned int slot;
> > > +
> > > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> > 
> > What if the two registers are read on a frame boundary ?
> 
> The reference manual says:
> 
> AMnMADRSL:
>  Note: When this register is read, AMnMADRSH of the higher-order address also latches the
>  address.
>  Note: Be sure to read AMnMADRSH after AMnMADRSL has been read.
> 
> AMnMADRSH:
>  Note: When the AMnMADRSL register is read, the higher address AMnMADRSH also latches the
>  address.
>  Note: Be sure to lead AMnMADRSH after AMnMADRSL lead.
> 
> Then I think we are safe from this perspective.

Sounds good. Please mention this in a comment, to ensure nobody tries to
swap the reads at some point in the future.

> > > +
> > > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > > +		dma_addr_t buf_addr;
> > > +
> > > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > > +			cru->mem_banks[slot].addrl;
> > > +
> > > +		/* Ensure amnmadrs is within this buffer range */
> > > +		if (amnmadrs >= buf_addr &&
> > > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > > +			return slot;
> > > +		}
> > > +	}
> > > +
> > > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > > +	return -EINVAL;
> > > +}
> > > +
> > > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > > +{
> > > +	struct rzg2l_cru_dev *cru = data;
> > > +	unsigned int handled = 0;
> > > +	unsigned long flags;
> > > +	unsigned int slot;
> > > +	u32 irq_status;
> > > +
> > > +	spin_lock_irqsave(&cru->qlock, flags);
> > > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > > +	if (!(irq_status))
> > > +		goto done;
> > > +
> > > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > > +
> > > +	handled = 1;
> > > +
> > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > +
> > > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > > +		goto done;
> > > +	}
> > > +
> > > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > > +		    irq_status & CRUnINTS2_FSxS(3))
> > > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > > +		goto done;
> > > +	}
> > > +
> > > +	slot = rzg3e_cru_get_current_slot(cru);
> > > +	if (slot < 0)
> > > +		goto done;
> > > +
> > > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > > +
> > > +	cru->mem_banks[slot].addrl = 0;
> > > +	cru->mem_banks[slot].addrh = 0;
> > > +
> > > +	/*
> > > +	 * To hand buffers back in a known order to userspace start
> > > +	 * to capture first from slot 0.
> > > +	 */
> > > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > > +		if (slot != 0) {
> > > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > > +			goto done;
> > > +		}
> > > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > > +	}
> > > +
> > > +	/* Capture frame */
> > > +	if (cru->queue_buf[slot]) {
> > > +		cru->queue_buf[slot]->field = cru->format.field;
> > > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > > +				VB2_BUF_STATE_DONE);
> > > +		cru->queue_buf[slot] = NULL;
> > > +	} else {
> > > +		/* Scratch buffer was used, dropping frame. */
> > > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > > +	}
> > > +
> > > +	cru->sequence++;
> > > +
> > > +	/* Prepare for next frame */
> > > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > > +
> > > +done:
> > > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > > +	return IRQ_RETVAL(handled);
> > > +}
> > > +
> > >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> > >  {
> > >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-24 18:38       ` Laurent Pinchart
@ 2025-02-25 11:28         ` Tommaso Merciai
  0 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-25 11:28 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

Hi Laurent,

Thank you for your comments.

On Mon, Feb 24, 2025 at 08:38:10PM +0200, Laurent Pinchart wrote:
> On Mon, Feb 24, 2025 at 07:15:31PM +0100, Tommaso Merciai wrote:
> > On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> > > On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > 
> > > > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > > > the Renesas RZ/G2L SoC, with the following differences:
> > > > 
> > > > - Additional registers rzg3e_cru_regs.
> > > > - A different irq handler rzg3e_cru_irq.
> > > > - A different rzg3e_cru_csi2_setup.
> > > > - A different max input width.
> > > > 
> > > > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > > > and RZ/G3E and related RZ/G3E functions:
> > > > 
> > > >  - rzg3e_cru_enable_interrupts()
> > > >  - rzg3e_cru_enable_interrupts()
> > > >  - rz3e_fifo_empty()
> > > >  - rzg3e_cru_csi2_setup()
> > > >  - rzg3e_cru_get_current_slot()
> > > > 
> > > > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > > > string "renesas,r9a09g047-cru".
> > > > 
> > > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > > ---
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> > > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> > > >  4 files changed, 282 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > index 3ae0cd83af16..075a3aa8af29 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > > >  		return ret;
> > > >  
> > > >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > > > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > > > +					    sizeof(struct rzg2l_cru_mem_bank),
> > > > +					    GFP_KERNEL);
> > > > +	if (!cru->mem_banks)
> > > > +		return dev_err_probe(dev, -ENOMEM,
> > > > +				     "Failed to init mem banks\n");
> > > > +
> > > >  	pm_suspend_ignore_children(dev, true);
> > > >  	ret = devm_pm_runtime_enable(dev);
> > > >  	if (ret)
> > > > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > > >  	rzg2l_cru_dma_unregister(cru);
> > > >  }
> > > >  
> > > > +static const u16 rzg3e_cru_regs[] = {
> > > > +	[CRUnCTRL] = 0x0,
> > > > +	[CRUnIE] = 0x4,
> > > > +	[CRUnIE2] = 0x8,
> > > > +	[CRUnINTS] = 0xc,
> > > > +	[CRUnINTS2] = 0x10,
> > > > +	[CRUnRST] = 0x18,
> > > > +	[AMnMB1ADDRL] = 0x40,
> > > > +	[AMnMB1ADDRH] = 0x44,
> > > > +	[AMnMB2ADDRL] = 0x48,
> > > > +	[AMnMB2ADDRH] = 0x4c,
> > > > +	[AMnMB3ADDRL] = 0x50,
> > > > +	[AMnMB3ADDRH] = 0x54,
> > > > +	[AMnMB4ADDRL] = 0x58,
> > > > +	[AMnMB4ADDRH] = 0x5c,
> > > > +	[AMnMB5ADDRL] = 0x60,
> > > > +	[AMnMB5ADDRH] = 0x64,
> > > > +	[AMnMB6ADDRL] = 0x68,
> > > > +	[AMnMB6ADDRH] = 0x6c,
> > > > +	[AMnMB7ADDRL] = 0x70,
> > > > +	[AMnMB7ADDRH] = 0x74,
> > > > +	[AMnMB8ADDRL] = 0x78,
> > > > +	[AMnMB8ADDRH] = 0x7c,
> > > > +	[AMnMBVALID] = 0x88,
> > > > +	[AMnMADRSL] = 0x8c,
> > > > +	[AMnMADRSH] = 0x90,
> > > > +	[AMnAXIATTR] = 0xec,
> > > > +	[AMnFIFOPNTR] = 0xf8,
> > > > +	[AMnAXISTP] = 0x110,
> > > > +	[AMnAXISTPACK] = 0x114,
> > > > +	[AMnIS] = 0x128,
> > > > +	[ICnEN] = 0x1f0,
> > > > +	[ICnSVCNUM] = 0x1f8,
> > > > +	[ICnSVC] = 0x1fc,
> > > > +	[ICnIPMC_C0] = 0x200,
> > > > +	[ICnMS] = 0x2d8,
> > > > +	[ICnDMR] = 0x304,
> > > > +};
> > > > +
> > > > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > > > +	.max_width = 4095,
> > > > +	.max_height = 4095,
> > > > +	.image_conv = ICnIPMC_C0,
> > > > +	.stride = 128,
> > > > +	.regs = rzg3e_cru_regs,
> > > > +	.irq_handler = rzg3e_cru_irq,
> > > > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > > > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > > > +	.fifo_empty = rz3e_fifo_empty,
> > > > +	.csi_setup = rzg3e_cru_csi2_setup,
> > > > +};
> > > > +
> > > >  static const u16 rzg2l_cru_regs[] = {
> > > >  	[CRUnCTRL] = 0x0,
> > > >  	[CRUnIE] = 0x4,
> > > > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> > > >  };
> > > >  
> > > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > > +	{
> > > > +		.compatible = "renesas,r9a09g047-cru",
> > > > +		.data = &rzg3e_cru_info,
> > > > +	},
> > > >  	{
> > > >  		.compatible = "renesas,rzg2l-cru",
> > > >  		.data = &rzgl2_cru_info,
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > index 82920db7134e..1646d1e2953c 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > @@ -14,8 +14,13 @@
> > > >  
> > > >  #define CRUnIE_EFE			BIT(17)
> > > >  
> > > > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > > > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > > > +
> > > >  #define CRUnINTS_SFS			BIT(16)
> > > >  
> > > > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > > > +
> > > >  #define CRUnRST_VRESETN			BIT(0)
> > > >  
> > > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > > @@ -32,7 +37,14 @@
> > > >  #define AMnAXIATTR_AXILEN		(0xf)
> > > >  
> > > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > > > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > > > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> > > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > > > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > > > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > > > +
> > > > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > > > +#define AMnIS_IS(x)			((x) << 7)
> > > >  
> > > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > > >  
> > > > @@ -40,6 +52,11 @@
> > > >  
> > > >  #define ICnEN_ICEN			BIT(0)
> > > >  
> > > > +#define ICnSVC_SVC0(x)			(x)
> > > > +#define ICnSVC_SVC1(x)			((x) << 4)
> > > > +#define ICnSVC_SVC2(x)			((x) << 8)
> > > > +#define ICnSVC_SVC3(x)			((x) << 12)
> > > > +
> > > >  #define ICnMC_CSCTHR			BIT(5)
> > > >  #define ICnMC_INF(x)			((x) << 16)
> > > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > > > @@ -52,7 +69,9 @@
> > > >  enum rzg2l_cru_common_regs {
> > > >  	CRUnCTRL,	/* CRU Control */
> > > >  	CRUnIE,		/* CRU Interrupt Enable */
> > > > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> > > >  	CRUnINTS,	/* CRU Interrupt Status */
> > > > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> > > >  	CRUnRST, 	/* CRU Reset */
> > > >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > > >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> > > >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > > >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > > >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > > > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> > > >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > > >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > > >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > > >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > > +	AMnIS,		/* Image Stride Setting Register */
> > > >  	ICnEN,		/* CRU Image Processing Enable */
> > > > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > > > +	ICnSVC,		/* CRU VC Select Register */
> > > >  	ICnMC,		/* CRU Image Processing Main Control */
> > > > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> > > >  	ICnMS,		/* CRU Module Status */
> > > >  	ICnDMR,		/* CRU Data Output Mode */
> > > >  };
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > index ccaba5220f1c..3301379c132c 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> > > >  	unsigned int max_width;
> > > >  	unsigned int max_height;
> > > >  	u16 image_conv;
> > > > +	u16 stride;
> > > >  	const u16 *regs;
> > > >  	irqreturn_t (*irq_handler)(int irq, void *data);
> > > >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > > > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> > > >  			  u8 csi_vc);
> > > >  };
> > > >  
> > > > +struct rzg2l_cru_mem_bank {
> > > > +	dma_addr_t addrl;
> > > > +	dma_addr_t addrh;
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > > >   * @dev:		(OF) device
> > > > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> > > >   * @vdev:		V4L2 video device associated with CRU
> > > >   * @v4l2_dev:		V4L2 device
> > > >   * @num_buf:		Holds the current number of buffers enabled
> > > > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > > > + * @mem_banks:		Memory addresses where current video data is written.
> > > >   * @notifier:		V4L2 asynchronous subdevs notifier
> > > >   *
> > > >   * @ip:			Image processing subdev info
> > > > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> > > >  	struct v4l2_device v4l2_dev;
> > > >  	u8 num_buf;
> > > >  
> > > > +	u8 svc_channel;
> > > > +	struct rzg2l_cru_mem_bank *mem_banks;
> > > > +
> > > >  	struct v4l2_async_notifier notifier;
> > > >  
> > > >  	struct rzg2l_cru_ip ip;
> > > > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> > > >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> > > >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > > > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> > > >  
> > > >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> > > >  
> > > > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> > > >  
> > > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > >  
> > > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > >  			  u8 csi_vc);
> > > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > > +			  u8 csi_vc);
> > > >  
> > > >  #endif
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > index 637c9c9f9ba8..efd70c13704e 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > > >  	/* Currently, we just use the buffer in 32 bits address */
> > > 
> > > Should this be fixed ?
> > > 
> > > >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > > >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > > > +
> > > > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > > > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> > > 
> > > Here you stplit the dma_addr_t in two fields, storing the low and high
> > > parts separately (but still in dma_addr_t variables), and below you
> > > recombine those two fields to recreate the full address. That doesn't
> > > seem needed.
> > 
> > We can use:
> > 
> > struct rzg2l_cru_mem_bank {
> > 	dma_addr_t addr;
> > };
> 
> Drop rzg2l_cru_mem_bank and just use dma_addr_t.

Oks, I will fix this in v3.

> 
> > cru->mem_banks[slot].addr = addr;
> > Instead of using low and high.
> > 
> > Then accordingly update the rzg3e_cru_get_current_slot()
> > 
> > > >  }
> > > >  
> > > >  /*
> > > > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> > > >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> > > >  }
> > > >  
> > > > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	unsigned int slot;
> > > >  	u32 amnaxiattr;
> > > > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > >  	for (slot = 0; slot < cru->num_buf; slot++)
> > > >  		rzg2l_cru_fill_hw_slot(cru, slot);
> > > >  
> > > > +	if (cru->info->stride) {
> > > 
> > > I'd name this field stride_align or something similar.
> > 
> > Agreed on stride_align.
> > Will update this in v3.
> > 
> > > > +		u32 stride = cru->format.bytesperline;
> > > > +		u32 amnis;
> > > > +
> > > > +		if (stride % cru->info->stride) {
> > > > +			dev_err(cru->dev,
> > > > +				"Bytesperline must be multiple of %u bytes\n",
> > > > +				cru->info->stride);
> > > > +			return -EINVAL;
> > > > +		}
> > > 
> > > This needs to be caught at set format time, and the stride must be
> > > adjusted then.
> > 
> > What about doing this into the rzg2l_cru_format_align() function?
> > Somenthing like:
> > 
> > 	if (info->stride_align) {
> > 		u32 stride = pix->width * fmt->bpp;
> 
> 		u32 stride = clamp(pix->bytesperline, pix->width * fmt->bpp,
> 				   RZG2L_CRU_MAX_STRIDE);
> 
> to honour the userspace request and to avoid overflows.
> 
> 
> RZG2L_CRU_MAX_STRIDE may need to be turned into an info field. That may
> be slightly over-engineered though, unless you expect other versions of
> the CRU with different stride alignments, maybe an info->has_stride
> field would be enough, you can then use macros for the stride alignement
> and maximum value.

Agreed.
I will go for info->has_stride field + macros way as you suggested.
Thanks.

> 
> > 
> > 		if (stride % info->stride_align) {
> > 			dev_warn(cru->dev,
> > 				"Bytesperline (%u) is not aligned to %u bytes, adjusting it\n",
> > 				stride, info->stride_align);
> 
> Drop the warning, we shouldn't allow userspace to flood the kernel log.
> 
> > 
> > 			stride = ALIGN_DOWN(stride, info->stride_align);
> 
> Align up, not down. ALIGN() requires the alignment to be a power of two,
> use round_up() if that's not a guarantee.
> 
> > 			pix->width = stride / fmt->bpp;
> 
> No, width doesn't change based on the stride. Only bytesperline does.
> Drop this whole conditional block, and just do
> 
> 		pix->bytesperline = round_up(stride, info->stride_align);
> 	} else {
> 		pix->bytesperline = pix->width * fmt->bpp;
> 	}

Thanks for the clarifications.

> 
> > 		}
> > 	}
> > 
> > 	/* Limit to CRU capabilities */
> > 	v4l_bound_align_image(&pix->width, 320, info->max_width, 1,
> > 			      &pix->height, 240, info->max_height, 2, 0);
> > 
> > 	pix->bytesperline = pix->width * fmt->bpp;
> 
> Drop this line.
> 
> > 	pix->sizeimage = pix->bytesperline * pix->height;
> > 
> > 
> > > 
> > > > +		stride = stride / cru->info->stride;
> > > 
> > > 		stride /= cru->info->stride;
> > > 
> > > > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > > > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > > > +	}
> > > > +
> > > >  	/* Set AXI burst max length to recommended setting */
> > > >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> > > >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> > > >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > > +			  u8 csi_vc)
> > > > +{
> > > > +	const struct rzg2l_cru_info *info = cru->info;
> > > > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > > > +
> > > > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > > > +
> > > > +	/* Set virtual channel CSI2 */
> > > > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > > > +
> > > > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> > > 
> > > As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> > > You can drop ths svc_channel field.
> > 
> > Agreed here I can directly use:
> > 
> > rzg2l_cru_write(cru, ICnSVCNUM, csi_vc);
> > 
> > Thanks
> > 
> > > > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > > > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > > > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> > > >  }
> > > >  
> > > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > > > +
> > > > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > > > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > > > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > > > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > > > +		return true;
> > > > +
> > > > +	return false;
> > > > +}
> > > > +
> > > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > > > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> > > >  	return fd.entry[0].bus.csi2.vc;
> > > >  }
> > > >  
> > > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > > > +}
> > > > +
> > > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > > > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > > > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > > +}
> > > > +
> > > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > > > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > > >  	if (ret < 0)
> > > >  		return ret;
> > > >  	csi_vc = ret;
> > > > +	cru->svc_channel = csi_vc;
> > > >  
> > > >  	spin_lock_irqsave(&cru->qlock, flags);
> > > >  
> > > > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > > >  	cru->info->disable_interrupts(cru);
> > > >  
> > > >  	/* Initialize the AXI master */
> > > > -	rzg2l_cru_initialize_axi(cru);
> > > > +	ret = rzg2l_cru_initialize_axi(cru);
> > > > +	if (ret) {
> > > > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > > > +		return ret;
> > > > +	}
> > > 
> > > This will go away once you remove the error check from
> > > rzg2l_cru_initialize_axi(), which should then remain a void function.
> > 
> > Ooks, thanks.
> > 
> > > There's another function returning an error here,
> > > rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> > > separate patch).
> > > 
> > > >  
> > > >  	/* Initialize image convert */
> > > >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > > > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> > > >  	return IRQ_RETVAL(handled);
> > > >  }
> > > >  
> > > > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	dma_addr_t amnmadrs;
> > > > +	unsigned int slot;
> > > > +
> > > > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > > > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> > > 
> > > What if the two registers are read on a frame boundary ?
> > 
> > Nice point.
> > 
> > You are suggesting here to read the AMnMADRSL and AMnMADRSH with a single
> > ioread64 starting from AMnMADRSL right?
> 
> Is that guaranteed to be atomic ? I wouldn't count on that if the
> APB/AHB interface to registers is 32-bit wide.
> 
> > > > +
> > > > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > > > +		dma_addr_t buf_addr;
> > > > +
> > > > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > > > +			cru->mem_banks[slot].addrl;
> > > > +
> > > > +		/* Ensure amnmadrs is within this buffer range */
> > > > +		if (amnmadrs >= buf_addr &&
> > > > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > > > +			return slot;
> > > > +		}
> > 
> > Here with the upper changes I can use:
> > 
> > 	for (slot = 0; slot < cru->num_buf; slot++) {
> > 
> > 		/* Ensure amnmadrs is within this buffer range */
> > 		if (amnmadrs >= cru->mem_banks[slot].addr &&
> > 		    amnmadrs < cru->mem_banks[slot].addr +
> > 		    cru->format.sizeimage) {
> > 			return slot;
> > 		}
> > 	}
> > 
> > > > +	}
> > > > +
> > > > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > > > +	return -EINVAL;
> > > > +}
> > > > +
> > > > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > > > +{
> > > > +	struct rzg2l_cru_dev *cru = data;
> > > > +	unsigned int handled = 0;
> > > > +	unsigned long flags;
> > > > +	unsigned int slot;
> > > > +	u32 irq_status;
> > > > +
> > > > +	spin_lock_irqsave(&cru->qlock, flags);
> > > > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > > > +	if (!(irq_status))
> > > > +		goto done;
> > > > +
> > > > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > > > +
> > > > +	handled = 1;
> > > > +
> > > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > > +
> > > > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > > > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > > > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > > > +		goto done;
> > > > +	}
> > > > +
> > > > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > > > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(3))
> > > > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > > > +		goto done;
> > > > +	}
> > > > +
> > > > +	slot = rzg3e_cru_get_current_slot(cru);
> > > > +	if (slot < 0)
> > > > +		goto done;
> > > > +
> > > > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > > > +
> > > > +	cru->mem_banks[slot].addrl = 0;
> > > > +	cru->mem_banks[slot].addrh = 0;
> > > > +
> > > > +	/*
> > > > +	 * To hand buffers back in a known order to userspace start
> > > > +	 * to capture first from slot 0.
> > > > +	 */
> > > > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > > > +		if (slot != 0) {
> > > > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > > > +			goto done;
> > > > +		}
> > > > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > > > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > > > +	}
> > > > +
> > > > +	/* Capture frame */
> > > > +	if (cru->queue_buf[slot]) {
> > > > +		cru->queue_buf[slot]->field = cru->format.field;
> > > > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > > > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > > > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > > > +				VB2_BUF_STATE_DONE);
> > > > +		cru->queue_buf[slot] = NULL;
> > > > +	} else {
> > > > +		/* Scratch buffer was used, dropping frame. */
> > > > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > > > +	}
> > > > +
> > > > +	cru->sequence++;
> > > > +
> > > > +	/* Prepare for next frame */
> > > > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > > > +
> > > > +done:
> > > > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > > > +	return IRQ_RETVAL(handled);
> > > > +}
> > > > +
> > > >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> > > >  {
> > > >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Thanks & Regards,
Tommaso

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

* Re: [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC
  2025-02-25 11:23       ` Laurent Pinchart
@ 2025-02-25 11:30         ` Tommaso Merciai
  0 siblings, 0 replies; 56+ messages in thread
From: Tommaso Merciai @ 2025-02-25 11:30 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: tomm.merciai, linux-renesas-soc, linux-media, biju.das.jz,
	prabhakar.mahadev-lad.rj, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
	Magnus Damm, Hans Verkuil, Uwe Kleine-König, devicetree,
	linux-kernel

On Tue, Feb 25, 2025 at 01:23:35PM +0200, Laurent Pinchart wrote:
> On Tue, Feb 25, 2025 at 11:52:54AM +0100, Tommaso Merciai wrote:
> > Hi Laurent,
> > 
> > Thanks for your review.
> > Back on some previous comments.
> > 
> > On Sun, Feb 23, 2025 at 10:32:30PM +0200, Laurent Pinchart wrote:
> > > Hi Tommaso,
> > > 
> > > Thank you for the patch.
> > > 
> > > On Fri, Feb 21, 2025 at 04:55:32PM +0100, Tommaso Merciai wrote:
> > > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > 
> > > > The CRU block on the Renesas RZ/G3E SoC is similar to the one found on
> > > > the Renesas RZ/G2L SoC, with the following differences:
> > > > 
> > > > - Additional registers rzg3e_cru_regs.
> > > > - A different irq handler rzg3e_cru_irq.
> > > > - A different rzg3e_cru_csi2_setup.
> > > > - A different max input width.
> > > > 
> > > > Introduce rzg3e_cru_info struct to handle differences between RZ/G2L
> > > > and RZ/G3E and related RZ/G3E functions:
> > > > 
> > > >  - rzg3e_cru_enable_interrupts()
> > > >  - rzg3e_cru_enable_interrupts()
> > > >  - rz3e_fifo_empty()
> > > >  - rzg3e_cru_csi2_setup()
> > > >  - rzg3e_cru_get_current_slot()
> > > > 
> > > > Add then support for the RZ/G3E SoC CRU block with the new compatible
> > > > string "renesas,r9a09g047-cru".
> > > > 
> > > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > > > ---
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  63 +++++++
> > > >  .../renesas/rzg2l-cru/rzg2l-cru-regs.h        |  25 +++
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  18 ++
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 178 +++++++++++++++++-
> > > >  4 files changed, 282 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > index 3ae0cd83af16..075a3aa8af29 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> > > > @@ -290,6 +290,13 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
> > > >  		return ret;
> > > >  
> > > >  	cru->num_buf = RZG2L_CRU_HW_BUFFER_DEFAULT;
> > > > +	cru->mem_banks = devm_kmalloc_array(dev, cru->num_buf,
> > > > +					    sizeof(struct rzg2l_cru_mem_bank),
> > > > +					    GFP_KERNEL);
> > > > +	if (!cru->mem_banks)
> > > > +		return dev_err_probe(dev, -ENOMEM,
> > > > +				     "Failed to init mem banks\n");
> > > > +
> > > >  	pm_suspend_ignore_children(dev, true);
> > > >  	ret = devm_pm_runtime_enable(dev);
> > > >  	if (ret)
> > > > @@ -321,6 +328,58 @@ static void rzg2l_cru_remove(struct platform_device *pdev)
> > > >  	rzg2l_cru_dma_unregister(cru);
> > > >  }
> > > >  
> > > > +static const u16 rzg3e_cru_regs[] = {
> > > > +	[CRUnCTRL] = 0x0,
> > > > +	[CRUnIE] = 0x4,
> > > > +	[CRUnIE2] = 0x8,
> > > > +	[CRUnINTS] = 0xc,
> > > > +	[CRUnINTS2] = 0x10,
> > > > +	[CRUnRST] = 0x18,
> > > > +	[AMnMB1ADDRL] = 0x40,
> > > > +	[AMnMB1ADDRH] = 0x44,
> > > > +	[AMnMB2ADDRL] = 0x48,
> > > > +	[AMnMB2ADDRH] = 0x4c,
> > > > +	[AMnMB3ADDRL] = 0x50,
> > > > +	[AMnMB3ADDRH] = 0x54,
> > > > +	[AMnMB4ADDRL] = 0x58,
> > > > +	[AMnMB4ADDRH] = 0x5c,
> > > > +	[AMnMB5ADDRL] = 0x60,
> > > > +	[AMnMB5ADDRH] = 0x64,
> > > > +	[AMnMB6ADDRL] = 0x68,
> > > > +	[AMnMB6ADDRH] = 0x6c,
> > > > +	[AMnMB7ADDRL] = 0x70,
> > > > +	[AMnMB7ADDRH] = 0x74,
> > > > +	[AMnMB8ADDRL] = 0x78,
> > > > +	[AMnMB8ADDRH] = 0x7c,
> > > > +	[AMnMBVALID] = 0x88,
> > > > +	[AMnMADRSL] = 0x8c,
> > > > +	[AMnMADRSH] = 0x90,
> > > > +	[AMnAXIATTR] = 0xec,
> > > > +	[AMnFIFOPNTR] = 0xf8,
> > > > +	[AMnAXISTP] = 0x110,
> > > > +	[AMnAXISTPACK] = 0x114,
> > > > +	[AMnIS] = 0x128,
> > > > +	[ICnEN] = 0x1f0,
> > > > +	[ICnSVCNUM] = 0x1f8,
> > > > +	[ICnSVC] = 0x1fc,
> > > > +	[ICnIPMC_C0] = 0x200,
> > > > +	[ICnMS] = 0x2d8,
> > > > +	[ICnDMR] = 0x304,
> > > > +};
> > > > +
> > > > +static const struct rzg2l_cru_info rzg3e_cru_info = {
> > > > +	.max_width = 4095,
> > > > +	.max_height = 4095,
> > > > +	.image_conv = ICnIPMC_C0,
> > > > +	.stride = 128,
> > > > +	.regs = rzg3e_cru_regs,
> > > > +	.irq_handler = rzg3e_cru_irq,
> > > > +	.enable_interrupts = rzg3e_cru_enable_interrupts,
> > > > +	.disable_interrupts = rzg3e_cru_disable_interrupts,
> > > > +	.fifo_empty = rz3e_fifo_empty,
> > > > +	.csi_setup = rzg3e_cru_csi2_setup,
> > > > +};
> > > > +
> > > >  static const u16 rzg2l_cru_regs[] = {
> > > >  	[CRUnCTRL] = 0x0,
> > > >  	[CRUnIE] = 0x4,
> > > > @@ -367,6 +426,10 @@ static const struct rzg2l_cru_info rzgl2_cru_info = {
> > > >  };
> > > >  
> > > >  static const struct of_device_id rzg2l_cru_of_id_table[] = {
> > > > +	{
> > > > +		.compatible = "renesas,r9a09g047-cru",
> > > > +		.data = &rzg3e_cru_info,
> > > > +	},
> > > >  	{
> > > >  		.compatible = "renesas,rzg2l-cru",
> > > >  		.data = &rzgl2_cru_info,
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > index 82920db7134e..1646d1e2953c 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
> > > > @@ -14,8 +14,13 @@
> > > >  
> > > >  #define CRUnIE_EFE			BIT(17)
> > > >  
> > > > +#define CRUnIE2_FSxE(x)			BIT(((x) * 3))
> > > > +#define CRUnIE2_FExE(x)			BIT(((x) * 3) + 1)
> > > > +
> > > >  #define CRUnINTS_SFS			BIT(16)
> > > >  
> > > > +#define CRUnINTS2_FSxS(x)		BIT(((x) * 3))
> > > > +
> > > >  #define CRUnRST_VRESETN			BIT(0)
> > > >  
> > > >  /* Memory Bank Base Address (Lower) Register for CRU Image Data */
> > > > @@ -32,7 +37,14 @@
> > > >  #define AMnAXIATTR_AXILEN		(0xf)
> > > >  
> > > >  #define AMnFIFOPNTR_FIFOWPNTR		GENMASK(7, 0)
> > > > +#define AMnFIFOPNTR_FIFOWPNTR_B0	AMnFIFOPNTR_FIFOWPNTR
> > > > +#define AMnFIFOPNTR_FIFOWPNTR_B1	GENMASK(15, 8)
> > > >  #define AMnFIFOPNTR_FIFORPNTR_Y		GENMASK(23, 16)
> > > > +#define AMnFIFOPNTR_FIFORPNTR_B0	AMnFIFOPNTR_FIFORPNTR_Y
> > > > +#define AMnFIFOPNTR_FIFORPNTR_B1	GENMASK(31, 24)
> > > > +
> > > > +#define AMnIS_IS_MASK			GENMASK(14, 7)
> > > > +#define AMnIS_IS(x)			((x) << 7)
> > > >  
> > > >  #define AMnAXISTP_AXI_STOP		BIT(0)
> > > >  
> > > > @@ -40,6 +52,11 @@
> > > >  
> > > >  #define ICnEN_ICEN			BIT(0)
> > > >  
> > > > +#define ICnSVC_SVC0(x)			(x)
> > > > +#define ICnSVC_SVC1(x)			((x) << 4)
> > > > +#define ICnSVC_SVC2(x)			((x) << 8)
> > > > +#define ICnSVC_SVC3(x)			((x) << 12)
> > > > +
> > > >  #define ICnMC_CSCTHR			BIT(5)
> > > >  #define ICnMC_INF(x)			((x) << 16)
> > > >  #define ICnMC_VCSEL(x)			((x) << 22)
> > > > @@ -52,7 +69,9 @@
> > > >  enum rzg2l_cru_common_regs {
> > > >  	CRUnCTRL,	/* CRU Control */
> > > >  	CRUnIE,		/* CRU Interrupt Enable */
> > > > +	CRUnIE2,	/* CRU Interrupt Enable(2) */
> > > >  	CRUnINTS,	/* CRU Interrupt Status */
> > > > +	CRUnINTS2,	/* CRU Interrupt Status(2) */
> > > >  	CRUnRST, 	/* CRU Reset */
> > > >  	AMnMB1ADDRL,	/* Bank 1 Address (Lower) for CRU Image Data */
> > > >  	AMnMB1ADDRH,	/* Bank 1 Address (Higher) for CRU Image Data */
> > > > @@ -72,12 +91,18 @@ enum rzg2l_cru_common_regs {
> > > >  	AMnMB8ADDRH,    /* Bank 8 Address (Higher) for CRU Image Data */
> > > >  	AMnMBVALID,	/* Memory Bank Enable for CRU Image Data */
> > > >  	AMnMBS,		/* Memory Bank Status for CRU Image Data */
> > > > +	AMnMADRSL,	/* VD Memory Address Lower Status Register */
> > > > +	AMnMADRSH,	/* VD Memory Address Higher Status Register */
> > > >  	AMnAXIATTR,	/* AXI Master Transfer Setting Register for CRU Image Data */
> > > >  	AMnFIFOPNTR,	/* AXI Master FIFO Pointer for CRU Image Data */
> > > >  	AMnAXISTP,	/* AXI Master Transfer Stop for CRU Image Data */
> > > >  	AMnAXISTPACK,	/* AXI Master Transfer Stop Status for CRU Image Data */
> > > > +	AMnIS,		/* Image Stride Setting Register */
> > > >  	ICnEN,		/* CRU Image Processing Enable */
> > > > +	ICnSVCNUM,	/* CRU SVC Number Register */
> > > > +	ICnSVC,		/* CRU VC Select Register */
> > > >  	ICnMC,		/* CRU Image Processing Main Control */
> > > > +	ICnIPMC_C0,	/* CRU Image Converter Main Control 0 */
> > > >  	ICnMS,		/* CRU Module Status */
> > > >  	ICnDMR,		/* CRU Data Output Mode */
> > > >  };
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > index ccaba5220f1c..3301379c132c 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> > > > @@ -84,6 +84,7 @@ struct rzg2l_cru_info {
> > > >  	unsigned int max_width;
> > > >  	unsigned int max_height;
> > > >  	u16 image_conv;
> > > > +	u16 stride;
> > > >  	const u16 *regs;
> > > >  	irqreturn_t (*irq_handler)(int irq, void *data);
> > > >  	void (*enable_interrupts)(struct rzg2l_cru_dev *cru);
> > > > @@ -94,6 +95,11 @@ struct rzg2l_cru_info {
> > > >  			  u8 csi_vc);
> > > >  };
> > > >  
> > > > +struct rzg2l_cru_mem_bank {
> > > > +	dma_addr_t addrl;
> > > > +	dma_addr_t addrh;
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct rzg2l_cru_dev - Renesas CRU device structure
> > > >   * @dev:		(OF) device
> > > > @@ -108,6 +114,8 @@ struct rzg2l_cru_info {
> > > >   * @vdev:		V4L2 video device associated with CRU
> > > >   * @v4l2_dev:		V4L2 device
> > > >   * @num_buf:		Holds the current number of buffers enabled
> > > > + * @svc_channel:	SVC0/1/2/3 to use for RZ/G3E
> > > > + * @mem_banks:		Memory addresses where current video data is written.
> > > >   * @notifier:		V4L2 asynchronous subdevs notifier
> > > >   *
> > > >   * @ip:			Image processing subdev info
> > > > @@ -144,6 +152,9 @@ struct rzg2l_cru_dev {
> > > >  	struct v4l2_device v4l2_dev;
> > > >  	u8 num_buf;
> > > >  
> > > > +	u8 svc_channel;
> > > > +	struct rzg2l_cru_mem_bank *mem_banks;
> > > > +
> > > >  	struct v4l2_async_notifier notifier;
> > > >  
> > > >  	struct rzg2l_cru_ip ip;
> > > > @@ -175,6 +186,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
> > > >  int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
> > > >  irqreturn_t rzg2l_cru_irq(int irq, void *data);
> > > > +irqreturn_t rzg3e_cru_irq(int irq, void *data);
> > > >  
> > > >  const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
> > > >  
> > > > @@ -188,10 +200,16 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
> > > >  
> > > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru);
> > > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru);
> > > >  
> > > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru);
> > > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru);
> > > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > >  			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > >  			  u8 csi_vc);
> > > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > > +			  u8 csi_vc);
> > > >  
> > > >  #endif
> > > > diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > index 637c9c9f9ba8..efd70c13704e 100644
> > > > --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> > > > @@ -138,6 +138,9 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
> > > >  	/* Currently, we just use the buffer in 32 bits address */
> > > 
> > > Should this be fixed ?
> > 
> > This feature support is in the pipeline and we shall start looking into once the
> > initial support for RZ/G3E and RZ/V2H gets in.
> > 
> > > 
> > > >  	rzg2l_cru_write(cru, AMnMBxADDRL(AMnMB1ADDRL, slot), addr);
> > > >  	rzg2l_cru_write(cru, AMnMBxADDRH(AMnMB1ADDRH, slot), 0);
> > > > +
> > > > +	cru->mem_banks[slot].addrl = lower_32_bits(addr);
> > > > +	cru->mem_banks[slot].addrh = upper_32_bits(addr);
> > > 
> > > Here you stplit the dma_addr_t in two fields, storing the low and high
> > > parts separately (but still in dma_addr_t variables), and below you
> > > recombine those two fields to recreate the full address. That doesn't
> > > seem needed.
> > > 
> > > >  }
> > > >  
> > > >  /*
> > > > @@ -176,7 +179,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
> > > >  	rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
> > > >  }
> > > >  
> > > > -static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > > +static int rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	unsigned int slot;
> > > >  	u32 amnaxiattr;
> > > > @@ -190,10 +193,45 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
> > > >  	for (slot = 0; slot < cru->num_buf; slot++)
> > > >  		rzg2l_cru_fill_hw_slot(cru, slot);
> > > >  
> > > > +	if (cru->info->stride) {
> > > 
> > > I'd name this field stride_align or something similar.
> > > 
> > > > +		u32 stride = cru->format.bytesperline;
> > > > +		u32 amnis;
> > > > +
> > > > +		if (stride % cru->info->stride) {
> > > > +			dev_err(cru->dev,
> > > > +				"Bytesperline must be multiple of %u bytes\n",
> > > > +				cru->info->stride);
> > > > +			return -EINVAL;
> > > > +		}
> > > 
> > > This needs to be caught at set format time, and the stride must be
> > > adjusted then.
> > > 
> > > > +		stride = stride / cru->info->stride;
> > > 
> > > 		stride /= cru->info->stride;
> > > 
> > > > +		amnis = rzg2l_cru_read(cru, AMnIS) & ~AMnIS_IS_MASK;
> > > > +		rzg2l_cru_write(cru, AMnIS, amnis | AMnIS_IS(stride));
> > > > +	}
> > > > +
> > > >  	/* Set AXI burst max length to recommended setting */
> > > >  	amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
> > > >  	amnaxiattr |= AMnAXIATTR_AXILEN;
> > > >  	rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > +			  const struct rzg2l_cru_ip_format *ip_fmt,
> > > > +			  u8 csi_vc)
> > > > +{
> > > > +	const struct rzg2l_cru_info *info = cru->info;
> > > > +	u32 icnmc = ICnMC_INF(ip_fmt->datatype);
> > > > +
> > > > +	icnmc |= (rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK);
> > > > +
> > > > +	/* Set virtual channel CSI2 */
> > > > +	icnmc |= ICnMC_VCSEL(csi_vc);
> > > > +
> > > > +	rzg2l_cru_write(cru, ICnSVCNUM, cru->svc_channel);
> > > 
> > > As far as I can tell, csi_vc and cru->svc_channel hold the same value.
> > > You can drop ths svc_channel field.
> > > 
> > > > +	rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
> > > > +			ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
> > > > +	rzg2l_cru_write(cru, info->image_conv, icnmc);
> > > >  }
> > > >  
> > > >  void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
> > > > @@ -244,6 +282,19 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
> > > >  	return 0;
> > > >  }
> > > >  
> > > > +bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR);
> > > > +
> > > > +	if ((((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B1) >> 24) ==
> > > > +	     ((amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B1) >> 8)) &&
> > > > +	    (((amnfifopntr & AMnFIFOPNTR_FIFORPNTR_B0) >> 16) ==
> > > > +	     (amnfifopntr & AMnFIFOPNTR_FIFOWPNTR_B0)))
> > > > +		return true;
> > > > +
> > > > +	return false;
> > > > +}
> > > > +
> > > >  bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	u32 amnfifopntr, amnfifopntr_w, amnfifopntr_r_y;
> > > > @@ -355,6 +406,20 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
> > > >  	return fd.entry[0].bus.csi2.vc;
> > > >  }
> > > >  
> > > > +void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
> > > > +	rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
> > > > +}
> > > > +
> > > > +void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	rzg2l_cru_write(cru, CRUnIE, 0);
> > > > +	rzg2l_cru_write(cru, CRUnIE2, 0);
> > > > +	rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
> > > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > > +}
> > > > +
> > > >  void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
> > > >  {
> > > >  	rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
> > > > @@ -377,6 +442,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > > >  	if (ret < 0)
> > > >  		return ret;
> > > >  	csi_vc = ret;
> > > > +	cru->svc_channel = csi_vc;
> > > >  
> > > >  	spin_lock_irqsave(&cru->qlock, flags);
> > > >  
> > > > @@ -390,7 +456,11 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
> > > >  	cru->info->disable_interrupts(cru);
> > > >  
> > > >  	/* Initialize the AXI master */
> > > > -	rzg2l_cru_initialize_axi(cru);
> > > > +	ret = rzg2l_cru_initialize_axi(cru);
> > > > +	if (ret) {
> > > > +		spin_unlock_irqrestore(&cru->qlock, flags);
> > > > +		return ret;
> > > > +	}
> > > 
> > > This will go away once you remove the error check from
> > > rzg2l_cru_initialize_axi(), which should then remain a void function.
> > > 
> > > There's another function returning an error here,
> > > rzg2l_cru_initialize_image_conv(). I think it can also become void (in a
> > > separate patch).
> > > 
> > > >  
> > > >  	/* Initialize image convert */
> > > >  	ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
> > > > @@ -555,6 +625,110 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
> > > >  	return IRQ_RETVAL(handled);
> > > >  }
> > > >  
> > > > +static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
> > > > +{
> > > > +	dma_addr_t amnmadrs;
> > > > +	unsigned int slot;
> > > > +
> > > > +	amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
> > > > +	amnmadrs |= ((dma_addr_t)rzg2l_cru_read(cru, AMnMADRSH) << 32);
> > > 
> > > What if the two registers are read on a frame boundary ?
> > 
> > The reference manual says:
> > 
> > AMnMADRSL:
> >  Note: When this register is read, AMnMADRSH of the higher-order address also latches the
> >  address.
> >  Note: Be sure to read AMnMADRSH after AMnMADRSL has been read.
> > 
> > AMnMADRSH:
> >  Note: When the AMnMADRSL register is read, the higher address AMnMADRSH also latches the
> >  address.
> >  Note: Be sure to lead AMnMADRSH after AMnMADRSL lead.
> > 
> > Then I think we are safe from this perspective.
> 
> Sounds good. Please mention this in a comment, to ensure nobody tries to
> swap the reads at some point in the future.

Will do, thanks.

> 
> > > > +
> > > > +	for (slot = 0; slot < cru->num_buf; slot++) {
> > > > +		dma_addr_t buf_addr;
> > > > +
> > > > +		buf_addr = cru->mem_banks[slot].addrh << 32 |
> > > > +			cru->mem_banks[slot].addrl;
> > > > +
> > > > +		/* Ensure amnmadrs is within this buffer range */
> > > > +		if (amnmadrs >= buf_addr &&
> > > > +		    amnmadrs < buf_addr + cru->format.sizeimage) {
> > > > +			return slot;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
> > > > +	return -EINVAL;
> > > > +}
> > > > +
> > > > +irqreturn_t rzg3e_cru_irq(int irq, void *data)
> > > > +{
> > > > +	struct rzg2l_cru_dev *cru = data;
> > > > +	unsigned int handled = 0;
> > > > +	unsigned long flags;
> > > > +	unsigned int slot;
> > > > +	u32 irq_status;
> > > > +
> > > > +	spin_lock_irqsave(&cru->qlock, flags);
> > > > +	irq_status = rzg2l_cru_read(cru, CRUnINTS2);
> > > > +	if (!(irq_status))
> > > > +		goto done;
> > > > +
> > > > +	dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
> > > > +
> > > > +	handled = 1;
> > > > +
> > > > +	rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
> > > > +
> > > > +	/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
> > > > +	if (cru->state == RZG2L_CRU_DMA_STOPPED) {
> > > > +		dev_dbg(cru->dev, "IRQ while state stopped\n");
> > > > +		goto done;
> > > > +	}
> > > > +
> > > > +	if (cru->state == RZG2L_CRU_DMA_STOPPING) {
> > > > +		if (irq_status & CRUnINTS2_FSxS(0) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(1) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(2) ||
> > > > +		    irq_status & CRUnINTS2_FSxS(3))
> > > > +			dev_dbg(cru->dev, "IRQ while state stopping\n");
> > > > +		goto done;
> > > > +	}
> > > > +
> > > > +	slot = rzg3e_cru_get_current_slot(cru);
> > > > +	if (slot < 0)
> > > > +		goto done;
> > > > +
> > > > +	dev_dbg(cru->dev, "Current written slot: %d\n", slot);
> > > > +
> > > > +	cru->mem_banks[slot].addrl = 0;
> > > > +	cru->mem_banks[slot].addrh = 0;
> > > > +
> > > > +	/*
> > > > +	 * To hand buffers back in a known order to userspace start
> > > > +	 * to capture first from slot 0.
> > > > +	 */
> > > > +	if (cru->state == RZG2L_CRU_DMA_STARTING) {
> > > > +		if (slot != 0) {
> > > > +			dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
> > > > +			goto done;
> > > > +		}
> > > > +		dev_dbg(cru->dev, "Capture start synced!\n");
> > > > +		cru->state = RZG2L_CRU_DMA_RUNNING;
> > > > +	}
> > > > +
> > > > +	/* Capture frame */
> > > > +	if (cru->queue_buf[slot]) {
> > > > +		cru->queue_buf[slot]->field = cru->format.field;
> > > > +		cru->queue_buf[slot]->sequence = cru->sequence;
> > > > +		cru->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
> > > > +		vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf,
> > > > +				VB2_BUF_STATE_DONE);
> > > > +		cru->queue_buf[slot] = NULL;
> > > > +	} else {
> > > > +		/* Scratch buffer was used, dropping frame. */
> > > > +		dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
> > > > +	}
> > > > +
> > > > +	cru->sequence++;
> > > > +
> > > > +	/* Prepare for next frame */
> > > > +	rzg2l_cru_fill_hw_slot(cru, slot);
> > > > +
> > > > +done:
> > > > +	spin_unlock_irqrestore(&cru->qlock, flags);
> > > > +	return IRQ_RETVAL(handled);
> > > > +}
> > > > +
> > > >  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
> > > >  {
> > > >  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
> 
> -- 
> Regards,
> 
> Laurent Pinchart

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

end of thread, other threads:[~2025-02-25 11:31 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-21 15:55 [PATCH v2 00/18] media: rzg2l-cru: Add support for RZ/G3E (CSI2, CRU) Tommaso Merciai
2025-02-21 15:55 ` [PATCH v2 01/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/V2H(P) SoC Tommaso Merciai
2025-02-23 18:08   ` Laurent Pinchart
2025-02-23 21:00     ` Lad, Prabhakar
2025-02-24  8:07       ` Tommaso Merciai
2025-02-24  9:00     ` Geert Uytterhoeven
2025-02-24  9:05       ` Geert Uytterhoeven
2025-02-24  9:09         ` Biju Das
2025-02-24  9:21           ` Geert Uytterhoeven
2025-02-24 17:25   ` Rob Herring (Arm)
2025-02-21 15:55 ` [PATCH v2 02/18] media: dt-bindings: renesas,rzg2l-csi2: Document Renesas RZ/G3E CSI-2 block Tommaso Merciai
2025-02-23 18:10   ` Laurent Pinchart
2025-02-23 21:11   ` Lad, Prabhakar
2025-02-24  8:11     ` Tommaso Merciai
2025-02-21 15:55 ` [PATCH v2 03/18] media: dt-bindings: renesas,rzg2l-cru: Document Renesas RZ/G3E SoC Tommaso Merciai
2025-02-24 17:27   ` Rob Herring (Arm)
2025-02-21 15:55 ` [PATCH v2 04/18] media: rzg2l-cru: csi2: Use local variable for struct device in rzg2l_csi2_probe() Tommaso Merciai
2025-02-23 18:13   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 05/18] media: rzg2l-cru: csi2: Use devm_pm_runtime_enable() Tommaso Merciai
2025-02-23 21:13   ` Lad, Prabhakar
2025-02-21 15:55 ` [PATCH v2 06/18] media: rzg2l-cru: rzg2l-core: Use local variable for struct device in rzg2l_cru_probe() Tommaso Merciai
2025-02-21 15:55 ` [PATCH v2 07/18] media: rzg2l-cru: rzg2l-core: Use devm_pm_runtime_enable() Tommaso Merciai
2025-02-23 18:14   ` Laurent Pinchart
2025-02-23 21:14   ` Lad, Prabhakar
2025-02-21 15:55 ` [PATCH v2 08/18] media: rzg2l-cru: csi2: Introduce SoC-specific D-PHY handling Tommaso Merciai
2025-02-23 18:17   ` Laurent Pinchart
2025-02-23 21:21     ` Lad, Prabhakar
2025-02-21 15:55 ` [PATCH v2 09/18] media: rzg2l-cru: csi2: Make system clock optional for RZ/V2H(P) SoC Tommaso Merciai
2025-02-23 18:19   ` Laurent Pinchart
2025-02-23 20:57     ` Lad, Prabhakar
2025-02-21 15:55 ` [PATCH v2 10/18] media: rzg2l-cru: csi2: Add support " Tommaso Merciai
2025-02-23 18:24   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 11/18] media: rzg2l-cru: Add register mapping support Tommaso Merciai
2025-02-23 19:52   ` Laurent Pinchart
2025-02-24 13:46     ` Tommaso Merciai
2025-02-24 18:44       ` Laurent Pinchart
2025-02-25 11:21         ` Tommaso Merciai
2025-02-21 15:55 ` [PATCH v2 12/18] media: rzg2l-cru: Pass resolution limits via OF data Tommaso Merciai
2025-02-23 19:54   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 13/18] media: rzg2l-cru: Add image_conv offset to " Tommaso Merciai
2025-02-21 15:55 ` [PATCH v2 14/18] media: rzg2l-cru: Add IRQ handler " Tommaso Merciai
2025-02-23 19:55   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 15/18] media: rzg2l-cru: Add function pointers to enable and disable interrupts Tommaso Merciai
2025-02-23 19:56   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 16/18] media: rzg2l-cru: Add function pointer to check if FIFO is empty Tommaso Merciai
2025-02-23 20:00   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 17/18] media: rzg2l-cru: Add function pointer to configure CSI Tommaso Merciai
2025-02-23 20:03   ` Laurent Pinchart
2025-02-21 15:55 ` [PATCH v2 18/18] media: rzg2l-cru: Add support for RZ/G3E SoC Tommaso Merciai
2025-02-23 20:32   ` Laurent Pinchart
2025-02-24 18:15     ` Tommaso Merciai
2025-02-24 18:38       ` Laurent Pinchart
2025-02-25 11:28         ` Tommaso Merciai
2025-02-25 10:52     ` Tommaso Merciai
2025-02-25 11:23       ` Laurent Pinchart
2025-02-25 11:30         ` Tommaso Merciai

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