mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 00/22] media: platform: rga: Add RGA3 support
@ 2025-12-03 15:52 Sven Püschel
  2025-12-03 15:52 ` [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3 Sven Püschel
                   ` (22 more replies)
  0 siblings, 23 replies; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel, Michael Olbrich

This series adds support for the Raster Graphic Acceleration 3 (RGA3)
peripheral, which is included in the RK3588 SoC. The RK3588
contains one RGA2 core (which is already implemented by the rockchip rga
driver) and two independent RGA3 cores. RGA2 and RGA3 feature
a similar functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

This patch set adds support for one RGA3 core in the existing
rga m2m driver. The feature set of the PR is limited to scaling and
format conversions between common 8bit RGB/YUV formats.
Also the color space conversion is fixed to BT601F.
This already allows a practical usage of the RGA3.

This was tested on a Radxa Rock 5T. Around 80 fps were measured when
scaling and converting from RGBA 480x360 to NV12 3840x2160 in a single
gstreamer pipeline. Format conversions were tested with a single
gstreamer pipeline converting a fixed input to a given input format.
Afterwards it's piped through the RGA3 and the result is converted back
to rgba and compared against a given hash value (generated after
comparing the output manually to the input).

The v4l2-compliance tests still complain about
the failing colorspace propagation for the RGA2.
For the RGA3 they complain about the ycbcr_enc
not being adopted with S_FMT, which is by design,
as the RGA3 currently has the BT601 full range
transfer hard coded:

  v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
  ...
  	Card type        : rga2
  ...
  		fail: v4l2-test-formats.cpp(923): fmt_cap.g_colorspace() != col
  	test VIDIOC_S_FMT: FAIL
  ...
  Total for rockchip-rga device /dev/video0: 47, Succeeded: 46, Failed: 1, Warnings: 0
  
  v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
  ...
  	Card type        : rga3
  ...
  		fail: v4l2-test-formats.cpp(920): fmt_out.g_ycbcr_enc() != ycbcr_enc
  	test VIDIOC_S_FMT: FAIL
  ...
  Total for rockchip-rga device /dev/video1: 47, Succeeded: 46, Failed: 1, Warnings: 0

To distinguish the RGA2 core from the RGA3 cores the Card type is set
accordingly. Scheduling operations between both RGA3 cores to double
the possible frame rate might be a future improvement. Until then
additional RGA3 cores are disabled to only provide one video device to
the user space. This prevents a potential ABI breakage when multi core
support is implemented.

The DTS change at the end is just as a preview, as this series targets
media/next. After it's merged the DTS change will be sent as a new
patch not targeting media.

Patch 1 documments the RGA3 compatible value
Patch 2-3 extend v4l2 common functionality
Patch 4-6 are general cleanups
Patch 7-20 prepare the rga driver for the RGA3
Patch 21 adds RGA3 support to the rga driver
Patch 22 dtsi additions for the RGA3

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v2:
- Removed overclocking (assigning higher clock speeds in the dts)
- Disable the second RGA3 core
- Improved RGA3 feature documentation and code comments
- Don't write the whole command buffer in each frame
- Don't announce CIDs for the RGA3 and error out on s_selection
- Check the max scaling factor of 16 (RGA2) and 8 (RGA3)
- Move stride alignment and alpha checking to v4l2 common
- Register the interrupt as shared for an external IOMMU
- Add IOMMU patch as dependency to fix sporadic hangups
- Link to v1: https://lore.kernel.org/r/20251007-spu-rga3-v1-0-36ad85570402@pengutronix.de

---
Michael Olbrich (1):
      media: rockchip: rga: share the interrupt when an external iommu is used

Sven Püschel (21):
      media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
      media: v4l2-common: add has_alpha to v4l2_format_info
      media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
      media: rockchip: rga: use clk_bulk api
      media: rockchip: rga: use stride for offset calculation
      media: rockchip: rga: remove redundant rga_frame variables
      media: rockchip: rga: move hw specific parts to a dedicated struct
      media: rockchip: rga: move cmdbuf to rga_ctx
      media: rockchip: rga: align stride to 4 bytes
      media: rockchip: rga: prepare cmdbuf on streamon
      media: rockchip: rga: check scaling factor
      media: rockchip: rga: use card type to specify rga type
      media: rockchip: rga: change offset to dma_addresses
      media: rockchip: rga: support external iommus
      media: rockchip: rga: remove size from rga_frame
      media: rockchip: rga: remove stride from rga_frame
      media: rockchip: rga: move rga_fmt to rga-hw.h
      media: rockchip: rga: add feature flags
      media: rockchip: rga: disable multi-core support
      media: rockchip: rga: add rga3 support
      arm64: dts: rockchip: add rga3 dt nodes

 .../devicetree/bindings/media/rockchip-rga.yaml    |   5 +-
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi      |  46 ++
 drivers/media/platform/rockchip/rga/Makefile       |   2 +-
 drivers/media/platform/rockchip/rga/rga-buf.c      |  78 ++--
 drivers/media/platform/rockchip/rga/rga-hw.c       | 404 ++++++++++++----
 drivers/media/platform/rockchip/rga/rga-hw.h       |  18 +-
 drivers/media/platform/rockchip/rga/rga.c          | 518 ++++++++-------------
 drivers/media/platform/rockchip/rga/rga.h          |  82 ++--
 drivers/media/platform/rockchip/rga/rga3-hw.c      | 471 +++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga3-hw.h      | 190 ++++++++
 drivers/media/v4l2-core/v4l2-common.c              |  48 +-
 include/media/v4l2-common.h                        |   6 +
 12 files changed, 1375 insertions(+), 493 deletions(-)
---
base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
change-id: 20251001-spu-rga3-8a00e018b120
prerequisite-change-id: 20251126-spu-iommudtefix-cd0c5244c74a:v1
prerequisite-patch-id: 10c6c977c0f71400931941b42da73adcaf63e810

Best regards,
-- 
Sven Püschel <s.pueschel@pengutronix.de>


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

* [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-03 20:28   ` Krzysztof Kozlowski
  2025-12-03 15:52 ` [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info Sven Püschel
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
peripheral found on the RK3588 SoC.

The existing rga node refers to the RGA2 peripheral. The RK3588
contains one RGA2 core and two RGA3 cores. Both feature a similar
functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 Documentation/devicetree/bindings/media/rockchip-rga.yaml | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.yaml b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
index ac17cda65191b..4d11ca313749f 100644
--- a/Documentation/devicetree/bindings/media/rockchip-rga.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
@@ -9,7 +9,9 @@ title: Rockchip 2D raster graphic acceleration controller (RGA)
 description:
   RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
   graphics operations, such as point/line drawing, image scaling, rotation,
-  BitBLT, alpha blending and image blur/sharpness.
+  BitBLT, alpha blending and image blur/sharpness. There exist two variants
+  named RGA2 and RGA3 that differ in the supported inputs/output formats,
+  the attached IOMMU and the supported operations on the input.
 
 maintainers:
   - Jacob Chen <jacob-chen@iotwrt.com>
@@ -20,6 +22,7 @@ properties:
     oneOf:
       - const: rockchip,rk3288-rga
       - const: rockchip,rk3399-rga
+      - const: rockchip,rk3588-rga3
       - items:
           - enum:
               - rockchip,rk3228-rga

-- 
2.52.0


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

* [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
  2025-12-03 15:52 ` [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3 Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 14:24   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper Sven Püschel
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add a has_alpha value to the v4l2_format_info struct to indicate if the
format contains an alpha component. The implementation is based on the
drm_format_info implementation.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/v4l2-core/v4l2-common.c | 14 +++++++-------
 include/media/v4l2-common.h           |  2 ++
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 554c591e11133..2c7ac70c0f486 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -256,10 +256,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
 		{ .format = V4L2_PIX_FMT_XRGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGBX32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_HSV32,   .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 		{ .format = V4L2_PIX_FMT_RGB565,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB555,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@@ -267,10 +267,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
 		{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
 		{ .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 		{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
-		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
 
 		/* YUV packed formats */
 		{ .format = V4L2_PIX_FMT_YUYV,    .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index f8b1faced79c8..401d8506c24b5 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -520,6 +520,7 @@ enum v4l2_pixel_encoding {
  * @vdiv: Vertical chroma subsampling factor
  * @block_w: Per-plane macroblock pixel width (optional)
  * @block_h: Per-plane macroblock pixel height (optional)
+ * @has_alpha: Does the format embeds an alpha component?
  */
 struct v4l2_format_info {
 	u32 format;
@@ -532,6 +533,7 @@ struct v4l2_format_info {
 	u8 vdiv;
 	u8 block_w[4];
 	u8 block_h[4];
+	bool has_alpha;
 };
 
 static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f)

-- 
2.52.0


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

* [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
  2025-12-03 15:52 ` [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3 Sven Püschel
  2025-12-03 15:52 ` [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 14:47   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api Sven Püschel
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add a v4l2_fill_pixfmt_mp_aligned helper which allows the user to
specify a custom stride alignment in bytes. This is necessary for
hardware like the Rockchip RGA3, which requires the stride value to be
aligned to a 16 byte boundary.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/v4l2-core/v4l2-common.c | 34 ++++++++++++++++++++++++----------
 include/media/v4l2-common.h           |  4 ++++
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 2c7ac70c0f486..f86e7d7d29b8e 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -404,11 +404,12 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
-						    unsigned int width)
+						    unsigned int width, u8 alignment)
 {
 	unsigned int hdiv = plane ? info->hdiv : 1;
 	unsigned int aligned_width =
 		ALIGN(width, v4l2_format_block_width(info, plane));
+	aligned_width = ALIGN(aligned_width, alignment);
 
 	return DIV_ROUND_UP(aligned_width, hdiv) *
 	       info->bpp[plane] / info->bpp_div[plane];
@@ -425,9 +426,10 @@ static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
-						  unsigned int width, unsigned int height)
+						  unsigned int width, unsigned int height,
+						  u8 stride_alignment)
 {
-	return v4l2_format_plane_stride(info, plane, width) *
+	return v4l2_format_plane_stride(info, plane, width, stride_alignment) *
 	       v4l2_format_plane_height(info, plane, height);
 }
 
@@ -448,8 +450,9 @@ void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
 }
 EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
 
-int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
-			u32 pixelformat, u32 width, u32 height)
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+				u32 pixelformat, u32 width, u32 height,
+				u8 stride_alignment)
 {
 	const struct v4l2_format_info *info;
 	struct v4l2_plane_pix_format *plane;
@@ -466,23 +469,34 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
 
 	if (info->mem_planes == 1) {
 		plane = &pixfmt->plane_fmt[0];
-		plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
+		plane->bytesperline = v4l2_format_plane_stride(info, 0, width,
+							       stride_alignment);
 		plane->sizeimage = 0;
 
 		for (i = 0; i < info->comp_planes; i++)
 			plane->sizeimage +=
-				v4l2_format_plane_size(info, i, width, height);
+				v4l2_format_plane_size(info, i, width, height,
+						       stride_alignment);
 	} else {
 		for (i = 0; i < info->comp_planes; i++) {
 			plane = &pixfmt->plane_fmt[i];
 			plane->bytesperline =
-				v4l2_format_plane_stride(info, i, width);
+				v4l2_format_plane_stride(info, i, width,
+							 stride_alignment);
 			plane->sizeimage = plane->bytesperline *
 				v4l2_format_plane_height(info, i, height);
 		}
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp_aligned);
+
+int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
+			u32 pixelformat, u32 width, u32 height)
+{
+	return v4l2_fill_pixfmt_mp_aligned(pixfmt, pixelformat,
+					   width, height, 1);
+}
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
 
 int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
@@ -502,12 +516,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
 	pixfmt->width = width;
 	pixfmt->height = height;
 	pixfmt->pixelformat = pixelformat;
-	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
+	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width, 1);
 	pixfmt->sizeimage = 0;
 
 	for (i = 0; i < info->comp_planes; i++)
 		pixfmt->sizeimage +=
-			v4l2_format_plane_size(info, i, width, height);
+			v4l2_format_plane_size(info, i, width, height, 1);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 401d8506c24b5..edd416178c333 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -558,6 +558,10 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
 		     u32 width, u32 height);
 int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
 			u32 width, u32 height);
+/* @stride_alignment is a power of 2 value in bytes */
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+				u32 pixelformat, u32 width, u32 height,
+				u8 stride_alignment);
 
 /**
  * v4l2_get_link_freq - Get link rate from transmitter

-- 
2.52.0


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

* [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (2 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 14:48   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation Sven Püschel
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Use the clk_bulk API to avoid code duplication for each of the three
clocks.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 64 ++++---------------------------
 drivers/media/platform/rockchip/rga/rga.h |  5 +--
 2 files changed, 9 insertions(+), 60 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 43f6a8d993811..ef568b3758380 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -698,48 +698,10 @@ static const struct video_device rga_videodev = {
 	.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
 };
 
-static int rga_enable_clocks(struct rockchip_rga *rga)
-{
-	int ret;
-
-	ret = clk_prepare_enable(rga->sclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
-		return ret;
-	}
-
-	ret = clk_prepare_enable(rga->aclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
-		goto err_disable_sclk;
-	}
-
-	ret = clk_prepare_enable(rga->hclk);
-	if (ret) {
-		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
-		goto err_disable_aclk;
-	}
-
-	return 0;
-
-err_disable_aclk:
-	clk_disable_unprepare(rga->aclk);
-err_disable_sclk:
-	clk_disable_unprepare(rga->sclk);
-
-	return ret;
-}
-
-static void rga_disable_clocks(struct rockchip_rga *rga)
-{
-	clk_disable_unprepare(rga->sclk);
-	clk_disable_unprepare(rga->hclk);
-	clk_disable_unprepare(rga->aclk);
-}
-
 static int rga_parse_dt(struct rockchip_rga *rga)
 {
 	struct reset_control *core_rst, *axi_rst, *ahb_rst;
+	int ret;
 
 	core_rst = devm_reset_control_get(rga->dev, "core");
 	if (IS_ERR(core_rst)) {
@@ -771,22 +733,10 @@ static int rga_parse_dt(struct rockchip_rga *rga)
 	udelay(1);
 	reset_control_deassert(ahb_rst);
 
-	rga->sclk = devm_clk_get(rga->dev, "sclk");
-	if (IS_ERR(rga->sclk)) {
-		dev_err(rga->dev, "failed to get sclk clock\n");
-		return PTR_ERR(rga->sclk);
-	}
-
-	rga->aclk = devm_clk_get(rga->dev, "aclk");
-	if (IS_ERR(rga->aclk)) {
-		dev_err(rga->dev, "failed to get aclk clock\n");
-		return PTR_ERR(rga->aclk);
-	}
-
-	rga->hclk = devm_clk_get(rga->dev, "hclk");
-	if (IS_ERR(rga->hclk)) {
-		dev_err(rga->dev, "failed to get hclk clock\n");
-		return PTR_ERR(rga->hclk);
+	ret = devm_clk_bulk_get(rga->dev, ARRAY_SIZE(rga->clks), rga->clks);
+	if (ret) {
+		dev_err(rga->dev, "failed to get clocks\n");
+		return ret;
 	}
 
 	return 0;
@@ -935,7 +885,7 @@ static int __maybe_unused rga_runtime_suspend(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
-	rga_disable_clocks(rga);
+	clk_bulk_disable_unprepare(ARRAY_SIZE(rga->clks), rga->clks);
 
 	return 0;
 }
@@ -944,7 +894,7 @@ static int __maybe_unused rga_runtime_resume(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
-	return rga_enable_clocks(rga);
+	return clk_bulk_prepare_enable(ARRAY_SIZE(rga->clks), rga->clks);
 }
 
 static const struct dev_pm_ops rga_pm = {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 72a28b120fabf..a922fac0c01a3 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -6,6 +6,7 @@
 #ifndef __RGA_H__
 #define __RGA_H__
 
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/v4l2-ctrls.h>
@@ -81,9 +82,7 @@ struct rockchip_rga {
 	struct device *dev;
 	struct regmap *grf;
 	void __iomem *regs;
-	struct clk *sclk;
-	struct clk *aclk;
-	struct clk *hclk;
+	struct clk_bulk_data clks[3];
 	struct rockchip_rga_version version;
 
 	/* vfd lock */

-- 
2.52.0


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

* [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (3 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:00   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables Sven Püschel
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Use the stride instead of the width for the offset calculation. This
ensures that the bytesperline value doesn't need to match the width
value of the image.

Furthermore this patch removes the dependency on the uv_factor property
and instead reuses the v4l2_format_info to determine the correct
division factor.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 730bdf98565a5..b5e6b1b527ca8 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -14,7 +14,6 @@
 #include <media/videobuf2-dma-sg.h>
 #include <media/videobuf2-v4l2.h>
 
-#include "rga-hw.h"
 #include "rga.h"
 
 static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
@@ -92,14 +91,19 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	return 0;
 }
 
-static int get_plane_offset(struct rga_frame *f, int plane)
+static int get_plane_offset(struct rga_frame *f,
+			    const struct v4l2_format_info *info,
+			    int plane)
 {
+	u32 stride = f->pix.plane_fmt[0].bytesperline;
+
 	if (plane == 0)
 		return 0;
 	if (plane == 1)
-		return f->width * f->height;
+		return stride * f->height;
 	if (plane == 2)
-		return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
+		return stride * f->height +
+		       (stride * f->height / info->hdiv / info->vdiv);
 
 	return -EINVAL;
 }
@@ -145,7 +149,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	/* Fill the remaining planes */
 	info = v4l2_format_info(f->fmt->fourcc);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
-		offsets[i] = get_plane_offset(f, i);
+		offsets[i] = get_plane_offset(f, info, i);
 
 	rbuf->offset.y_off = offsets[0];
 	rbuf->offset.u_off = offsets[1];

-- 
2.52.0


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

* [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (4 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:03   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct Sven Püschel
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Remove the redundant rga_frame variables width, height and color space.
The value of these variables is already contained in the pix member
of rga_frame. The code also keeps these values in sync. Therefore drop
them in favor of the existing pix member.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  6 ++---
 drivers/media/platform/rockchip/rga/rga-hw.c  |  6 ++---
 drivers/media/platform/rockchip/rga/rga.c     | 32 ++++++++++-----------------
 drivers/media/platform/rockchip/rga/rga.h     |  5 -----
 4 files changed, 18 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index b5e6b1b527ca8..0c59a4d330888 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -100,10 +100,10 @@ static int get_plane_offset(struct rga_frame *f,
 	if (plane == 0)
 		return 0;
 	if (plane == 1)
-		return stride * f->height;
+		return stride * f->pix.height;
 	if (plane == 2)
-		return stride * f->height +
-		       (stride * f->height / info->hdiv / info->vdiv);
+		return stride * f->pix.height +
+		       (stride * f->pix.height / info->hdiv / info->vdiv);
 
 	return -EINVAL;
 }
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 43ed742a16492..f1d5237472941 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -53,7 +53,7 @@ rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
 	uv_stride = frm->stride / x_div;
-	pixel_width = frm->stride / frm->width;
+	pixel_width = frm->stride / frm->pix.width;
 
 	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
 	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
@@ -191,7 +191,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 
 	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
 	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
-		switch (ctx->in.colorspace) {
+		switch (ctx->in.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
 			break;
@@ -203,7 +203,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 
 	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
 	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
-		switch (ctx->out.colorspace) {
+		switch (ctx->out.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
 			break;
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index ef568b3758380..f50fbbab0645e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -345,9 +345,6 @@ static struct rga_fmt *rga_fmt_find(u32 pixelformat)
 }
 
 static struct rga_frame def_frame = {
-	.width = DEFAULT_WIDTH,
-	.height = DEFAULT_HEIGHT,
-	.colorspace = V4L2_COLORSPACE_DEFAULT,
 	.crop.left = 0,
 	.crop.top = 0,
 	.crop.width = DEFAULT_WIDTH,
@@ -379,9 +376,9 @@ static int rga_open(struct file *file)
 	ctx->out = def_frame;
 
 	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
+			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
 	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
+			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		kfree(ctx);
@@ -469,10 +466,8 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
 
-	v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
-
+	*pix_fmt = frm->pix;
 	pix_fmt->field = V4L2_FIELD_NONE;
-	pix_fmt->colorspace = frm->colorspace;
 
 	return 0;
 }
@@ -521,27 +516,24 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->width = pix_fmt->width;
-	frm->height = pix_fmt->height;
 	frm->size = 0;
 	for (i = 0; i < pix_fmt->num_planes; i++)
 		frm->size += pix_fmt->plane_fmt[i].sizeimage;
 	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
-	frm->colorspace = pix_fmt->colorspace;
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
 	frm->crop.top = 0;
-	frm->crop.width = frm->width;
-	frm->crop.height = frm->height;
+	frm->crop.width = pix_fmt->width;
+	frm->crop.height = pix_fmt->height;
 
 	frm->pix = *pix_fmt;
 
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
 		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
-		  &frm->fmt->fourcc, frm->width, frm->height,
+		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
 		  frm->stride, frm->size);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
@@ -595,8 +587,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
 	} else {
 		s->r.left = 0;
 		s->r.top = 0;
-		s->r.width = f->width;
-		s->r.height = f->height;
+		s->r.width = f->pix.width;
+		s->r.height = f->pix.height;
 	}
 
 	return 0;
@@ -645,8 +637,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
 		return -EINVAL;
 	}
 
-	if (s->r.left + s->r.width > f->width ||
-	    s->r.top + s->r.height > f->height ||
+	if (s->r.left + s->r.width > f->pix.width ||
+	    s->r.top + s->r.height > f->pix.height ||
 	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
 		return -EINVAL;
@@ -836,8 +828,8 @@ static int rga_probe(struct platform_device *pdev)
 		goto rel_m2m;
 	}
 
-	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * def_frame.height;
+	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
 
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index a922fac0c01a3..7ec1fcc03ed32 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -25,11 +25,6 @@ struct rga_fmt {
 };
 
 struct rga_frame {
-	/* Original dimensions */
-	u32 width;
-	u32 height;
-	u32 colorspace;
-
 	/* Crop */
 	struct v4l2_rect crop;
 

-- 
2.52.0


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

* [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (5 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:05   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx Sven Püschel
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

In preparation for the RGA3 unit, move RGA2 specific parts from rga.c
to rga-hw.c and create a struct to reference the RGA2 specific functions
and formats. This also allows to remove the rga-hw.h reference from the
include list of the rga driver.

Also document the command finish interrupt with a dedicated define.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 183 ++++++++++++++++++++-
 drivers/media/platform/rockchip/rga/rga-hw.h |   5 +-
 drivers/media/platform/rockchip/rga/rga.c    | 228 +++++----------------------
 drivers/media/platform/rockchip/rga/rga.h    |  23 ++-
 4 files changed, 245 insertions(+), 194 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index f1d5237472941..7419784efc693 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -437,8 +437,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 		PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
-void rga_hw_start(struct rockchip_rga *rga,
-		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+static void rga_hw_start(struct rockchip_rga *rga,
+			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
 {
 	struct rga_ctx *ctx = rga->curr;
 
@@ -452,3 +452,182 @@ void rga_hw_start(struct rockchip_rga *rga,
 
 	rga_write(rga, RGA_CMD_CTRL, 0x1);
 }
+
+static bool rga_handle_irq(struct rockchip_rga *rga)
+{
+	int intr;
+
+	intr = rga_read(rga, RGA_INT) & 0xf;
+
+	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+	return intr & RGA_INT_COMMAND_FINISHED;
+}
+
+static void rga_get_version(struct rockchip_rga *rga)
+{
+	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+}
+
+static struct rga_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR4444,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR1555,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_BGR565,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422P,
+
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+};
+
+const struct rga_hw rga2_hw = {
+	.formats = formats,
+	.num_formats = ARRAY_SIZE(formats),
+	.cmdbuf_size = RGA_CMDBUF_SIZE,
+	.min_width = MIN_WIDTH,
+	.max_width = MAX_WIDTH,
+	.min_height = MIN_HEIGHT,
+	.max_height = MAX_HEIGHT,
+
+	.start = rga_hw_start,
+	.handle_irq = rga_handle_irq,
+	.get_version = rga_get_version,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index cc6bd7f5b0300..f4752aa823051 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -15,9 +15,6 @@
 #define MIN_WIDTH 34
 #define MIN_HEIGHT 34
 
-#define DEFAULT_WIDTH 100
-#define DEFAULT_HEIGHT 100
-
 #define RGA_TIMEOUT 500
 
 /* Registers address */
@@ -178,6 +175,8 @@
 #define RGA_ALPHA_COLOR_NORMAL 0
 #define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
 
+#define RGA_INT_COMMAND_FINISHED 4
+
 /* Registers union */
 union rga_mode_ctrl {
 	unsigned int val;
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f50fbbab0645e..d8b14c2d9f6a4 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -25,7 +25,6 @@
 #include <media/videobuf2-dma-sg.h>
 #include <media/videobuf2-v4l2.h>
 
-#include "rga-hw.h"
 #include "rga.h"
 
 static int debug;
@@ -47,7 +46,7 @@ static void device_run(void *prv)
 
 	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
-	rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
+	rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
 
 	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
 }
@@ -55,13 +54,8 @@ static void device_run(void *prv)
 static irqreturn_t rga_isr(int irq, void *prv)
 {
 	struct rockchip_rga *rga = prv;
-	int intr;
 
-	intr = rga_read(rga, RGA_INT) & 0xf;
-
-	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
-
-	if (intr & 0x04) {
+	if (rga->hw->handle_irq(rga)) {
 		struct vb2_v4l2_buffer *src, *dst;
 		struct rga_ctx *ctx = rga->curr;
 
@@ -184,174 +178,17 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 	return 0;
 }
 
-static struct rga_fmt formats[] = {
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB32,
-		.color_swap = RGA_COLOR_ALPHA_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ABGR32,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_XBGR32,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_XBGR8888,
-		.depth = 32,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_RGB24,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_RGB888,
-		.depth = 24,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_BGR24,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_RGB888,
-		.depth = 24,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB444,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR4444,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_ARGB555,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_ABGR1555,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.color_swap = RGA_COLOR_RB_SWAP,
-		.hw_format = RGA_COLOR_FMT_BGR565,
-		.depth = 16,
-		.uv_factor = 1,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV21,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV61,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422SP,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV12,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV12M,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420SP,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_NV16,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422SP,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 1,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YUV420,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420P,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 2,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YUV422P,
-		.color_swap = RGA_COLOR_NONE_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV422P,
-		.depth = 16,
-		.uv_factor = 2,
-		.y_div = 1,
-		.x_div = 2,
-	},
-	{
-		.fourcc = V4L2_PIX_FMT_YVU420,
-		.color_swap = RGA_COLOR_UV_SWAP,
-		.hw_format = RGA_COLOR_FMT_YUV420P,
-		.depth = 12,
-		.uv_factor = 4,
-		.y_div = 2,
-		.x_div = 2,
-	},
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-static struct rga_fmt *rga_fmt_find(u32 pixelformat)
+static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
 {
 	unsigned int i;
 
-	for (i = 0; i < NUM_FORMATS; i++) {
-		if (formats[i].fourcc == pixelformat)
-			return &formats[i];
+	for (i = 0; i < rga->hw->num_formats; i++) {
+		if (rga->hw->formats[i].fourcc == pixelformat)
+			return &rga->hw->formats[i];
 	}
 	return NULL;
 }
 
-static struct rga_frame def_frame = {
-	.crop.left = 0,
-	.crop.top = 0,
-	.crop.width = DEFAULT_WIDTH,
-	.crop.height = DEFAULT_HEIGHT,
-	.fmt = &formats[0],
-};
-
 struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
 {
 	if (V4L2_TYPE_IS_OUTPUT(type))
@@ -366,6 +203,18 @@ static int rga_open(struct file *file)
 	struct rockchip_rga *rga = video_drvdata(file);
 	struct rga_ctx *ctx = NULL;
 	int ret = 0;
+	u32 def_width = clamp(DEFAULT_WIDTH, rga->hw->min_width, rga->hw->max_width);
+	u32 def_height = clamp(DEFAULT_HEIGHT, rga->hw->min_height, rga->hw->max_height);
+	struct rga_frame def_frame = {
+		.crop.left = 0,
+		.crop.top = 0,
+		.crop.width = def_width,
+		.crop.height = def_height,
+		.fmt = &rga->hw->formats[0],
+	};
+
+	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * def_height;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -376,9 +225,9 @@ static int rga_open(struct file *file)
 	ctx->out = def_frame;
 
 	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+			    ctx->in.fmt->fourcc, def_width, def_height);
 	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+			    ctx->out.fmt->fourcc, def_width, def_height);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		kfree(ctx);
@@ -445,12 +294,13 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 
 static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
 {
+	struct rockchip_rga *rga = video_drvdata(file);
 	struct rga_fmt *fmt;
 
-	if (f->index >= NUM_FORMATS)
+	if (f->index >= rga->hw->num_formats)
 		return -EINVAL;
 
-	fmt = &formats[f->index];
+	fmt = &rga->hw->formats[f->index];
 	f->pixelformat = fmt->fourcc;
 
 	return 0;
@@ -475,16 +325,18 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
+	struct rockchip_rga *rga = video_drvdata(file);
+	const struct rga_hw *hw = rga->hw;
 	struct rga_fmt *fmt;
 
-	fmt = rga_fmt_find(pix_fmt->pixelformat);
+	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	if (!fmt)
-		fmt = &formats[0];
+		fmt = &hw->formats[0];
 
 	pix_fmt->width = clamp(pix_fmt->width,
-			       (u32)MIN_WIDTH, (u32)MAX_WIDTH);
+			       hw->min_width, hw->max_width);
 	pix_fmt->height = clamp(pix_fmt->height,
-				(u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
+				hw->min_height, hw->max_height);
 
 	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
 	pix_fmt->field = V4L2_FIELD_NONE;
@@ -519,7 +371,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm->size = 0;
 	for (i = 0; i < pix_fmt->num_planes; i++)
 		frm->size += pix_fmt->plane_fmt[i].sizeimage;
-	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
+	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
 	/* Reset crop settings */
@@ -639,7 +491,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
 
 	if (s->r.left + s->r.width > f->pix.width ||
 	    s->r.top + s->r.height > f->pix.height ||
-	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+	    s->r.width < rga->hw->min_width || s->r.height < rga->hw->min_height) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
 		return -EINVAL;
 	}
@@ -748,6 +600,10 @@ static int rga_probe(struct platform_device *pdev)
 	if (!rga)
 		return -ENOMEM;
 
+	rga->hw = of_device_get_match_data(&pdev->dev);
+	if (!rga->hw)
+		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
+
 	rga->dev = &pdev->dev;
 	spin_lock_init(&rga->ctrl_lock);
 	mutex_init(&rga->mutex);
@@ -811,8 +667,7 @@ static int rga_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto rel_m2m;
 
-	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
-	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+	rga->hw->get_version(rga);
 
 	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
 		  rga->version.major, rga->version.minor);
@@ -820,7 +675,7 @@ static int rga_probe(struct platform_device *pdev)
 	pm_runtime_put(rga->dev);
 
 	/* Create CMD buffer */
-	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
 					   &rga->cmdbuf_phy, GFP_KERNEL,
 					   DMA_ATTR_WRITE_COMBINE);
 	if (!rga->cmdbuf_virt) {
@@ -828,9 +683,6 @@ static int rga_probe(struct platform_device *pdev)
 		goto rel_m2m;
 	}
 
-	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
-
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
 		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
@@ -843,7 +695,7 @@ static int rga_probe(struct platform_device *pdev)
 	return 0;
 
 free_dma:
-	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
 		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_m2m:
 	v4l2_m2m_release(rga->m2m_dev);
@@ -861,7 +713,7 @@ static void rga_remove(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga = platform_get_drvdata(pdev);
 
-	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
 		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
@@ -897,9 +749,11 @@ static const struct dev_pm_ops rga_pm = {
 static const struct of_device_id rockchip_rga_match[] = {
 	{
 		.compatible = "rockchip,rk3288-rga",
+		.data = &rga2_hw,
 	},
 	{
 		.compatible = "rockchip,rk3399-rga",
+		.data = &rga2_hw,
 	},
 	{},
 };
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 7ec1fcc03ed32..98635ddd50d7c 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -14,6 +14,9 @@
 
 #define RGA_NAME "rockchip-rga"
 
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
 struct rga_fmt {
 	u32 fourcc;
 	int depth;
@@ -69,6 +72,8 @@ static inline struct rga_ctx *file_to_rga_ctx(struct file *filp)
 	return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh);
 }
 
+struct rga_hw;
+
 struct rockchip_rga {
 	struct v4l2_device v4l2_dev;
 	struct v4l2_m2m_dev *m2m_dev;
@@ -88,6 +93,8 @@ struct rockchip_rga {
 	struct rga_ctx *curr;
 	dma_addr_t cmdbuf_phy;
 	void *cmdbuf_virt;
+
+	const struct rga_hw *hw;
 };
 
 struct rga_addr_offset {
@@ -138,7 +145,19 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 	rga_write(rga, reg, temp);
 };
 
-void rga_hw_start(struct rockchip_rga *rga,
-		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+struct rga_hw {
+	struct rga_fmt *formats;
+	u32 num_formats;
+	size_t cmdbuf_size;
+	u32 min_width, min_height;
+	u32 max_width, max_height;
+
+	void (*start)(struct rockchip_rga *rga,
+		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+	bool (*handle_irq)(struct rockchip_rga *rga);
+	void (*get_version)(struct rockchip_rga *rga);
+};
+
+extern const struct rga_hw rga2_hw;
 
 #endif

-- 
2.52.0


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

* [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (6 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:21   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes Sven Püschel
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Move the command buffer to the rga_ctx struct in preparation to reuse
an already prepared command buffer. Having a command buffer per context
allows to reuse the command buffer for other frames even when
multiple applications are using the RGA in at the same time.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 28 +++++++---------
 drivers/media/platform/rockchip/rga/rga.c    | 48 ++++++++++++++++------------
 drivers/media/platform/rockchip/rga/rga.h    |  5 +--
 3 files changed, 41 insertions(+), 40 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 7419784efc693..79bf911e74779 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -113,8 +113,7 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
 
 static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
@@ -126,8 +125,7 @@ static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 
 static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
@@ -139,8 +137,7 @@ static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 
 static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int reg;
 
 	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
@@ -153,7 +150,7 @@ static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
 static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 {
 	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int scale_dst_w, scale_dst_h;
 	unsigned int src_h, src_w, dst_h, dst_w;
 	union rga_src_info src_info;
@@ -313,8 +310,7 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
 				 struct rga_addr_offset *offset)
 {
 	struct rga_corners_addr_offset src_offsets;
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int src_h, src_w, src_x, src_y;
 
 	src_h = ctx->in.crop.height;
@@ -341,8 +337,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 {
 	struct rga_addr_offset *dst_offset;
 	struct rga_corners_addr_offset offsets;
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int dst_h, dst_w, dst_x, dst_y;
 	unsigned int mir_mode = 0;
 	unsigned int rot_mode = 0;
@@ -388,8 +383,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 
 static void rga_cmd_set_mode(struct rga_ctx *ctx)
 {
-	struct rockchip_rga *rga = ctx->rga;
-	u32 *dest = rga->cmdbuf_virt;
+	u32 *dest = ctx->cmdbuf_virt;
 	union rga_mode_ctrl mode;
 	union rga_alpha_ctrl0 alpha_ctrl0;
 	union rga_alpha_ctrl1 alpha_ctrl1;
@@ -414,7 +408,7 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 {
 	struct rockchip_rga *rga = ctx->rga;
 
-	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
 
 	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
 	/*
@@ -430,11 +424,11 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 	rga_cmd_set_dst_info(ctx, &dst->offset);
 	rga_cmd_set_trans_info(ctx);
 
-	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
+	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
 	/* sync CMD buf for RGA */
-	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
-		PAGE_SIZE, DMA_BIDIRECTIONAL);
+	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
 static void rga_hw_start(struct rockchip_rga *rga,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index d8b14c2d9f6a4..74d94c7fe31ff 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -219,6 +219,16 @@ static int rga_open(struct file *file)
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
+
+	/* Create CMD buffer */
+	ctx->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
+					   &ctx->cmdbuf_phy, GFP_KERNEL,
+					   DMA_ATTR_WRITE_COMBINE);
+	if (!ctx->cmdbuf_virt) {
+		ret = -ENOMEM;
+		goto rel_ctx;
+	}
+
 	ctx->rga = rga;
 	/* Set default formats */
 	ctx->in = def_frame;
@@ -230,15 +240,13 @@ static int rga_open(struct file *file)
 			    ctx->out.fmt->fourcc, def_width, def_height);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
-		kfree(ctx);
-		return -ERESTARTSYS;
+		ret = -ERESTARTSYS;
+		goto rel_cmdbuf;
 	}
 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
 	if (IS_ERR(ctx->fh.m2m_ctx)) {
 		ret = PTR_ERR(ctx->fh.m2m_ctx);
-		mutex_unlock(&rga->mutex);
-		kfree(ctx);
-		return ret;
+		goto unlock_mutex;
 	}
 	v4l2_fh_init(&ctx->fh, video_devdata(file));
 	v4l2_fh_add(&ctx->fh, file);
@@ -252,6 +260,15 @@ static int rga_open(struct file *file)
 	mutex_unlock(&rga->mutex);
 
 	return 0;
+
+unlock_mutex:
+	mutex_unlock(&rga->mutex);
+rel_cmdbuf:
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+rel_ctx:
+	kfree(ctx);
+	return ret;
 }
 
 static int rga_release(struct file *file)
@@ -266,6 +283,10 @@ static int rga_release(struct file *file)
 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 	v4l2_fh_del(&ctx->fh, file);
 	v4l2_fh_exit(&ctx->fh);
+
+	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+
 	kfree(ctx);
 
 	mutex_unlock(&rga->mutex);
@@ -674,19 +695,10 @@ static int rga_probe(struct platform_device *pdev)
 
 	pm_runtime_put(rga->dev);
 
-	/* Create CMD buffer */
-	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
-					   &rga->cmdbuf_phy, GFP_KERNEL,
-					   DMA_ATTR_WRITE_COMBINE);
-	if (!rga->cmdbuf_virt) {
-		ret = -ENOMEM;
-		goto rel_m2m;
-	}
-
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
 		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
-		goto free_dma;
+		goto rel_m2m;
 	}
 
 	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
@@ -694,9 +706,6 @@ static int rga_probe(struct platform_device *pdev)
 
 	return 0;
 
-free_dma:
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
-		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_m2m:
 	v4l2_m2m_release(rga->m2m_dev);
 rel_vdev:
@@ -713,9 +722,6 @@ static void rga_remove(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga = platform_get_drvdata(pdev);
 
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
-		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
-
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
 
 	v4l2_m2m_release(rga->m2m_dev);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 98635ddd50d7c..f8c932fdec21a 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -56,6 +56,9 @@ struct rga_ctx {
 	struct rga_frame out;
 	struct v4l2_ctrl_handler ctrl_handler;
 
+	void *cmdbuf_virt;
+	dma_addr_t cmdbuf_phy;
+
 	int osequence;
 	int csequence;
 
@@ -91,8 +94,6 @@ struct rockchip_rga {
 	spinlock_t ctrl_lock;
 
 	struct rga_ctx *curr;
-	dma_addr_t cmdbuf_phy;
-	void *cmdbuf_virt;
 
 	const struct rga_hw *hw;
 };

-- 
2.52.0


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

* [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (7 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:26   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon Sven Püschel
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add an alignment setting to rga_hw to set the desired stride alignment.
As the RGA2 register for the stride counts in word units, the code
already divides the bytesperline value by 4 when writing it into the
register. Therefore fix the alignment to a multiple of 4 to avoid
potential off by one errors due from the division.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
 drivers/media/platform/rockchip/rga/rga.c    | 11 ++++++-----
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 79bf911e74779..56a2558539bfb 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -620,6 +620,7 @@ const struct rga_hw rga2_hw = {
 	.max_width = MAX_WIDTH,
 	.min_height = MIN_HEIGHT,
 	.max_height = MAX_HEIGHT,
+	.stride_alignment = 4,
 
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 74d94c7fe31ff..592c977a07cf3 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -234,10 +234,10 @@ static int rga_open(struct file *file)
 	ctx->in = def_frame;
 	ctx->out = def_frame;
 
-	v4l2_fill_pixfmt_mp(&ctx->in.pix,
-			    ctx->in.fmt->fourcc, def_width, def_height);
-	v4l2_fill_pixfmt_mp(&ctx->out.pix,
-			    ctx->out.fmt->fourcc, def_width, def_height);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+				    def_width, def_height, rga->hw->stride_alignment);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+				    def_width, def_height, rga->hw->stride_alignment);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
 		ret = -ERESTARTSYS;
@@ -359,7 +359,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	pix_fmt->height = clamp(pix_fmt->height,
 				hw->min_height, hw->max_height);
 
-	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
+	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
+				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
 	pix_fmt->field = V4L2_FIELD_NONE;
 
 	return 0;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index f8c932fdec21a..0aef348dddb95 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -152,6 +152,7 @@ struct rga_hw {
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
+	u8 stride_alignment;
 
 	void (*start)(struct rockchip_rga *rga,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);

-- 
2.52.0


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

* [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (8 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:29   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 11/22] media: rockchip: rga: check scaling factor Sven Püschel
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Prepare the command buffer on streamon to reuse it's contents instead of
completely writing it for every frame. Due to the stream settings being
fixed after a streamon we only need to replace the source and destination
addresses for each frame. This reduces the amount of CPU and memory
operations done in each frame.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
 drivers/media/platform/rockchip/rga/rga.c    | 13 ++++++++++++-
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 56a2558539bfb..8cdfe089fd636 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -408,8 +408,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 {
 	struct rockchip_rga *rga = ctx->rga;
 
-	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
-
 	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
 	/*
 	 * Due to hardware bug,
@@ -418,11 +416,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 	rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
 
 	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
-	rga_cmd_set_mode(ctx);
 
 	rga_cmd_set_src_info(ctx, &src->offset);
 	rga_cmd_set_dst_info(ctx, &dst->offset);
-	rga_cmd_set_trans_info(ctx);
 
 	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
@@ -431,6 +427,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
+static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+
+	rga_cmd_set_mode(ctx);
+	rga_cmd_set_trans_info(ctx);
+}
+
 static void rga_hw_start(struct rockchip_rga *rga,
 			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
 {
@@ -622,6 +626,7 @@ const struct rga_hw rga2_hw = {
 	.max_height = MAX_HEIGHT,
 	.stride_alignment = 4,
 
+	.setup_cmdbuf = rga_hw_setup_cmdbuf,
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
 	.get_version = rga_get_version,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 592c977a07cf3..f02ae02de26ca 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -523,6 +523,17 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	return ret;
 }
 
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct rga_ctx *ctx = file_to_rga_ctx(file);
+	const struct rga_hw *hw = ctx->rga->hw;
+
+	hw->setup_cmdbuf(ctx);
+
+	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
+}
+
 static const struct v4l2_ioctl_ops rga_ioctl_ops = {
 	.vidioc_querycap = vidioc_querycap,
 
@@ -547,7 +558,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 
-	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamon = vidioc_streamon,
 	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
 
 	.vidioc_g_selection = vidioc_g_selection,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 0aef348dddb95..93162b118d069 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -154,6 +154,7 @@ struct rga_hw {
 	u32 max_width, max_height;
 	u8 stride_alignment;
 
+	void (*setup_cmdbuf)(struct rga_ctx *ctx);
 	void (*start)(struct rockchip_rga *rga,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
 	bool (*handle_irq)(struct rockchip_rga *rga);

-- 
2.52.0


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

* [PATCH v2 11/22] media: rockchip: rga: check scaling factor
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (9 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:39   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type Sven Püschel
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Check the scaling factor to avoid potential problems. This is relevant
for the upcoming RGA3 support, as it can hang when the scaling factor
is exceeded.

There are two relevant scenarios that have to be considered to protect
against invalid scaling values:

When the output or capture is already streaming, setting the format on
the other side should consider the max scaling factor and clamp it
accordingly. This is only done in the streaming case, as it otherwise
may unintentionally clamp the value when the application sets the first
format (due to a default format on the other side).

When the format is set on both sides first, then the format won't be
corrected by above means. Therefore the second streamon call has to
check the scaling factor and fail otherwise.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
 drivers/media/platform/rockchip/rga/rga-hw.h |  1 +
 drivers/media/platform/rockchip/rga/rga.c    | 60 +++++++++++++++++++++++++---
 drivers/media/platform/rockchip/rga/rga.h    |  1 +
 4 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 8cdfe089fd636..2ed4f22a999d5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -624,6 +624,7 @@ const struct rga_hw rga2_hw = {
 	.max_width = MAX_WIDTH,
 	.min_height = MIN_HEIGHT,
 	.max_height = MAX_HEIGHT,
+	.max_scaling_factor = MAX_SCALING_FACTOR,
 	.stride_alignment = 4,
 
 	.setup_cmdbuf = rga_hw_setup_cmdbuf,
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index f4752aa823051..fffcab0131225 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -14,6 +14,7 @@
 
 #define MIN_WIDTH 34
 #define MIN_HEIGHT 34
+#define MAX_SCALING_FACTOR 16
 
 #define RGA_TIMEOUT 500
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f02ae02de26ca..46dc94db6f85e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -346,18 +346,47 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
-	struct rockchip_rga *rga = video_drvdata(file);
+	struct rga_ctx *ctx = file_to_rga_ctx(file);
+	struct rockchip_rga *rga = ctx->rga;
 	const struct rga_hw *hw = rga->hw;
 	struct rga_fmt *fmt;
+	u32 min_width = hw->min_width;
+	u32 max_width = hw->max_width;
+	u32 min_height = hw->min_height;
+	u32 max_height = hw->max_height;
 
 	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	if (!fmt)
 		fmt = &hw->formats[0];
 
-	pix_fmt->width = clamp(pix_fmt->width,
-			       hw->min_width, hw->max_width);
-	pix_fmt->height = clamp(pix_fmt->height,
-				hw->min_height, hw->max_height);
+	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
+	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
+		min_width =
+			MAX(min_width, DIV_ROUND_UP(ctx->out.pix.width,
+						    hw->max_scaling_factor));
+		max_width = MIN(max_width,
+				ctx->out.pix.width * hw->max_scaling_factor);
+		min_height =
+			MAX(min_height, DIV_ROUND_UP(ctx->out.pix.height,
+						     hw->max_scaling_factor));
+		max_height = MIN(max_height,
+				 ctx->out.pix.height * hw->max_scaling_factor);
+	} else if (V4L2_TYPE_IS_CAPTURE(f->type) &&
+		   v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming) {
+		min_width =
+			MAX(min_width, DIV_ROUND_UP(ctx->in.pix.width,
+						    hw->max_scaling_factor));
+		max_width = MIN(max_width,
+				ctx->in.pix.width * hw->max_scaling_factor);
+		min_height =
+			MAX(min_height, DIV_ROUND_UP(ctx->in.pix.height,
+						     hw->max_scaling_factor));
+		max_height = MIN(max_height,
+				 ctx->in.pix.height * hw->max_scaling_factor);
+	}
+
+	pix_fmt->width = clamp(pix_fmt->width, min_width, max_width);
+	pix_fmt->height = clamp(pix_fmt->height, min_height, max_height);
 
 	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
 				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
@@ -523,12 +552,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	return ret;
 }
 
+static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
+{
+	if (src_size < dst_size)
+		return src_size * hw->max_scaling_factor >= dst_size;
+	else
+		return dst_size * hw->max_scaling_factor >= src_size;
+}
+
 static int vidioc_streamon(struct file *file, void *priv,
 			   enum v4l2_buf_type type)
 {
 	struct rga_ctx *ctx = file_to_rga_ctx(file);
 	const struct rga_hw *hw = ctx->rga->hw;
 
+	if ((V4L2_TYPE_IS_OUTPUT(type) &&
+	     v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
+	    (V4L2_TYPE_IS_CAPTURE(type) &&
+	     v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
+		/*
+		 * As the other side is already streaming,
+		 * check that the max scaling factor isn't exceeded.
+		 */
+		if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
+		    !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
+			return -EINVAL;
+	}
+
 	hw->setup_cmdbuf(ctx);
 
 	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 93162b118d069..d02d5730b4e3b 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -152,6 +152,7 @@ struct rga_hw {
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
+	u8 max_scaling_factor;
 	u8 stride_alignment;
 
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);

-- 
2.52.0


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

* [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (10 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 11/22] media: rockchip: rga: check scaling factor Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:40   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses Sven Püschel
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

In preparation of the RGA3 support add a filed to the rga_hw struct
to specify the desired card type value. This allows the user to
differentiate the RGA2 and RGA3 video device nodes.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
 drivers/media/platform/rockchip/rga/rga.c    | 4 +++-
 drivers/media/platform/rockchip/rga/rga.h    | 1 +
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 2ed4f22a999d5..8953960d33bc5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
 };
 
 const struct rga_hw rga2_hw = {
+	.card_type = "rga2",
 	.formats = formats,
 	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 46dc94db6f85e..c9719c7bcfc1c 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -306,8 +306,10 @@ static const struct v4l2_file_operations rga_fops = {
 static int
 vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 {
+	struct rockchip_rga *rga = video_drvdata(file);
+
 	strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
-	strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
+	strscpy(cap->card, rga->hw->card_type, sizeof(cap->card));
 	strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
 
 	return 0;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index d02d5730b4e3b..ee50f7f3ed601 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -147,6 +147,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 };
 
 struct rga_hw {
+	const char *card_type;
 	struct rga_fmt *formats;
 	u32 num_formats;
 	size_t cmdbuf_size;

-- 
2.52.0


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

* [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (11 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:41   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 14/22] media: rockchip: rga: support external iommus Sven Püschel
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Change the offset to dma_addresses, as the current naming is misleading.
The offset naming comes from the fact that it references the offset in
the mapped iommu address space. But from the hardware point of view this
is an address, as also pointed out by the register naming
(e.g. RGA_DST_Y_RGB_BASE_ADDR). Therefore also change the type to
dma_addr_t, as with an external iommu driver this would also be the
correct type.

This change is a preparation for the RGA3 support, which uses an external
iommu and therefore just gets an dma_addr_t for each buffer. The field
renaming allows to reuse the existing fields of rga_vb_buffer to store
these values.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  12 +--
 drivers/media/platform/rockchip/rga/rga-hw.c  | 105 +++++++++++++-------------
 drivers/media/platform/rockchip/rga/rga.h     |  12 +--
 3 files changed, 64 insertions(+), 65 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 0c59a4d330888..8845e1f894f29 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -118,7 +118,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	size_t curr_desc = 0;
 	int i;
 	const struct v4l2_format_info *info;
-	unsigned int offsets[VIDEO_MAX_PLANES];
+	unsigned int dma_addrs[VIDEO_MAX_PLANES];
 
 	if (IS_ERR(f))
 		return PTR_ERR(f);
@@ -142,18 +142,18 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 				 "Failed to map video buffer to RGA\n");
 			return n_desc;
 		}
-		offsets[i] = curr_desc << PAGE_SHIFT;
+		dma_addrs[i] = curr_desc << PAGE_SHIFT;
 		curr_desc += n_desc;
 	}
 
 	/* Fill the remaining planes */
 	info = v4l2_format_info(f->fmt->fourcc);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
-		offsets[i] = get_plane_offset(f, info, i);
+		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
 
-	rbuf->offset.y_off = offsets[0];
-	rbuf->offset.u_off = offsets[1];
-	rbuf->offset.v_off = offsets[2];
+	rbuf->dma_addrs.y_addr = dma_addrs[0];
+	rbuf->dma_addrs.u_addr = dma_addrs[1];
+	rbuf->dma_addrs.v_addr = dma_addrs[2];
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 8953960d33bc5..fe6f518aedd4e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -16,11 +16,11 @@ enum e_rga_start_pos {
 	RB = 3,
 };
 
-struct rga_corners_addr_offset {
-	struct rga_addr_offset left_top;
-	struct rga_addr_offset right_top;
-	struct rga_addr_offset left_bottom;
-	struct rga_addr_offset right_bottom;
+struct rga_corners_addrs {
+	struct rga_addrs left_top;
+	struct rga_addrs right_top;
+	struct rga_addrs left_bottom;
+	struct rga_addrs right_bottom;
 };
 
 static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
@@ -36,48 +36,47 @@ static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
 	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
 }
 
-static struct rga_corners_addr_offset
-rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
-		    unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+static struct rga_corners_addrs
+rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
+		     unsigned int x, unsigned int y, unsigned int w, unsigned int h)
 {
-	struct rga_corners_addr_offset offsets;
-	struct rga_addr_offset *lt, *lb, *rt, *rb;
+	struct rga_corners_addrs corner_addrs;
+	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
 		     y_div = 0, uv_stride = 0, pixel_width = 0;
 
-	lt = &offsets.left_top;
-	lb = &offsets.left_bottom;
-	rt = &offsets.right_top;
-	rb = &offsets.right_bottom;
+	lt = &corner_addrs.left_top;
+	lb = &corner_addrs.left_bottom;
+	rt = &corner_addrs.right_top;
+	rb = &corner_addrs.right_bottom;
 
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
 	uv_stride = frm->stride / x_div;
 	pixel_width = frm->stride / frm->pix.width;
 
-	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
-	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
-	lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
+	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
+	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
+	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
 
-	lb->y_off = lt->y_off + (h - 1) * frm->stride;
-	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
-	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
+	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
+	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
+	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
 
-	rt->y_off = lt->y_off + (w - 1) * pixel_width;
-	rt->u_off = lt->u_off + w / x_div - 1;
-	rt->v_off = lt->v_off + w / x_div - 1;
+	rt->y_addr = lt->y_addr + (w - 1) * pixel_width;
+	rt->u_addr = lt->u_addr + w / x_div - 1;
+	rt->v_addr = lt->v_addr + w / x_div - 1;
 
-	rb->y_off = lb->y_off + (w - 1) * pixel_width;
-	rb->u_off = lb->u_off + w / x_div - 1;
-	rb->v_off = lb->v_off + w / x_div - 1;
+	rb->y_addr = lb->y_addr + (w - 1) * pixel_width;
+	rb->u_addr = lb->u_addr + w / x_div - 1;
+	rb->v_addr = lb->v_addr + w / x_div - 1;
 
-	return offsets;
+	return corner_addrs;
 }
 
-static struct rga_addr_offset *rga_lookup_draw_pos(struct
-		rga_corners_addr_offset
-		* offsets, u32 rotate_mode,
-		u32 mirr_mode)
+static struct rga_addrs *rga_lookup_draw_pos(struct rga_corners_addrs *corner_addrs,
+					     u32 rotate_mode,
+					     u32 mirr_mode)
 {
 	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
 		{
@@ -94,18 +93,18 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
 		},
 	};
 
-	if (!offsets)
+	if (!corner_addrs)
 		return NULL;
 
 	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
 	case LT:
-		return &offsets->left_top;
+		return &corner_addrs->left_top;
 	case LB:
-		return &offsets->left_bottom;
+		return &corner_addrs->left_bottom;
 	case RT:
-		return &offsets->right_top;
+		return &corner_addrs->right_top;
 	case RB:
-		return &offsets->right_bottom;
+		return &corner_addrs->right_bottom;
 	}
 
 	return NULL;
@@ -307,9 +306,9 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 }
 
 static void rga_cmd_set_src_info(struct rga_ctx *ctx,
-				 struct rga_addr_offset *offset)
+				 struct rga_addrs *addrs)
 {
-	struct rga_corners_addr_offset src_offsets;
+	struct rga_corners_addrs src_corner_addrs;
 	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int src_h, src_w, src_x, src_y;
 
@@ -321,22 +320,22 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
 	/*
 	 * Calculate the source framebuffer base address with offset pixel.
 	 */
-	src_offsets = rga_get_addr_offset(&ctx->in, offset,
-					  src_x, src_y, src_w, src_h);
+	src_corner_addrs = rga_get_corner_addrs(&ctx->in, addrs,
+						src_x, src_y, src_w, src_h);
 
 	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.y_off;
+		src_corner_addrs.left_top.y_addr;
 	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.u_off;
+		src_corner_addrs.left_top.u_addr;
 	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		src_offsets.left_top.v_off;
+		src_corner_addrs.left_top.v_addr;
 }
 
 static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
-				 struct rga_addr_offset *offset)
+				 struct rga_addrs *addrs)
 {
-	struct rga_addr_offset *dst_offset;
-	struct rga_corners_addr_offset offsets;
+	struct rga_addrs *dst_addrs;
+	struct rga_corners_addrs corner_addrs;
 	u32 *dest = ctx->cmdbuf_virt;
 	unsigned int dst_h, dst_w, dst_x, dst_y;
 	unsigned int mir_mode = 0;
@@ -370,15 +369,15 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
 	/*
 	 * Configure the dest framebuffer base address with pixel offset.
 	 */
-	offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h);
-	dst_offset = rga_lookup_draw_pos(&offsets, rot_mode, mir_mode);
+	corner_addrs = rga_get_corner_addrs(&ctx->out, addrs, dst_x, dst_y, dst_w, dst_h);
+	dst_addrs = rga_lookup_draw_pos(&corner_addrs, rot_mode, mir_mode);
 
 	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->y_off;
+		dst_addrs->y_addr;
 	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->u_off;
+		dst_addrs->u_addr;
 	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
-		dst_offset->v_off;
+		dst_addrs->v_addr;
 }
 
 static void rga_cmd_set_mode(struct rga_ctx *ctx)
@@ -417,8 +416,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 
 	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
 
-	rga_cmd_set_src_info(ctx, &src->offset);
-	rga_cmd_set_dst_info(ctx, &dst->offset);
+	rga_cmd_set_src_info(ctx, &src->dma_addrs);
+	rga_cmd_set_dst_info(ctx, &dst->dma_addrs);
 
 	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index ee50f7f3ed601..772f7dff9a8e5 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -98,10 +98,10 @@ struct rockchip_rga {
 	const struct rga_hw *hw;
 };
 
-struct rga_addr_offset {
-	unsigned int y_off;
-	unsigned int u_off;
-	unsigned int v_off;
+struct rga_addrs {
+	dma_addr_t y_addr;
+	dma_addr_t u_addr;
+	dma_addr_t v_addr;
 };
 
 struct rga_vb_buffer {
@@ -113,8 +113,8 @@ struct rga_vb_buffer {
 	dma_addr_t dma_desc_pa;
 	size_t n_desc;
 
-	/* Plane offsets of this buffer into the mapping */
-	struct rga_addr_offset offset;
+	/* Plane DMA addresses after the MMU mapping of the buffer */
+	struct rga_addrs dma_addrs;
 };
 
 static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)

-- 
2.52.0


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

* [PATCH v2 14/22] media: rockchip: rga: support external iommus
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (12 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:50   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used Sven Püschel
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

In preparation for the RGA3 add support for external iommus. This is a
transition step to just disable the RGA2 specific mmu table setup code.

Currently a simple rga_hw struct field is used to set the internal iommu.
But to handle the case of more sophisticated detection mechanisms
(e.g. check for an iommu property in the device tree), it is abstracted
by an inline function.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 46 ++++++++++++++++-----------
 drivers/media/platform/rockchip/rga/rga-hw.c  |  1 +
 drivers/media/platform/rockchip/rga/rga.c     | 11 +++++--
 drivers/media/platform/rockchip/rga/rga.h     |  6 ++++
 4 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 8845e1f894f29..e8d1e2e579140 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -12,6 +12,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-v4l2.h>
 
 #include "rga.h"
@@ -79,14 +80,16 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
 	size_t n_desc = 0;
 
-	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+	if (rga_has_internal_iommu(rga)) {
+		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
 
-	rbuf->n_desc = n_desc;
-	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
-					    rbuf->n_desc * sizeof(*rbuf->dma_desc),
-					    &rbuf->dma_desc_pa, GFP_KERNEL);
-	if (!rbuf->dma_desc)
-		return -ENOMEM;
+		rbuf->n_desc = n_desc;
+		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
+						    rbuf->n_desc * sizeof(*rbuf->dma_desc),
+						    &rbuf->dma_desc_pa, GFP_KERNEL);
+		if (!rbuf->dma_desc)
+			return -ENOMEM;
+	}
 
 	return 0;
 }
@@ -133,17 +136,21 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	for (i = 0; i < vb->num_planes; i++) {
 		vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
 
-		/* Create local MMU table for RGA */
-		n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
-					  rbuf->n_desc - curr_desc,
-					  vb2_dma_sg_plane_desc(vb, i));
-		if (n_desc < 0) {
-			v4l2_err(&ctx->rga->v4l2_dev,
-				 "Failed to map video buffer to RGA\n");
-			return n_desc;
+		if (rga_has_internal_iommu(ctx->rga)) {
+			/* Create local MMU table for RGA */
+			n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
+						  rbuf->n_desc - curr_desc,
+						  vb2_dma_sg_plane_desc(vb, i));
+			if (n_desc < 0) {
+				v4l2_err(&ctx->rga->v4l2_dev,
+					 "Failed to map video buffer to RGA\n");
+				return n_desc;
+			}
+			dma_addrs[i] = curr_desc << PAGE_SHIFT;
+			curr_desc += n_desc;
+		} else {
+			dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i);
 		}
-		dma_addrs[i] = curr_desc << PAGE_SHIFT;
-		curr_desc += n_desc;
 	}
 
 	/* Fill the remaining planes */
@@ -173,8 +180,9 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
 	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct rockchip_rga *rga = ctx->rga;
 
-	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
-			  rbuf->dma_desc, rbuf->dma_desc_pa);
+	if (rga_has_internal_iommu(rga))
+		dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
+				  rbuf->dma_desc, rbuf->dma_desc_pa);
 }
 
 static void rga_buf_return_buffers(struct vb2_queue *q,
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index fe6f518aedd4e..fb0389ae8e132 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
 
 const struct rga_hw rga2_hw = {
 	.card_type = "rga2",
+	.has_internal_iommu = true,
 	.formats = formats,
 	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index c9719c7bcfc1c..f28ec88c186fa 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -23,6 +23,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-v4l2.h>
 
 #include "rga.h"
@@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	src_vq->drv_priv = ctx;
 	src_vq->ops = &rga_qops;
-	src_vq->mem_ops = &vb2_dma_sg_memops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
 	src_vq->gfp_flags = __GFP_DMA32;
 	src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock = &ctx->rga->mutex;
 	src_vq->dev = ctx->rga->v4l2_dev.dev;
 
+	if (rga_has_internal_iommu(ctx->rga))
+		src_vq->mem_ops = &vb2_dma_sg_memops;
+
 	ret = vb2_queue_init(src_vq);
 	if (ret)
 		return ret;
@@ -110,13 +114,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 	dst_vq->drv_priv = ctx;
 	dst_vq->ops = &rga_qops;
-	dst_vq->mem_ops = &vb2_dma_sg_memops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
 	dst_vq->gfp_flags = __GFP_DMA32;
 	dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	dst_vq->lock = &ctx->rga->mutex;
 	dst_vq->dev = ctx->rga->v4l2_dev.dev;
 
+	if (rga_has_internal_iommu(ctx->rga))
+		dst_vq->mem_ops = &vb2_dma_sg_memops;
+
 	return vb2_queue_init(dst_vq);
 }
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 772f7dff9a8e5..fc81bc5562792 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -148,6 +148,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 
 struct rga_hw {
 	const char *card_type;
+	bool has_internal_iommu;
 	struct rga_fmt *formats;
 	u32 num_formats;
 	size_t cmdbuf_size;
@@ -163,6 +164,11 @@ struct rga_hw {
 	void (*get_version)(struct rockchip_rga *rga);
 };
 
+static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
+{
+	return rga->hw->has_internal_iommu;
+}
+
 extern const struct rga_hw rga2_hw;
 
 #endif

-- 
2.52.0


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

* [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (13 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 14/22] media: rockchip: rga: support external iommus Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:50   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame Sven Püschel
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel, Michael Olbrich

From: Michael Olbrich <m.olbrich@pengutronix.de>

The RGA3 and the corresponding iommu share the interrupt. So in that
case, request a shared interrupt so that the iommu driver can request
it as well.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f28ec88c186fa..1bfc4021f4a7b 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -718,7 +718,8 @@ static int rga_probe(struct platform_device *pdev)
 		goto err_put_clk;
 	}
 
-	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
+	ret = devm_request_irq(rga->dev, irq, rga_isr,
+			       rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
 			       dev_name(rga->dev), rga);
 	if (ret < 0) {
 		dev_err(rga->dev, "failed to request irq\n");

-- 
2.52.0


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

* [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (14 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:54   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 17/22] media: rockchip: rga: remove stride " Sven Püschel
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

The size member is only used for the mmu page table mapping.
Therefore avoid storing the value and instead only calculate it
in place. This also avoids the calculation entirely when an external
iommu is used.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c | 6 +++++-
 drivers/media/platform/rockchip/rga/rga.c     | 8 ++------
 drivers/media/platform/rockchip/rga/rga.h     | 1 -
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index e8d1e2e579140..8de6b9c3fd615 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -79,9 +79,13 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	struct rockchip_rga *rga = ctx->rga;
 	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
 	size_t n_desc = 0;
+	u32 size = 0;
+	u8 i;
 
 	if (rga_has_internal_iommu(rga)) {
-		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+		for (i = 0; i < f->pix.num_planes; i++)
+			size += f->pix.plane_fmt[i].sizeimage;
+		n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
 
 		rbuf->n_desc = n_desc;
 		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 1bfc4021f4a7b..0d7b0bcac950e 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -221,7 +221,6 @@ static int rga_open(struct file *file)
 	};
 
 	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
-	def_frame.size = def_frame.stride * def_height;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -428,9 +427,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->size = 0;
-	for (i = 0; i < pix_fmt->num_planes; i++)
-		frm->size += pix_fmt->plane_fmt[i].sizeimage;
 	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
 	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
@@ -443,10 +439,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm->pix = *pix_fmt;
 
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
-		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
+		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
 		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
-		  frm->stride, frm->size);
+		  frm->stride);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index fc81bc5562792..466d568b9e614 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -37,7 +37,6 @@ struct rga_frame {
 
 	/* Variables that can calculated once and reused */
 	u32 stride;
-	u32 size;
 };
 
 struct rga_dma_desc {

-- 
2.52.0


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

* [PATCH v2 17/22] media: rockchip: rga: remove stride from rga_frame
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (15 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:56   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h Sven Püschel
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Remove the stride variable from rga_frame. Despite the comment it
didn't involve any calculation and is just a copy of the
plane_fmt[0].bytesperline value. Therefore avoid this struct member
and use the bytesperline value directly in the places where it is
required.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 20 ++++++++++++--------
 drivers/media/platform/rockchip/rga/rga.c    |  5 +----
 drivers/media/platform/rockchip/rga/rga.h    |  3 ---
 3 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index fb0389ae8e132..4dee33d8f7206 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -43,7 +43,7 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 	struct rga_corners_addrs corner_addrs;
 	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
-		     y_div = 0, uv_stride = 0, pixel_width = 0;
+		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
 
 	lt = &corner_addrs.left_top;
 	lb = &corner_addrs.left_bottom;
@@ -52,14 +52,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 
 	x_div = frm->fmt->x_div;
 	y_div = frm->fmt->y_div;
-	uv_stride = frm->stride / x_div;
-	pixel_width = frm->stride / frm->pix.width;
+	y_stride = frm->pix.plane_fmt[0].bytesperline;
+	uv_stride = y_stride / x_div;
+	pixel_width = y_stride / frm->pix.width;
 
-	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
+	lt->y_addr = addrs->y_addr + y * y_stride + x * pixel_width;
 	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
 	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
 
-	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
+	lb->y_addr = lt->y_addr + (h - 1) * y_stride;
 	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
 	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
 
@@ -160,6 +161,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	union rga_src_act_info src_act_info;
 	union rga_dst_vir_info dst_vir_info;
 	union rga_dst_act_info dst_act_info;
+	u32 in_stride, out_stride;
 
 	src_h = ctx->in.crop.height;
 	src_w = ctx->in.crop.width;
@@ -282,13 +284,15 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	 * Calculate the framebuffer virtual strides and active size,
 	 * note that the step of vir_stride / vir_width is 4 byte words
 	 */
-	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
-	src_vir_info.data.vir_width = ctx->in.stride >> 2;
+	in_stride = ctx->in.pix.plane_fmt[0].bytesperline;
+	src_vir_info.data.vir_stride = in_stride >> 2;
+	src_vir_info.data.vir_width = in_stride >> 2;
 
 	src_act_info.data.act_height = src_h - 1;
 	src_act_info.data.act_width = src_w - 1;
 
-	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+	out_stride = ctx->out.pix.plane_fmt[0].bytesperline;
+	dst_vir_info.data.vir_stride = out_stride >> 2;
 	dst_act_info.data.act_height = dst_h - 1;
 	dst_act_info.data.act_width = dst_w - 1;
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0d7b0bcac950e..7e30fafb25fab 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -220,8 +220,6 @@ static int rga_open(struct file *file)
 		.fmt = &rga->hw->formats[0],
 	};
 
-	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
-
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
@@ -428,7 +426,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
 	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
-	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
@@ -442,7 +439,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
 		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
-		  frm->stride);
+		  pix_fmt->plane_fmt[0].bytesperline);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
 		v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 466d568b9e614..a7f891b94a478 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -34,9 +34,6 @@ struct rga_frame {
 	/* Image format */
 	struct rga_fmt *fmt;
 	struct v4l2_pix_format_mplane pix;
-
-	/* Variables that can calculated once and reused */
-	u32 stride;
 };
 
 struct rga_dma_desc {

-- 
2.52.0


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

* [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (16 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 17/22] media: rockchip: rga: remove stride " Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 15:59   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 19/22] media: rockchip: rga: add feature flags Sven Püschel
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
contains many RGA2 specific values. They are used to write the correct
register values quickly based on the chosen format. Therefore the
pointer to the rga_fmt struct is kept but changed to an opaque void
pointer outside of the rga-hw.h.

To enumerate and set the correct formats, two helper functions need to
be exposed in the rga_hw struct:

enum_format just get's the vidioc_enum_fmt format and it's return value
is also returned from vidioc_enum_fmt. This is a simple pass-through,
as the implementation is very simple.

adjust_and_map_format is a simple abstraction around the previous
rga_find_format. But unlike rga_find_format, it always returns a valid
format. Therefore the passed format value is also a pointer to update
it in case the values are not supported by the hardware.
Due to the RGA3 supporting different formats on the capture and output
side, an additional parameter is_capture has been added to support
this use-case.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |  2 +-
 drivers/media/platform/rockchip/rga/rga-hw.c  | 53 +++++++++++++++++++++------
 drivers/media/platform/rockchip/rga/rga-hw.h  | 12 ++++++
 drivers/media/platform/rockchip/rga/rga.c     | 38 +++++--------------
 drivers/media/platform/rockchip/rga/rga.h     | 17 ++-------
 5 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 8de6b9c3fd615..b0f226f7f06d9 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -158,7 +158,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
 	}
 
 	/* Fill the remaining planes */
-	info = v4l2_format_info(f->fmt->fourcc);
+	info = v4l2_format_info(f->pix.pixelformat);
 	for (i = info->mem_planes; i < info->comp_planes; i++)
 		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
 
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 4dee33d8f7206..a868a34a1452e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -44,14 +44,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
 	struct rga_addrs *lt, *lb, *rt, *rb;
 	unsigned int x_div = 0,
 		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
+	struct rga_fmt *fmt = frm->fmt;
 
 	lt = &corner_addrs.left_top;
 	lb = &corner_addrs.left_bottom;
 	rt = &corner_addrs.right_top;
 	rb = &corner_addrs.right_bottom;
 
-	x_div = frm->fmt->x_div;
-	y_div = frm->fmt->y_div;
+	x_div = fmt->x_div;
+	y_div = fmt->y_div;
 	y_stride = frm->pix.plane_fmt[0].bytesperline;
 	uv_stride = y_stride / x_div;
 	pixel_width = y_stride / frm->pix.width;
@@ -162,6 +163,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	union rga_dst_vir_info dst_vir_info;
 	union rga_dst_act_info dst_act_info;
 	u32 in_stride, out_stride;
+	struct rga_fmt *in_fmt = ctx->in.fmt;
+	struct rga_fmt *out_fmt = ctx->out.fmt;
 
 	src_h = ctx->in.crop.height;
 	src_w = ctx->in.crop.width;
@@ -177,18 +180,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
 	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
 
-	src_info.data.format = ctx->in.fmt->hw_format;
-	src_info.data.swap = ctx->in.fmt->color_swap;
-	dst_info.data.format = ctx->out.fmt->hw_format;
-	dst_info.data.swap = ctx->out.fmt->color_swap;
+	src_info.data.format = in_fmt->hw_format;
+	src_info.data.swap = in_fmt->color_swap;
+	dst_info.data.format = out_fmt->hw_format;
+	dst_info.data.swap = out_fmt->color_swap;
 
 	/*
 	 * CSC mode must only be set when the colorspace families differ between
 	 * input and output. It must remain unset (zeroed) if both are the same.
 	 */
 
-	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
-	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
+	if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
 		switch (ctx->in.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -199,8 +202,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
 		}
 	}
 
-	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
-	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
+	if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
+	    RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
 		switch (ctx->out.pix.colorspace) {
 		case V4L2_COLORSPACE_REC709:
 			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -619,11 +622,35 @@ static struct rga_fmt formats[] = {
 	},
 };
 
+static void *rga_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
+				       bool is_output)
+{
+	unsigned int i;
+
+	if (!format)
+		return &formats[0];
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].fourcc == format->pixelformat)
+			return &formats[i];
+	}
+
+	format->pixelformat = formats[0].fourcc;
+	return &formats[0];
+}
+
+static int rga_enum_format(struct v4l2_fmtdesc *f)
+{
+	if (f->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	f->pixelformat = formats[f->index].fourcc;
+	return 0;
+}
+
 const struct rga_hw rga2_hw = {
 	.card_type = "rga2",
 	.has_internal_iommu = true,
-	.formats = formats,
-	.num_formats = ARRAY_SIZE(formats),
 	.cmdbuf_size = RGA_CMDBUF_SIZE,
 	.min_width = MIN_WIDTH,
 	.max_width = MAX_WIDTH,
@@ -636,4 +663,6 @@ const struct rga_hw rga2_hw = {
 	.start = rga_hw_start,
 	.handle_irq = rga_handle_irq,
 	.get_version = rga_get_version,
+	.adjust_and_map_format = rga_adjust_and_map_format,
+	.enum_format = rga_enum_format,
 };
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index fffcab0131225..3bc4b1f5acba2 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -6,6 +6,8 @@
 #ifndef __RGA_HW_H__
 #define __RGA_HW_H__
 
+#include <linux/types.h>
+
 #define RGA_CMDBUF_SIZE 0x20
 
 /* Hardware limits */
@@ -431,4 +433,14 @@ union rga_pat_con {
 	} data;
 };
 
+struct rga_fmt {
+	u32 fourcc;
+	int depth;
+	u8 uv_factor;
+	u8 y_div;
+	u8 x_div;
+	u8 color_swap;
+	u8 hw_format;
+};
+
 #endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 7e30fafb25fab..c991cc64b4b7f 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -185,17 +185,6 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 	return 0;
 }
 
-static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
-{
-	unsigned int i;
-
-	for (i = 0; i < rga->hw->num_formats; i++) {
-		if (rga->hw->formats[i].fourcc == pixelformat)
-			return &rga->hw->formats[i];
-	}
-	return NULL;
-}
-
 struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
 {
 	if (V4L2_TYPE_IS_OUTPUT(type))
@@ -217,7 +206,6 @@ static int rga_open(struct file *file)
 		.crop.top = 0,
 		.crop.width = def_width,
 		.crop.height = def_height,
-		.fmt = &rga->hw->formats[0],
 	};
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -238,9 +226,11 @@ static int rga_open(struct file *file)
 	ctx->in = def_frame;
 	ctx->out = def_frame;
 
-	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+	ctx->in.fmt = rga->hw->adjust_and_map_format(&ctx->in.pix, true);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
 				    def_width, def_height, rga->hw->stride_alignment);
-	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+	ctx->out.fmt = rga->hw->adjust_and_map_format(&ctx->out.pix, false);
+	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
 				    def_width, def_height, rga->hw->stride_alignment);
 
 	if (mutex_lock_interruptible(&rga->mutex)) {
@@ -322,15 +312,8 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
 static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
 {
 	struct rockchip_rga *rga = video_drvdata(file);
-	struct rga_fmt *fmt;
 
-	if (f->index >= rga->hw->num_formats)
-		return -EINVAL;
-
-	fmt = &rga->hw->formats[f->index];
-	f->pixelformat = fmt->fourcc;
-
-	return 0;
+	return rga->hw->enum_format(f);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -355,15 +338,13 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	struct rga_ctx *ctx = file_to_rga_ctx(file);
 	struct rockchip_rga *rga = ctx->rga;
 	const struct rga_hw *hw = rga->hw;
-	struct rga_fmt *fmt;
 	u32 min_width = hw->min_width;
 	u32 max_width = hw->max_width;
 	u32 min_height = hw->min_height;
 	u32 max_height = hw->max_height;
 
-	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
-	if (!fmt)
-		fmt = &hw->formats[0];
+	hw->adjust_and_map_format(pix_fmt,
+				  V4L2_TYPE_IS_OUTPUT(f->type));
 
 	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
 	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
@@ -425,7 +406,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	frm = rga_get_frame(ctx, f->type);
 	if (IS_ERR(frm))
 		return PTR_ERR(frm);
-	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
+	frm->fmt = rga->hw->adjust_and_map_format(pix_fmt,
+						  V4L2_TYPE_IS_OUTPUT(f->type));
 
 	/* Reset crop settings */
 	frm->crop.left = 0;
@@ -438,7 +420,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	v4l2_dbg(debug, 1, &rga->v4l2_dev,
 		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
 		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
-		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
+		  &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
 		  pix_fmt->plane_fmt[0].bytesperline);
 
 	for (i = 0; i < pix_fmt->num_planes; i++) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index a7f891b94a478..980f70f842317 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -17,22 +17,12 @@
 #define DEFAULT_WIDTH 100
 #define DEFAULT_HEIGHT 100
 
-struct rga_fmt {
-	u32 fourcc;
-	int depth;
-	u8 uv_factor;
-	u8 y_div;
-	u8 x_div;
-	u8 color_swap;
-	u8 hw_format;
-};
-
 struct rga_frame {
 	/* Crop */
 	struct v4l2_rect crop;
 
 	/* Image format */
-	struct rga_fmt *fmt;
+	void *fmt;
 	struct v4l2_pix_format_mplane pix;
 };
 
@@ -145,8 +135,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 struct rga_hw {
 	const char *card_type;
 	bool has_internal_iommu;
-	struct rga_fmt *formats;
-	u32 num_formats;
 	size_t cmdbuf_size;
 	u32 min_width, min_height;
 	u32 max_width, max_height;
@@ -158,6 +146,9 @@ struct rga_hw {
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
 	bool (*handle_irq)(struct rockchip_rga *rga);
 	void (*get_version)(struct rockchip_rga *rga);
+	void *(*adjust_and_map_format)(struct v4l2_pix_format_mplane *format,
+				       bool is_output);
+	int (*enum_format)(struct v4l2_fmtdesc *f);
 };
 
 static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)

-- 
2.52.0


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

* [PATCH v2 19/22] media: rockchip: rga: add feature flags
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (17 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 16:00   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 20/22] media: rockchip: rga: disable multi-core support Sven Püschel
                   ` (3 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

In preparation to the RGA3 addition add feature flags, which can limit
the exposed feature set of the video device, like rotating or selection
support. This is necessary as the RGA3 doesn't initially implement the
full feature set currently exposed by the driver.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c |  4 ++++
 drivers/media/platform/rockchip/rga/rga.c    | 23 +++++++++++++++--------
 drivers/media/platform/rockchip/rga/rga.h    |  7 +++++++
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index a868a34a1452e..0d1cf911af0d5 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -658,6 +658,10 @@ const struct rga_hw rga2_hw = {
 	.max_height = MAX_HEIGHT,
 	.max_scaling_factor = MAX_SCALING_FACTOR,
 	.stride_alignment = 4,
+	.features = RGA_FEATURE_FLIP
+		  | RGA_FEATURE_ROTATE
+		  | RGA_FEATURE_BG_COLOR
+		  | RGA_FEATURE_SELECTION,
 
 	.setup_cmdbuf = rga_hw_setup_cmdbuf,
 	.start = rga_hw_start,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index c991cc64b4b7f..3958e71b8987d 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -162,17 +162,21 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
 
 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	if (rga->hw->features & RGA_FEATURE_FLIP) {
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_HFLIP, 0, 1, 1, 0);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_VFLIP, 0, 1, 1, 0);
+	}
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+	if (rga->hw->features & RGA_FEATURE_ROTATE)
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_ROTATE, 0, 270, 90, 0);
 
-	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
-			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+	if (rga->hw->features & RGA_FEATURE_BG_COLOR)
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+				  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
 
 	if (ctx->ctrl_handler.error) {
 		int err = ctx->ctrl_handler.error;
@@ -489,6 +493,9 @@ static int vidioc_s_selection(struct file *file, void *priv,
 	struct rga_frame *f;
 	int ret = 0;
 
+	if (!(rga->hw->features & RGA_FEATURE_SELECTION))
+		return -EINVAL;
+
 	f = rga_get_frame(ctx, s->type);
 	if (IS_ERR(f))
 		return PTR_ERR(f);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 980f70f842317..b9c75b5fda4dc 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -6,6 +6,7 @@
 #ifndef __RGA_H__
 #define __RGA_H__
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <media/videobuf2-v4l2.h>
@@ -132,6 +133,11 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
 	rga_write(rga, reg, temp);
 };
 
+#define RGA_FEATURE_FLIP	BIT(0)
+#define RGA_FEATURE_ROTATE	BIT(1)
+#define RGA_FEATURE_BG_COLOR	BIT(2)
+#define RGA_FEATURE_SELECTION	BIT(3)
+
 struct rga_hw {
 	const char *card_type;
 	bool has_internal_iommu;
@@ -140,6 +146,7 @@ struct rga_hw {
 	u32 max_width, max_height;
 	u8 max_scaling_factor;
 	u8 stride_alignment;
+	u8 features;
 
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);
 	void (*start)(struct rockchip_rga *rga,

-- 
2.52.0


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

* [PATCH v2 20/22] media: rockchip: rga: disable multi-core support
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (18 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 19/22] media: rockchip: rga: add feature flags Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 16:02   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 21/22] media: rockchip: rga: add rga3 support Sven Püschel
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Disable multi-core support in preparation of the RGA3 addition. The
RK3588 SoC features two equal RGA3 cores. This allows scheduling of the
work between both cores, which is not yet implemented. Until it is
implemented avoid exposing both cores as independent video devices to
prevent an ABI breakage when multi-core support is added.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 3958e71b8987d..65686228b7300 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -660,6 +660,30 @@ static int rga_parse_dt(struct rockchip_rga *rga)
 	return 0;
 }
 
+static int rga_disable_multicore(struct device *dev)
+{
+	const char *compatible;
+	struct device_node *node;
+	int ret;
+
+	/* Intentionally ignores the fallback strings */
+	ret = of_property_read_string(dev->of_node, "compatible", &compatible);
+	if (ret)
+		return ret;
+
+	/* first compatible node found from the root node is considered the main core */
+	node = of_find_compatible_node(NULL, NULL, compatible);
+	if (!node)
+		return -EINVAL; /* broken DT? */
+
+	if (dev->of_node != node) {
+		dev_info(dev, "missing multi-core support, ignoring this instance\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int rga_probe(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga;
@@ -670,6 +694,10 @@ static int rga_probe(struct platform_device *pdev)
 	if (!pdev->dev.of_node)
 		return -ENODEV;
 
+	ret = rga_disable_multicore(&pdev->dev);
+	if (ret)
+		return ret;
+
 	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
 	if (!rga)
 		return -ENOMEM;

-- 
2.52.0


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

* [PATCH v2 21/22] media: rockchip: rga: add rga3 support
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (19 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 20/22] media: rockchip: rga: disable multi-core support Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-24 16:34   ` Nicolas Dufresne
  2025-12-03 15:52 ` [PATCH v2 22/22] arm64: dts: rockchip: add rga3 dt nodes Sven Püschel
  2025-12-05 22:36 ` [PATCH v2 00/22] media: platform: rga: Add RGA3 support Rob Herring
  22 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add support for the RGA3 unit contained in the RK3588.

Only a basic feature set consisting of scaling and color conversion is
implemented. Also the BT601F color space conversion is currently hard
coded. Currently unimplemented features include:
- Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
- Colorspace conversions functions BT601L, BT709, BT2020
- Background color (V4L2_CID_BG_COLOR)
- Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
- Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
- Image rotation (V4L2_CID_ROTATE)
- Image cropping/composing (VIDIOC_S_SELECTION)

The register address defines were copied from the
vendor Rockchip kernel sources and slightly adjusted to not start at 0
again for the cmd registers.

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 drivers/media/platform/rockchip/rga/Makefile  |   2 +-
 drivers/media/platform/rockchip/rga/rga.c     |   4 +
 drivers/media/platform/rockchip/rga/rga.h     |   2 +-
 drivers/media/platform/rockchip/rga/rga3-hw.c | 471 ++++++++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga3-hw.h | 190 +++++++++++
 5 files changed, 667 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
index 1bbecdc3d8df2..7326a548f3dc7 100644
--- a/drivers/media/platform/rockchip/rga/Makefile
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
 
 obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 65686228b7300..313d875c789bf 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -843,6 +843,10 @@ static const struct of_device_id rockchip_rga_match[] = {
 		.compatible = "rockchip,rk3399-rga",
 		.data = &rga2_hw,
 	},
+	{
+		.compatible = "rockchip,rk3588-rga3",
+		.data = &rga3_hw,
+	},
 	{},
 };
 
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index b9c75b5fda4dc..2c5f0330879fa 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -163,6 +163,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
 	return rga->hw->has_internal_iommu;
 }
 
-extern const struct rga_hw rga2_hw;
+extern const struct rga_hw rga2_hw, rga3_hw;
 
 #endif
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
new file mode 100644
index 0000000000000..2b8cd639da39b
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/printk.h>
+
+#include <media/v4l2-common.h>
+
+#include "rga3-hw.h"
+#include "rga.h"
+
+static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
+{
+	/*
+	 * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
+	 * of the TRM Part 2. The resulting scaling factor is a 16-bit value
+	 * and therefore normalized with 2^16.
+	 *
+	 * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
+	 * it didn't work as the value always exceeds 16 bit. Flipping the
+	 * factors results in a correct up-scaling. This is possible as the
+	 * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
+	 * an up or downscale.
+	 *
+	 * With a scaling factor of 1.0 the calculation technically also
+	 * overflows 16 bit. This isn't relevant, as in this case the
+	 * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
+	 */
+	if (dst > src) {
+		if (((src - 1) << 16) % (dst - 1) == 0)
+			return ((src - 1) << 16) / (dst - 1) - 1;
+		else
+			return ((src - 1) << 16) / (dst - 1);
+	} else {
+		return ((dst - 1) << 16) / (src - 1) + 1;
+	}
+}
+
+/*
+ * Check if the given format can be captured, as the RGA3 doesn't support all
+ * input formats also on it's output.
+ */
+static bool rga3_can_capture(const struct rga3_fmt *fmt)
+{
+	return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
+}
+
+/*
+ * Map the transformations to the RGA3 command buffer.
+ * Currently this is just the scaling settings and a fixed alpha value.
+ */
+static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int src_h, src_w, dst_h, dst_w;
+	unsigned int reg;
+	u16 hor_scl_fac, ver_scl_fac;
+	const struct rga3_fmt *in = ctx->in.fmt;
+
+	src_h = ctx->in.pix.height;
+	src_w = ctx->in.pix.width;
+	dst_h = ctx->out.pix.height;
+	dst_w = ctx->out.pix.width;
+
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
+		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
+
+	hor_scl_fac = rga3_get_scaling(src_w, dst_w);
+	ver_scl_fac = rga3_get_scaling(src_h, dst_h);
+	reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
+		      | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
+
+	if (v4l2_format_info(in->fourcc)->has_alpha) {
+		/* copy alpha from input */
+		reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+		reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+	} else {
+		/* just use a 255 alpha value */
+		reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+		reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
+		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+	}
+}
+
+static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
+				   const struct rga_addrs *addrs)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->y_addr;
+	reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->u_addr;
+}
+
+static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
+				 const struct rga_addrs *addrs)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->y_addr;
+	reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = addrs->u_addr;
+}
+
+/* Map the input pixel format to win0 of the comamnd buffer. */
+static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	const struct rga3_fmt *in = ctx->in.fmt;
+	const struct rga3_fmt *out = ctx->out.fmt;
+	const struct v4l2_format_info *in_fmt, *out_fmt;
+	unsigned int src_h, src_w;
+	bool r2y, y2r;
+	u8 rd_format;
+	unsigned int reg;
+
+	src_h = ctx->in.pix.height;
+	src_w = ctx->in.pix.width;
+
+	in_fmt = v4l2_format_info(in->fourcc);
+	out_fmt = v4l2_format_info(out->fourcc);
+	r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
+	y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
+
+	if (in->semi_planar)
+		rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+	else
+		rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+	/* set pixel format and CSC */
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
+		      |  FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
+		      |  FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
+		      |  FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
+		      |  FIELD_PREP(RGA3_WIN_R2Y, r2y)
+		      |  FIELD_PREP(RGA3_WIN_Y2R, y2r)
+		      |  FIELD_PREP(RGA3_WIN_CSC_MODE, RGA3_WIN_CSC_MODE_BT601_F);
+
+	/* set stride */
+	reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* stride needs to be in words */
+	cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+	reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* The Hardware only supports formats with 1/2 planes */
+	if (ctx->in.pix.num_planes == 2)
+		cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
+	else
+		cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+
+	/* set size */
+	reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+		      | FIELD_PREP(RGA3_HEIGHT, src_h);
+	/* no cropping support. Use same value as ACT_SIZE */
+	reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+		      | FIELD_PREP(RGA3_HEIGHT, src_h);
+}
+
+static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
+}
+
+/* Map the output pixel format to the command buffer */
+static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	const struct rga3_fmt *out = ctx->out.fmt;
+	unsigned int dst_h, dst_w;
+	u8 wr_format;
+	unsigned int reg;
+
+	dst_h = ctx->out.pix.height;
+	dst_w = ctx->out.pix.width;
+
+	if (out->semi_planar)
+		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+	else
+		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+	/* set pixel format */
+	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
+		      |  FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
+		      |  FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
+		      |  FIELD_PREP(RGA3_WR_FORMAT, wr_format);
+
+	/* set stride */
+	reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* stride needs to be in words */
+	cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+	reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+	/* The Hardware only supports formats with 1/2 planes */
+	if (ctx->out.pix.num_planes == 2)
+		cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
+	else
+		cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+
+	/* Set size.
+	 * As two inputs are not supported, we don't use win1.
+	 * Therefore only set the size for win0.
+	 */
+	reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
+		      | FIELD_PREP(RGA3_HEIGHT, dst_h);
+}
+
+static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
+{
+	u32 *cmd = ctx->cmdbuf_virt;
+	unsigned int reg;
+
+	/* Use the max value to avoid limiting the write speed */
+	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
+}
+
+static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
+
+	rga3_cmd_set_win0_format(ctx);
+	rga3_cmd_enable_win0(ctx);
+	rga3_cmd_set_trans_info(ctx);
+	rga3_cmd_set_wr_format(ctx);
+	rga3_cmd_disable_wr_limitation(ctx);
+}
+
+static void rga3_hw_start(struct rockchip_rga *rga,
+			  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+{
+	struct rga_ctx *ctx = rga->curr;
+
+	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
+	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
+
+	rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
+
+	/* sync CMD buf for RGA */
+	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+				   PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+	/* set to master mode and start the conversion */
+	rga_write(rga, RGA3_SYS_CTRL,
+		  FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
+	rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
+	rga_write(rga, RGA3_CMD_CTRL,
+		  FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
+}
+
+static bool rga3_handle_irq(struct rockchip_rga *rga)
+{
+	u32 intr;
+
+	intr = rga_read(rga, RGA3_INT_RAW);
+	/* clear all interrupts */
+	rga_write(rga, RGA3_INT_CLR, intr);
+
+	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
+}
+
+static void rga3_get_version(struct rockchip_rga *rga)
+{
+	u32 version = rga_read(rga, RGA3_VERSION_NUM);
+
+	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
+	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
+}
+
+static struct rga3_fmt rga3_formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.hw_format = RGA3_COLOR_FMT_BGR888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.hw_format = RGA3_COLOR_FMT_BGR888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGBA32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGBX32,
+		.hw_format = RGA3_COLOR_FMT_BGRA8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.hw_format = RGA3_COLOR_FMT_BGR565,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12M,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21M,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.hw_format = RGA3_COLOR_FMT_YUV420,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16M,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61M,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+		.semi_planar = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.yc_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVYU,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.yc_swap = 1,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_VYUY,
+		.hw_format = RGA3_COLOR_FMT_YUV422,
+		.rbuv_swap = 1,
+	},
+	/* Input only formats last to keep rga3_enum_format simple */
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGRA32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+		.rbuv_swap = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGRX32,
+		.hw_format = RGA3_COLOR_FMT_ABGR8888,
+	},
+};
+
+static int rga3_enum_format(struct v4l2_fmtdesc *f)
+{
+	struct rga3_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(rga3_formats))
+		return -EINVAL;
+
+	fmt = &rga3_formats[f->index];
+	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
+		return -EINVAL;
+
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static void *rga3_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
+					bool is_output)
+{
+	unsigned int i;
+
+	if (!format)
+		return &rga3_formats[0];
+
+	format->ycbcr_enc = V4L2_YCBCR_ENC_601;
+	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
+		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
+			continue;
+
+		if (rga3_formats[i].fourcc == format->pixelformat)
+			return &rga3_formats[i];
+	}
+
+	format->pixelformat = rga3_formats[0].fourcc;
+	return &rga3_formats[0];
+}
+
+const struct rga_hw rga3_hw = {
+	.card_type = "rga3",
+	.has_internal_iommu = false,
+	.cmdbuf_size = RGA3_CMDBUF_SIZE,
+	.min_width = RGA3_MIN_WIDTH,
+	.min_height = RGA3_MIN_HEIGHT,
+	/* use output size, as it's a bit smaller than the input size */
+	.max_width = RGA3_MAX_OUTPUT_WIDTH,
+	.max_height = RGA3_MAX_OUTPUT_HEIGHT,
+	.max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
+	.stride_alignment = 16,
+	.features = 0,
+
+	.setup_cmdbuf = rga3_hw_setup_cmdbuf,
+	.start = rga3_hw_start,
+	.handle_irq = rga3_handle_irq,
+	.get_version = rga3_get_version,
+	.enum_format = rga3_enum_format,
+	.adjust_and_map_format = rga3_adjust_and_map_format,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
new file mode 100644
index 0000000000000..fa16b95fb43ba
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+#ifndef __RGA3_HW_H__
+#define __RGA3_HW_H__
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define RGA3_CMDBUF_SIZE 0x2e
+
+#define RGA3_MIN_WIDTH 128
+#define RGA3_MIN_HEIGHT 128
+#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
+#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
+#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
+#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
+#define RGA3_MAX_SCALING_FACTOR 8
+#define RGA3_RESET_TIMEOUT 1000
+
+/* Registers address */
+/* sys reg */
+#define RGA3_SYS_CTRL				0x000
+#define RGA3_CMD_CTRL				0x004
+#define RGA3_CMD_ADDR				0x008
+#define RGA3_MI_GROUP_CTRL			0x00c
+#define RGA3_ARQOS_CTRL				0x010
+#define RGA3_VERSION_NUM			0x018
+#define RGA3_VERSION_TIM			0x01c
+#define RGA3_INT_EN				0x020
+#define RGA3_INT_RAW				0x024
+#define RGA3_INT_MSK				0x028
+#define RGA3_INT_CLR				0x02c
+#define RGA3_RO_SRST				0x030
+#define RGA3_STATUS0				0x034
+#define RGA3_SCAN_CNT				0x038
+#define RGA3_CMD_STATE				0x040
+
+/* cmd reg */
+#define RGA3_WIN0_RD_CTRL			0x100
+#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
+#define RGA3_WIN0_Y_BASE			0x110
+#define RGA3_WIN0_U_BASE			0x114
+#define RGA3_WIN0_V_BASE			0x118
+#define RGA3_WIN0_VIR_STRIDE			0x11c
+#define RGA3_WIN0_FBC_OFF			0x120
+#define RGA3_WIN0_SRC_SIZE			0x124
+#define RGA3_WIN0_ACT_OFF			0x128
+#define RGA3_WIN0_ACT_SIZE			0x12c
+#define RGA3_WIN0_DST_SIZE			0x130
+#define RGA3_WIN0_SCL_FAC			0x134
+#define RGA3_WIN0_UV_VIR_STRIDE			0x138
+#define RGA3_WIN1_RD_CTRL			0x140
+#define RGA3_WIN1_Y_BASE			0x150
+#define RGA3_WIN1_U_BASE			0x154
+#define RGA3_WIN1_V_BASE			0x158
+#define RGA3_WIN1_VIR_STRIDE			0x15c
+#define RGA3_WIN1_FBC_OFF			0x160
+#define RGA3_WIN1_SRC_SIZE			0x164
+#define RGA3_WIN1_ACT_OFF			0x168
+#define RGA3_WIN1_ACT_SIZE			0x16c
+#define RGA3_WIN1_DST_SIZE			0x170
+#define RGA3_WIN1_SCL_FAC			0x174
+#define RGA3_WIN1_UV_VIR_STRIDE			0x178
+#define RGA3_OVLP_CTRL				0x180
+#define RGA3_OVLP_OFF				0x184
+#define RGA3_OVLP_TOP_KEY_MIN			0x188
+#define RGA3_OVLP_TOP_KEY_MAX			0x18c
+#define RGA3_OVLP_TOP_CTRL			0x190
+#define RGA3_OVLP_BOT_CTRL			0x194
+#define RGA3_OVLP_TOP_ALPHA			0x198
+#define RGA3_OVLP_BOT_ALPHA			0x19c
+#define RGA3_WR_CTRL				0x1a0
+#define RGA3_WR_FBCE_CTRL			0x1a4
+#define RGA3_WR_VIR_STRIDE			0x1a8
+#define RGA3_WR_PL_VIR_STRIDE			0x1ac
+#define RGA3_WR_Y_BASE				0x1b0
+#define RGA3_WR_U_BASE				0x1b4
+#define RGA3_WR_V_BASE				0x1b8
+
+/* Registers value */
+#define RGA3_COLOR_FMT_YUV420		0x0
+#define RGA3_COLOR_FMT_YUV422		0x1
+#define RGA3_COLOR_FMT_YUV420_10B	0x2
+#define RGA3_COLOR_FMT_YUV422_10B	0x3
+/*
+ * Use memory ordering names
+ * instead of the datasheet naming RGB formats in big endian order
+ */
+#define RGA3_COLOR_FMT_BGR565		0x4
+#define RGA3_COLOR_FMT_BGR888		0x5
+#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
+#define RGA3_COLOR_FMT_BGRA8888		0x6
+#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
+/* the following are only supported as inputs */
+#define RGA3_COLOR_FMT_ABGR8888		0x7
+/*
+ * the following seem to be unnecessary,
+ * as they can be achieved with RB swaps
+ */
+#define RGA3_COLOR_FMT_RGBA8888		0x8
+#define RGA3_COLOR_FMT_ARGB8888		0x9
+
+#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
+#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
+
+#define RGA3_CMD_MODE_MASTER 0x1
+
+#define RGA3_WIN_CSC_MODE_BT601_F 0x2
+
+/* RGA masks */
+/* SYS_CTRL */
+#define RGA3_CCLK_SRESET BIT(4)
+#define RGA3_ACLK_SRESET BIT(3)
+#define RGA3_CMD_MODE BIT(1)
+
+/* CMD_CTRL */
+#define RGA3_CMD_LINE_START_PULSE BIT(0)
+
+/* VERSION_NUM */
+#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
+#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
+
+/* INT_* */
+#define RGA3_INT_FRM_DONE BIT(0)
+#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
+#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
+#define RGA3_INT_WIN0_HOR_ERR BIT(6)
+#define RGA3_INT_WIN0_VER_ERR BIT(7)
+#define RGA3_INT_WR_VER_ERR BIT(13)
+#define RGA3_INT_WR_HOR_ERR BIT(14)
+#define RGA3_INT_WR_BUS_ERR BIT(15)
+#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
+#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
+#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
+#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
+#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
+#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
+
+/* RO_SRST */
+#define RGA3_RO_SRST_DONE GENMASK(5, 0)
+
+/* *_SIZE */
+#define RGA3_HEIGHT GENMASK(28, 16)
+#define RGA3_WIDTH GENMASK(12, 0)
+
+/* SCL_FAC */
+#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
+#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
+
+/* WINx_CTRL */
+#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
+#define RGA3_WIN_R2Y BIT(25)
+#define RGA3_WIN_Y2R BIT(24)
+#define RGA3_WIN_SCALE_VER_UP BIT(23)
+#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
+#define RGA3_WIN_SCALE_HOR_UP BIT(21)
+#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
+#define RGA3_WIN_YC_SWAP BIT(13)
+#define RGA3_WIN_RBUV_SWAP BIT(12)
+#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
+#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
+#define RGA3_WIN_ENABLE BIT(0)
+
+/* COLOR_CTRL */
+#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
+#define RGA3_OVLP_COLOR_MODE BIT(0)
+
+/* ALPHA_CTRL */
+#define RGA3_ALPHA_SELECT_MODE BIT(4)
+#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
+
+/* WR_CTRL */
+#define RGA3_WR_YC_SWAP BIT(20)
+#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
+#define RGA3_WR_RBUV_SWAP BIT(12)
+#define RGA3_WR_FORMAT GENMASK(9, 8)
+#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
+
+struct rga3_fmt {
+	u32 fourcc;
+	u8 hw_format;
+	bool rbuv_swap;
+	bool yc_swap;
+	bool semi_planar;
+};
+
+#endif

-- 
2.52.0


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

* [PATCH v2 22/22] arm64: dts: rockchip: add rga3 dt nodes
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (20 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 21/22] media: rockchip: rga: add rga3 support Sven Püschel
@ 2025-12-03 15:52 ` Sven Püschel
  2025-12-05 22:36 ` [PATCH v2 00/22] media: platform: rga: Add RGA3 support Rob Herring
  22 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 15:52 UTC (permalink / raw)
  To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Sven Püschel

Add devicetree nodes for the RGA3 (Raster Graphics Acceleration 3)
peripheral in the RK3588.

The existing rga node refers to the RGA2 peripheral. The RK3588
contains one RGA2 core and two RGA3 cores. Both feature a similar
functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:

- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8

Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 46 +++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index e2500e31c434a..11bad1f41a864 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1273,6 +1273,52 @@ rga: rga@fdb80000 {
 		power-domains = <&power RK3588_PD_VDPU>;
 	};
 
+	rga3_core0: rga@fdb60000 {
+		compatible = "rockchip,rk3588-rga3";
+		reg = <0x0 0xfdb60000 0x0 0x200>;
+		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = "rga3_core0_irq";
+		clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>, <&cru CLK_RGA3_0_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA3_0_CORE>, <&cru SRST_A_RGA3_0>, <&cru SRST_H_RGA3_0>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3588_PD_RGA30>;
+		iommus = <&rga3_0_mmu>;
+	};
+
+	rga3_0_mmu: iommu@fdb60f00 {
+		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdb60f00 0x0 0x100>;
+		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		power-domains = <&power RK3588_PD_RGA30>;
+	};
+
+	rga3_core1: rga@fdb70000 {
+		compatible = "rockchip,rk3588-rga3";
+		reg = <0x0 0xfdb70000 0x0 0x200>;
+		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = "rga3_core1_irq";
+		clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>, <&cru CLK_RGA3_1_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA3_1_CORE>, <&cru SRST_A_RGA3_1>, <&cru SRST_H_RGA3_1>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3588_PD_RGA31>;
+		iommus = <&rga3_1_mmu>;
+	};
+
+	rga3_1_mmu: iommu@fdb70f00 {
+		compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+		reg = <0x0 0xfdb70f00 0x0 0x100>;
+		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>;
+		clock-names = "aclk", "iface";
+		#iommu-cells = <0>;
+		power-domains = <&power RK3588_PD_RGA31>;
+	};
+
 	vepu121_0: video-codec@fdba0000 {
 		compatible = "rockchip,rk3588-vepu121";
 		reg = <0x0 0xfdba0000 0x0 0x800>;

-- 
2.52.0


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

* Re: [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
  2025-12-03 15:52 ` [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3 Sven Püschel
@ 2025-12-03 20:28   ` Krzysztof Kozlowski
  2025-12-03 21:21     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Krzysztof Kozlowski @ 2025-12-03 20:28 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

On 03/12/2025 16:52, Sven Püschel wrote:
> Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
> peripheral found on the RK3588 SoC.
> 
> The existing rga node refers to the RGA2 peripheral. The RK3588

What is "existing rga node"? There is no node here. This is a patch for
bindings, so you say which hardware existing binding describes and what
are the differences against that older hardware.

> contains one RGA2 core and two RGA3 cores. Both feature a similar
> functionality of scaling, cropping and rotating of up to two input
> images into one output image. Key differences of the RGA3 are:
> 
> - supports 10bit YUV output formats
> - supports 8x8 tiles and FBCD as inputs and outputs
> - supports BT2020 color space conversion
> - max output resolution of (8192-64)x(8192-64)
> - MMU can map up to 32G DDR RAM
> - fully planar formats (3 planes) are not supported
> - max scale up/down factor of 8

"differences" in meaning nothing above is supported by RGA2?

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>


Best regards,
Krzysztof

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

* Re: [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
  2025-12-03 20:28   ` Krzysztof Kozlowski
@ 2025-12-03 21:21     ` Sven Püschel
  0 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2025-12-03 21:21 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

Hi Krzysztof,

On 12/3/25 9:28 PM, Krzysztof Kozlowski wrote:
> On 03/12/2025 16:52, Sven Püschel wrote:
>> Add a new compatible for the RGA3 (Raster Graphic Acceleration 3)
>> peripheral found on the RK3588 SoC.
>>
>> The existing rga node refers to the RGA2 peripheral. The RK3588
> What is "existing rga node"? There is no node here. This is a patch for
> bindings, so you say which hardware existing binding describes and what
> are the differences against that older hardware.
Yeah that is misleading. I refer to the existing binding/compatible 
values of rockchip-rk3xxx-rga which describe the hardware named RGA2 in 
the rk3588 TRM.
>
>> contains one RGA2 core and two RGA3 cores. Both feature a similar
>> functionality of scaling, cropping and rotating of up to two input
>> images into one output image. Key differences of the RGA3 are:
>>
>> - supports 10bit YUV output formats
>> - supports 8x8 tiles and FBCD as inputs and outputs
>> - supports BT2020 color space conversion
>> - max output resolution of (8192-64)x(8192-64)
>> - MMU can map up to 32G DDR RAM
>> - fully planar formats (3 planes) are not supported
>> - max scale up/down factor of 8
> "differences" in meaning nothing above is supported by RGA2?

except the last two points yes. The RGA2 supports fully planar formats 
with 3 planes and can scale up to a factor of 16. For the scaling I can 
add a note to make it more obvious that the RGA3 is worse in this regard.

Sincerely
     Sven

>
>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>
>
> Best regards,
> Krzysztof
>

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

* Re: [PATCH v2 00/22] media: platform: rga: Add RGA3 support
  2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
                   ` (21 preceding siblings ...)
  2025-12-03 15:52 ` [PATCH v2 22/22] arm64: dts: rockchip: add rga3 dt nodes Sven Püschel
@ 2025-12-05 22:36 ` Rob Herring
  22 siblings, 0 replies; 52+ messages in thread
From: Rob Herring @ 2025-12-05 22:36 UTC (permalink / raw)
  To: Sven Püschel
  Cc: linux-kernel, Michael Olbrich, Heiko Stuebner,
	Krzysztof Kozlowski, kernel, devicetree, Conor Dooley,
	Jacob Chen, Mauro Carvalho Chehab, linux-arm-kernel,
	linux-rockchip, Ezequiel Garcia, linux-media


On Wed, 03 Dec 2025 16:52:22 +0100, Sven Püschel wrote:
> This series adds support for the Raster Graphic Acceleration 3 (RGA3)
> peripheral, which is included in the RK3588 SoC. The RK3588
> contains one RGA2 core (which is already implemented by the rockchip rga
> driver) and two independent RGA3 cores. RGA2 and RGA3 feature
> a similar functionality of scaling, cropping and rotating of up to two input
> images into one output image. Key differences of the RGA3 are:
> 
> - supports 10bit YUV output formats
> - supports 8x8 tiles and FBCD as inputs and outputs
> - supports BT2020 color space conversion
> - max output resolution of (8192-64)x(8192-64)
> - MMU can map up to 32G DDR RAM
> - fully planar formats (3 planes) are not supported
> - max scale up/down factor of 8
> 
> This patch set adds support for one RGA3 core in the existing
> rga m2m driver. The feature set of the PR is limited to scaling and
> format conversions between common 8bit RGB/YUV formats.
> Also the color space conversion is fixed to BT601F.
> This already allows a practical usage of the RGA3.
> 
> This was tested on a Radxa Rock 5T. Around 80 fps were measured when
> scaling and converting from RGBA 480x360 to NV12 3840x2160 in a single
> gstreamer pipeline. Format conversions were tested with a single
> gstreamer pipeline converting a fixed input to a given input format.
> Afterwards it's piped through the RGA3 and the result is converted back
> to rgba and compared against a given hash value (generated after
> comparing the output manually to the input).
> 
> The v4l2-compliance tests still complain about
> the failing colorspace propagation for the RGA2.
> For the RGA3 they complain about the ycbcr_enc
> not being adopted with S_FMT, which is by design,
> as the RGA3 currently has the BT601 full range
> transfer hard coded:
> 
>   v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
>   ...
>   	Card type        : rga2
>   ...
>   		fail: v4l2-test-formats.cpp(923): fmt_cap.g_colorspace() != col
>   	test VIDIOC_S_FMT: FAIL
>   ...
>   Total for rockchip-rga device /dev/video0: 47, Succeeded: 46, Failed: 1, Warnings: 0
> 
>   v4l2-compliance 1.28.1, 64 bits, 64-bit time_t
>   ...
>   	Card type        : rga3
>   ...
>   		fail: v4l2-test-formats.cpp(920): fmt_out.g_ycbcr_enc() != ycbcr_enc
>   	test VIDIOC_S_FMT: FAIL
>   ...
>   Total for rockchip-rga device /dev/video1: 47, Succeeded: 46, Failed: 1, Warnings: 0
> 
> To distinguish the RGA2 core from the RGA3 cores the Card type is set
> accordingly. Scheduling operations between both RGA3 cores to double
> the possible frame rate might be a future improvement. Until then
> additional RGA3 cores are disabled to only provide one video device to
> the user space. This prevents a potential ABI breakage when multi core
> support is implemented.
> 
> The DTS change at the end is just as a preview, as this series targets
> media/next. After it's merged the DTS change will be sent as a new
> patch not targeting media.
> 
> Patch 1 documments the RGA3 compatible value
> Patch 2-3 extend v4l2 common functionality
> Patch 4-6 are general cleanups
> Patch 7-20 prepare the rga driver for the RGA3
> Patch 21 adds RGA3 support to the rga driver
> Patch 22 dtsi additions for the RGA3
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
> Changes in v2:
> - Removed overclocking (assigning higher clock speeds in the dts)
> - Disable the second RGA3 core
> - Improved RGA3 feature documentation and code comments
> - Don't write the whole command buffer in each frame
> - Don't announce CIDs for the RGA3 and error out on s_selection
> - Check the max scaling factor of 16 (RGA2) and 8 (RGA3)
> - Move stride alignment and alpha checking to v4l2 common
> - Register the interrupt as shared for an external IOMMU
> - Add IOMMU patch as dependency to fix sporadic hangups
> - Link to v1: https://lore.kernel.org/r/20251007-spu-rga3-v1-0-36ad85570402@pengutronix.de
> 
> ---
> Michael Olbrich (1):
>       media: rockchip: rga: share the interrupt when an external iommu is used
> 
> Sven Püschel (21):
>       media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3
>       media: v4l2-common: add has_alpha to v4l2_format_info
>       media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
>       media: rockchip: rga: use clk_bulk api
>       media: rockchip: rga: use stride for offset calculation
>       media: rockchip: rga: remove redundant rga_frame variables
>       media: rockchip: rga: move hw specific parts to a dedicated struct
>       media: rockchip: rga: move cmdbuf to rga_ctx
>       media: rockchip: rga: align stride to 4 bytes
>       media: rockchip: rga: prepare cmdbuf on streamon
>       media: rockchip: rga: check scaling factor
>       media: rockchip: rga: use card type to specify rga type
>       media: rockchip: rga: change offset to dma_addresses
>       media: rockchip: rga: support external iommus
>       media: rockchip: rga: remove size from rga_frame
>       media: rockchip: rga: remove stride from rga_frame
>       media: rockchip: rga: move rga_fmt to rga-hw.h
>       media: rockchip: rga: add feature flags
>       media: rockchip: rga: disable multi-core support
>       media: rockchip: rga: add rga3 support
>       arm64: dts: rockchip: add rga3 dt nodes
> 
>  .../devicetree/bindings/media/rockchip-rga.yaml    |   5 +-
>  arch/arm64/boot/dts/rockchip/rk3588-base.dtsi      |  46 ++
>  drivers/media/platform/rockchip/rga/Makefile       |   2 +-
>  drivers/media/platform/rockchip/rga/rga-buf.c      |  78 ++--
>  drivers/media/platform/rockchip/rga/rga-hw.c       | 404 ++++++++++++----
>  drivers/media/platform/rockchip/rga/rga-hw.h       |  18 +-
>  drivers/media/platform/rockchip/rga/rga.c          | 518 ++++++++-------------
>  drivers/media/platform/rockchip/rga/rga.h          |  82 ++--
>  drivers/media/platform/rockchip/rga/rga3-hw.c      | 471 +++++++++++++++++++
>  drivers/media/platform/rockchip/rga/rga3-hw.h      | 190 ++++++++
>  drivers/media/v4l2-core/v4l2-common.c              |  48 +-
>  include/media/v4l2-common.h                        |   6 +
>  12 files changed, 1375 insertions(+), 493 deletions(-)
> ---
> base-commit: 1f2353f5a1af995efbf7bea44341aa0d03460b28
> change-id: 20251001-spu-rga3-8a00e018b120
> prerequisite-change-id: 20251126-spu-iommudtefix-cd0c5244c74a:v1
> prerequisite-patch-id: 10c6c977c0f71400931941b42da73adcaf63e810
> 
> Best regards,
> --
> Sven Püschel <s.pueschel@pengutronix.de>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Deps: looking for dependencies matching 1 patch-ids
 Deps: Applying prerequisite patch: [PATCH] iommu/rockchip: disable fetch dte time limit
 Base: 1f2353f5a1af995efbf7bea44341aa0d03460b28 (use --merge-base to override)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/rockchip/' for 20251203-spu-rga3-v2-0-989a67947f71@pengutronix.de:

arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-roc-rt.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-roc-rt.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-h96-max-v58.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-ultra.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-ultra.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-jaguar.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-jaguar.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-mnt-reform2.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-mnt-reform2.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-max.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-firefly-itx-3588j.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb2-v10.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-evb2-v10.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dtb: rga@fdb60000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml
arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dtb: rga@fdb70000 (rockchip,rk3588-rga3): 'interrupt-names', 'iommus' do not match any of the regexes: '^pinctrl-[0-9]+$'
	from schema $id: http://devicetree.org/schemas/media/rockchip-rga.yaml






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

* Re: [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info
  2025-12-03 15:52 ` [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info Sven Püschel
@ 2025-12-24 14:24   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 14:24 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 6508 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Add a has_alpha value to the v4l2_format_info struct to indicate if the
> format contains an alpha component. The implementation is based on the
> drm_format_info implementation.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/v4l2-core/v4l2-common.c | 14 +++++++-------
>  include/media/v4l2-common.h           |  2 ++
>  2 files changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index 554c591e11133..2c7ac70c0f486 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -256,10 +256,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
>  		{ .format = V4L2_PIX_FMT_XRGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_RGBX32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_HSV32,   .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ARGB32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_RGBA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_ABGR32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_BGRA32,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
>  		{ .format = V4L2_PIX_FMT_RGB565,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_RGB555,  .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> @@ -267,10 +267,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
>  		{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>  		{ .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
> +		{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
>  		{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> -		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> +		{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
>  
>  		/* YUV packed formats */
>  		{ .format = V4L2_PIX_FMT_YUYV,    .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index f8b1faced79c8..401d8506c24b5 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -520,6 +520,7 @@ enum v4l2_pixel_encoding {
>   * @vdiv: Vertical chroma subsampling factor
>   * @block_w: Per-plane macroblock pixel width (optional)
>   * @block_h: Per-plane macroblock pixel height (optional)
> + * @has_alpha: Does the format embeds an alpha component?
>   */
>  struct v4l2_format_info {
>  	u32 format;
> @@ -532,6 +533,7 @@ struct v4l2_format_info {
>  	u8 vdiv;
>  	u8 block_w[4];
>  	u8 block_h[4];
> +	bool has_alpha;
>  };
>  
>  static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
  2025-12-03 15:52 ` [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper Sven Püschel
@ 2025-12-24 14:47   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 14:47 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 6405 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Add a v4l2_fill_pixfmt_mp_aligned helper which allows the user to
> specify a custom stride alignment in bytes. This is necessary for
> hardware like the Rockchip RGA3, which requires the stride value to be
> aligned to a 16 byte boundary.

                  byte -> bytes

You way aligned to bytes here ...


> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/v4l2-core/v4l2-common.c | 34 ++++++++++++++++++++++++----------
>  include/media/v4l2-common.h           |  4 ++++
>  2 files changed, 28 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index 2c7ac70c0f486..f86e7d7d29b8e 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -404,11 +404,12 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
>  }
>  
>  static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
> -						    unsigned int width)
> +						    unsigned int width, u8 alignment)
>  {
>  	unsigned int hdiv = plane ? info->hdiv : 1;
>  	unsigned int aligned_width =
>  		ALIGN(width, v4l2_format_block_width(info, plane));
> +	aligned_width = ALIGN(aligned_width, alignment);

But you actually align the width, which can already be achieved using frmsize-
>step_width and v4l2_apply_frmsize_constraints(). It would make little sense for
the step to not be a multiple of the block for tiled format, but it shows you
forgot to take into considering the fact that block_width has precedence here,
since you can't split tiles.

If you go back to your original idea, stride alignment, remember that you cannot
break the block alignment. For non-mplane format, you also need to special case
subsampled planer format (3 planes) so that userspace can guess the subsequence
plane strides (which is done by dividing the luma plane stride by 2, and if you
need 16 bytes alignment across all strides, then you need the luma plane to be
32 bytes alignment). The mplane format don't have this requirement, since you
pass explicitly the stride of each planes, though, you may want to double it
anyway for compatibility reason (small cost, big gain).

Nicolas

>  
>  	return DIV_ROUND_UP(aligned_width, hdiv) *
>  	       info->bpp[plane] / info->bpp_div[plane];
> @@ -425,9 +426,10 @@ static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_inf
>  }
>  
>  static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
> -						  unsigned int width, unsigned int height)
> +						  unsigned int width, unsigned int height,
> +						  u8 stride_alignment)
>  {
> -	return v4l2_format_plane_stride(info, plane, width) *
> +	return v4l2_format_plane_stride(info, plane, width, stride_alignment) *
>  	       v4l2_format_plane_height(info, plane, height);
>  }
>  
> @@ -448,8 +450,9 @@ void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
>  
> -int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
> -			u32 pixelformat, u32 width, u32 height)
> +int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
> +				u32 pixelformat, u32 width, u32 height,
> +				u8 stride_alignment)
>  {
>  	const struct v4l2_format_info *info;
>  	struct v4l2_plane_pix_format *plane;
> @@ -466,23 +469,34 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
>  
>  	if (info->mem_planes == 1) {
>  		plane = &pixfmt->plane_fmt[0];
> -		plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
> +		plane->bytesperline = v4l2_format_plane_stride(info, 0, width,
> +							       stride_alignment);
>  		plane->sizeimage = 0;
>  
>  		for (i = 0; i < info->comp_planes; i++)
>  			plane->sizeimage +=
> -				v4l2_format_plane_size(info, i, width, height);
> +				v4l2_format_plane_size(info, i, width, height,
> +						       stride_alignment);
>  	} else {
>  		for (i = 0; i < info->comp_planes; i++) {
>  			plane = &pixfmt->plane_fmt[i];
>  			plane->bytesperline =
> -				v4l2_format_plane_stride(info, i, width);
> +				v4l2_format_plane_stride(info, i, width,
> +							 stride_alignment);
>  			plane->sizeimage = plane->bytesperline *
>  				v4l2_format_plane_height(info, i, height);
>  		}
>  	}
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp_aligned);
> +
> +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
> +			u32 pixelformat, u32 width, u32 height)
> +{
> +	return v4l2_fill_pixfmt_mp_aligned(pixfmt, pixelformat,
> +					   width, height, 1);
> +}
>  EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
>  
>  int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
> @@ -502,12 +516,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
>  	pixfmt->width = width;
>  	pixfmt->height = height;
>  	pixfmt->pixelformat = pixelformat;
> -	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
> +	pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width, 1);
>  	pixfmt->sizeimage = 0;
>  
>  	for (i = 0; i < info->comp_planes; i++)
>  		pixfmt->sizeimage +=
> -			v4l2_format_plane_size(info, i, width, height);
> +			v4l2_format_plane_size(info, i, width, height, 1);
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index 401d8506c24b5..edd416178c333 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -558,6 +558,10 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
>  		     u32 width, u32 height);
>  int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
>  			u32 width, u32 height);
> +/* @stride_alignment is a power of 2 value in bytes */
> +int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
> +				u32 pixelformat, u32 width, u32 height,
> +				u8 stride_alignment);
>  
>  /**
>   * v4l2_get_link_freq - Get link rate from transmitter

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api
  2025-12-03 15:52 ` [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api Sven Püschel
@ 2025-12-24 14:48   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 14:48 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 4270 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Use the clk_bulk API to avoid code duplication for each of the three
> clocks.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga.c | 64 ++++---------------------------
>  drivers/media/platform/rockchip/rga/rga.h |  5 +--
>  2 files changed, 9 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 43f6a8d993811..ef568b3758380 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -698,48 +698,10 @@ static const struct video_device rga_videodev = {
>  	.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
>  };
>  
> -static int rga_enable_clocks(struct rockchip_rga *rga)
> -{
> -	int ret;
> -
> -	ret = clk_prepare_enable(rga->sclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
> -		return ret;
> -	}
> -
> -	ret = clk_prepare_enable(rga->aclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
> -		goto err_disable_sclk;
> -	}
> -
> -	ret = clk_prepare_enable(rga->hclk);
> -	if (ret) {
> -		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
> -		goto err_disable_aclk;
> -	}
> -
> -	return 0;
> -
> -err_disable_aclk:
> -	clk_disable_unprepare(rga->aclk);
> -err_disable_sclk:
> -	clk_disable_unprepare(rga->sclk);
> -
> -	return ret;
> -}
> -
> -static void rga_disable_clocks(struct rockchip_rga *rga)
> -{
> -	clk_disable_unprepare(rga->sclk);
> -	clk_disable_unprepare(rga->hclk);
> -	clk_disable_unprepare(rga->aclk);
> -}
> -
>  static int rga_parse_dt(struct rockchip_rga *rga)
>  {
>  	struct reset_control *core_rst, *axi_rst, *ahb_rst;
> +	int ret;
>  
>  	core_rst = devm_reset_control_get(rga->dev, "core");
>  	if (IS_ERR(core_rst)) {
> @@ -771,22 +733,10 @@ static int rga_parse_dt(struct rockchip_rga *rga)
>  	udelay(1);
>  	reset_control_deassert(ahb_rst);
>  
> -	rga->sclk = devm_clk_get(rga->dev, "sclk");
> -	if (IS_ERR(rga->sclk)) {
> -		dev_err(rga->dev, "failed to get sclk clock\n");
> -		return PTR_ERR(rga->sclk);
> -	}
> -
> -	rga->aclk = devm_clk_get(rga->dev, "aclk");
> -	if (IS_ERR(rga->aclk)) {
> -		dev_err(rga->dev, "failed to get aclk clock\n");
> -		return PTR_ERR(rga->aclk);
> -	}
> -
> -	rga->hclk = devm_clk_get(rga->dev, "hclk");
> -	if (IS_ERR(rga->hclk)) {
> -		dev_err(rga->dev, "failed to get hclk clock\n");
> -		return PTR_ERR(rga->hclk);
> +	ret = devm_clk_bulk_get(rga->dev, ARRAY_SIZE(rga->clks), rga->clks);
> +	if (ret) {
> +		dev_err(rga->dev, "failed to get clocks\n");
> +		return ret;
>  	}
>  
>  	return 0;
> @@ -935,7 +885,7 @@ static int __maybe_unused rga_runtime_suspend(struct device *dev)
>  {
>  	struct rockchip_rga *rga = dev_get_drvdata(dev);
>  
> -	rga_disable_clocks(rga);
> +	clk_bulk_disable_unprepare(ARRAY_SIZE(rga->clks), rga->clks);
>  
>  	return 0;
>  }
> @@ -944,7 +894,7 @@ static int __maybe_unused rga_runtime_resume(struct device *dev)
>  {
>  	struct rockchip_rga *rga = dev_get_drvdata(dev);
>  
> -	return rga_enable_clocks(rga);
> +	return clk_bulk_prepare_enable(ARRAY_SIZE(rga->clks), rga->clks);
>  }
>  
>  static const struct dev_pm_ops rga_pm = {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 72a28b120fabf..a922fac0c01a3 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -6,6 +6,7 @@
>  #ifndef __RGA_H__
>  #define __RGA_H__
>  
> +#include <linux/clk.h>
>  #include <linux/platform_device.h>
>  #include <media/videobuf2-v4l2.h>
>  #include <media/v4l2-ctrls.h>
> @@ -81,9 +82,7 @@ struct rockchip_rga {
>  	struct device *dev;
>  	struct regmap *grf;
>  	void __iomem *regs;
> -	struct clk *sclk;
> -	struct clk *aclk;
> -	struct clk *hclk;
> +	struct clk_bulk_data clks[3];
>  	struct rockchip_rga_version version;
>  
>  	/* vfd lock */

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation
  2025-12-03 15:52 ` [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation Sven Püschel
@ 2025-12-24 15:00   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:00 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 2703 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Use the stride instead of the width for the offset calculation. This
> ensures that the bytesperline value doesn't need to match the width
> value of the image.
> 
> Furthermore this patch removes the dependency on the uv_factor property
> and instead reuses the v4l2_format_info to determine the correct
> division factor.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 730bdf98565a5..b5e6b1b527ca8 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -14,7 +14,6 @@
>  #include <media/videobuf2-dma-sg.h>
>  #include <media/videobuf2-v4l2.h>
>  
> -#include "rga-hw.h"
>  #include "rga.h"
>  
>  static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
> @@ -92,14 +91,19 @@ static int rga_buf_init(struct vb2_buffer *vb)
>  	return 0;
>  }
>  
> -static int get_plane_offset(struct rga_frame *f, int plane)
> +static int get_plane_offset(struct rga_frame *f,
> +			    const struct v4l2_format_info *info,
> +			    int plane)
>  {
> +	u32 stride = f->pix.plane_fmt[0].bytesperline;
> +
>  	if (plane == 0)
>  		return 0;
>  	if (plane == 1)
> -		return f->width * f->height;
> +		return stride * f->height;
>  	if (plane == 2)
> -		return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
> +		return stride * f->height +
> +		       (stride * f->height / info->hdiv / info->vdiv);

This was the only user of uv_factor, please cleanup rga.h/rga.c. I see there is
also redudant x_div/y_div, with this similar code re-implemented in
rga_get_addr_offset(), can you check for v3 if we can cleanup some more ?

One thought though is that this code is already hidden inside v4l2-common,
perhaps you could just expose it, this ensure that we don't accidently have
different information when configuring the HW and communicating with the user.

Nicolas

>  
>  	return -EINVAL;
>  }
> @@ -145,7 +149,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>  	/* Fill the remaining planes */
>  	info = v4l2_format_info(f->fmt->fourcc);
>  	for (i = info->mem_planes; i < info->comp_planes; i++)
> -		offsets[i] = get_plane_offset(f, i);
> +		offsets[i] = get_plane_offset(f, info, i);
>  
>  	rbuf->offset.y_off = offsets[0];
>  	rbuf->offset.u_off = offsets[1];

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables
  2025-12-03 15:52 ` [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables Sven Püschel
@ 2025-12-24 15:03   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:03 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 7401 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Remove the redundant rga_frame variables width, height and color space.
> The value of these variables is already contained in the pix member
> of rga_frame. The code also keeps these values in sync. Therefore drop
> them in favor of the existing pix member.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c |  6 ++---
>  drivers/media/platform/rockchip/rga/rga-hw.c  |  6 ++---
>  drivers/media/platform/rockchip/rga/rga.c     | 32 ++++++++++-----------------
>  drivers/media/platform/rockchip/rga/rga.h     |  5 -----
>  4 files changed, 18 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index b5e6b1b527ca8..0c59a4d330888 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -100,10 +100,10 @@ static int get_plane_offset(struct rga_frame *f,
>  	if (plane == 0)
>  		return 0;
>  	if (plane == 1)
> -		return stride * f->height;
> +		return stride * f->pix.height;
>  	if (plane == 2)
> -		return stride * f->height +
> -		       (stride * f->height / info->hdiv / info->vdiv);
> +		return stride * f->pix.height +
> +		       (stride * f->pix.height / info->hdiv / info->vdiv);
>  
>  	return -EINVAL;
>  }
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 43ed742a16492..f1d5237472941 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -53,7 +53,7 @@ rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
>  	x_div = frm->fmt->x_div;
>  	y_div = frm->fmt->y_div;
>  	uv_stride = frm->stride / x_div;
> -	pixel_width = frm->stride / frm->width;
> +	pixel_width = frm->stride / frm->pix.width;
>  
>  	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
>  	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
> @@ -191,7 +191,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  
>  	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
>  	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
> -		switch (ctx->in.colorspace) {
> +		switch (ctx->in.pix.colorspace) {
>  		case V4L2_COLORSPACE_REC709:
>  			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
>  			break;
> @@ -203,7 +203,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  
>  	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
>  	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
> -		switch (ctx->out.colorspace) {
> +		switch (ctx->out.pix.colorspace) {
>  		case V4L2_COLORSPACE_REC709:
>  			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
>  			break;
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index ef568b3758380..f50fbbab0645e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -345,9 +345,6 @@ static struct rga_fmt *rga_fmt_find(u32 pixelformat)
>  }
>  
>  static struct rga_frame def_frame = {
> -	.width = DEFAULT_WIDTH,
> -	.height = DEFAULT_HEIGHT,
> -	.colorspace = V4L2_COLORSPACE_DEFAULT,
>  	.crop.left = 0,
>  	.crop.top = 0,
>  	.crop.width = DEFAULT_WIDTH,
> @@ -379,9 +376,9 @@ static int rga_open(struct file *file)
>  	ctx->out = def_frame;
>  
>  	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			    ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
> +			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
>  	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			    ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
> +			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
>  
>  	if (mutex_lock_interruptible(&rga->mutex)) {
>  		kfree(ctx);
> @@ -469,10 +466,8 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	if (IS_ERR(frm))
>  		return PTR_ERR(frm);
>  
> -	v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
> -
> +	*pix_fmt = frm->pix;
>  	pix_fmt->field = V4L2_FIELD_NONE;
> -	pix_fmt->colorspace = frm->colorspace;
>  
>  	return 0;
>  }
> @@ -521,27 +516,24 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	frm = rga_get_frame(ctx, f->type);
>  	if (IS_ERR(frm))
>  		return PTR_ERR(frm);
> -	frm->width = pix_fmt->width;
> -	frm->height = pix_fmt->height;
>  	frm->size = 0;
>  	for (i = 0; i < pix_fmt->num_planes; i++)
>  		frm->size += pix_fmt->plane_fmt[i].sizeimage;
>  	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
>  	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
> -	frm->colorspace = pix_fmt->colorspace;
>  
>  	/* Reset crop settings */
>  	frm->crop.left = 0;
>  	frm->crop.top = 0;
> -	frm->crop.width = frm->width;
> -	frm->crop.height = frm->height;
> +	frm->crop.width = pix_fmt->width;
> +	frm->crop.height = pix_fmt->height;
>  
>  	frm->pix = *pix_fmt;
>  
>  	v4l2_dbg(debug, 1, &rga->v4l2_dev,
>  		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
>  		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> -		  &frm->fmt->fourcc, frm->width, frm->height,
> +		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
>  		  frm->stride, frm->size);
>  
>  	for (i = 0; i < pix_fmt->num_planes; i++) {
> @@ -595,8 +587,8 @@ static int vidioc_g_selection(struct file *file, void *priv,
>  	} else {
>  		s->r.left = 0;
>  		s->r.top = 0;
> -		s->r.width = f->width;
> -		s->r.height = f->height;
> +		s->r.width = f->pix.width;
> +		s->r.height = f->pix.height;
>  	}
>  
>  	return 0;
> @@ -645,8 +637,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
>  		return -EINVAL;
>  	}
>  
> -	if (s->r.left + s->r.width > f->width ||
> -	    s->r.top + s->r.height > f->height ||
> +	if (s->r.left + s->r.width > f->pix.width ||
> +	    s->r.top + s->r.height > f->pix.height ||
>  	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
>  		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
>  		return -EINVAL;
> @@ -836,8 +828,8 @@ static int rga_probe(struct platform_device *pdev)
>  		goto rel_m2m;
>  	}
>  
> -	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * def_frame.height;
> +	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
> +	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
>  
>  	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
>  	if (ret) {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index a922fac0c01a3..7ec1fcc03ed32 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -25,11 +25,6 @@ struct rga_fmt {
>  };
>  
>  struct rga_frame {
> -	/* Original dimensions */
> -	u32 width;
> -	u32 height;
> -	u32 colorspace;
> -
>  	/* Crop */
>  	struct v4l2_rect crop;
>  

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct
  2025-12-03 15:52 ` [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct Sven Püschel
@ 2025-12-24 15:05   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:05 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 20073 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> In preparation for the RGA3 unit, move RGA2 specific parts from rga.c
> to rga-hw.c and create a struct to reference the RGA2 specific functions
> and formats. This also allows to remove the rga-hw.h reference from the
> include list of the rga driver.
> 
> Also document the command finish interrupt with a dedicated define.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c | 183 ++++++++++++++++++++-
>  drivers/media/platform/rockchip/rga/rga-hw.h |   5 +-
>  drivers/media/platform/rockchip/rga/rga.c    | 228 +++++----------------------
>  drivers/media/platform/rockchip/rga/rga.h    |  23 ++-
>  4 files changed, 245 insertions(+), 194 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index f1d5237472941..7419784efc693 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -437,8 +437,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  		PAGE_SIZE, DMA_BIDIRECTIONAL);
>  }
>  
> -void rga_hw_start(struct rockchip_rga *rga,
> -		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
> +static void rga_hw_start(struct rockchip_rga *rga,
> +			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
>  {
>  	struct rga_ctx *ctx = rga->curr;
>  
> @@ -452,3 +452,182 @@ void rga_hw_start(struct rockchip_rga *rga,
>  
>  	rga_write(rga, RGA_CMD_CTRL, 0x1);
>  }
> +
> +static bool rga_handle_irq(struct rockchip_rga *rga)
> +{
> +	int intr;
> +
> +	intr = rga_read(rga, RGA_INT) & 0xf;
> +
> +	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
> +
> +	return intr & RGA_INT_COMMAND_FINISHED;
> +}
> +
> +static void rga_get_version(struct rockchip_rga *rga)
> +{
> +	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
> +	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
> +}
> +
> +static struct rga_fmt formats[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB32,
> +		.color_swap = RGA_COLOR_ALPHA_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ABGR32,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XBGR32,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_XBGR8888,
> +		.depth = 32,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB24,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_RGB888,
> +		.depth = 24,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGR24,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_RGB888,
> +		.depth = 24,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB444,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR4444,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB555,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_ABGR1555,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB565,
> +		.color_swap = RGA_COLOR_RB_SWAP,
> +		.hw_format = RGA_COLOR_FMT_BGR565,
> +		.depth = 16,
> +		.uv_factor = 1,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422SP,
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12M,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420SP,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422SP,
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUV420,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420P,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 2,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUV422P,
> +		.color_swap = RGA_COLOR_NONE_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV422P,
> +
> +		.depth = 16,
> +		.uv_factor = 2,
> +		.y_div = 1,
> +		.x_div = 2,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YVU420,
> +		.color_swap = RGA_COLOR_UV_SWAP,
> +		.hw_format = RGA_COLOR_FMT_YUV420P,
> +		.depth = 12,
> +		.uv_factor = 4,
> +		.y_div = 2,
> +		.x_div = 2,
> +	},
> +};
> +
> +const struct rga_hw rga2_hw = {
> +	.formats = formats,
> +	.num_formats = ARRAY_SIZE(formats),
> +	.cmdbuf_size = RGA_CMDBUF_SIZE,
> +	.min_width = MIN_WIDTH,
> +	.max_width = MAX_WIDTH,
> +	.min_height = MIN_HEIGHT,
> +	.max_height = MAX_HEIGHT,
> +
> +	.start = rga_hw_start,
> +	.handle_irq = rga_handle_irq,
> +	.get_version = rga_get_version,
> +};
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index cc6bd7f5b0300..f4752aa823051 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -15,9 +15,6 @@
>  #define MIN_WIDTH 34
>  #define MIN_HEIGHT 34
>  
> -#define DEFAULT_WIDTH 100
> -#define DEFAULT_HEIGHT 100
> -
>  #define RGA_TIMEOUT 500
>  
>  /* Registers address */
> @@ -178,6 +175,8 @@
>  #define RGA_ALPHA_COLOR_NORMAL 0
>  #define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
>  
> +#define RGA_INT_COMMAND_FINISHED 4
> +
>  /* Registers union */
>  union rga_mode_ctrl {
>  	unsigned int val;
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index f50fbbab0645e..d8b14c2d9f6a4 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -25,7 +25,6 @@
>  #include <media/videobuf2-dma-sg.h>
>  #include <media/videobuf2-v4l2.h>
>  
> -#include "rga-hw.h"
>  #include "rga.h"
>  
>  static int debug;
> @@ -47,7 +46,7 @@ static void device_run(void *prv)
>  
>  	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
>  
> -	rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
> +	rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
>  
>  	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
>  }
> @@ -55,13 +54,8 @@ static void device_run(void *prv)
>  static irqreturn_t rga_isr(int irq, void *prv)
>  {
>  	struct rockchip_rga *rga = prv;
> -	int intr;
>  
> -	intr = rga_read(rga, RGA_INT) & 0xf;
> -
> -	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
> -
> -	if (intr & 0x04) {
> +	if (rga->hw->handle_irq(rga)) {
>  		struct vb2_v4l2_buffer *src, *dst;
>  		struct rga_ctx *ctx = rga->curr;
>  
> @@ -184,174 +178,17 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
>  	return 0;
>  }
>  
> -static struct rga_fmt formats[] = {
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB32,
> -		.color_swap = RGA_COLOR_ALPHA_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ABGR32,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_XBGR32,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_XBGR8888,
> -		.depth = 32,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_RGB24,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_RGB888,
> -		.depth = 24,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_BGR24,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_RGB888,
> -		.depth = 24,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB444,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR4444,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_ARGB555,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_ABGR1555,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_RGB565,
> -		.color_swap = RGA_COLOR_RB_SWAP,
> -		.hw_format = RGA_COLOR_FMT_BGR565,
> -		.depth = 16,
> -		.uv_factor = 1,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV21,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV61,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422SP,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV12,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV12M,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420SP,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_NV16,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422SP,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 1,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YUV420,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420P,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 2,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YUV422P,
> -		.color_swap = RGA_COLOR_NONE_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV422P,
> -		.depth = 16,
> -		.uv_factor = 2,
> -		.y_div = 1,
> -		.x_div = 2,
> -	},
> -	{
> -		.fourcc = V4L2_PIX_FMT_YVU420,
> -		.color_swap = RGA_COLOR_UV_SWAP,
> -		.hw_format = RGA_COLOR_FMT_YUV420P,
> -		.depth = 12,
> -		.uv_factor = 4,
> -		.y_div = 2,
> -		.x_div = 2,
> -	},
> -};
> -
> -#define NUM_FORMATS ARRAY_SIZE(formats)
> -
> -static struct rga_fmt *rga_fmt_find(u32 pixelformat)
> +static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
>  {
>  	unsigned int i;
>  
> -	for (i = 0; i < NUM_FORMATS; i++) {
> -		if (formats[i].fourcc == pixelformat)
> -			return &formats[i];
> +	for (i = 0; i < rga->hw->num_formats; i++) {
> +		if (rga->hw->formats[i].fourcc == pixelformat)
> +			return &rga->hw->formats[i];
>  	}
>  	return NULL;
>  }
>  
> -static struct rga_frame def_frame = {
> -	.crop.left = 0,
> -	.crop.top = 0,
> -	.crop.width = DEFAULT_WIDTH,
> -	.crop.height = DEFAULT_HEIGHT,
> -	.fmt = &formats[0],
> -};
> -
>  struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
>  {
>  	if (V4L2_TYPE_IS_OUTPUT(type))
> @@ -366,6 +203,18 @@ static int rga_open(struct file *file)
>  	struct rockchip_rga *rga = video_drvdata(file);
>  	struct rga_ctx *ctx = NULL;
>  	int ret = 0;
> +	u32 def_width = clamp(DEFAULT_WIDTH, rga->hw->min_width, rga->hw->max_width);
> +	u32 def_height = clamp(DEFAULT_HEIGHT, rga->hw->min_height, rga->hw->max_height);
> +	struct rga_frame def_frame = {
> +		.crop.left = 0,
> +		.crop.top = 0,
> +		.crop.width = def_width,
> +		.crop.height = def_height,
> +		.fmt = &rga->hw->formats[0],
> +	};
> +
> +	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> +	def_frame.size = def_frame.stride * def_height;
>  
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
> @@ -376,9 +225,9 @@ static int rga_open(struct file *file)
>  	ctx->out = def_frame;
>  
>  	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			    ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> +			    ctx->in.fmt->fourcc, def_width, def_height);
>  	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			    ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
> +			    ctx->out.fmt->fourcc, def_width, def_height);
>  
>  	if (mutex_lock_interruptible(&rga->mutex)) {
>  		kfree(ctx);
> @@ -445,12 +294,13 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
>  
>  static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
>  {
> +	struct rockchip_rga *rga = video_drvdata(file);
>  	struct rga_fmt *fmt;
>  
> -	if (f->index >= NUM_FORMATS)
> +	if (f->index >= rga->hw->num_formats)
>  		return -EINVAL;
>  
> -	fmt = &formats[f->index];
> +	fmt = &rga->hw->formats[f->index];
>  	f->pixelformat = fmt->fourcc;
>  
>  	return 0;
> @@ -475,16 +325,18 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  {
>  	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
> +	struct rockchip_rga *rga = video_drvdata(file);
> +	const struct rga_hw *hw = rga->hw;
>  	struct rga_fmt *fmt;
>  
> -	fmt = rga_fmt_find(pix_fmt->pixelformat);
> +	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
>  	if (!fmt)
> -		fmt = &formats[0];
> +		fmt = &hw->formats[0];
>  
>  	pix_fmt->width = clamp(pix_fmt->width,
> -			       (u32)MIN_WIDTH, (u32)MAX_WIDTH);
> +			       hw->min_width, hw->max_width);
>  	pix_fmt->height = clamp(pix_fmt->height,
> -				(u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
> +				hw->min_height, hw->max_height);
>  
>  	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
>  	pix_fmt->field = V4L2_FIELD_NONE;
> @@ -519,7 +371,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	frm->size = 0;
>  	for (i = 0; i < pix_fmt->num_planes; i++)
>  		frm->size += pix_fmt->plane_fmt[i].sizeimage;
> -	frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
> +	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
>  	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
>  
>  	/* Reset crop settings */
> @@ -639,7 +491,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
>  
>  	if (s->r.left + s->r.width > f->pix.width ||
>  	    s->r.top + s->r.height > f->pix.height ||
> -	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
> +	    s->r.width < rga->hw->min_width || s->r.height < rga->hw->min_height) {
>  		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
>  		return -EINVAL;
>  	}
> @@ -748,6 +600,10 @@ static int rga_probe(struct platform_device *pdev)
>  	if (!rga)
>  		return -ENOMEM;
>  
> +	rga->hw = of_device_get_match_data(&pdev->dev);
> +	if (!rga->hw)
> +		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
> +
>  	rga->dev = &pdev->dev;
>  	spin_lock_init(&rga->ctrl_lock);
>  	mutex_init(&rga->mutex);
> @@ -811,8 +667,7 @@ static int rga_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		goto rel_m2m;
>  
> -	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
> -	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
> +	rga->hw->get_version(rga);
>  
>  	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
>  		  rga->version.major, rga->version.minor);
> @@ -820,7 +675,7 @@ static int rga_probe(struct platform_device *pdev)
>  	pm_runtime_put(rga->dev);
>  
>  	/* Create CMD buffer */
> -	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
> +	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
>  					   &rga->cmdbuf_phy, GFP_KERNEL,
>  					   DMA_ATTR_WRITE_COMBINE);
>  	if (!rga->cmdbuf_virt) {
> @@ -828,9 +683,6 @@ static int rga_probe(struct platform_device *pdev)
>  		goto rel_m2m;
>  	}
>  
> -	def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
> -
>  	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
>  	if (ret) {
>  		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
> @@ -843,7 +695,7 @@ static int rga_probe(struct platform_device *pdev)
>  	return 0;
>  
>  free_dma:
> -	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
>  		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
>  rel_m2m:
>  	v4l2_m2m_release(rga->m2m_dev);
> @@ -861,7 +713,7 @@ static void rga_remove(struct platform_device *pdev)
>  {
>  	struct rockchip_rga *rga = platform_get_drvdata(pdev);
>  
> -	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
>  		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
>  
>  	v4l2_info(&rga->v4l2_dev, "Removing\n");
> @@ -897,9 +749,11 @@ static const struct dev_pm_ops rga_pm = {
>  static const struct of_device_id rockchip_rga_match[] = {
>  	{
>  		.compatible = "rockchip,rk3288-rga",
> +		.data = &rga2_hw,
>  	},
>  	{
>  		.compatible = "rockchip,rk3399-rga",
> +		.data = &rga2_hw,
>  	},
>  	{},
>  };
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 7ec1fcc03ed32..98635ddd50d7c 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -14,6 +14,9 @@
>  
>  #define RGA_NAME "rockchip-rga"
>  
> +#define DEFAULT_WIDTH 100
> +#define DEFAULT_HEIGHT 100
> +
>  struct rga_fmt {
>  	u32 fourcc;
>  	int depth;
> @@ -69,6 +72,8 @@ static inline struct rga_ctx *file_to_rga_ctx(struct file *filp)
>  	return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh);
>  }
>  
> +struct rga_hw;
> +
>  struct rockchip_rga {
>  	struct v4l2_device v4l2_dev;
>  	struct v4l2_m2m_dev *m2m_dev;
> @@ -88,6 +93,8 @@ struct rockchip_rga {
>  	struct rga_ctx *curr;
>  	dma_addr_t cmdbuf_phy;
>  	void *cmdbuf_virt;
> +
> +	const struct rga_hw *hw;
>  };
>  
>  struct rga_addr_offset {
> @@ -138,7 +145,19 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>  	rga_write(rga, reg, temp);
>  };
>  
> -void rga_hw_start(struct rockchip_rga *rga,
> -		  struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> +struct rga_hw {
> +	struct rga_fmt *formats;
> +	u32 num_formats;
> +	size_t cmdbuf_size;
> +	u32 min_width, min_height;
> +	u32 max_width, max_height;
> +
> +	void (*start)(struct rockchip_rga *rga,
> +		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
> +	bool (*handle_irq)(struct rockchip_rga *rga);
> +	void (*get_version)(struct rockchip_rga *rga);
> +};
> +
> +extern const struct rga_hw rga2_hw;
>  
>  #endif

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx
  2025-12-03 15:52 ` [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx Sven Püschel
@ 2025-12-24 15:21   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:21 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 9510 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Move the command buffer to the rga_ctx struct in preparation to reuse
> an already prepared command buffer. Having a command buffer per context
> allows to reuse the command buffer for other frames even when
> multiple applications are using the RGA in at the same time.

So the command buffer is only holding commands for a single render, and its not
possible to append to it right ? It has no sync point or anything that would let
us program it live ?

In this context, that sounds about right. Though please rework the commit
message, I find it a little miss-leading, since in the code you still program it
in device_run(), which is during the idle portion of the hardware.

To really benefit, you would have to program and flush it on the context qbuf,
so that once device_run() is call, you just have to set the command buf for the
context and trigger. Basically, no performance is gained from this patch I
believe.

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

With a clear commit message:

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c | 28 +++++++---------
>  drivers/media/platform/rockchip/rga/rga.c    | 48 ++++++++++++++++-----------
> -
>  drivers/media/platform/rockchip/rga/rga.h    |  5 +--
>  3 files changed, 41 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 7419784efc693..79bf911e74779 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -113,8 +113,7 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
>  
>  static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
>  {
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int reg;
>  
>  	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
> @@ -126,8 +125,7 @@ static void rga_cmd_set_src_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
>  
>  static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
>  {
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int reg;
>  
>  	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
> @@ -139,8 +137,7 @@ static void rga_cmd_set_src1_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
>  
>  static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
>  {
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int reg;
>  
>  	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
> @@ -153,7 +150,7 @@ static void rga_cmd_set_dst_addr(struct rga_ctx *ctx,
> dma_addr_t dma_addr)
>  static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  {
>  	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int scale_dst_w, scale_dst_h;
>  	unsigned int src_h, src_w, dst_h, dst_w;
>  	union rga_src_info src_info;
> @@ -313,8 +310,7 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
>  				 struct rga_addr_offset *offset)
>  {
>  	struct rga_corners_addr_offset src_offsets;
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int src_h, src_w, src_x, src_y;
>  
>  	src_h = ctx->in.crop.height;
> @@ -341,8 +337,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
>  {
>  	struct rga_addr_offset *dst_offset;
>  	struct rga_corners_addr_offset offsets;
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int dst_h, dst_w, dst_x, dst_y;
>  	unsigned int mir_mode = 0;
>  	unsigned int rot_mode = 0;
> @@ -388,8 +383,7 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
>  
>  static void rga_cmd_set_mode(struct rga_ctx *ctx)
>  {
> -	struct rockchip_rga *rga = ctx->rga;
> -	u32 *dest = rga->cmdbuf_virt;
> +	u32 *dest = ctx->cmdbuf_virt;
>  	union rga_mode_ctrl mode;
>  	union rga_alpha_ctrl0 alpha_ctrl0;
>  	union rga_alpha_ctrl1 alpha_ctrl1;
> @@ -414,7 +408,7 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  {
>  	struct rockchip_rga *rga = ctx->rga;
>  
> -	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> +	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
>  
>  	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
>  	/*
> @@ -430,11 +424,11 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  	rga_cmd_set_dst_info(ctx, &dst->offset);
>  	rga_cmd_set_trans_info(ctx);
>  
> -	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
> +	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
>  
>  	/* sync CMD buf for RGA */
> -	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
> -		PAGE_SIZE, DMA_BIDIRECTIONAL);
> +	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
> +				   PAGE_SIZE, DMA_BIDIRECTIONAL);
>  }
>  
>  static void rga_hw_start(struct rockchip_rga *rga,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index d8b14c2d9f6a4..74d94c7fe31ff 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -219,6 +219,16 @@ static int rga_open(struct file *file)
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
>  		return -ENOMEM;
> +
> +	/* Create CMD buffer */
> +	ctx->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
> +					   &ctx->cmdbuf_phy, GFP_KERNEL,
> +					   DMA_ATTR_WRITE_COMBINE);
> +	if (!ctx->cmdbuf_virt) {
> +		ret = -ENOMEM;
> +		goto rel_ctx;
> +	}
> +
>  	ctx->rga = rga;
>  	/* Set default formats */
>  	ctx->in = def_frame;
> @@ -230,15 +240,13 @@ static int rga_open(struct file *file)
>  			    ctx->out.fmt->fourcc, def_width, def_height);
>  
>  	if (mutex_lock_interruptible(&rga->mutex)) {
> -		kfree(ctx);
> -		return -ERESTARTSYS;
> +		ret = -ERESTARTSYS;
> +		goto rel_cmdbuf;
>  	}
>  	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
>  	if (IS_ERR(ctx->fh.m2m_ctx)) {
>  		ret = PTR_ERR(ctx->fh.m2m_ctx);
> -		mutex_unlock(&rga->mutex);
> -		kfree(ctx);
> -		return ret;
> +		goto unlock_mutex;
>  	}
>  	v4l2_fh_init(&ctx->fh, video_devdata(file));
>  	v4l2_fh_add(&ctx->fh, file);
> @@ -252,6 +260,15 @@ static int rga_open(struct file *file)
>  	mutex_unlock(&rga->mutex);
>  
>  	return 0;
> +
> +unlock_mutex:
> +	mutex_unlock(&rga->mutex);
> +rel_cmdbuf:
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
> +		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> +rel_ctx:
> +	kfree(ctx);
> +	return ret;
>  }
>  
>  static int rga_release(struct file *file)
> @@ -266,6 +283,10 @@ static int rga_release(struct file *file)
>  	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>  	v4l2_fh_del(&ctx->fh, file);
>  	v4l2_fh_exit(&ctx->fh);
> +
> +	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
> +		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> +
>  	kfree(ctx);
>  
>  	mutex_unlock(&rga->mutex);
> @@ -674,19 +695,10 @@ static int rga_probe(struct platform_device *pdev)
>  
>  	pm_runtime_put(rga->dev);
>  
> -	/* Create CMD buffer */
> -	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
> -					   &rga->cmdbuf_phy, GFP_KERNEL,
> -					   DMA_ATTR_WRITE_COMBINE);
> -	if (!rga->cmdbuf_virt) {
> -		ret = -ENOMEM;
> -		goto rel_m2m;
> -	}
> -
>  	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
>  	if (ret) {
>  		v4l2_err(&rga->v4l2_dev, "Failed to register video
> device\n");
> -		goto free_dma;
> +		goto rel_m2m;
>  	}
>  
>  	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
> @@ -694,9 +706,6 @@ static int rga_probe(struct platform_device *pdev)
>  
>  	return 0;
>  
> -free_dma:
> -	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> -		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
>  rel_m2m:
>  	v4l2_m2m_release(rga->m2m_dev);
>  rel_vdev:
> @@ -713,9 +722,6 @@ static void rga_remove(struct platform_device *pdev)
>  {
>  	struct rockchip_rga *rga = platform_get_drvdata(pdev);
>  
> -	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
> -		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
> -
>  	v4l2_info(&rga->v4l2_dev, "Removing\n");
>  
>  	v4l2_m2m_release(rga->m2m_dev);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 98635ddd50d7c..f8c932fdec21a 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -56,6 +56,9 @@ struct rga_ctx {
>  	struct rga_frame out;
>  	struct v4l2_ctrl_handler ctrl_handler;
>  
> +	void *cmdbuf_virt;
> +	dma_addr_t cmdbuf_phy;
> +
>  	int osequence;
>  	int csequence;
>  
> @@ -91,8 +94,6 @@ struct rockchip_rga {
>  	spinlock_t ctrl_lock;
>  
>  	struct rga_ctx *curr;
> -	dma_addr_t cmdbuf_phy;
> -	void *cmdbuf_virt;
>  
>  	const struct rga_hw *hw;
>  };

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes
  2025-12-03 15:52 ` [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes Sven Püschel
@ 2025-12-24 15:26   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:26 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 3463 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Add an alignment setting to rga_hw to set the desired stride alignment.
> As the RGA2 register for the stride counts in word units, the code
> already divides the bytesperline value by 4 when writing it into the
> register. Therefore fix the alignment to a multiple of 4 to avoid
> potential off by one errors due from the division.

If you decide to keep the stride alignment to be width alignment, then please
make use struct v4l2_frmsize_stepwise and v4l2_apply_frmsize_constraints
instead.

It will also make the per-variant description a lot more clear, with the min/max
resolution exposed.

Nicolas

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
>  drivers/media/platform/rockchip/rga/rga.c    | 11 ++++++-----
>  drivers/media/platform/rockchip/rga/rga.h    |  1 +
>  3 files changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 79bf911e74779..56a2558539bfb 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -620,6 +620,7 @@ const struct rga_hw rga2_hw = {
>  	.max_width = MAX_WIDTH,
>  	.min_height = MIN_HEIGHT,
>  	.max_height = MAX_HEIGHT,
> +	.stride_alignment = 4,
>  
>  	.start = rga_hw_start,
>  	.handle_irq = rga_handle_irq,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 74d94c7fe31ff..592c977a07cf3 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -234,10 +234,10 @@ static int rga_open(struct file *file)
>  	ctx->in = def_frame;
>  	ctx->out = def_frame;
>  
> -	v4l2_fill_pixfmt_mp(&ctx->in.pix,
> -			    ctx->in.fmt->fourcc, def_width, def_height);
> -	v4l2_fill_pixfmt_mp(&ctx->out.pix,
> -			    ctx->out.fmt->fourcc, def_width, def_height);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
> +				    def_width, def_height, rga->hw->stride_alignment);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
> +				    def_width, def_height, rga->hw->stride_alignment);
>  
>  	if (mutex_lock_interruptible(&rga->mutex)) {
>  		ret = -ERESTARTSYS;
> @@ -359,7 +359,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	pix_fmt->height = clamp(pix_fmt->height,
>  				hw->min_height, hw->max_height);
>  
> -	v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
> +	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
> +				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
>  	pix_fmt->field = V4L2_FIELD_NONE;
>  
>  	return 0;
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index f8c932fdec21a..0aef348dddb95 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -152,6 +152,7 @@ struct rga_hw {
>  	size_t cmdbuf_size;
>  	u32 min_width, min_height;
>  	u32 max_width, max_height;
> +	u8 stride_alignment;
>  
>  	void (*start)(struct rockchip_rga *rga,
>  		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon
  2025-12-03 15:52 ` [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon Sven Püschel
@ 2025-12-24 15:29   ` Nicolas Dufresne
  2026-01-07 12:00     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:29 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 4494 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Prepare the command buffer on streamon to reuse it's contents instead of
> completely writing it for every frame. Due to the stream settings being
> fixed after a streamon we only need to replace the source and destination
> addresses for each frame. This reduces the amount of CPU and memory
> operations done in each frame.

My speculation is that flushing to device is usually more expensive then this,
but I didn't check closely if you have enabled the caches. That being said, this
is good change. It highlight the inflexible nature of V4L2 imho, which in this
case can be used to optimize.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
>  drivers/media/platform/rockchip/rga/rga.c    | 13 ++++++++++++-
>  drivers/media/platform/rockchip/rga/rga.h    |  1 +
>  3 files changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 56a2558539bfb..8cdfe089fd636 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -408,8 +408,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  {
>  	struct rockchip_rga *rga = ctx->rga;
>  
> -	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> -
>  	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
>  	/*
>  	 * Due to hardware bug,
> @@ -418,11 +416,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  	rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
>  
>  	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
> -	rga_cmd_set_mode(ctx);
>  
>  	rga_cmd_set_src_info(ctx, &src->offset);
>  	rga_cmd_set_dst_info(ctx, &dst->offset);
> -	rga_cmd_set_trans_info(ctx);
>  
>  	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
>  
> @@ -431,6 +427,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  				   PAGE_SIZE, DMA_BIDIRECTIONAL);
>  }
>  
> +static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
> +{
> +	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
> +
> +	rga_cmd_set_mode(ctx);
> +	rga_cmd_set_trans_info(ctx);
> +}
> +
>  static void rga_hw_start(struct rockchip_rga *rga,
>  			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
>  {
> @@ -622,6 +626,7 @@ const struct rga_hw rga2_hw = {
>  	.max_height = MAX_HEIGHT,
>  	.stride_alignment = 4,
>  
> +	.setup_cmdbuf = rga_hw_setup_cmdbuf,
>  	.start = rga_hw_start,
>  	.handle_irq = rga_handle_irq,
>  	.get_version = rga_get_version,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 592c977a07cf3..f02ae02de26ca 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -523,6 +523,17 @@ static int vidioc_s_selection(struct file *file, void *priv,
>  	return ret;
>  }
>  
> +static int vidioc_streamon(struct file *file, void *priv,
> +			   enum v4l2_buf_type type)
> +{
> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
> +	const struct rga_hw *hw = ctx->rga->hw;
> +
> +	hw->setup_cmdbuf(ctx);
> +
> +	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
> +}
> +
>  static const struct v4l2_ioctl_ops rga_ioctl_ops = {
>  	.vidioc_querycap = vidioc_querycap,
>  
> @@ -547,7 +558,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
>  	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
>  	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>  
> -	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
> +	.vidioc_streamon = vidioc_streamon,
>  	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
>  
>  	.vidioc_g_selection = vidioc_g_selection,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 0aef348dddb95..93162b118d069 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -154,6 +154,7 @@ struct rga_hw {
>  	u32 max_width, max_height;
>  	u8 stride_alignment;
>  
> +	void (*setup_cmdbuf)(struct rga_ctx *ctx);
>  	void (*start)(struct rockchip_rga *rga,
>  		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
>  	bool (*handle_irq)(struct rockchip_rga *rga);

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 11/22] media: rockchip: rga: check scaling factor
  2025-12-03 15:52 ` [PATCH v2 11/22] media: rockchip: rga: check scaling factor Sven Püschel
@ 2025-12-24 15:39   ` Nicolas Dufresne
  2026-01-09 12:18     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:39 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 7241 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Check the scaling factor to avoid potential problems. This is relevant
> for the upcoming RGA3 support, as it can hang when the scaling factor
> is exceeded.
> 
> There are two relevant scenarios that have to be considered to protect
> against invalid scaling values:
> 
> When the output or capture is already streaming, setting the format on
> the other side should consider the max scaling factor and clamp it
> accordingly. This is only done in the streaming case, as it otherwise
> may unintentionally clamp the value when the application sets the first
> format (due to a default format on the other side).
> 
> When the format is set on both sides first, then the format won't be
> corrected by above means. Therefore the second streamon call has to
> check the scaling factor and fail otherwise.

In codec specifications, we resolve this issue by resetting the capture format
every-time the output format is set. But without specification for color
transforms, its impossible to say if this is right or wrong, and I don't expect
perfect interroperability between drivers until someone make the effort to
specify this type of hardware.

What you describe is fine of course, but its a bit off nature of the way format
is normally being fixed by the driver to stay valid.

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
>  drivers/media/platform/rockchip/rga/rga-hw.h |  1 +
>  drivers/media/platform/rockchip/rga/rga.c    | 60 +++++++++++++++++++++++++---
>  drivers/media/platform/rockchip/rga/rga.h    |  1 +
>  4 files changed, 58 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 8cdfe089fd636..2ed4f22a999d5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -624,6 +624,7 @@ const struct rga_hw rga2_hw = {
>  	.max_width = MAX_WIDTH,
>  	.min_height = MIN_HEIGHT,
>  	.max_height = MAX_HEIGHT,
> +	.max_scaling_factor = MAX_SCALING_FACTOR,
>  	.stride_alignment = 4,
>  
>  	.setup_cmdbuf = rga_hw_setup_cmdbuf,
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index f4752aa823051..fffcab0131225 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -14,6 +14,7 @@
>  
>  #define MIN_WIDTH 34
>  #define MIN_HEIGHT 34
> +#define MAX_SCALING_FACTOR 16
>  
>  #define RGA_TIMEOUT 500
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index f02ae02de26ca..46dc94db6f85e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -346,18 +346,47 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  {
>  	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
> -	struct rockchip_rga *rga = video_drvdata(file);
> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
> +	struct rockchip_rga *rga = ctx->rga;
>  	const struct rga_hw *hw = rga->hw;
>  	struct rga_fmt *fmt;
> +	u32 min_width = hw->min_width;
> +	u32 max_width = hw->max_width;
> +	u32 min_height = hw->min_height;
> +	u32 max_height = hw->max_height;
>  
>  	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
>  	if (!fmt)
>  		fmt = &hw->formats[0];
>  
> -	pix_fmt->width = clamp(pix_fmt->width,
> -			       hw->min_width, hw->max_width);
> -	pix_fmt->height = clamp(pix_fmt->height,
> -				hw->min_height, hw->max_height);
> +	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
> +	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {

What if userspace wanted to get the buffer size computed, so it can allocate
externally before it calls streamoff ? Hans did mention recently that try
function should only be state aware if specified.

I'd like other reviewers feedback on what should be done here, of course writing
a spec would be ideal.

Nicolas

> +		min_width =
> +			MAX(min_width, DIV_ROUND_UP(ctx->out.pix.width,
> +						    hw->max_scaling_factor));
> +		max_width = MIN(max_width,
> +				ctx->out.pix.width * hw->max_scaling_factor);
> +		min_height =
> +			MAX(min_height, DIV_ROUND_UP(ctx->out.pix.height,
> +						     hw->max_scaling_factor));
> +		max_height = MIN(max_height,
> +				 ctx->out.pix.height * hw->max_scaling_factor);
> +	} else if (V4L2_TYPE_IS_CAPTURE(f->type) &&
> +		   v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming) {
> +		min_width =
> +			MAX(min_width, DIV_ROUND_UP(ctx->in.pix.width,
> +						    hw->max_scaling_factor));
> +		max_width = MIN(max_width,
> +				ctx->in.pix.width * hw->max_scaling_factor);
> +		min_height =
> +			MAX(min_height, DIV_ROUND_UP(ctx->in.pix.height,
> +						     hw->max_scaling_factor));
> +		max_height = MIN(max_height,
> +				 ctx->in.pix.height * hw->max_scaling_factor);
> +	}
> +
> +	pix_fmt->width = clamp(pix_fmt->width, min_width, max_width);
> +	pix_fmt->height = clamp(pix_fmt->height, min_height, max_height);
>  
>  	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
>  				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
> @@ -523,12 +552,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
>  	return ret;
>  }
>  
> +static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
> +{
> +	if (src_size < dst_size)
> +		return src_size * hw->max_scaling_factor >= dst_size;
> +	else
> +		return dst_size * hw->max_scaling_factor >= src_size;
> +}
> +
>  static int vidioc_streamon(struct file *file, void *priv,
>  			   enum v4l2_buf_type type)
>  {
>  	struct rga_ctx *ctx = file_to_rga_ctx(file);
>  	const struct rga_hw *hw = ctx->rga->hw;
>  
> +	if ((V4L2_TYPE_IS_OUTPUT(type) &&
> +	     v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
> +	    (V4L2_TYPE_IS_CAPTURE(type) &&
> +	     v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
> +		/*
> +		 * As the other side is already streaming,
> +		 * check that the max scaling factor isn't exceeded.
> +		 */
> +		if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
> +		    !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
> +			return -EINVAL;
> +	}
> +
>  	hw->setup_cmdbuf(ctx);
>  
>  	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 93162b118d069..d02d5730b4e3b 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -152,6 +152,7 @@ struct rga_hw {
>  	size_t cmdbuf_size;
>  	u32 min_width, min_height;
>  	u32 max_width, max_height;
> +	u8 max_scaling_factor;
>  	u8 stride_alignment;
>  
>  	void (*setup_cmdbuf)(struct rga_ctx *ctx);

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type
  2025-12-03 15:52 ` [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type Sven Püschel
@ 2025-12-24 15:40   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:40 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 2401 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> In preparation of the RGA3 support add a filed to the rga_hw struct
> to specify the desired card type value. This allows the user to
> differentiate the RGA2 and RGA3 video device nodes.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
>  drivers/media/platform/rockchip/rga/rga.c    | 4 +++-
>  drivers/media/platform/rockchip/rga/rga.h    | 1 +
>  3 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 2ed4f22a999d5..8953960d33bc5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
>  };
>  
>  const struct rga_hw rga2_hw = {
> +	.card_type = "rga2",
>  	.formats = formats,
>  	.num_formats = ARRAY_SIZE(formats),
>  	.cmdbuf_size = RGA_CMDBUF_SIZE,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 46dc94db6f85e..c9719c7bcfc1c 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -306,8 +306,10 @@ static const struct v4l2_file_operations rga_fops = {
>  static int
>  vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
>  {
> +	struct rockchip_rga *rga = video_drvdata(file);
> +
>  	strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
> -	strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
> +	strscpy(cap->card, rga->hw->card_type, sizeof(cap->card));
>  	strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
>  
>  	return 0;
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index d02d5730b4e3b..ee50f7f3ed601 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -147,6 +147,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>  };
>  
>  struct rga_hw {
> +	const char *card_type;
>  	struct rga_fmt *formats;
>  	u32 num_formats;
>  	size_t cmdbuf_size;

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses
  2025-12-03 15:52 ` [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses Sven Püschel
@ 2025-12-24 15:41   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:41 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 11001 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Change the offset to dma_addresses, as the current naming is misleading.
> The offset naming comes from the fact that it references the offset in
> the mapped iommu address space. But from the hardware point of view this
> is an address, as also pointed out by the register naming
> (e.g. RGA_DST_Y_RGB_BASE_ADDR). Therefore also change the type to
> dma_addr_t, as with an external iommu driver this would also be the
> correct type.
> 
> This change is a preparation for the RGA3 support, which uses an external
> iommu and therefore just gets an dma_addr_t for each buffer. The field
> renaming allows to reuse the existing fields of rga_vb_buffer to store
> these values.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c |  12 +--
>  drivers/media/platform/rockchip/rga/rga-hw.c  | 105 +++++++++++++------------
> -
>  drivers/media/platform/rockchip/rga/rga.h     |  12 +--
>  3 files changed, 64 insertions(+), 65 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c
> b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 0c59a4d330888..8845e1f894f29 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -118,7 +118,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>  	size_t curr_desc = 0;
>  	int i;
>  	const struct v4l2_format_info *info;
> -	unsigned int offsets[VIDEO_MAX_PLANES];
> +	unsigned int dma_addrs[VIDEO_MAX_PLANES];
>  
>  	if (IS_ERR(f))
>  		return PTR_ERR(f);
> @@ -142,18 +142,18 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>  				 "Failed to map video buffer to RGA\n");
>  			return n_desc;
>  		}
> -		offsets[i] = curr_desc << PAGE_SHIFT;
> +		dma_addrs[i] = curr_desc << PAGE_SHIFT;
>  		curr_desc += n_desc;
>  	}
>  
>  	/* Fill the remaining planes */
>  	info = v4l2_format_info(f->fmt->fourcc);
>  	for (i = info->mem_planes; i < info->comp_planes; i++)
> -		offsets[i] = get_plane_offset(f, info, i);
> +		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
>  
> -	rbuf->offset.y_off = offsets[0];
> -	rbuf->offset.u_off = offsets[1];
> -	rbuf->offset.v_off = offsets[2];
> +	rbuf->dma_addrs.y_addr = dma_addrs[0];
> +	rbuf->dma_addrs.u_addr = dma_addrs[1];
> +	rbuf->dma_addrs.v_addr = dma_addrs[2];
>  
>  	return 0;
>  }
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 8953960d33bc5..fe6f518aedd4e 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -16,11 +16,11 @@ enum e_rga_start_pos {
>  	RB = 3,
>  };
>  
> -struct rga_corners_addr_offset {
> -	struct rga_addr_offset left_top;
> -	struct rga_addr_offset right_top;
> -	struct rga_addr_offset left_bottom;
> -	struct rga_addr_offset right_bottom;
> +struct rga_corners_addrs {
> +	struct rga_addrs left_top;
> +	struct rga_addrs right_top;
> +	struct rga_addrs left_bottom;
> +	struct rga_addrs right_bottom;
>  };
>  
>  static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
> @@ -36,48 +36,47 @@ static unsigned int rga_get_scaling(unsigned int src,
> unsigned int dst)
>  	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
>  }
>  
> -static struct rga_corners_addr_offset
> -rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
> -		    unsigned int x, unsigned int y, unsigned int w, unsigned
> int h)
> +static struct rga_corners_addrs
> +rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
> +		     unsigned int x, unsigned int y, unsigned int w, unsigned
> int h)
>  {
> -	struct rga_corners_addr_offset offsets;
> -	struct rga_addr_offset *lt, *lb, *rt, *rb;
> +	struct rga_corners_addrs corner_addrs;
> +	struct rga_addrs *lt, *lb, *rt, *rb;
>  	unsigned int x_div = 0,
>  		     y_div = 0, uv_stride = 0, pixel_width = 0;
>  
> -	lt = &offsets.left_top;
> -	lb = &offsets.left_bottom;
> -	rt = &offsets.right_top;
> -	rb = &offsets.right_bottom;
> +	lt = &corner_addrs.left_top;
> +	lb = &corner_addrs.left_bottom;
> +	rt = &corner_addrs.right_top;
> +	rb = &corner_addrs.right_bottom;
>  
>  	x_div = frm->fmt->x_div;
>  	y_div = frm->fmt->y_div;
>  	uv_stride = frm->stride / x_div;
>  	pixel_width = frm->stride / frm->pix.width;
>  
> -	lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
> -	lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
> -	lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
> +	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
> +	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
> +	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
>  
> -	lb->y_off = lt->y_off + (h - 1) * frm->stride;
> -	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
> -	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
> +	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
> +	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
> +	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
>  
> -	rt->y_off = lt->y_off + (w - 1) * pixel_width;
> -	rt->u_off = lt->u_off + w / x_div - 1;
> -	rt->v_off = lt->v_off + w / x_div - 1;
> +	rt->y_addr = lt->y_addr + (w - 1) * pixel_width;
> +	rt->u_addr = lt->u_addr + w / x_div - 1;
> +	rt->v_addr = lt->v_addr + w / x_div - 1;
>  
> -	rb->y_off = lb->y_off + (w - 1) * pixel_width;
> -	rb->u_off = lb->u_off + w / x_div - 1;
> -	rb->v_off = lb->v_off + w / x_div - 1;
> +	rb->y_addr = lb->y_addr + (w - 1) * pixel_width;
> +	rb->u_addr = lb->u_addr + w / x_div - 1;
> +	rb->v_addr = lb->v_addr + w / x_div - 1;
>  
> -	return offsets;
> +	return corner_addrs;
>  }
>  
> -static struct rga_addr_offset *rga_lookup_draw_pos(struct
> -		rga_corners_addr_offset
> -		* offsets, u32 rotate_mode,
> -		u32 mirr_mode)
> +static struct rga_addrs *rga_lookup_draw_pos(struct rga_corners_addrs
> *corner_addrs,
> +					     u32 rotate_mode,
> +					     u32 mirr_mode)
>  {
>  	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
>  		{
> @@ -94,18 +93,18 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
>  		},
>  	};
>  
> -	if (!offsets)
> +	if (!corner_addrs)
>  		return NULL;
>  
>  	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
>  	case LT:
> -		return &offsets->left_top;
> +		return &corner_addrs->left_top;
>  	case LB:
> -		return &offsets->left_bottom;
> +		return &corner_addrs->left_bottom;
>  	case RT:
> -		return &offsets->right_top;
> +		return &corner_addrs->right_top;
>  	case RB:
> -		return &offsets->right_bottom;
> +		return &corner_addrs->right_bottom;
>  	}
>  
>  	return NULL;
> @@ -307,9 +306,9 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  }
>  
>  static void rga_cmd_set_src_info(struct rga_ctx *ctx,
> -				 struct rga_addr_offset *offset)
> +				 struct rga_addrs *addrs)
>  {
> -	struct rga_corners_addr_offset src_offsets;
> +	struct rga_corners_addrs src_corner_addrs;
>  	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int src_h, src_w, src_x, src_y;
>  
> @@ -321,22 +320,22 @@ static void rga_cmd_set_src_info(struct rga_ctx *ctx,
>  	/*
>  	 * Calculate the source framebuffer base address with offset pixel.
>  	 */
> -	src_offsets = rga_get_addr_offset(&ctx->in, offset,
> -					  src_x, src_y, src_w, src_h);
> +	src_corner_addrs = rga_get_corner_addrs(&ctx->in, addrs,
> +						src_x, src_y, src_w, src_h);
>  
>  	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.y_off;
> +		src_corner_addrs.left_top.y_addr;
>  	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.u_off;
> +		src_corner_addrs.left_top.u_addr;
>  	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		src_offsets.left_top.v_off;
> +		src_corner_addrs.left_top.v_addr;
>  }
>  
>  static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
> -				 struct rga_addr_offset *offset)
> +				 struct rga_addrs *addrs)
>  {
> -	struct rga_addr_offset *dst_offset;
> -	struct rga_corners_addr_offset offsets;
> +	struct rga_addrs *dst_addrs;
> +	struct rga_corners_addrs corner_addrs;
>  	u32 *dest = ctx->cmdbuf_virt;
>  	unsigned int dst_h, dst_w, dst_x, dst_y;
>  	unsigned int mir_mode = 0;
> @@ -370,15 +369,15 @@ static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
>  	/*
>  	 * Configure the dest framebuffer base address with pixel offset.
>  	 */
> -	offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w,
> dst_h);
> -	dst_offset = rga_lookup_draw_pos(&offsets, rot_mode, mir_mode);
> +	corner_addrs = rga_get_corner_addrs(&ctx->out, addrs, dst_x, dst_y,
> dst_w, dst_h);
> +	dst_addrs = rga_lookup_draw_pos(&corner_addrs, rot_mode, mir_mode);
>  
>  	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->y_off;
> +		dst_addrs->y_addr;
>  	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->u_off;
> +		dst_addrs->u_addr;
>  	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
> -		dst_offset->v_off;
> +		dst_addrs->v_addr;
>  }
>  
>  static void rga_cmd_set_mode(struct rga_ctx *ctx)
> @@ -417,8 +416,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>  
>  	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
>  
> -	rga_cmd_set_src_info(ctx, &src->offset);
> -	rga_cmd_set_dst_info(ctx, &dst->offset);
> +	rga_cmd_set_src_info(ctx, &src->dma_addrs);
> +	rga_cmd_set_dst_info(ctx, &dst->dma_addrs);
>  
>  	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index ee50f7f3ed601..772f7dff9a8e5 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -98,10 +98,10 @@ struct rockchip_rga {
>  	const struct rga_hw *hw;
>  };
>  
> -struct rga_addr_offset {
> -	unsigned int y_off;
> -	unsigned int u_off;
> -	unsigned int v_off;
> +struct rga_addrs {
> +	dma_addr_t y_addr;
> +	dma_addr_t u_addr;
> +	dma_addr_t v_addr;
>  };
>  
>  struct rga_vb_buffer {
> @@ -113,8 +113,8 @@ struct rga_vb_buffer {
>  	dma_addr_t dma_desc_pa;
>  	size_t n_desc;
>  
> -	/* Plane offsets of this buffer into the mapping */
> -	struct rga_addr_offset offset;
> +	/* Plane DMA addresses after the MMU mapping of the buffer */
> +	struct rga_addrs dma_addrs;
>  };
>  
>  static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 14/22] media: rockchip: rga: support external iommus
  2025-12-03 15:52 ` [PATCH v2 14/22] media: rockchip: rga: support external iommus Sven Püschel
@ 2025-12-24 15:50   ` Nicolas Dufresne
  2026-01-07 14:19     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:50 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 7508 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> In preparation for the RGA3 add support for external iommus. This is a
> transition step to just disable the RGA2 specific mmu table setup code.
> 
> Currently a simple rga_hw struct field is used to set the internal iommu.
> But to handle the case of more sophisticated detection mechanisms
> (e.g. check for an iommu property in the device tree), it is abstracted
> by an inline function.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c | 46 ++++++++++++++++-----------
>  drivers/media/platform/rockchip/rga/rga-hw.c  |  1 +
>  drivers/media/platform/rockchip/rga/rga.c     | 11 +++++--
>  drivers/media/platform/rockchip/rga/rga.h     |  6 ++++
>  4 files changed, 43 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 8845e1f894f29..e8d1e2e579140 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -12,6 +12,7 @@
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-mem2mem.h>
>  #include <media/videobuf2-dma-sg.h>
> +#include <media/videobuf2-dma-contig.h>
>  #include <media/videobuf2-v4l2.h>
>  
>  #include "rga.h"
> @@ -79,14 +80,16 @@ static int rga_buf_init(struct vb2_buffer *vb)
>  	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
>  	size_t n_desc = 0;
>  
> -	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> +	if (rga_has_internal_iommu(rga)) {
> +		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);

n_desc is not used outside of this scope, perhap drop the definition with the 0
init, and use:

		const size_t n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
		
>  
> -	rbuf->n_desc = n_desc;
> -	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> -					    rbuf->n_desc * sizeof(*rbuf->dma_desc),
> -					    &rbuf->dma_desc_pa, GFP_KERNEL);
> -	if (!rbuf->dma_desc)
> -		return -ENOMEM;
> +		rbuf->n_desc = n_desc;
> +		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> +						    rbuf->n_desc * sizeof(*rbuf->dma_desc),
> +						    &rbuf->dma_desc_pa, GFP_KERNEL);
> +		if (!rbuf->dma_desc)
> +			return -ENOMEM;
> +	}
>  
>  	return 0;
>  }
> @@ -133,17 +136,21 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>  	for (i = 0; i < vb->num_planes; i++) {
>  		vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
>  
> -		/* Create local MMU table for RGA */
> -		n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
> -					  rbuf->n_desc - curr_desc,
> -					  vb2_dma_sg_plane_desc(vb, i));
> -		if (n_desc < 0) {
> -			v4l2_err(&ctx->rga->v4l2_dev,
> -				 "Failed to map video buffer to RGA\n");
> -			return n_desc;
> +		if (rga_has_internal_iommu(ctx->rga)) {
> +			/* Create local MMU table for RGA */
> +			n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
> +						  rbuf->n_desc - curr_desc,
> +						  vb2_dma_sg_plane_desc(vb, i));
> +			if (n_desc < 0) {
> +				v4l2_err(&ctx->rga->v4l2_dev,
> +					 "Failed to map video buffer to RGA\n");
> +				return n_desc;
> +			}
> +			dma_addrs[i] = curr_desc << PAGE_SHIFT;
> +			curr_desc += n_desc;
> +		} else {
> +			dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i);
>  		}
> -		dma_addrs[i] = curr_desc << PAGE_SHIFT;
> -		curr_desc += n_desc;
>  	}
>  
>  	/* Fill the remaining planes */
> @@ -173,8 +180,9 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
>  	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>  	struct rockchip_rga *rga = ctx->rga;
>  
> -	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
> -			  rbuf->dma_desc, rbuf->dma_desc_pa);
> +	if (rga_has_internal_iommu(rga))
> +		dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
> +				  rbuf->dma_desc, rbuf->dma_desc_pa);
>  }
>  
>  static void rga_buf_return_buffers(struct vb2_queue *q,
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index fe6f518aedd4e..fb0389ae8e132 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
>  
>  const struct rga_hw rga2_hw = {
>  	.card_type = "rga2",
> +	.has_internal_iommu = true,
>  	.formats = formats,
>  	.num_formats = ARRAY_SIZE(formats),
>  	.cmdbuf_size = RGA_CMDBUF_SIZE,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index c9719c7bcfc1c..f28ec88c186fa 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -23,6 +23,7 @@
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-mem2mem.h>
>  #include <media/videobuf2-dma-sg.h>
> +#include <media/videobuf2-dma-contig.h>
>  #include <media/videobuf2-v4l2.h>
>  
>  #include "rga.h"
> @@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
>  	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>  	src_vq->drv_priv = ctx;
>  	src_vq->ops = &rga_qops;
> -	src_vq->mem_ops = &vb2_dma_sg_memops;
> +	src_vq->mem_ops = &vb2_dma_contig_memops;

That's a bit I'm less knowledgeable here, since I never used the sg_memops in
any of my work, but what is the consequence ? (appart from gaining external
iommu support)

>  	src_vq->gfp_flags = __GFP_DMA32;
>  	src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
>  	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>  	src_vq->lock = &ctx->rga->mutex;
>  	src_vq->dev = ctx->rga->v4l2_dev.dev;
>  
> +	if (rga_has_internal_iommu(ctx->rga))
> +		src_vq->mem_ops = &vb2_dma_sg_memops;
> +
>  	ret = vb2_queue_init(src_vq);
>  	if (ret)
>  		return ret;
> @@ -110,13 +114,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
>  	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>  	dst_vq->drv_priv = ctx;
>  	dst_vq->ops = &rga_qops;
> -	dst_vq->mem_ops = &vb2_dma_sg_memops;
> +	dst_vq->mem_ops = &vb2_dma_contig_memops;
>  	dst_vq->gfp_flags = __GFP_DMA32;
>  	dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
>  	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>  	dst_vq->lock = &ctx->rga->mutex;
>  	dst_vq->dev = ctx->rga->v4l2_dev.dev;
>  
> +	if (rga_has_internal_iommu(ctx->rga))
> +		dst_vq->mem_ops = &vb2_dma_sg_memops;
> +
>  	return vb2_queue_init(dst_vq);
>  }
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index 772f7dff9a8e5..fc81bc5562792 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -148,6 +148,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>  
>  struct rga_hw {
>  	const char *card_type;
> +	bool has_internal_iommu;
>  	struct rga_fmt *formats;
>  	u32 num_formats;
>  	size_t cmdbuf_size;
> @@ -163,6 +164,11 @@ struct rga_hw {
>  	void (*get_version)(struct rockchip_rga *rga);
>  };
>  
> +static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
> +{
> +	return rga->hw->has_internal_iommu;
> +}
> +
>  extern const struct rga_hw rga2_hw;
>  
>  #endif

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used
  2025-12-03 15:52 ` [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used Sven Püschel
@ 2025-12-24 15:50   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:50 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel, Michael Olbrich

[-- Attachment #1: Type: text/plain, Size: 1260 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> From: Michael Olbrich <m.olbrich@pengutronix.de>
> 
> The RGA3 and the corresponding iommu share the interrupt. So in that
> case, request a shared interrupt so that the iommu driver can request
> it as well.
> 
> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index f28ec88c186fa..1bfc4021f4a7b 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -718,7 +718,8 @@ static int rga_probe(struct platform_device *pdev)
>  		goto err_put_clk;
>  	}
>  
> -	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
> +	ret = devm_request_irq(rga->dev, irq, rga_isr,
> +			       rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
>  			       dev_name(rga->dev), rga);
>  	if (ret < 0) {
>  		dev_err(rga->dev, "failed to request irq\n");

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame
  2025-12-03 15:52 ` [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame Sven Püschel
@ 2025-12-24 15:54   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:54 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 3717 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> The size member is only used for the mmu page table mapping.
> Therefore avoid storing the value and instead only calculate it
> in place. This also avoids the calculation entirely when an external
> iommu is used.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c | 6 +++++-
>  drivers/media/platform/rockchip/rga/rga.c     | 8 ++------
>  drivers/media/platform/rockchip/rga/rga.h     | 1 -
>  3 files changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index e8d1e2e579140..8de6b9c3fd615 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -79,9 +79,13 @@ static int rga_buf_init(struct vb2_buffer *vb)
>  	struct rockchip_rga *rga = ctx->rga;
>  	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
>  	size_t n_desc = 0;
> +	u32 size = 0;
> +	u8 i;

Move in it the scope it is being used.

>  
>  	if (rga_has_internal_iommu(rga)) {

though, after looking more attentively, this function is a no-op when the is an
external iommu. Using an early return would make this so much clearer, and you
can then drop the indent.

	if (rga_has_internal_iommu(rga))
		return 0;

Perhaps a comment to be applied on patch 14 though.

> -		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> +		for (i = 0; i < f->pix.num_planes; i++)
> +			size += f->pix.plane_fmt[i].sizeimage;
> +		n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
>  
>  		rbuf->n_desc = n_desc;
>  		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 1bfc4021f4a7b..0d7b0bcac950e 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -221,7 +221,6 @@ static int rga_open(struct file *file)
>  	};
>  
>  	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> -	def_frame.size = def_frame.stride * def_height;
>  
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
> @@ -428,9 +427,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	frm = rga_get_frame(ctx, f->type);
>  	if (IS_ERR(frm))
>  		return PTR_ERR(frm);
> -	frm->size = 0;
> -	for (i = 0; i < pix_fmt->num_planes; i++)
> -		frm->size += pix_fmt->plane_fmt[i].sizeimage;
>  	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
>  	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
>  
> @@ -443,10 +439,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	frm->pix = *pix_fmt;
>  
>  	v4l2_dbg(debug, 1, &rga->v4l2_dev,
> -		 "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
> +		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
>  		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
>  		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> -		  frm->stride, frm->size);
> +		  frm->stride);
>  
>  	for (i = 0; i < pix_fmt->num_planes; i++) {
>  		v4l2_dbg(debug, 1, &rga->v4l2_dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index fc81bc5562792..466d568b9e614 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -37,7 +37,6 @@ struct rga_frame {
>  
>  	/* Variables that can calculated once and reused */
>  	u32 stride;
> -	u32 size;
>  };
>  
>  struct rga_dma_desc {

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 17/22] media: rockchip: rga: remove stride from rga_frame
  2025-12-03 15:52 ` [PATCH v2 17/22] media: rockchip: rga: remove stride " Sven Püschel
@ 2025-12-24 15:56   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:56 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 5450 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Remove the stride variable from rga_frame. Despite the comment it
> didn't involve any calculation and is just a copy of the
> plane_fmt[0].bytesperline value. Therefore avoid this struct member
> and use the bytesperline value directly in the places where it is
> required.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

This I believe was the only user of fmt->x_div / fmt->y_div, please cleanup the
structure definition.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c | 20 ++++++++++++--------
>  drivers/media/platform/rockchip/rga/rga.c    |  5 +----
>  drivers/media/platform/rockchip/rga/rga.h    |  3 ---
>  3 files changed, 13 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index fb0389ae8e132..4dee33d8f7206 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -43,7 +43,7 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs
> *addrs,
>  	struct rga_corners_addrs corner_addrs;
>  	struct rga_addrs *lt, *lb, *rt, *rb;
>  	unsigned int x_div = 0,
> -		     y_div = 0, uv_stride = 0, pixel_width = 0;
> +		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
>  
>  	lt = &corner_addrs.left_top;
>  	lb = &corner_addrs.left_bottom;
> @@ -52,14 +52,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct
> rga_addrs *addrs,
>  
>  	x_div = frm->fmt->x_div;
>  	y_div = frm->fmt->y_div;
> -	uv_stride = frm->stride / x_div;
> -	pixel_width = frm->stride / frm->pix.width;
> +	y_stride = frm->pix.plane_fmt[0].bytesperline;
> +	uv_stride = y_stride / x_div;
> +	pixel_width = y_stride / frm->pix.width;
>  
> -	lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
> +	lt->y_addr = addrs->y_addr + y * y_stride + x * pixel_width;
>  	lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
>  	lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
>  
> -	lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
> +	lb->y_addr = lt->y_addr + (h - 1) * y_stride;
>  	lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
>  	lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
>  
> @@ -160,6 +161,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  	union rga_src_act_info src_act_info;
>  	union rga_dst_vir_info dst_vir_info;
>  	union rga_dst_act_info dst_act_info;
> +	u32 in_stride, out_stride;
>  
>  	src_h = ctx->in.crop.height;
>  	src_w = ctx->in.crop.width;
> @@ -282,13 +284,15 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  	 * Calculate the framebuffer virtual strides and active size,
>  	 * note that the step of vir_stride / vir_width is 4 byte words
>  	 */
> -	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
> -	src_vir_info.data.vir_width = ctx->in.stride >> 2;
> +	in_stride = ctx->in.pix.plane_fmt[0].bytesperline;
> +	src_vir_info.data.vir_stride = in_stride >> 2;
> +	src_vir_info.data.vir_width = in_stride >> 2;
>  
>  	src_act_info.data.act_height = src_h - 1;
>  	src_act_info.data.act_width = src_w - 1;
>  
> -	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
> +	out_stride = ctx->out.pix.plane_fmt[0].bytesperline;
> +	dst_vir_info.data.vir_stride = out_stride >> 2;
>  	dst_act_info.data.act_height = dst_h - 1;
>  	dst_act_info.data.act_width = dst_w - 1;
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index 0d7b0bcac950e..7e30fafb25fab 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -220,8 +220,6 @@ static int rga_open(struct file *file)
>  		.fmt = &rga->hw->formats[0],
>  	};
>  
> -	def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
> -
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
>  		return -ENOMEM;
> @@ -428,7 +426,6 @@ static int vidioc_s_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
>  	if (IS_ERR(frm))
>  		return PTR_ERR(frm);
>  	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> -	frm->stride = pix_fmt->plane_fmt[0].bytesperline;
>  
>  	/* Reset crop settings */
>  	frm->crop.left = 0;
> @@ -442,7 +439,7 @@ static int vidioc_s_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
>  		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
>  		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
>  		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> -		  frm->stride);
> +		  pix_fmt->plane_fmt[0].bytesperline);
>  
>  	for (i = 0; i < pix_fmt->num_planes; i++) {
>  		v4l2_dbg(debug, 1, &rga->v4l2_dev,
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 466d568b9e614..a7f891b94a478 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -34,9 +34,6 @@ struct rga_frame {
>  	/* Image format */
>  	struct rga_fmt *fmt;
>  	struct v4l2_pix_format_mplane pix;
> -
> -	/* Variables that can calculated once and reused */
> -	u32 stride;
>  };
>  
>  struct rga_dma_desc {

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h
  2025-12-03 15:52 ` [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h Sven Püschel
@ 2025-12-24 15:59   ` Nicolas Dufresne
  2026-01-07 14:52     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 15:59 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 12725 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
> contains many RGA2 specific values. They are used to write the correct
> register values quickly based on the chosen format. Therefore the
> pointer to the rga_fmt struct is kept but changed to an opaque void
> pointer outside of the rga-hw.h.
> 
> To enumerate and set the correct formats, two helper functions need to
> be exposed in the rga_hw struct:
> 
> enum_format just get's the vidioc_enum_fmt format and it's return value
> is also returned from vidioc_enum_fmt. This is a simple pass-through,
> as the implementation is very simple.
> 
> adjust_and_map_format is a simple abstraction around the previous
> rga_find_format. But unlike rga_find_format, it always returns a valid
> format. Therefore the passed format value is also a pointer to update
> it in case the values are not supported by the hardware.
> Due to the RGA3 supporting different formats on the capture and output
> side, an additional parameter is_capture has been added to support
> this use-case.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/rga-buf.c |  2 +-
>  drivers/media/platform/rockchip/rga/rga-hw.c  | 53 +++++++++++++++++++++------
>  drivers/media/platform/rockchip/rga/rga-hw.h  | 12 ++++++
>  drivers/media/platform/rockchip/rga/rga.c     | 38 +++++--------------
>  drivers/media/platform/rockchip/rga/rga.h     | 17 ++-------
>  5 files changed, 68 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
> index 8de6b9c3fd615..b0f226f7f06d9 100644
> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
> @@ -158,7 +158,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>  	}
>  
>  	/* Fill the remaining planes */
> -	info = v4l2_format_info(f->fmt->fourcc);
> +	info = v4l2_format_info(f->pix.pixelformat);
>  	for (i = info->mem_planes; i < info->comp_planes; i++)
>  		dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
> index 4dee33d8f7206..a868a34a1452e 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -44,14 +44,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
>  	struct rga_addrs *lt, *lb, *rt, *rb;
>  	unsigned int x_div = 0,
>  		     y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
> +	struct rga_fmt *fmt = frm->fmt;
>  
>  	lt = &corner_addrs.left_top;
>  	lb = &corner_addrs.left_bottom;
>  	rt = &corner_addrs.right_top;
>  	rb = &corner_addrs.right_bottom;
>  
> -	x_div = frm->fmt->x_div;
> -	y_div = frm->fmt->y_div;
> +	x_div = fmt->x_div;
> +	y_div = fmt->y_div;
>  	y_stride = frm->pix.plane_fmt[0].bytesperline;
>  	uv_stride = y_stride / x_div;
>  	pixel_width = y_stride / frm->pix.width;
> @@ -162,6 +163,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  	union rga_dst_vir_info dst_vir_info;
>  	union rga_dst_act_info dst_act_info;
>  	u32 in_stride, out_stride;
> +	struct rga_fmt *in_fmt = ctx->in.fmt;
> +	struct rga_fmt *out_fmt = ctx->out.fmt;
>  
>  	src_h = ctx->in.crop.height;
>  	src_w = ctx->in.crop.width;
> @@ -177,18 +180,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
>  	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
>  
> -	src_info.data.format = ctx->in.fmt->hw_format;
> -	src_info.data.swap = ctx->in.fmt->color_swap;
> -	dst_info.data.format = ctx->out.fmt->hw_format;
> -	dst_info.data.swap = ctx->out.fmt->color_swap;
> +	src_info.data.format = in_fmt->hw_format;
> +	src_info.data.swap = in_fmt->color_swap;
> +	dst_info.data.format = out_fmt->hw_format;
> +	dst_info.data.swap = out_fmt->color_swap;
>  
>  	/*
>  	 * CSC mode must only be set when the colorspace families differ between
>  	 * input and output. It must remain unset (zeroed) if both are the same.
>  	 */
>  
> -	if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
> -	    RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
> +	if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
> +	    RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
>  		switch (ctx->in.pix.colorspace) {
>  		case V4L2_COLORSPACE_REC709:
>  			src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> @@ -199,8 +202,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>  		}
>  	}
>  
> -	if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
> -	    RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
> +	if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
> +	    RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
>  		switch (ctx->out.pix.colorspace) {
>  		case V4L2_COLORSPACE_REC709:
>  			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
> @@ -619,11 +622,35 @@ static struct rga_fmt formats[] = {
>  	},
>  };
>  
> +static void *rga_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
> +				       bool is_output)
> +{
> +	unsigned int i;
> +
> +	if (!format)
> +		return &formats[0];
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
> +		if (formats[i].fourcc == format->pixelformat)
> +			return &formats[i];
> +	}
> +
> +	format->pixelformat = formats[0].fourcc;
> +	return &formats[0];
> +}
> +
> +static int rga_enum_format(struct v4l2_fmtdesc *f)
> +{
> +	if (f->index >= ARRAY_SIZE(formats))
> +		return -EINVAL;
> +
> +	f->pixelformat = formats[f->index].fourcc;
> +	return 0;
> +}
> +
>  const struct rga_hw rga2_hw = {
>  	.card_type = "rga2",
>  	.has_internal_iommu = true,
> -	.formats = formats,
> -	.num_formats = ARRAY_SIZE(formats),
>  	.cmdbuf_size = RGA_CMDBUF_SIZE,
>  	.min_width = MIN_WIDTH,
>  	.max_width = MAX_WIDTH,
> @@ -636,4 +663,6 @@ const struct rga_hw rga2_hw = {
>  	.start = rga_hw_start,
>  	.handle_irq = rga_handle_irq,
>  	.get_version = rga_get_version,
> +	.adjust_and_map_format = rga_adjust_and_map_format,
> +	.enum_format = rga_enum_format,
>  };
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
> index fffcab0131225..3bc4b1f5acba2 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
> @@ -6,6 +6,8 @@
>  #ifndef __RGA_HW_H__
>  #define __RGA_HW_H__
>  
> +#include <linux/types.h>
> +
>  #define RGA_CMDBUF_SIZE 0x20
>  
>  /* Hardware limits */
> @@ -431,4 +433,14 @@ union rga_pat_con {
>  	} data;
>  };
>  
> +struct rga_fmt {
> +	u32 fourcc;
> +	int depth;
> +	u8 uv_factor;
> +	u8 y_div;
> +	u8 x_div;
> +	u8 color_swap;
> +	u8 hw_format;
> +};
> +
>  #endif
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 7e30fafb25fab..c991cc64b4b7f 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -185,17 +185,6 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
>  	return 0;
>  }
>  
> -static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
> -{
> -	unsigned int i;
> -
> -	for (i = 0; i < rga->hw->num_formats; i++) {
> -		if (rga->hw->formats[i].fourcc == pixelformat)
> -			return &rga->hw->formats[i];
> -	}
> -	return NULL;
> -}
> -
>  struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
>  {
>  	if (V4L2_TYPE_IS_OUTPUT(type))
> @@ -217,7 +206,6 @@ static int rga_open(struct file *file)
>  		.crop.top = 0,
>  		.crop.width = def_width,
>  		.crop.height = def_height,
> -		.fmt = &rga->hw->formats[0],
>  	};
>  
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> @@ -238,9 +226,11 @@ static int rga_open(struct file *file)
>  	ctx->in = def_frame;
>  	ctx->out = def_frame;
>  
> -	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
> +	ctx->in.fmt = rga->hw->adjust_and_map_format(&ctx->in.pix, true);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
>  				    def_width, def_height, rga->hw->stride_alignment);
> -	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
> +	ctx->out.fmt = rga->hw->adjust_and_map_format(&ctx->out.pix, false);
> +	v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
>  				    def_width, def_height, rga->hw->stride_alignment);
>  
>  	if (mutex_lock_interruptible(&rga->mutex)) {
> @@ -322,15 +312,8 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
>  static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
>  {
>  	struct rockchip_rga *rga = video_drvdata(file);
> -	struct rga_fmt *fmt;
>  
> -	if (f->index >= rga->hw->num_formats)
> -		return -EINVAL;
> -
> -	fmt = &rga->hw->formats[f->index];
> -	f->pixelformat = fmt->fourcc;
> -
> -	return 0;
> +	return rga->hw->enum_format(f);
>  }
>  
>  static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
> @@ -355,15 +338,13 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	struct rga_ctx *ctx = file_to_rga_ctx(file);
>  	struct rockchip_rga *rga = ctx->rga;
>  	const struct rga_hw *hw = rga->hw;
> -	struct rga_fmt *fmt;
>  	u32 min_width = hw->min_width;
>  	u32 max_width = hw->max_width;
>  	u32 min_height = hw->min_height;
>  	u32 max_height = hw->max_height;
>  
> -	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> -	if (!fmt)
> -		fmt = &hw->formats[0];
> +	hw->adjust_and_map_format(pix_fmt,
> +				  V4L2_TYPE_IS_OUTPUT(f->type));
>  
>  	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
>  	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
> @@ -425,7 +406,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	frm = rga_get_frame(ctx, f->type);
>  	if (IS_ERR(frm))
>  		return PTR_ERR(frm);
> -	frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
> +	frm->fmt = rga->hw->adjust_and_map_format(pix_fmt,
> +						  V4L2_TYPE_IS_OUTPUT(f->type));
>  
>  	/* Reset crop settings */
>  	frm->crop.left = 0;
> @@ -438,7 +420,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  	v4l2_dbg(debug, 1, &rga->v4l2_dev,
>  		 "[%s] fmt - %p4cc %dx%d (stride %d)\n",
>  		  V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
> -		  &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
> +		  &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
>  		  pix_fmt->plane_fmt[0].bytesperline);
>  
>  	for (i = 0; i < pix_fmt->num_planes; i++) {
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index a7f891b94a478..980f70f842317 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -17,22 +17,12 @@
>  #define DEFAULT_WIDTH 100
>  #define DEFAULT_HEIGHT 100
>  
> -struct rga_fmt {
> -	u32 fourcc;
> -	int depth;
> -	u8 uv_factor;
> -	u8 y_div;
> -	u8 x_div;
> -	u8 color_swap;
> -	u8 hw_format;
> -};

Ah! here's the removal of the unused variable. Not review friendly, but at last
removed.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> -
>  struct rga_frame {
>  	/* Crop */
>  	struct v4l2_rect crop;
>  
>  	/* Image format */
> -	struct rga_fmt *fmt;
> +	void *fmt;
>  	struct v4l2_pix_format_mplane pix;
>  };
>  
> @@ -145,8 +135,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>  struct rga_hw {
>  	const char *card_type;
>  	bool has_internal_iommu;
> -	struct rga_fmt *formats;
> -	u32 num_formats;
>  	size_t cmdbuf_size;
>  	u32 min_width, min_height;
>  	u32 max_width, max_height;
> @@ -158,6 +146,9 @@ struct rga_hw {
>  		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
>  	bool (*handle_irq)(struct rockchip_rga *rga);
>  	void (*get_version)(struct rockchip_rga *rga);
> +	void *(*adjust_and_map_format)(struct v4l2_pix_format_mplane *format,
> +				       bool is_output);
> +	int (*enum_format)(struct v4l2_fmtdesc *f);
>  };
>  
>  static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 19/22] media: rockchip: rga: add feature flags
  2025-12-03 15:52 ` [PATCH v2 19/22] media: rockchip: rga: add feature flags Sven Püschel
@ 2025-12-24 16:00   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 16:00 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 4267 bytes --]

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> In preparation to the RGA3 addition add feature flags, which can limit
> the exposed feature set of the video device, like rotating or selection
> support. This is necessary as the RGA3 doesn't initially implement the
> full feature set currently exposed by the driver.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga-hw.c |  4 ++++
>  drivers/media/platform/rockchip/rga/rga.c    | 23 +++++++++++++++--------
>  drivers/media/platform/rockchip/rga/rga.h    |  7 +++++++
>  3 files changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c
> b/drivers/media/platform/rockchip/rga/rga-hw.c
> index a868a34a1452e..0d1cf911af0d5 100644
> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
> @@ -658,6 +658,10 @@ const struct rga_hw rga2_hw = {
>  	.max_height = MAX_HEIGHT,
>  	.max_scaling_factor = MAX_SCALING_FACTOR,
>  	.stride_alignment = 4,
> +	.features = RGA_FEATURE_FLIP
> +		  | RGA_FEATURE_ROTATE
> +		  | RGA_FEATURE_BG_COLOR
> +		  | RGA_FEATURE_SELECTION,
>  
>  	.setup_cmdbuf = rga_hw_setup_cmdbuf,
>  	.start = rga_hw_start,
> diff --git a/drivers/media/platform/rockchip/rga/rga.c
> b/drivers/media/platform/rockchip/rga/rga.c
> index c991cc64b4b7f..3958e71b8987d 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -162,17 +162,21 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
>  
>  	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
>  
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			  V4L2_CID_HFLIP, 0, 1, 1, 0);
> +	if (rga->hw->features & RGA_FEATURE_FLIP) {
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				  V4L2_CID_HFLIP, 0, 1, 1, 0);
>  
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			  V4L2_CID_VFLIP, 0, 1, 1, 0);
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				  V4L2_CID_VFLIP, 0, 1, 1, 0);
> +	}
>  
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			  V4L2_CID_ROTATE, 0, 270, 90, 0);
> +	if (rga->hw->features & RGA_FEATURE_ROTATE)
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				  V4L2_CID_ROTATE, 0, 270, 90, 0);
>  
> -	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> -			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
> +	if (rga->hw->features & RGA_FEATURE_BG_COLOR)
> +		v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
> +				  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
>  
>  	if (ctx->ctrl_handler.error) {
>  		int err = ctx->ctrl_handler.error;
> @@ -489,6 +493,9 @@ static int vidioc_s_selection(struct file *file, void
> *priv,
>  	struct rga_frame *f;
>  	int ret = 0;
>  
> +	if (!(rga->hw->features & RGA_FEATURE_SELECTION))
> +		return -EINVAL;
> +
>  	f = rga_get_frame(ctx, s->type);
>  	if (IS_ERR(f))
>  		return PTR_ERR(f);
> diff --git a/drivers/media/platform/rockchip/rga/rga.h
> b/drivers/media/platform/rockchip/rga/rga.h
> index 980f70f842317..b9c75b5fda4dc 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -6,6 +6,7 @@
>  #ifndef __RGA_H__
>  #define __RGA_H__
>  
> +#include <linux/bits.h>
>  #include <linux/clk.h>
>  #include <linux/platform_device.h>
>  #include <media/videobuf2-v4l2.h>
> @@ -132,6 +133,11 @@ static inline void rga_mod(struct rockchip_rga *rga, u32
> reg, u32 val, u32 mask)
>  	rga_write(rga, reg, temp);
>  };
>  
> +#define RGA_FEATURE_FLIP	BIT(0)
> +#define RGA_FEATURE_ROTATE	BIT(1)
> +#define RGA_FEATURE_BG_COLOR	BIT(2)
> +#define RGA_FEATURE_SELECTION	BIT(3)
> +
>  struct rga_hw {
>  	const char *card_type;
>  	bool has_internal_iommu;
> @@ -140,6 +146,7 @@ struct rga_hw {
>  	u32 max_width, max_height;
>  	u8 max_scaling_factor;
>  	u8 stride_alignment;
> +	u8 features;
>  
>  	void (*setup_cmdbuf)(struct rga_ctx *ctx);
>  	void (*start)(struct rockchip_rga *rga,

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 20/22] media: rockchip: rga: disable multi-core support
  2025-12-03 15:52 ` [PATCH v2 20/22] media: rockchip: rga: disable multi-core support Sven Püschel
@ 2025-12-24 16:02   ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 16:02 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 2232 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Disable multi-core support in preparation of the RGA3 addition. The
> RK3588 SoC features two equal RGA3 cores. This allows scheduling of the
> work between both cores, which is not yet implemented. Until it is
> implemented avoid exposing both cores as independent video devices to
> prevent an ABI breakage when multi-core support is added.

Please add a Link: and reference to the Hantro patch from which is code is from.

> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

> ---
>  drivers/media/platform/rockchip/rga/rga.c | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
> 
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 3958e71b8987d..65686228b7300 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -660,6 +660,30 @@ static int rga_parse_dt(struct rockchip_rga *rga)
>  	return 0;
>  }
>  
> +static int rga_disable_multicore(struct device *dev)
> +{
> +	const char *compatible;
> +	struct device_node *node;
> +	int ret;
> +
> +	/* Intentionally ignores the fallback strings */
> +	ret = of_property_read_string(dev->of_node, "compatible", &compatible);
> +	if (ret)
> +		return ret;
> +
> +	/* first compatible node found from the root node is considered the main core */
> +	node = of_find_compatible_node(NULL, NULL, compatible);
> +	if (!node)
> +		return -EINVAL; /* broken DT? */
> +
> +	if (dev->of_node != node) {
> +		dev_info(dev, "missing multi-core support, ignoring this instance\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
>  static int rga_probe(struct platform_device *pdev)
>  {
>  	struct rockchip_rga *rga;
> @@ -670,6 +694,10 @@ static int rga_probe(struct platform_device *pdev)
>  	if (!pdev->dev.of_node)
>  		return -ENODEV;
>  
> +	ret = rga_disable_multicore(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
>  	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
>  	if (!rga)
>  		return -ENOMEM;

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 21/22] media: rockchip: rga: add rga3 support
  2025-12-03 15:52 ` [PATCH v2 21/22] media: rockchip: rga: add rga3 support Sven Püschel
@ 2025-12-24 16:34   ` Nicolas Dufresne
  2026-01-21 14:40     ` Sven Püschel
  0 siblings, 1 reply; 52+ messages in thread
From: Nicolas Dufresne @ 2025-12-24 16:34 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 26192 bytes --]

Hi,

Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
> Add support for the RGA3 unit contained in the RK3588.
> 
> Only a basic feature set consisting of scaling and color conversion is
> implemented. Also the BT601F color space conversion is currently hard
> coded. Currently unimplemented features include:
> - Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
> - Colorspace conversions functions BT601L, BT709, BT2020

This one I already raised in v1 as problematic omission. I applied the changes
locally and just ran few conversions that I saved to PNG, and I could
immediately see that range handling and colors are all over the place. Comparing
reference against conversion very often show difference in brighness or small
discoloration. On top of which, the compliance is failing.

More investigation needed, but I suspect the implementation is a little too
loose. Not handling any of it while accepting to do YCbCr to RGB (or vis-versa)
incorrect and should be fixed.

> - Background color (V4L2_CID_BG_COLOR)
> - Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
> - Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
> - Image rotation (V4L2_CID_ROTATE)
> - Image cropping/composing (VIDIOC_S_SELECTION)
> 
> The register address defines were copied from the
> vendor Rockchip kernel sources and slightly adjusted to not start at 0
> again for the cmd registers.
> 
> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
> ---
>  drivers/media/platform/rockchip/rga/Makefile  |   2 +-
>  drivers/media/platform/rockchip/rga/rga.c     |   4 +
>  drivers/media/platform/rockchip/rga/rga.h     |   2 +-
>  drivers/media/platform/rockchip/rga/rga3-hw.c | 471 ++++++++++++++++++++++++++
>  drivers/media/platform/rockchip/rga/rga3-hw.h | 190 +++++++++++
>  5 files changed, 667 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
> index 1bbecdc3d8df2..7326a548f3dc7 100644
> --- a/drivers/media/platform/rockchip/rga/Makefile
> +++ b/drivers/media/platform/rockchip/rga/Makefile
> @@ -1,4 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> -rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
> +rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
>  
>  obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
> index 65686228b7300..313d875c789bf 100644
> --- a/drivers/media/platform/rockchip/rga/rga.c
> +++ b/drivers/media/platform/rockchip/rga/rga.c
> @@ -843,6 +843,10 @@ static const struct of_device_id rockchip_rga_match[] = {
>  		.compatible = "rockchip,rk3399-rga",
>  		.data = &rga2_hw,
>  	},
> +	{
> +		.compatible = "rockchip,rk3588-rga3",
> +		.data = &rga3_hw,
> +	},
>  	{},
>  };
>  
> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
> index b9c75b5fda4dc..2c5f0330879fa 100644
> --- a/drivers/media/platform/rockchip/rga/rga.h
> +++ b/drivers/media/platform/rockchip/rga/rga.h
> @@ -163,6 +163,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
>  	return rga->hw->has_internal_iommu;
>  }
>  
> -extern const struct rga_hw rga2_hw;
> +extern const struct rga_hw rga2_hw, rga3_hw;

nit: Add a line instead.

>  
>  #endif
> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
> new file mode 100644
> index 0000000000000..2b8cd639da39b
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
> @@ -0,0 +1,471 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) Pengutronix e.K.

No year ?

> + * Author: Sven Püschel <s.pueschel@pengutronix.de>
> + */
> +
> +#include <linux/pm_runtime.h>
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/printk.h>
> +
> +#include <media/v4l2-common.h>
> +
> +#include "rga3-hw.h"
> +#include "rga.h"
> +
> +static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
> +{
> +	/*
> +	 * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
> +	 * of the TRM Part 2. The resulting scaling factor is a 16-bit value
> +	 * and therefore normalized with 2^16.
> +	 *
> +	 * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
> +	 * it didn't work as the value always exceeds 16 bit. Flipping the
> +	 * factors results in a correct up-scaling. This is possible as the
> +	 * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
> +	 * an up or downscale.
> +	 *
> +	 * With a scaling factor of 1.0 the calculation technically also
> +	 * overflows 16 bit. This isn't relevant, as in this case the
> +	 * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
> +	 */
> +	if (dst > src) {
> +		if (((src - 1) << 16) % (dst - 1) == 0)
> +			return ((src - 1) << 16) / (dst - 1) - 1;
> +		else
> +			return ((src - 1) << 16) / (dst - 1);
> +	} else {
> +		return ((dst - 1) << 16) / (src - 1) + 1;
> +	}
> +}
> +
> +/*
> + * Check if the given format can be captured, as the RGA3 doesn't support all
> + * input formats also on it's output.
> + */
> +static bool rga3_can_capture(const struct rga3_fmt *fmt)
> +{
> +	return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
> +}
> +
> +/*
> + * Map the transformations to the RGA3 command buffer.
> + * Currently this is just the scaling settings and a fixed alpha value.
> + */
> +static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int src_h, src_w, dst_h, dst_w;
> +	unsigned int reg;
> +	u16 hor_scl_fac, ver_scl_fac;
> +	const struct rga3_fmt *in = ctx->in.fmt;
> +
> +	src_h = ctx->in.pix.height;
> +	src_w = ctx->in.pix.width;
> +	dst_h = ctx->out.pix.height;
> +	dst_w = ctx->out.pix.width;

These are padded dimensions, I think there should be code here that go pick from
the selection rectangles. Can't skip that, its way too common to have 1088 src_h
as an example. Otherwise, its not clear what will be result of using a scaling
factor while doing 1088 -> 1080, where the 8 lines are actually padding.

> +
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
> +		      |  FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
> +		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
> +		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
> +
> +	hor_scl_fac = rga3_get_scaling(src_w, dst_w);
> +	ver_scl_fac = rga3_get_scaling(src_h, dst_h);
> +	reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
> +		      | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
> +
> +	if (v4l2_format_info(in->fourcc)->has_alpha) {
> +		/* copy alpha from input */
> +		reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
> +			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
> +		reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
> +			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
> +	} else {
> +		/* just use a 255 alpha value */
> +		reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
> +			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
> +		reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
> +			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
> +	}
> +}
> +
> +static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
> +				   const struct rga_addrs *addrs)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->y_addr;
> +	reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->u_addr;
> +}
> +
> +static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
> +				 const struct rga_addrs *addrs)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->y_addr;
> +	reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = addrs->u_addr;
> +}
> +
> +/* Map the input pixel format to win0 of the comamnd buffer. */
> +static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	const struct rga3_fmt *in = ctx->in.fmt;
> +	const struct rga3_fmt *out = ctx->out.fmt;
> +	const struct v4l2_format_info *in_fmt, *out_fmt;
> +	unsigned int src_h, src_w;
> +	bool r2y, y2r;
> +	u8 rd_format;
> +	unsigned int reg;
> +
> +	src_h = ctx->in.pix.height;
> +	src_w = ctx->in.pix.width;
> +
> +	in_fmt = v4l2_format_info(in->fourcc);
> +	out_fmt = v4l2_format_info(out->fourcc);
> +	r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
> +	y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
> +
> +	if (in->semi_planar)
> +		rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
> +	else
> +		rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
> +
> +	/* set pixel format and CSC */
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
> +		      |  FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
> +		      |  FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
> +		      |  FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
> +		      |  FIELD_PREP(RGA3_WIN_R2Y, r2y)
> +		      |  FIELD_PREP(RGA3_WIN_Y2R, y2r)
> +		      |  FIELD_PREP(RGA3_WIN_CSC_MODE, RGA3_WIN_CSC_MODE_BT601_F);

I'd say don't hardcode BT601 Full-Range. This in fact explains a lot of the
weird stuff I've seen so far.

This IP is extremely limited in CSC, it would be good to limite the choice in
try_fmt. Basically BT601 is the only thing that support full range, where the
more common BT709 and 2020 coeffiicent are most commonly used. Fortunatly,
limited range is more common, I can only guess, but RGB is likely always full
range.

I'm guessing when doing YCbCr to YCbCr the CSC is untouched. Make sure the
capture and output format reflects that.

Nicolas

> +
> +	/* set stride */
> +	reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* stride needs to be in words */
> +	cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
> +	reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* The Hardware only supports formats with 1/2 planes */
> +	if (ctx->in.pix.num_planes == 2)
> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
> +	else
> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
> +
> +	/* set size */
> +	reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
> +		      | FIELD_PREP(RGA3_HEIGHT, src_h);
> +	/* no cropping support. Use same value as ACT_SIZE */
> +	reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
> +		      | FIELD_PREP(RGA3_HEIGHT, src_h);
> +}
> +
> +static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
> +}
> +
> +/* Map the output pixel format to the command buffer */
> +static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	const struct rga3_fmt *out = ctx->out.fmt;
> +	unsigned int dst_h, dst_w;
> +	u8 wr_format;
> +	unsigned int reg;
> +
> +	dst_h = ctx->out.pix.height;
> +	dst_w = ctx->out.pix.width;
> +
> +	if (out->semi_planar)
> +		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
> +	else
> +		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
> +
> +	/* set pixel format */
> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
> +		      |  FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
> +		      |  FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
> +		      |  FIELD_PREP(RGA3_WR_FORMAT, wr_format);
> +
> +	/* set stride */
> +	reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* stride needs to be in words */
> +	cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
> +	reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
> +	/* The Hardware only supports formats with 1/2 planes */
> +	if (ctx->out.pix.num_planes == 2)
> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
> +	else
> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
> +
> +	/* Set size.
> +	 * As two inputs are not supported, we don't use win1.
> +	 * Therefore only set the size for win0.
> +	 */
> +	reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
> +		      | FIELD_PREP(RGA3_HEIGHT, dst_h);
> +}
> +
> +static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
> +{
> +	u32 *cmd = ctx->cmdbuf_virt;
> +	unsigned int reg;
> +
> +	/* Use the max value to avoid limiting the write speed */
> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
> +}
> +
> +static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
> +{
> +	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
> +
> +	rga3_cmd_set_win0_format(ctx);
> +	rga3_cmd_enable_win0(ctx);
> +	rga3_cmd_set_trans_info(ctx);
> +	rga3_cmd_set_wr_format(ctx);
> +	rga3_cmd_disable_wr_limitation(ctx);
> +}
> +
> +static void rga3_hw_start(struct rockchip_rga *rga,
> +			  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
> +{
> +	struct rga_ctx *ctx = rga->curr;
> +
> +	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
> +	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
> +
> +	rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
> +
> +	/* sync CMD buf for RGA */
> +	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
> +				   PAGE_SIZE, DMA_BIDIRECTIONAL);
> +
> +	/* set to master mode and start the conversion */
> +	rga_write(rga, RGA3_SYS_CTRL,
> +		  FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
> +	rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
> +	rga_write(rga, RGA3_CMD_CTRL,
> +		  FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
> +}
> +
> +static bool rga3_handle_irq(struct rockchip_rga *rga)
> +{
> +	u32 intr;
> +
> +	intr = rga_read(rga, RGA3_INT_RAW);
> +	/* clear all interrupts */
> +	rga_write(rga, RGA3_INT_CLR, intr);
> +
> +	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
> +}
> +
> +static void rga3_get_version(struct rockchip_rga *rga)
> +{
> +	u32 version = rga_read(rga, RGA3_VERSION_NUM);
> +
> +	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
> +	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
> +}
> +
> +static struct rga3_fmt rga3_formats[] = {
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB24,
> +		.hw_format = RGA3_COLOR_FMT_BGR888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGR24,
> +		.hw_format = RGA3_COLOR_FMT_BGR888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_ABGR32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGBA32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XBGR32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGBX32,
> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_RGB565,
> +		.hw_format = RGA3_COLOR_FMT_BGR565,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12M,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV12,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21M,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV21,
> +		.hw_format = RGA3_COLOR_FMT_YUV420,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16M,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV16,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61M,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_NV61,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +		.semi_planar = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YUYV,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.yc_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_YVYU,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.yc_swap = 1,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_UYVY,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_VYUY,
> +		.hw_format = RGA3_COLOR_FMT_YUV422,
> +		.rbuv_swap = 1,
> +	},
> +	/* Input only formats last to keep rga3_enum_format simple */
> +	{
> +		.fourcc = V4L2_PIX_FMT_ARGB32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGRA32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_XRGB32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +		.rbuv_swap = 1,
> +	},
> +	{
> +		.fourcc = V4L2_PIX_FMT_BGRX32,
> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
> +	},
> +};
> +
> +static int rga3_enum_format(struct v4l2_fmtdesc *f)
> +{
> +	struct rga3_fmt *fmt;
> +
> +	if (f->index >= ARRAY_SIZE(rga3_formats))
> +		return -EINVAL;
> +
> +	fmt = &rga3_formats[f->index];
> +	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
> +		return -EINVAL;
> +
> +	f->pixelformat = fmt->fourcc;
> +	return 0;
> +}
> +
> +static void *rga3_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
> +					bool is_output)
> +{
> +	unsigned int i;
> +
> +	if (!format)
> +		return &rga3_formats[0];
> +
> +	format->ycbcr_enc = V4L2_YCBCR_ENC_601;
> +	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> +
> +	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
> +		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
> +			continue;
> +
> +		if (rga3_formats[i].fourcc == format->pixelformat)
> +			return &rga3_formats[i];
> +	}
> +
> +	format->pixelformat = rga3_formats[0].fourcc;
> +	return &rga3_formats[0];
> +}
> +
> +const struct rga_hw rga3_hw = {
> +	.card_type = "rga3",
> +	.has_internal_iommu = false,
> +	.cmdbuf_size = RGA3_CMDBUF_SIZE,
> +	.min_width = RGA3_MIN_WIDTH,
> +	.min_height = RGA3_MIN_HEIGHT,
> +	/* use output size, as it's a bit smaller than the input size */
> +	.max_width = RGA3_MAX_OUTPUT_WIDTH,
> +	.max_height = RGA3_MAX_OUTPUT_HEIGHT,
> +	.max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
> +	.stride_alignment = 16,
> +	.features = 0,
> +
> +	.setup_cmdbuf = rga3_hw_setup_cmdbuf,
> +	.start = rga3_hw_start,
> +	.handle_irq = rga3_handle_irq,
> +	.get_version = rga3_get_version,
> +	.enum_format = rga3_enum_format,
> +	.adjust_and_map_format = rga3_adjust_and_map_format,
> +};
> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
> new file mode 100644
> index 0000000000000..fa16b95fb43ba
> --- /dev/null
> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
> @@ -0,0 +1,190 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) Pengutronix e.K.
> + * Author: Sven Püschel <s.pueschel@pengutronix.de>
> + */
> +#ifndef __RGA3_HW_H__
> +#define __RGA3_HW_H__
> +
> +#include <linux/bits.h>
> +#include <linux/types.h>
> +
> +#define RGA3_CMDBUF_SIZE 0x2e
> +
> +#define RGA3_MIN_WIDTH 128
> +#define RGA3_MIN_HEIGHT 128
> +#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
> +#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
> +#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
> +#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
> +#define RGA3_MAX_SCALING_FACTOR 8
> +#define RGA3_RESET_TIMEOUT 1000
> +
> +/* Registers address */
> +/* sys reg */
> +#define RGA3_SYS_CTRL				0x000
> +#define RGA3_CMD_CTRL				0x004
> +#define RGA3_CMD_ADDR				0x008
> +#define RGA3_MI_GROUP_CTRL			0x00c
> +#define RGA3_ARQOS_CTRL				0x010
> +#define RGA3_VERSION_NUM			0x018
> +#define RGA3_VERSION_TIM			0x01c
> +#define RGA3_INT_EN				0x020
> +#define RGA3_INT_RAW				0x024
> +#define RGA3_INT_MSK				0x028
> +#define RGA3_INT_CLR				0x02c
> +#define RGA3_RO_SRST				0x030
> +#define RGA3_STATUS0				0x034
> +#define RGA3_SCAN_CNT				0x038
> +#define RGA3_CMD_STATE				0x040
> +
> +/* cmd reg */
> +#define RGA3_WIN0_RD_CTRL			0x100
> +#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
> +#define RGA3_WIN0_Y_BASE			0x110
> +#define RGA3_WIN0_U_BASE			0x114
> +#define RGA3_WIN0_V_BASE			0x118
> +#define RGA3_WIN0_VIR_STRIDE			0x11c
> +#define RGA3_WIN0_FBC_OFF			0x120
> +#define RGA3_WIN0_SRC_SIZE			0x124
> +#define RGA3_WIN0_ACT_OFF			0x128
> +#define RGA3_WIN0_ACT_SIZE			0x12c
> +#define RGA3_WIN0_DST_SIZE			0x130
> +#define RGA3_WIN0_SCL_FAC			0x134
> +#define RGA3_WIN0_UV_VIR_STRIDE			0x138
> +#define RGA3_WIN1_RD_CTRL			0x140
> +#define RGA3_WIN1_Y_BASE			0x150
> +#define RGA3_WIN1_U_BASE			0x154
> +#define RGA3_WIN1_V_BASE			0x158
> +#define RGA3_WIN1_VIR_STRIDE			0x15c
> +#define RGA3_WIN1_FBC_OFF			0x160
> +#define RGA3_WIN1_SRC_SIZE			0x164
> +#define RGA3_WIN1_ACT_OFF			0x168
> +#define RGA3_WIN1_ACT_SIZE			0x16c
> +#define RGA3_WIN1_DST_SIZE			0x170
> +#define RGA3_WIN1_SCL_FAC			0x174
> +#define RGA3_WIN1_UV_VIR_STRIDE			0x178
> +#define RGA3_OVLP_CTRL				0x180
> +#define RGA3_OVLP_OFF				0x184
> +#define RGA3_OVLP_TOP_KEY_MIN			0x188
> +#define RGA3_OVLP_TOP_KEY_MAX			0x18c
> +#define RGA3_OVLP_TOP_CTRL			0x190
> +#define RGA3_OVLP_BOT_CTRL			0x194
> +#define RGA3_OVLP_TOP_ALPHA			0x198
> +#define RGA3_OVLP_BOT_ALPHA			0x19c
> +#define RGA3_WR_CTRL				0x1a0
> +#define RGA3_WR_FBCE_CTRL			0x1a4
> +#define RGA3_WR_VIR_STRIDE			0x1a8
> +#define RGA3_WR_PL_VIR_STRIDE			0x1ac
> +#define RGA3_WR_Y_BASE				0x1b0
> +#define RGA3_WR_U_BASE				0x1b4
> +#define RGA3_WR_V_BASE				0x1b8
> +
> +/* Registers value */
> +#define RGA3_COLOR_FMT_YUV420		0x0
> +#define RGA3_COLOR_FMT_YUV422		0x1
> +#define RGA3_COLOR_FMT_YUV420_10B	0x2
> +#define RGA3_COLOR_FMT_YUV422_10B	0x3
> +/*
> + * Use memory ordering names
> + * instead of the datasheet naming RGB formats in big endian order
> + */
> +#define RGA3_COLOR_FMT_BGR565		0x4
> +#define RGA3_COLOR_FMT_BGR888		0x5
> +#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
> +#define RGA3_COLOR_FMT_BGRA8888		0x6
> +#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
> +/* the following are only supported as inputs */
> +#define RGA3_COLOR_FMT_ABGR8888		0x7
> +/*
> + * the following seem to be unnecessary,
> + * as they can be achieved with RB swaps
> + */
> +#define RGA3_COLOR_FMT_RGBA8888		0x8
> +#define RGA3_COLOR_FMT_ARGB8888		0x9
> +
> +#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
> +#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
> +
> +#define RGA3_CMD_MODE_MASTER 0x1
> +
> +#define RGA3_WIN_CSC_MODE_BT601_F 0x2
> +
> +/* RGA masks */
> +/* SYS_CTRL */
> +#define RGA3_CCLK_SRESET BIT(4)
> +#define RGA3_ACLK_SRESET BIT(3)
> +#define RGA3_CMD_MODE BIT(1)
> +
> +/* CMD_CTRL */
> +#define RGA3_CMD_LINE_START_PULSE BIT(0)
> +
> +/* VERSION_NUM */
> +#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
> +#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
> +
> +/* INT_* */
> +#define RGA3_INT_FRM_DONE BIT(0)
> +#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
> +#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
> +#define RGA3_INT_WIN0_HOR_ERR BIT(6)
> +#define RGA3_INT_WIN0_VER_ERR BIT(7)
> +#define RGA3_INT_WR_VER_ERR BIT(13)
> +#define RGA3_INT_WR_HOR_ERR BIT(14)
> +#define RGA3_INT_WR_BUS_ERR BIT(15)
> +#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
> +#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
> +#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
> +#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
> +#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
> +#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
> +
> +/* RO_SRST */
> +#define RGA3_RO_SRST_DONE GENMASK(5, 0)
> +
> +/* *_SIZE */
> +#define RGA3_HEIGHT GENMASK(28, 16)
> +#define RGA3_WIDTH GENMASK(12, 0)
> +
> +/* SCL_FAC */
> +#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
> +#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
> +
> +/* WINx_CTRL */
> +#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
> +#define RGA3_WIN_R2Y BIT(25)
> +#define RGA3_WIN_Y2R BIT(24)
> +#define RGA3_WIN_SCALE_VER_UP BIT(23)
> +#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
> +#define RGA3_WIN_SCALE_HOR_UP BIT(21)
> +#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
> +#define RGA3_WIN_YC_SWAP BIT(13)
> +#define RGA3_WIN_RBUV_SWAP BIT(12)
> +#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
> +#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
> +#define RGA3_WIN_ENABLE BIT(0)
> +
> +/* COLOR_CTRL */
> +#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
> +#define RGA3_OVLP_COLOR_MODE BIT(0)
> +
> +/* ALPHA_CTRL */
> +#define RGA3_ALPHA_SELECT_MODE BIT(4)
> +#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
> +
> +/* WR_CTRL */
> +#define RGA3_WR_YC_SWAP BIT(20)
> +#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
> +#define RGA3_WR_RBUV_SWAP BIT(12)
> +#define RGA3_WR_FORMAT GENMASK(9, 8)
> +#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
> +
> +struct rga3_fmt {
> +	u32 fourcc;
> +	u8 hw_format;
> +	bool rbuv_swap;
> +	bool yc_swap;
> +	bool semi_planar;
> +};
> +
> +#endif

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon
  2025-12-24 15:29   ` Nicolas Dufresne
@ 2026-01-07 12:00     ` Sven Püschel
  0 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2026-01-07 12:00 UTC (permalink / raw)
  To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

Hi,

On 12/24/25 4:29 PM, Nicolas Dufresne wrote:
> Hi,
>
> Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
>> Prepare the command buffer on streamon to reuse it's contents instead of
>> completely writing it for every frame. Due to the stream settings being
>> fixed after a streamon we only need to replace the source and destination
>> addresses for each frame. This reduces the amount of CPU and memory
>> operations done in each frame.
> My speculation is that flushing to device is usually more expensive then this,

Yeah, it was an idea to maybe get a bit more performance. I didn't see a 
performance improvement after implementing it.

But I thought that it could be beneficial when the CPU is fully loaded 
(instead of my small test with an idle CPU). Therefore I've left it in.

Sincerely
     Sven

> but I didn't check closely if you have enabled the caches. That being said, this
> is good change. It highlight the inflexible nature of V4L2 imho, which in this
> case can be used to optimize.
>
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
>
>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
>>   drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
>>   drivers/media/platform/rockchip/rga/rga.c    | 13 ++++++++++++-
>>   drivers/media/platform/rockchip/rga/rga.h    |  1 +
>>   3 files changed, 22 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
>> index 56a2558539bfb..8cdfe089fd636 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
>> @@ -408,8 +408,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>>   {
>>   	struct rockchip_rga *rga = ctx->rga;
>>   
>> -	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
>> -
>>   	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
>>   	/*
>>   	 * Due to hardware bug,
>> @@ -418,11 +416,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>>   	rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
>>   
>>   	rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
>> -	rga_cmd_set_mode(ctx);
>>   
>>   	rga_cmd_set_src_info(ctx, &src->offset);
>>   	rga_cmd_set_dst_info(ctx, &dst->offset);
>> -	rga_cmd_set_trans_info(ctx);
>>   
>>   	rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
>>   
>> @@ -431,6 +427,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
>>   				   PAGE_SIZE, DMA_BIDIRECTIONAL);
>>   }
>>   
>> +static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
>> +{
>> +	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
>> +
>> +	rga_cmd_set_mode(ctx);
>> +	rga_cmd_set_trans_info(ctx);
>> +}
>> +
>>   static void rga_hw_start(struct rockchip_rga *rga,
>>   			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
>>   {
>> @@ -622,6 +626,7 @@ const struct rga_hw rga2_hw = {
>>   	.max_height = MAX_HEIGHT,
>>   	.stride_alignment = 4,
>>   
>> +	.setup_cmdbuf = rga_hw_setup_cmdbuf,
>>   	.start = rga_hw_start,
>>   	.handle_irq = rga_handle_irq,
>>   	.get_version = rga_get_version,
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
>> index 592c977a07cf3..f02ae02de26ca 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -523,6 +523,17 @@ static int vidioc_s_selection(struct file *file, void *priv,
>>   	return ret;
>>   }
>>   
>> +static int vidioc_streamon(struct file *file, void *priv,
>> +			   enum v4l2_buf_type type)
>> +{
>> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
>> +	const struct rga_hw *hw = ctx->rga->hw;
>> +
>> +	hw->setup_cmdbuf(ctx);
>> +
>> +	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
>> +}
>> +
>>   static const struct v4l2_ioctl_ops rga_ioctl_ops = {
>>   	.vidioc_querycap = vidioc_querycap,
>>   
>> @@ -547,7 +558,7 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
>>   	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
>>   	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>>   
>> -	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
>> +	.vidioc_streamon = vidioc_streamon,
>>   	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
>>   
>>   	.vidioc_g_selection = vidioc_g_selection,
>> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
>> index 0aef348dddb95..93162b118d069 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.h
>> +++ b/drivers/media/platform/rockchip/rga/rga.h
>> @@ -154,6 +154,7 @@ struct rga_hw {
>>   	u32 max_width, max_height;
>>   	u8 stride_alignment;
>>   
>> +	void (*setup_cmdbuf)(struct rga_ctx *ctx);
>>   	void (*start)(struct rockchip_rga *rga,
>>   		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
>>   	bool (*handle_irq)(struct rockchip_rga *rga);

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

* Re: [PATCH v2 14/22] media: rockchip: rga: support external iommus
  2025-12-24 15:50   ` Nicolas Dufresne
@ 2026-01-07 14:19     ` Sven Püschel
  2026-01-07 14:24       ` Nicolas Dufresne
  0 siblings, 1 reply; 52+ messages in thread
From: Sven Püschel @ 2026-01-07 14:19 UTC (permalink / raw)
  To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

Hi,

On 12/24/25 4:50 PM, Nicolas Dufresne wrote:
> Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
>> In preparation for the RGA3 add support for external iommus. This is a
>> transition step to just disable the RGA2 specific mmu table setup code.
>>
>> Currently a simple rga_hw struct field is used to set the internal iommu.
>> But to handle the case of more sophisticated detection mechanisms
>> (e.g. check for an iommu property in the device tree), it is abstracted
>> by an inline function.
>>
>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
>>   drivers/media/platform/rockchip/rga/rga-buf.c | 46 ++++++++++++++++-----------
>>   drivers/media/platform/rockchip/rga/rga-hw.c  |  1 +
>>   drivers/media/platform/rockchip/rga/rga.c     | 11 +++++--
>>   drivers/media/platform/rockchip/rga/rga.h     |  6 ++++
>>   4 files changed, 43 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
>> index 8845e1f894f29..e8d1e2e579140 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-buf.c
>> +++ b/drivers/media/platform/rockchip/rga/rga-buf.c
>> @@ -12,6 +12,7 @@
>>   #include <media/v4l2-ioctl.h>
>>   #include <media/v4l2-mem2mem.h>
>>   #include <media/videobuf2-dma-sg.h>
>> +#include <media/videobuf2-dma-contig.h>
>>   #include <media/videobuf2-v4l2.h>
>>   
>>   #include "rga.h"
>> @@ -79,14 +80,16 @@ static int rga_buf_init(struct vb2_buffer *vb)
>>   	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
>>   	size_t n_desc = 0;
>>   
>> -	n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
>> +	if (rga_has_internal_iommu(rga)) {
>> +		n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> n_desc is not used outside of this scope, perhap drop the definition with the 0
> init, and use:
>
> 		const size_t n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
> 		
>>   
>> -	rbuf->n_desc = n_desc;
>> -	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
>> -					    rbuf->n_desc * sizeof(*rbuf->dma_desc),
>> -					    &rbuf->dma_desc_pa, GFP_KERNEL);
>> -	if (!rbuf->dma_desc)
>> -		return -ENOMEM;
>> +		rbuf->n_desc = n_desc;
>> +		rbuf->dma_desc = dma_alloc_coherent(rga->dev,
>> +						    rbuf->n_desc * sizeof(*rbuf->dma_desc),
>> +						    &rbuf->dma_desc_pa, GFP_KERNEL);
>> +		if (!rbuf->dma_desc)
>> +			return -ENOMEM;
>> +	}
>>   
>>   	return 0;
>>   }
>> @@ -133,17 +136,21 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
>>   	for (i = 0; i < vb->num_planes; i++) {
>>   		vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
>>   
>> -		/* Create local MMU table for RGA */
>> -		n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
>> -					  rbuf->n_desc - curr_desc,
>> -					  vb2_dma_sg_plane_desc(vb, i));
>> -		if (n_desc < 0) {
>> -			v4l2_err(&ctx->rga->v4l2_dev,
>> -				 "Failed to map video buffer to RGA\n");
>> -			return n_desc;
>> +		if (rga_has_internal_iommu(ctx->rga)) {
>> +			/* Create local MMU table for RGA */
>> +			n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
>> +						  rbuf->n_desc - curr_desc,
>> +						  vb2_dma_sg_plane_desc(vb, i));
>> +			if (n_desc < 0) {
>> +				v4l2_err(&ctx->rga->v4l2_dev,
>> +					 "Failed to map video buffer to RGA\n");
>> +				return n_desc;
>> +			}
>> +			dma_addrs[i] = curr_desc << PAGE_SHIFT;
>> +			curr_desc += n_desc;
>> +		} else {
>> +			dma_addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i);
>>   		}
>> -		dma_addrs[i] = curr_desc << PAGE_SHIFT;
>> -		curr_desc += n_desc;
>>   	}
>>   
>>   	/* Fill the remaining planes */
>> @@ -173,8 +180,9 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
>>   	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>>   	struct rockchip_rga *rga = ctx->rga;
>>   
>> -	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
>> -			  rbuf->dma_desc, rbuf->dma_desc_pa);
>> +	if (rga_has_internal_iommu(rga))
>> +		dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
>> +				  rbuf->dma_desc, rbuf->dma_desc_pa);
>>   }
>>   
>>   static void rga_buf_return_buffers(struct vb2_queue *q,
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
>> index fe6f518aedd4e..fb0389ae8e132 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
>> @@ -617,6 +617,7 @@ static struct rga_fmt formats[] = {
>>   
>>   const struct rga_hw rga2_hw = {
>>   	.card_type = "rga2",
>> +	.has_internal_iommu = true,
>>   	.formats = formats,
>>   	.num_formats = ARRAY_SIZE(formats),
>>   	.cmdbuf_size = RGA_CMDBUF_SIZE,
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
>> index c9719c7bcfc1c..f28ec88c186fa 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -23,6 +23,7 @@
>>   #include <media/v4l2-ioctl.h>
>>   #include <media/v4l2-mem2mem.h>
>>   #include <media/videobuf2-dma-sg.h>
>> +#include <media/videobuf2-dma-contig.h>
>>   #include <media/videobuf2-v4l2.h>
>>   
>>   #include "rga.h"
>> @@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
>>   	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>>   	src_vq->drv_priv = ctx;
>>   	src_vq->ops = &rga_qops;
>> -	src_vq->mem_ops = &vb2_dma_sg_memops;
>> +	src_vq->mem_ops = &vb2_dma_contig_memops;
> That's a bit I'm less knowledgeable here, since I never used the sg_memops in
> any of my work, but what is the consequence ? (appart from gaining external
> iommu support)

This is only for the external iommu support, which uses the 
vb2_dma_contig_plane_dma_addr function to get a single linear address 
(instead of vb2_dma_sg_plane_desc used for the manual iommu mapping).

Without an external iommu the value is overridden afterwards to 
vb2_dma_sg_memops. I probably should move the if up to make clear that 
this is only set for the external iommu case.

Or did I misunderstand your question?

>>   	src_vq->gfp_flags = __GFP_DMA32;
>>   	src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
>>   	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>>   	src_vq->lock = &ctx->rga->mutex;
>>   	src_vq->dev = ctx->rga->v4l2_dev.dev;
>>   
>> +	if (rga_has_internal_iommu(ctx->rga))
>> +		src_vq->mem_ops = &vb2_dma_sg_memops;
>> +
>>   	ret = vb2_queue_init(src_vq);
>>   	if (ret)
>>   		return ret;
>> @@ -110,13 +114,16 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
>>   	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>>   	dst_vq->drv_priv = ctx;
>>   	dst_vq->ops = &rga_qops;
>> -	dst_vq->mem_ops = &vb2_dma_sg_memops;
>> +	dst_vq->mem_ops = &vb2_dma_contig_memops;
>>   	dst_vq->gfp_flags = __GFP_DMA32;
>>   	dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
>>   	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>>   	dst_vq->lock = &ctx->rga->mutex;
>>   	dst_vq->dev = ctx->rga->v4l2_dev.dev;
>>   
>> +	if (rga_has_internal_iommu(ctx->rga))
>> +		dst_vq->mem_ops = &vb2_dma_sg_memops;
>> +
>>   	return vb2_queue_init(dst_vq);
>>   }
>>   
>> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
>> index 772f7dff9a8e5..fc81bc5562792 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.h
>> +++ b/drivers/media/platform/rockchip/rga/rga.h
>> @@ -148,6 +148,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>>   
>>   struct rga_hw {
>>   	const char *card_type;
>> +	bool has_internal_iommu;
>>   	struct rga_fmt *formats;
>>   	u32 num_formats;
>>   	size_t cmdbuf_size;
>> @@ -163,6 +164,11 @@ struct rga_hw {
>>   	void (*get_version)(struct rockchip_rga *rga);
>>   };
>>   
>> +static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
>> +{
>> +	return rga->hw->has_internal_iommu;
>> +}
>> +
>>   extern const struct rga_hw rga2_hw;
>>   
>>   #endif

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

* Re: [PATCH v2 14/22] media: rockchip: rga: support external iommus
  2026-01-07 14:19     ` Sven Püschel
@ 2026-01-07 14:24       ` Nicolas Dufresne
  0 siblings, 0 replies; 52+ messages in thread
From: Nicolas Dufresne @ 2026-01-07 14:24 UTC (permalink / raw)
  To: Sven Püschel, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

[-- Attachment #1: Type: text/plain, Size: 1286 bytes --]

Hi,

Le mercredi 07 janvier 2026 à 15:19 +0100, Sven Püschel a écrit :
> > > @@ -95,13 +96,16 @@ queue_init(void *priv, struct vb2_queue *src_vq,
> > > struct vb2_queue *dst_vq)
> > >    	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> > >    	src_vq->drv_priv = ctx;
> > >    	src_vq->ops = &rga_qops;
> > > -	src_vq->mem_ops = &vb2_dma_sg_memops;
> > > +	src_vq->mem_ops = &vb2_dma_contig_memops;
> > That's a bit I'm less knowledgeable here, since I never used the sg_memops
> > in
> > any of my work, but what is the consequence ? (appart from gaining external
> > iommu support)
> 
> This is only for the external iommu support, which uses the 
> vb2_dma_contig_plane_dma_addr function to get a single linear address 
> (instead of vb2_dma_sg_plane_desc used for the manual iommu mapping).
> 
> Without an external iommu the value is overridden afterwards to 
> vb2_dma_sg_memops. I probably should move the if up to make clear that 
> this is only set for the external iommu case.
> 
> Or did I misunderstand your question?

That was it, I read quickly thinking it was always vb2_dma_contig_memops now,
regardless which iommu implementation is used. If you can make it clearer that
the ops depends on the context, that would be great.

Nicolas

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h
  2025-12-24 15:59   ` Nicolas Dufresne
@ 2026-01-07 14:52     ` Sven Püschel
  0 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2026-01-07 14:52 UTC (permalink / raw)
  To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

Hi,

On 12/24/25 4:59 PM, Nicolas Dufresne wrote:
> Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
>> Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
>> contains many RGA2 specific values. They are used to write the correct
>> register values quickly based on the chosen format. Therefore the
>> pointer to the rga_fmt struct is kept but changed to an opaque void
>> pointer outside of the rga-hw.h.
[...]
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
>> index fffcab0131225..3bc4b1f5acba2 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
>> @@ -6,6 +6,8 @@
>>   #ifndef __RGA_HW_H__
>>   #define __RGA_HW_H__
>>   
>> +#include <linux/types.h>
>> +
>>   #define RGA_CMDBUF_SIZE 0x20
>>   
>>   /* Hardware limits */
>> @@ -431,4 +433,14 @@ union rga_pat_con {
>>   	} data;
>>   };
>>   
>> +struct rga_fmt {
>> +	u32 fourcc;
>> +	int depth;
>> +	u8 uv_factor;
>> +	u8 y_div;
>> +	u8 x_div;
>> +	u8 color_swap;
>> +	u8 hw_format;
>> +};

[...]

>>   
>> -struct rga_fmt {
>> -	u32 fourcc;
>> -	int depth;
>> -	u8 uv_factor;
>> -	u8 y_div;
>> -	u8 x_div;
>> -	u8 color_swap;
>> -	u8 hw_format;
>> -};
> Ah! here's the removal of the unused variable. Not review friendly, but at last
> removed.

I've just moved it, so your review comments are still right. x_div/y_div 
is still used at one place in rga_hw.c, but I'll remove it too in my v3 
(and have these removals in the other commits to keep this reviewed-by).

Sincerely
     Sven

>
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
>
>> -
>>   struct rga_frame {
>>   	/* Crop */
>>   	struct v4l2_rect crop;
>>   
>>   	/* Image format */
>> -	struct rga_fmt *fmt;
>> +	void *fmt;
>>   	struct v4l2_pix_format_mplane pix;
>>   };
>>   
>> @@ -145,8 +135,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>>   struct rga_hw {
>>   	const char *card_type;
>>   	bool has_internal_iommu;
>> -	struct rga_fmt *formats;
>> -	u32 num_formats;
>>   	size_t cmdbuf_size;
>>   	u32 min_width, min_height;
>>   	u32 max_width, max_height;
>> @@ -158,6 +146,9 @@ struct rga_hw {
>>   		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
>>   	bool (*handle_irq)(struct rockchip_rga *rga);
>>   	void (*get_version)(struct rockchip_rga *rga);
>> +	void *(*adjust_and_map_format)(struct v4l2_pix_format_mplane *format,
>> +				       bool is_output);
>> +	int (*enum_format)(struct v4l2_fmtdesc *f);
>>   };
>>   
>>   static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)

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

* Re: [PATCH v2 11/22] media: rockchip: rga: check scaling factor
  2025-12-24 15:39   ` Nicolas Dufresne
@ 2026-01-09 12:18     ` Sven Püschel
  0 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2026-01-09 12:18 UTC (permalink / raw)
  To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

On 12/24/25 4:39 PM, Nicolas Dufresne wrote:

> Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
>> Check the scaling factor to avoid potential problems. This is relevant
>> for the upcoming RGA3 support, as it can hang when the scaling factor
>> is exceeded.
>>
>> There are two relevant scenarios that have to be considered to protect
>> against invalid scaling values:
>>
>> When the output or capture is already streaming, setting the format on
>> the other side should consider the max scaling factor and clamp it
>> accordingly. This is only done in the streaming case, as it otherwise
>> may unintentionally clamp the value when the application sets the first
>> format (due to a default format on the other side).
>>
>> When the format is set on both sides first, then the format won't be
>> corrected by above means. Therefore the second streamon call has to
>> check the scaling factor and fail otherwise.
> In codec specifications, we resolve this issue by resetting the capture format
> every-time the output format is set. But without specification for color
> transforms, its impossible to say if this is right or wrong, and I don't expect
> perfect interroperability between drivers until someone make the effort to
> specify this type of hardware.
>
> What you describe is fine of course, but its a bit off nature of the way format
> is normally being fixed by the driver to stay valid.

thanks for the info. Given the missing spec, I'd keep it at the current 
unusual implementation unless I'd need to adjust it for the try_fmt 
state issue.

>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
>>   drivers/media/platform/rockchip/rga/rga-hw.c |  1 +
>>   drivers/media/platform/rockchip/rga/rga-hw.h |  1 +
>>   drivers/media/platform/rockchip/rga/rga.c    | 60 +++++++++++++++++++++++++---
>>   drivers/media/platform/rockchip/rga/rga.h    |  1 +
>>   4 files changed, 58 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
>> index 8cdfe089fd636..2ed4f22a999d5 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.c
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.c
>> @@ -624,6 +624,7 @@ const struct rga_hw rga2_hw = {
>>   	.max_width = MAX_WIDTH,
>>   	.min_height = MIN_HEIGHT,
>>   	.max_height = MAX_HEIGHT,
>> +	.max_scaling_factor = MAX_SCALING_FACTOR,
>>   	.stride_alignment = 4,
>>   
>>   	.setup_cmdbuf = rga_hw_setup_cmdbuf,
>> diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
>> index f4752aa823051..fffcab0131225 100644
>> --- a/drivers/media/platform/rockchip/rga/rga-hw.h
>> +++ b/drivers/media/platform/rockchip/rga/rga-hw.h
>> @@ -14,6 +14,7 @@
>>   
>>   #define MIN_WIDTH 34
>>   #define MIN_HEIGHT 34
>> +#define MAX_SCALING_FACTOR 16
>>   
>>   #define RGA_TIMEOUT 500
>>   
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
>> index f02ae02de26ca..46dc94db6f85e 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -346,18 +346,47 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>>   static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
>>   {
>>   	struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
>> -	struct rockchip_rga *rga = video_drvdata(file);
>> +	struct rga_ctx *ctx = file_to_rga_ctx(file);
>> +	struct rockchip_rga *rga = ctx->rga;
>>   	const struct rga_hw *hw = rga->hw;
>>   	struct rga_fmt *fmt;
>> +	u32 min_width = hw->min_width;
>> +	u32 max_width = hw->max_width;
>> +	u32 min_height = hw->min_height;
>> +	u32 max_height = hw->max_height;
>>   
>>   	fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
>>   	if (!fmt)
>>   		fmt = &hw->formats[0];
>>   
>> -	pix_fmt->width = clamp(pix_fmt->width,
>> -			       hw->min_width, hw->max_width);
>> -	pix_fmt->height = clamp(pix_fmt->height,
>> -				hw->min_height, hw->max_height);
>> +	if (V4L2_TYPE_IS_OUTPUT(f->type) &&
>> +	    v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) {
> What if userspace wanted to get the buffer size computed, so it can allocate
> externally before it calls streamoff ? Hans did mention recently that try
> function should only be state aware if specified.

My plan is to move the try logic into a separate helper function with an 
additional boolean parameter depending on which I do the state aware 
adjustments. And then call this helper with false for try_fmt and true 
for set_fmt.

Or is this also problematic as it violates the contract that try_fmt is 
equivalent to set_fmt?

>
> I'd like other reviewers feedback on what should be done here, of course writing
> a spec would be ideal.
>
> Nicolas
>
>> +		min_width =
>> +			MAX(min_width, DIV_ROUND_UP(ctx->out.pix.width,
>> +						    hw->max_scaling_factor));
>> +		max_width = MIN(max_width,
>> +				ctx->out.pix.width * hw->max_scaling_factor);
>> +		min_height =
>> +			MAX(min_height, DIV_ROUND_UP(ctx->out.pix.height,
>> +						     hw->max_scaling_factor));
>> +		max_height = MIN(max_height,
>> +				 ctx->out.pix.height * hw->max_scaling_factor);
>> +	} else if (V4L2_TYPE_IS_CAPTURE(f->type) &&
>> +		   v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming) {
>> +		min_width =
>> +			MAX(min_width, DIV_ROUND_UP(ctx->in.pix.width,
>> +						    hw->max_scaling_factor));
>> +		max_width = MIN(max_width,
>> +				ctx->in.pix.width * hw->max_scaling_factor);
>> +		min_height =
>> +			MAX(min_height, DIV_ROUND_UP(ctx->in.pix.height,
>> +						     hw->max_scaling_factor));
>> +		max_height = MIN(max_height,
>> +				 ctx->in.pix.height * hw->max_scaling_factor);
>> +	}
>> +
>> +	pix_fmt->width = clamp(pix_fmt->width, min_width, max_width);
>> +	pix_fmt->height = clamp(pix_fmt->height, min_height, max_height);
>>   
>>   	v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
>>   				    pix_fmt->width, pix_fmt->height, hw->stride_alignment);
>> @@ -523,12 +552,33 @@ static int vidioc_s_selection(struct file *file, void *priv,
>>   	return ret;
>>   }
>>   
>> +static bool check_scaling(const struct rga_hw *hw, u32 src_size, u32 dst_size)
>> +{
>> +	if (src_size < dst_size)
>> +		return src_size * hw->max_scaling_factor >= dst_size;
>> +	else
>> +		return dst_size * hw->max_scaling_factor >= src_size;
>> +}
>> +
>>   static int vidioc_streamon(struct file *file, void *priv,
>>   			   enum v4l2_buf_type type)
>>   {
>>   	struct rga_ctx *ctx = file_to_rga_ctx(file);
>>   	const struct rga_hw *hw = ctx->rga->hw;
>>   
>> +	if ((V4L2_TYPE_IS_OUTPUT(type) &&
>> +	     v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)->streaming) ||
>> +	    (V4L2_TYPE_IS_CAPTURE(type) &&
>> +	     v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)->streaming)) {
>> +		/*
>> +		 * As the other side is already streaming,
>> +		 * check that the max scaling factor isn't exceeded.
>> +		 */
>> +		if (!check_scaling(hw, ctx->in.pix.width, ctx->out.pix.width) ||
>> +		    !check_scaling(hw, ctx->in.pix.height, ctx->out.pix.height))
>> +			return -EINVAL;
>> +	}
>> +
>>   	hw->setup_cmdbuf(ctx);
>>   
>>   	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
>> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
>> index 93162b118d069..d02d5730b4e3b 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.h
>> +++ b/drivers/media/platform/rockchip/rga/rga.h
>> @@ -152,6 +152,7 @@ struct rga_hw {
>>   	size_t cmdbuf_size;
>>   	u32 min_width, min_height;
>>   	u32 max_width, max_height;
>> +	u8 max_scaling_factor;
>>   	u8 stride_alignment;
>>   
>>   	void (*setup_cmdbuf)(struct rga_ctx *ctx);

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

* Re: [PATCH v2 21/22] media: rockchip: rga: add rga3 support
  2025-12-24 16:34   ` Nicolas Dufresne
@ 2026-01-21 14:40     ` Sven Püschel
  0 siblings, 0 replies; 52+ messages in thread
From: Sven Püschel @ 2026-01-21 14:40 UTC (permalink / raw)
  To: Nicolas Dufresne, Jacob Chen, Ezequiel Garcia,
	Mauro Carvalho Chehab, Heiko Stuebner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
	devicetree, kernel

Hi Nicolas,

On 12/24/25 5:34 PM, Nicolas Dufresne wrote:
> Hi,
>
> Le mercredi 03 décembre 2025 à 16:52 +0100, Sven Püschel a écrit :
>> Add support for the RGA3 unit contained in the RK3588.
>>
>> Only a basic feature set consisting of scaling and color conversion is
>> implemented. Also the BT601F color space conversion is currently hard
>> coded. Currently unimplemented features include:
>> - Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
>> - Colorspace conversions functions BT601L, BT709, BT2020
> This one I already raised in v1 as problematic omission. I applied the changes
> locally and just ran few conversions that I saved to PNG, and I could
> immediately see that range handling and colors are all over the place. Comparing
> reference against conversion very often show difference in brighness or small
> discoloration. On top of which, the compliance is failing.
>
> More investigation needed, but I suspect the implementation is a little too
> loose. Not handling any of it while accepting to do YCbCr to RGB (or vis-versa)
> incorrect and should be fixed.

While I don't know how you tested this, I've reproduced your findings 
with the following gstreamer 1.26 pipeline:

gst-launch-1.0 videotestsrc num-buffers=1 ! 
video/x-raw,format=RGBA,width=128,height=128 ! v4l2convert ! 
video/x-raw,format=YUY2 ! videoconvert ! video/x-raw,format=RGBA ! 
pngenc ! filesink location=/tmp/test.png

After debugging the GStreamer pipeline, I've found that it didn't 
consider the colorspace from the driver on it's src pad. Therefore it 
didn't properly add it to the YUY2 caps, which caused the RGA3 driver to 
do BT601 full range and videoconvert the default colorspace (i think 
BT601 limited range). See [1], which fixes the problem.

I'd be interested if this also fixes the issue(s) you've noticed.


Sincerely
     Sven

[1] 
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10582

>> - Background color (V4L2_CID_BG_COLOR)
>> - Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
>> - Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
>> - Image rotation (V4L2_CID_ROTATE)
>> - Image cropping/composing (VIDIOC_S_SELECTION)
>>
>> The register address defines were copied from the
>> vendor Rockchip kernel sources and slightly adjusted to not start at 0
>> again for the cmd registers.
>>
>> Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
>> ---
>>   drivers/media/platform/rockchip/rga/Makefile  |   2 +-
>>   drivers/media/platform/rockchip/rga/rga.c     |   4 +
>>   drivers/media/platform/rockchip/rga/rga.h     |   2 +-
>>   drivers/media/platform/rockchip/rga/rga3-hw.c | 471 ++++++++++++++++++++++++++
>>   drivers/media/platform/rockchip/rga/rga3-hw.h | 190 +++++++++++
>>   5 files changed, 667 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
>> index 1bbecdc3d8df2..7326a548f3dc7 100644
>> --- a/drivers/media/platform/rockchip/rga/Makefile
>> +++ b/drivers/media/platform/rockchip/rga/Makefile
>> @@ -1,4 +1,4 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>> -rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
>> +rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
>>   
>>   obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
>> diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
>> index 65686228b7300..313d875c789bf 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.c
>> +++ b/drivers/media/platform/rockchip/rga/rga.c
>> @@ -843,6 +843,10 @@ static const struct of_device_id rockchip_rga_match[] = {
>>   		.compatible = "rockchip,rk3399-rga",
>>   		.data = &rga2_hw,
>>   	},
>> +	{
>> +		.compatible = "rockchip,rk3588-rga3",
>> +		.data = &rga3_hw,
>> +	},
>>   	{},
>>   };
>>   
>> diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
>> index b9c75b5fda4dc..2c5f0330879fa 100644
>> --- a/drivers/media/platform/rockchip/rga/rga.h
>> +++ b/drivers/media/platform/rockchip/rga/rga.h
>> @@ -163,6 +163,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
>>   	return rga->hw->has_internal_iommu;
>>   }
>>   
>> -extern const struct rga_hw rga2_hw;
>> +extern const struct rga_hw rga2_hw, rga3_hw;
> nit: Add a line instead.
>
>>   
>>   #endif
>> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
>> new file mode 100644
>> index 0000000000000..2b8cd639da39b
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
>> @@ -0,0 +1,471 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (C) Pengutronix e.K.
> No year ?
>
>> + * Author: Sven Püschel <s.pueschel@pengutronix.de>
>> + */
>> +
>> +#include <linux/pm_runtime.h>
>> +#include <linux/bitfield.h>
>> +#include <linux/delay.h>
>> +#include <linux/printk.h>
>> +
>> +#include <media/v4l2-common.h>
>> +
>> +#include "rga3-hw.h"
>> +#include "rga.h"
>> +
>> +static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
>> +{
>> +	/*
>> +	 * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
>> +	 * of the TRM Part 2. The resulting scaling factor is a 16-bit value
>> +	 * and therefore normalized with 2^16.
>> +	 *
>> +	 * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
>> +	 * it didn't work as the value always exceeds 16 bit. Flipping the
>> +	 * factors results in a correct up-scaling. This is possible as the
>> +	 * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
>> +	 * an up or downscale.
>> +	 *
>> +	 * With a scaling factor of 1.0 the calculation technically also
>> +	 * overflows 16 bit. This isn't relevant, as in this case the
>> +	 * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
>> +	 */
>> +	if (dst > src) {
>> +		if (((src - 1) << 16) % (dst - 1) == 0)
>> +			return ((src - 1) << 16) / (dst - 1) - 1;
>> +		else
>> +			return ((src - 1) << 16) / (dst - 1);
>> +	} else {
>> +		return ((dst - 1) << 16) / (src - 1) + 1;
>> +	}
>> +}
>> +
>> +/*
>> + * Check if the given format can be captured, as the RGA3 doesn't support all
>> + * input formats also on it's output.
>> + */
>> +static bool rga3_can_capture(const struct rga3_fmt *fmt)
>> +{
>> +	return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
>> +}
>> +
>> +/*
>> + * Map the transformations to the RGA3 command buffer.
>> + * Currently this is just the scaling settings and a fixed alpha value.
>> + */
>> +static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	unsigned int src_h, src_w, dst_h, dst_w;
>> +	unsigned int reg;
>> +	u16 hor_scl_fac, ver_scl_fac;
>> +	const struct rga3_fmt *in = ctx->in.fmt;
>> +
>> +	src_h = ctx->in.pix.height;
>> +	src_w = ctx->in.pix.width;
>> +	dst_h = ctx->out.pix.height;
>> +	dst_w = ctx->out.pix.width;
> These are padded dimensions, I think there should be code here that go pick from
> the selection rectangles. Can't skip that, its way too common to have 1088 src_h
> as an example. Otherwise, its not clear what will be result of using a scaling
> factor while doing 1088 -> 1080, where the 8 lines are actually padding.
>
>> +
>> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
>> +		      |  FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
>> +		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
>> +		      |  FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
>> +
>> +	hor_scl_fac = rga3_get_scaling(src_w, dst_w);
>> +	ver_scl_fac = rga3_get_scaling(src_h, dst_h);
>> +	reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
>> +		      | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
>> +
>> +	if (v4l2_format_info(in->fourcc)->has_alpha) {
>> +		/* copy alpha from input */
>> +		reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
>> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
>> +			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
>> +		reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
>> +		cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
>> +			      | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
>> +	} else {
>> +		/* just use a 255 alpha value */
>> +		reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
>> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
>> +			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
>> +		reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
>> +		cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
>> +			      | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
>> +	}
>> +}
>> +
>> +static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
>> +				   const struct rga_addrs *addrs)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = addrs->y_addr;
>> +	reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = addrs->u_addr;
>> +}
>> +
>> +static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
>> +				 const struct rga_addrs *addrs)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = addrs->y_addr;
>> +	reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = addrs->u_addr;
>> +}
>> +
>> +/* Map the input pixel format to win0 of the comamnd buffer. */
>> +static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	const struct rga3_fmt *in = ctx->in.fmt;
>> +	const struct rga3_fmt *out = ctx->out.fmt;
>> +	const struct v4l2_format_info *in_fmt, *out_fmt;
>> +	unsigned int src_h, src_w;
>> +	bool r2y, y2r;
>> +	u8 rd_format;
>> +	unsigned int reg;
>> +
>> +	src_h = ctx->in.pix.height;
>> +	src_w = ctx->in.pix.width;
>> +
>> +	in_fmt = v4l2_format_info(in->fourcc);
>> +	out_fmt = v4l2_format_info(out->fourcc);
>> +	r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
>> +	y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
>> +
>> +	if (in->semi_planar)
>> +		rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
>> +	else
>> +		rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
>> +
>> +	/* set pixel format and CSC */
>> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
>> +		      |  FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
>> +		      |  FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
>> +		      |  FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
>> +		      |  FIELD_PREP(RGA3_WIN_R2Y, r2y)
>> +		      |  FIELD_PREP(RGA3_WIN_Y2R, y2r)
>> +		      |  FIELD_PREP(RGA3_WIN_CSC_MODE, RGA3_WIN_CSC_MODE_BT601_F);
> I'd say don't hardcode BT601 Full-Range. This in fact explains a lot of the
> weird stuff I've seen so far.
>
> This IP is extremely limited in CSC, it would be good to limite the choice in
> try_fmt. Basically BT601 is the only thing that support full range, where the
> more common BT709 and 2020 coeffiicent are most commonly used. Fortunatly,
> limited range is more common, I can only guess, but RGB is likely always full
> range.
>
> I'm guessing when doing YCbCr to YCbCr the CSC is untouched. Make sure the
> capture and output format reflects that.
>
> Nicolas
>
>> +
>> +	/* set stride */
>> +	reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
>> +	/* stride needs to be in words */
>> +	cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
>> +	reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
>> +	/* The Hardware only supports formats with 1/2 planes */
>> +	if (ctx->in.pix.num_planes == 2)
>> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
>> +	else
>> +		cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
>> +
>> +	/* set size */
>> +	reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
>> +		      | FIELD_PREP(RGA3_HEIGHT, src_h);
>> +	/* no cropping support. Use same value as ACT_SIZE */
>> +	reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
>> +		      | FIELD_PREP(RGA3_HEIGHT, src_h);
>> +}
>> +
>> +static void rga3_cmd_enable_win0(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1);
>> +}
>> +
>> +/* Map the output pixel format to the command buffer */
>> +static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	const struct rga3_fmt *out = ctx->out.fmt;
>> +	unsigned int dst_h, dst_w;
>> +	u8 wr_format;
>> +	unsigned int reg;
>> +
>> +	dst_h = ctx->out.pix.height;
>> +	dst_w = ctx->out.pix.width;
>> +
>> +	if (out->semi_planar)
>> +		wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
>> +	else
>> +		wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
>> +
>> +	/* set pixel format */
>> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
>> +		      |  FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
>> +		      |  FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
>> +		      |  FIELD_PREP(RGA3_WR_FORMAT, wr_format);
>> +
>> +	/* set stride */
>> +	reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
>> +	/* stride needs to be in words */
>> +	cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
>> +	reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
>> +	/* The Hardware only supports formats with 1/2 planes */
>> +	if (ctx->out.pix.num_planes == 2)
>> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
>> +	else
>> +		cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
>> +
>> +	/* Set size.
>> +	 * As two inputs are not supported, we don't use win1.
>> +	 * Therefore only set the size for win0.
>> +	 */
>> +	reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
>> +		      | FIELD_PREP(RGA3_HEIGHT, dst_h);
>> +}
>> +
>> +static void rga3_cmd_disable_wr_limitation(struct rga_ctx *ctx)
>> +{
>> +	u32 *cmd = ctx->cmdbuf_virt;
>> +	unsigned int reg;
>> +
>> +	/* Use the max value to avoid limiting the write speed */
>> +	reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
>> +	cmd[reg >> 2] |= FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
>> +}
>> +
>> +static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
>> +{
>> +	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE * 4);
>> +
>> +	rga3_cmd_set_win0_format(ctx);
>> +	rga3_cmd_enable_win0(ctx);
>> +	rga3_cmd_set_trans_info(ctx);
>> +	rga3_cmd_set_wr_format(ctx);
>> +	rga3_cmd_disable_wr_limitation(ctx);
>> +}
>> +
>> +static void rga3_hw_start(struct rockchip_rga *rga,
>> +			  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
>> +{
>> +	struct rga_ctx *ctx = rga->curr;
>> +
>> +	rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
>> +	rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
>> +
>> +	rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
>> +
>> +	/* sync CMD buf for RGA */
>> +	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
>> +				   PAGE_SIZE, DMA_BIDIRECTIONAL);
>> +
>> +	/* set to master mode and start the conversion */
>> +	rga_write(rga, RGA3_SYS_CTRL,
>> +		  FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
>> +	rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
>> +	rga_write(rga, RGA3_CMD_CTRL,
>> +		  FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
>> +}
>> +
>> +static bool rga3_handle_irq(struct rockchip_rga *rga)
>> +{
>> +	u32 intr;
>> +
>> +	intr = rga_read(rga, RGA3_INT_RAW);
>> +	/* clear all interrupts */
>> +	rga_write(rga, RGA3_INT_CLR, intr);
>> +
>> +	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
>> +}
>> +
>> +static void rga3_get_version(struct rockchip_rga *rga)
>> +{
>> +	u32 version = rga_read(rga, RGA3_VERSION_NUM);
>> +
>> +	rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
>> +	rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
>> +}
>> +
>> +static struct rga3_fmt rga3_formats[] = {
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGB24,
>> +		.hw_format = RGA3_COLOR_FMT_BGR888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGR24,
>> +		.hw_format = RGA3_COLOR_FMT_BGR888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_ABGR32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGBA32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_XBGR32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGBX32,
>> +		.hw_format = RGA3_COLOR_FMT_BGRA8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_RGB565,
>> +		.hw_format = RGA3_COLOR_FMT_BGR565,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV12M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV12,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV21M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV21,
>> +		.hw_format = RGA3_COLOR_FMT_YUV420,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV16M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV16,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV61M,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_NV61,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
>> +		.semi_planar = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_YUYV,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.yc_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_YVYU,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.yc_swap = 1,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_UYVY,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_VYUY,
>> +		.hw_format = RGA3_COLOR_FMT_YUV422,
>> +		.rbuv_swap = 1,
>> +	},
>> +	/* Input only formats last to keep rga3_enum_format simple */
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_ARGB32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGRA32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_XRGB32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +		.rbuv_swap = 1,
>> +	},
>> +	{
>> +		.fourcc = V4L2_PIX_FMT_BGRX32,
>> +		.hw_format = RGA3_COLOR_FMT_ABGR8888,
>> +	},
>> +};
>> +
>> +static int rga3_enum_format(struct v4l2_fmtdesc *f)
>> +{
>> +	struct rga3_fmt *fmt;
>> +
>> +	if (f->index >= ARRAY_SIZE(rga3_formats))
>> +		return -EINVAL;
>> +
>> +	fmt = &rga3_formats[f->index];
>> +	if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
>> +		return -EINVAL;
>> +
>> +	f->pixelformat = fmt->fourcc;
>> +	return 0;
>> +}
>> +
>> +static void *rga3_adjust_and_map_format(struct v4l2_pix_format_mplane *format,
>> +					bool is_output)
>> +{
>> +	unsigned int i;
>> +
>> +	if (!format)
>> +		return &rga3_formats[0];
>> +
>> +	format->ycbcr_enc = V4L2_YCBCR_ENC_601;
>> +	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
>> +		if (!is_output && !rga3_can_capture(&rga3_formats[i]))
>> +			continue;
>> +
>> +		if (rga3_formats[i].fourcc == format->pixelformat)
>> +			return &rga3_formats[i];
>> +	}
>> +
>> +	format->pixelformat = rga3_formats[0].fourcc;
>> +	return &rga3_formats[0];
>> +}
>> +
>> +const struct rga_hw rga3_hw = {
>> +	.card_type = "rga3",
>> +	.has_internal_iommu = false,
>> +	.cmdbuf_size = RGA3_CMDBUF_SIZE,
>> +	.min_width = RGA3_MIN_WIDTH,
>> +	.min_height = RGA3_MIN_HEIGHT,
>> +	/* use output size, as it's a bit smaller than the input size */
>> +	.max_width = RGA3_MAX_OUTPUT_WIDTH,
>> +	.max_height = RGA3_MAX_OUTPUT_HEIGHT,
>> +	.max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
>> +	.stride_alignment = 16,
>> +	.features = 0,
>> +
>> +	.setup_cmdbuf = rga3_hw_setup_cmdbuf,
>> +	.start = rga3_hw_start,
>> +	.handle_irq = rga3_handle_irq,
>> +	.get_version = rga3_get_version,
>> +	.enum_format = rga3_enum_format,
>> +	.adjust_and_map_format = rga3_adjust_and_map_format,
>> +};
>> diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
>> new file mode 100644
>> index 0000000000000..fa16b95fb43ba
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
>> @@ -0,0 +1,190 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (C) Pengutronix e.K.
>> + * Author: Sven Püschel <s.pueschel@pengutronix.de>
>> + */
>> +#ifndef __RGA3_HW_H__
>> +#define __RGA3_HW_H__
>> +
>> +#include <linux/bits.h>
>> +#include <linux/types.h>
>> +
>> +#define RGA3_CMDBUF_SIZE 0x2e
>> +
>> +#define RGA3_MIN_WIDTH 128
>> +#define RGA3_MIN_HEIGHT 128
>> +#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
>> +#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
>> +#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
>> +#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
>> +#define RGA3_MAX_SCALING_FACTOR 8
>> +#define RGA3_RESET_TIMEOUT 1000
>> +
>> +/* Registers address */
>> +/* sys reg */
>> +#define RGA3_SYS_CTRL				0x000
>> +#define RGA3_CMD_CTRL				0x004
>> +#define RGA3_CMD_ADDR				0x008
>> +#define RGA3_MI_GROUP_CTRL			0x00c
>> +#define RGA3_ARQOS_CTRL				0x010
>> +#define RGA3_VERSION_NUM			0x018
>> +#define RGA3_VERSION_TIM			0x01c
>> +#define RGA3_INT_EN				0x020
>> +#define RGA3_INT_RAW				0x024
>> +#define RGA3_INT_MSK				0x028
>> +#define RGA3_INT_CLR				0x02c
>> +#define RGA3_RO_SRST				0x030
>> +#define RGA3_STATUS0				0x034
>> +#define RGA3_SCAN_CNT				0x038
>> +#define RGA3_CMD_STATE				0x040
>> +
>> +/* cmd reg */
>> +#define RGA3_WIN0_RD_CTRL			0x100
>> +#define RGA3_FIRST_CMD_REG			RGA3_WIN0_RD_CTRL
>> +#define RGA3_WIN0_Y_BASE			0x110
>> +#define RGA3_WIN0_U_BASE			0x114
>> +#define RGA3_WIN0_V_BASE			0x118
>> +#define RGA3_WIN0_VIR_STRIDE			0x11c
>> +#define RGA3_WIN0_FBC_OFF			0x120
>> +#define RGA3_WIN0_SRC_SIZE			0x124
>> +#define RGA3_WIN0_ACT_OFF			0x128
>> +#define RGA3_WIN0_ACT_SIZE			0x12c
>> +#define RGA3_WIN0_DST_SIZE			0x130
>> +#define RGA3_WIN0_SCL_FAC			0x134
>> +#define RGA3_WIN0_UV_VIR_STRIDE			0x138
>> +#define RGA3_WIN1_RD_CTRL			0x140
>> +#define RGA3_WIN1_Y_BASE			0x150
>> +#define RGA3_WIN1_U_BASE			0x154
>> +#define RGA3_WIN1_V_BASE			0x158
>> +#define RGA3_WIN1_VIR_STRIDE			0x15c
>> +#define RGA3_WIN1_FBC_OFF			0x160
>> +#define RGA3_WIN1_SRC_SIZE			0x164
>> +#define RGA3_WIN1_ACT_OFF			0x168
>> +#define RGA3_WIN1_ACT_SIZE			0x16c
>> +#define RGA3_WIN1_DST_SIZE			0x170
>> +#define RGA3_WIN1_SCL_FAC			0x174
>> +#define RGA3_WIN1_UV_VIR_STRIDE			0x178
>> +#define RGA3_OVLP_CTRL				0x180
>> +#define RGA3_OVLP_OFF				0x184
>> +#define RGA3_OVLP_TOP_KEY_MIN			0x188
>> +#define RGA3_OVLP_TOP_KEY_MAX			0x18c
>> +#define RGA3_OVLP_TOP_CTRL			0x190
>> +#define RGA3_OVLP_BOT_CTRL			0x194
>> +#define RGA3_OVLP_TOP_ALPHA			0x198
>> +#define RGA3_OVLP_BOT_ALPHA			0x19c
>> +#define RGA3_WR_CTRL				0x1a0
>> +#define RGA3_WR_FBCE_CTRL			0x1a4
>> +#define RGA3_WR_VIR_STRIDE			0x1a8
>> +#define RGA3_WR_PL_VIR_STRIDE			0x1ac
>> +#define RGA3_WR_Y_BASE				0x1b0
>> +#define RGA3_WR_U_BASE				0x1b4
>> +#define RGA3_WR_V_BASE				0x1b8
>> +
>> +/* Registers value */
>> +#define RGA3_COLOR_FMT_YUV420		0x0
>> +#define RGA3_COLOR_FMT_YUV422		0x1
>> +#define RGA3_COLOR_FMT_YUV420_10B	0x2
>> +#define RGA3_COLOR_FMT_YUV422_10B	0x3
>> +/*
>> + * Use memory ordering names
>> + * instead of the datasheet naming RGB formats in big endian order
>> + */
>> +#define RGA3_COLOR_FMT_BGR565		0x4
>> +#define RGA3_COLOR_FMT_BGR888		0x5
>> +#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA	RGA3_COLOR_FMT_BGRA8888
>> +#define RGA3_COLOR_FMT_BGRA8888		0x6
>> +#define RGA3_COLOR_FMT_LAST_OUTPUT	RGA3_COLOR_FMT_BGRA8888
>> +/* the following are only supported as inputs */
>> +#define RGA3_COLOR_FMT_ABGR8888		0x7
>> +/*
>> + * the following seem to be unnecessary,
>> + * as they can be achieved with RB swaps
>> + */
>> +#define RGA3_COLOR_FMT_RGBA8888		0x8
>> +#define RGA3_COLOR_FMT_ARGB8888		0x9
>> +
>> +#define RGA3_RDWR_FORMAT_SEMI_PLANAR	0x1
>> +#define RGA3_RDWR_FORMAT_INTERLEAVED	0x2
>> +
>> +#define RGA3_CMD_MODE_MASTER 0x1
>> +
>> +#define RGA3_WIN_CSC_MODE_BT601_F 0x2
>> +
>> +/* RGA masks */
>> +/* SYS_CTRL */
>> +#define RGA3_CCLK_SRESET BIT(4)
>> +#define RGA3_ACLK_SRESET BIT(3)
>> +#define RGA3_CMD_MODE BIT(1)
>> +
>> +/* CMD_CTRL */
>> +#define RGA3_CMD_LINE_START_PULSE BIT(0)
>> +
>> +/* VERSION_NUM */
>> +#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
>> +#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
>> +
>> +/* INT_* */
>> +#define RGA3_INT_FRM_DONE BIT(0)
>> +#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
>> +#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
>> +#define RGA3_INT_WIN0_HOR_ERR BIT(6)
>> +#define RGA3_INT_WIN0_VER_ERR BIT(7)
>> +#define RGA3_INT_WR_VER_ERR BIT(13)
>> +#define RGA3_INT_WR_HOR_ERR BIT(14)
>> +#define RGA3_INT_WR_BUS_ERR BIT(15)
>> +#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
>> +#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
>> +#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
>> +#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
>> +#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
>> +#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
>> +
>> +/* RO_SRST */
>> +#define RGA3_RO_SRST_DONE GENMASK(5, 0)
>> +
>> +/* *_SIZE */
>> +#define RGA3_HEIGHT GENMASK(28, 16)
>> +#define RGA3_WIDTH GENMASK(12, 0)
>> +
>> +/* SCL_FAC */
>> +#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
>> +#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
>> +
>> +/* WINx_CTRL */
>> +#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
>> +#define RGA3_WIN_R2Y BIT(25)
>> +#define RGA3_WIN_Y2R BIT(24)
>> +#define RGA3_WIN_SCALE_VER_UP BIT(23)
>> +#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
>> +#define RGA3_WIN_SCALE_HOR_UP BIT(21)
>> +#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
>> +#define RGA3_WIN_YC_SWAP BIT(13)
>> +#define RGA3_WIN_RBUV_SWAP BIT(12)
>> +#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
>> +#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
>> +#define RGA3_WIN_ENABLE BIT(0)
>> +
>> +/* COLOR_CTRL */
>> +#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
>> +#define RGA3_OVLP_COLOR_MODE BIT(0)
>> +
>> +/* ALPHA_CTRL */
>> +#define RGA3_ALPHA_SELECT_MODE BIT(4)
>> +#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
>> +
>> +/* WR_CTRL */
>> +#define RGA3_WR_YC_SWAP BIT(20)
>> +#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
>> +#define RGA3_WR_RBUV_SWAP BIT(12)
>> +#define RGA3_WR_FORMAT GENMASK(9, 8)
>> +#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
>> +
>> +struct rga3_fmt {
>> +	u32 fourcc;
>> +	u8 hw_format;
>> +	bool rbuv_swap;
>> +	bool yc_swap;
>> +	bool semi_planar;
>> +};
>> +
>> +#endif

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

end of thread, other threads:[~2026-01-21 14:40 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-03 15:52 [PATCH v2 00/22] media: platform: rga: Add RGA3 support Sven Püschel
2025-12-03 15:52 ` [PATCH v2 01/22] media: dt-bindings: media: rockchip-rga: add rockchip,rk3588-rga3 Sven Püschel
2025-12-03 20:28   ` Krzysztof Kozlowski
2025-12-03 21:21     ` Sven Püschel
2025-12-03 15:52 ` [PATCH v2 02/22] media: v4l2-common: add has_alpha to v4l2_format_info Sven Püschel
2025-12-24 14:24   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 03/22] media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper Sven Püschel
2025-12-24 14:47   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 04/22] media: rockchip: rga: use clk_bulk api Sven Püschel
2025-12-24 14:48   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 05/22] media: rockchip: rga: use stride for offset calculation Sven Püschel
2025-12-24 15:00   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 06/22] media: rockchip: rga: remove redundant rga_frame variables Sven Püschel
2025-12-24 15:03   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 07/22] media: rockchip: rga: move hw specific parts to a dedicated struct Sven Püschel
2025-12-24 15:05   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 08/22] media: rockchip: rga: move cmdbuf to rga_ctx Sven Püschel
2025-12-24 15:21   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 09/22] media: rockchip: rga: align stride to 4 bytes Sven Püschel
2025-12-24 15:26   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 10/22] media: rockchip: rga: prepare cmdbuf on streamon Sven Püschel
2025-12-24 15:29   ` Nicolas Dufresne
2026-01-07 12:00     ` Sven Püschel
2025-12-03 15:52 ` [PATCH v2 11/22] media: rockchip: rga: check scaling factor Sven Püschel
2025-12-24 15:39   ` Nicolas Dufresne
2026-01-09 12:18     ` Sven Püschel
2025-12-03 15:52 ` [PATCH v2 12/22] media: rockchip: rga: use card type to specify rga type Sven Püschel
2025-12-24 15:40   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 13/22] media: rockchip: rga: change offset to dma_addresses Sven Püschel
2025-12-24 15:41   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 14/22] media: rockchip: rga: support external iommus Sven Püschel
2025-12-24 15:50   ` Nicolas Dufresne
2026-01-07 14:19     ` Sven Püschel
2026-01-07 14:24       ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 15/22] media: rockchip: rga: share the interrupt when an external iommu is used Sven Püschel
2025-12-24 15:50   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 16/22] media: rockchip: rga: remove size from rga_frame Sven Püschel
2025-12-24 15:54   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 17/22] media: rockchip: rga: remove stride " Sven Püschel
2025-12-24 15:56   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 18/22] media: rockchip: rga: move rga_fmt to rga-hw.h Sven Püschel
2025-12-24 15:59   ` Nicolas Dufresne
2026-01-07 14:52     ` Sven Püschel
2025-12-03 15:52 ` [PATCH v2 19/22] media: rockchip: rga: add feature flags Sven Püschel
2025-12-24 16:00   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 20/22] media: rockchip: rga: disable multi-core support Sven Püschel
2025-12-24 16:02   ` Nicolas Dufresne
2025-12-03 15:52 ` [PATCH v2 21/22] media: rockchip: rga: add rga3 support Sven Püschel
2025-12-24 16:34   ` Nicolas Dufresne
2026-01-21 14:40     ` Sven Püschel
2025-12-03 15:52 ` [PATCH v2 22/22] arm64: dts: rockchip: add rga3 dt nodes Sven Püschel
2025-12-05 22:36 ` [PATCH v2 00/22] media: platform: rga: Add RGA3 support Rob Herring

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

all inboxes | Powered by JetHome®