* [PATCH v9 01/10] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/G3E SoC
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-11-04 10:16 ` Krzysztof Kozlowski
2026-10-23 16:47 ` [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem Tommaso Merciai
` (8 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
The RZ/G3E Soc has 2 LCD controller (LCDC), contain a Frame Compression
Processor (FCPVD), a Video Signal Processor (VSPD), Video Signal
Processor (VSPD), and Display Unit (DU).
- LCDC0 supports DSI and LVDS (single or dual-channel) outputs.
- LCDC1 supports DSI, LVDS (single-channel), and RGB outputs.
Add new SoC-specific compatible string 'renesas,r9a09g047-du'.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- Step back to v5 + added refusal of port3 for others SoCs.
- Adjusted order and ports description.
[v5] https://patchwork.kernel.org/project/linux-renesas-soc/patch/ca022fdbba5236c36e0cb3095db4c31e8e0cb1b8.1770996493.git.tommaso.merciai.xr@bp.renesas.com/
v7->v8:
- Rebased on top of RZ/G3L du support [1]
- Modelled using ports/port instead of port/ep.
[1] https://lore.kernel.org/all/20260826174854.199139-1-biju.das.jz@bp.renesas.com/
- Improved commit msg and commit body.
v6->v7:
- Rebased on top of [1]
[1] https://lore.kernel.org/all/20260429170012.366537-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
- Use single DRM device aggregating both DU instances (1 DU dt node),
modelling single port for each DU0, DU1 and multiple endpoints for
outputs.
v5->v6:
- Extend patternProperties from "^port@[0-1]$" to "^port@[0-3]$" and
explicitly disable port@2 and port@3 for existing SoCs that do not expose
them.
- Reworked ports numbering + improved/fixed ports descriptions in the
bindings documentation.
- Improved commit body.
v4->v5:
- Dropped renesas,id property and updated bindings
accordingly.
v2->v3:
- No changes.
v2->v3:
- No changes.
v1->v2:
- Use single compatible string instead of multiple compatible strings
for the two DU instances, leveraging a 'renesas,id' property to
differentiate between DU0 and DU1.
- Updated commit message accordingly.
.../bindings/display/renesas,rzg2l-du.yaml | 28 ++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml b/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
index 5c9b15a09dee..14315b2898e1 100644
--- a/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
+++ b/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
@@ -21,6 +21,7 @@ properties:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
- renesas,r9a08g046-du # RZ/G3L
+ - renesas,r9a09g047-du # RZ/G3E
- renesas,r9a09g057-du # RZ/V2H(P)
- renesas,r9a09g077-du # RZ/T2H
- items:
@@ -66,7 +67,7 @@ properties:
model-dependent. Each port shall have a single endpoint.
patternProperties:
- "^port@[0-2]$":
+ "^port@[0-3]$":
$ref: /schemas/graph.yaml#/properties/port
unevaluatedProperties: false
@@ -110,6 +111,7 @@ allOf:
description: DPI
port@1: false
port@2: false
+ port@3: false
required:
- port@0
@@ -127,6 +129,7 @@ allOf:
port@1:
description: DPI
port@2: false
+ port@3: false
required:
- port@0
@@ -146,11 +149,33 @@ allOf:
description: DPI
port@2:
description: LVDS
+ port@3: false
required:
- port@0
- port@1
- port@2
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g047-du
+ then:
+ properties:
+ ports:
+ properties:
+ port@0:
+ description: DSI
+ port@1:
+ description: DPAD
+ port@2:
+ description: LVDS 0
+ port@3:
+ description: LVDS 1
+
+ required:
+ - port@0
+ - port@3
- if:
properties:
compatible:
@@ -164,6 +189,7 @@ allOf:
description: DSI
port@1: false
port@2: false
+ port@3: false
required:
- port@0
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v9 01/10] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/G3E SoC
2026-10-23 16:47 ` [PATCH v9 01/10] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/G3E SoC Tommaso Merciai
@ 2026-11-04 10:16 ` Krzysztof Kozlowski
0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-04 10:16 UTC (permalink / raw)
To: Tommaso Merciai
Cc: tomm.merciai, prabhakar.mahadev-lad.rj, linux-renesas-soc,
biju.das.jz, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
Magnus Damm, Laurent Pinchart, dri-devel, devicetree,
linux-kernel
On Fri, Oct 23, 2026 at 06:47:34PM +0200, Tommaso Merciai wrote:
> The RZ/G3E Soc has 2 LCD controller (LCDC), contain a Frame Compression
> Processor (FCPVD), a Video Signal Processor (VSPD), Video Signal
> Processor (VSPD), and Display Unit (DU).
>
> - LCDC0 supports DSI and LVDS (single or dual-channel) outputs.
> - LCDC1 supports DSI, LVDS (single-channel), and RGB outputs.
>
> Add new SoC-specific compatible string 'renesas,r9a09g047-du'.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 01/10] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/G3E SoC Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-11-04 10:19 ` Krzysztof Kozlowski
2026-10-23 16:47 ` [PATCH v9 03/10] drm: renesas: rz-du: vsp: Keep the planes in the VSP Tommaso Merciai
` (7 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
The Renesas RZ/G3E (R9A09G047) SoC has two LCD Controllers, LCDC0 and
LCDC1, each containing a Display Unit (DU). The two DUs are separate
instances of the same IP, with their own registers, interrupt, clocks,
reset and VSP, and are therefore described by two device tree nodes.
The DSI encoder and channel 1 of the LVDS encoder can be fed by either
DU, the source being selected at runtime. Driving those outputs from
either DU requires handling both DUs as a single display subsystem.
Document the renesas,r9a09g047-display-subsystem node that groups the
two Display Unit instances.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch.
.../renesas,r9a09g047-display-subsystem.yaml | 44 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 45 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
diff --git a/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
new file mode 100644
index 000000000000..e23cc53a1fea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/renesas,r9a09g047-display-subsystem.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G3E Display Subsystem
+
+maintainers:
+ - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+
+description:
+ The Renesas RZ/G3E display subsystem is a virtual device needed to list the
+ Display Unit instances that comprise the graphics subsystem.
+
+properties:
+ compatible:
+ const: renesas,r9a09g047-display-subsystem
+
+ ports:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ minItems: 2
+ maxItems: 2
+ items:
+ maxItems: 1
+ description:
+ Should contain a list of phandles pointing to the ports node of the
+ Display Unit devices that comprise the display subsystem. Display Unit
+ definitions as defined in
+ Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
+
+required:
+ - compatible
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ display-subsystem {
+ compatible = "renesas,r9a09g047-display-subsystem";
+ ports = <&du0_ports>, <&du1_ports>;
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 04f465490612..2f4abeb594e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9110,6 +9110,7 @@ L: dri-devel@lists.freedesktop.org
L: linux-renesas-soc@vger.kernel.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
F: Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
F: drivers/gpu/drm/renesas/rz-du/
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem
2026-10-23 16:47 ` [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem Tommaso Merciai
@ 2026-11-04 10:19 ` Krzysztof Kozlowski
2026-11-12 10:32 ` Tommaso Merciai
0 siblings, 1 reply; 14+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-04 10:19 UTC (permalink / raw)
To: Tommaso Merciai
Cc: tomm.merciai, prabhakar.mahadev-lad.rj, linux-renesas-soc,
biju.das.jz, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
Magnus Damm, Laurent Pinchart, dri-devel, devicetree,
linux-kernel
On Fri, Oct 23, 2026 at 06:47:35PM +0200, Tommaso Merciai wrote:
> The Renesas RZ/G3E (R9A09G047) SoC has two LCD Controllers, LCDC0 and
> LCDC1, each containing a Display Unit (DU). The two DUs are separate
> instances of the same IP, with their own registers, interrupt, clocks,
> reset and VSP, and are therefore described by two device tree nodes.
>
> The DSI encoder and channel 1 of the LVDS encoder can be fed by either
> DU, the source being selected at runtime. Driving those outputs from
> either DU requires handling both DUs as a single display subsystem.
>
> Document the renesas,r9a09g047-display-subsystem node that groups the
> two Display Unit instances.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
> v8->v9:
> - New patch.
>
> .../renesas,r9a09g047-display-subsystem.yaml | 44 +++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 45 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
>
> diff --git a/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
> new file mode 100644
> index 000000000000..e23cc53a1fea
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/renesas,r9a09g047-display-subsystem.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Renesas RZ/G3E Display Subsystem
> +
> +maintainers:
> + - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> +
> +description:
> + The Renesas RZ/G3E display subsystem is a virtual device needed to list the
We do not take bindings for virtual devices, because you do not need
them. Instantiate your driver from existing bindings, instead of
creating fake device just for Linux drivers.
> + Display Unit instances that comprise the graphics subsystem.
> +
> +properties:
> + compatible:
> + const: renesas,r9a09g047-display-subsystem
> +
> + ports:
> + $ref: /schemas/types.yaml#/definitions/phandle-array
Properties have only one type and ports is already defined as object for
graph.
Why isn't this a graph?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem
2026-11-04 10:19 ` Krzysztof Kozlowski
@ 2026-11-12 10:32 ` Tommaso Merciai
0 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-11-12 10:32 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: tomm.merciai, prabhakar.mahadev-lad.rj, linux-renesas-soc,
biju.das.jz, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Geert Uytterhoeven,
Magnus Damm, Laurent Pinchart, dri-devel, devicetree,
linux-kernel
Hi Krzysztof,
Thanks for your review.
On Wed, Nov 04, 2026 at 11:19:47AM +0100, Krzysztof Kozlowski wrote:
> On Fri, Oct 23, 2026 at 06:47:35PM +0200, Tommaso Merciai wrote:
> > The Renesas RZ/G3E (R9A09G047) SoC has two LCD Controllers, LCDC0 and
> > LCDC1, each containing a Display Unit (DU). The two DUs are separate
> > instances of the same IP, with their own registers, interrupt, clocks,
> > reset and VSP, and are therefore described by two device tree nodes.
> >
> > The DSI encoder and channel 1 of the LVDS encoder can be fed by either
> > DU, the source being selected at runtime. Driving those outputs from
> > either DU requires handling both DUs as a single display subsystem.
> >
> > Document the renesas,r9a09g047-display-subsystem node that groups the
> > two Display Unit instances.
> >
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > ---
> > v8->v9:
> > - New patch.
> >
> > .../renesas,r9a09g047-display-subsystem.yaml | 44 +++++++++++++++++++
> > MAINTAINERS | 1 +
> > 2 files changed, 45 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
> > new file mode 100644
> > index 000000000000..e23cc53a1fea
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/renesas,r9a09g047-display-subsystem.yaml
> > @@ -0,0 +1,44 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/renesas,r9a09g047-display-subsystem.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Renesas RZ/G3E Display Subsystem
> > +
> > +maintainers:
> > + - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > +
> > +description:
> > + The Renesas RZ/G3E display subsystem is a virtual device needed to list the
>
> We do not take bindings for virtual devices, because you do not need
> them. Instantiate your driver from existing bindings, instead of
> creating fake device just for Linux drivers.
Thanks for sharing.
I will drop this patch into the next version, also I will
instantiate the driver from existing bindings like you suggested.
Kind regards,
Tommaso
>
> > + Display Unit instances that comprise the graphics subsystem.
> > +
> > +properties:
> > + compatible:
> > + const: renesas,r9a09g047-display-subsystem
> > +
> > + ports:
> > + $ref: /schemas/types.yaml#/definitions/phandle-array
>
> Properties have only one type and ports is already defined as object for
> graph.
>
> Why isn't this a graph?
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 03/10] drm: renesas: rz-du: vsp: Keep the planes in the VSP
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 01/10] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/G3E SoC Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 02/10] dt-bindings: display: Document Renesas RZ/G3E display subsystem Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 04/10] drm: renesas: rz-du: Reference the DRM device by pointer Tommaso Merciai
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
Each VSP numbers its planes from zero, so the device-wide search in
rzg2l_du_vsp_get_drm_plane() picks the wrong plane as soon as a SoC has
more than one VSP: the primary plane of the second CRTC is looked up on
the first VSP, whose possible_crtcs mask does not cover that CRTC.
In preparation for supporting RZ/G3E, store the planes in the VSP that
owns them and index the per-VSP array directly from
rzg2l_du_crtc_create(), as the R-Car DU driver does, and drop the now
unused search helper.
No functional change intended.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- Dropped the vsp_pipe bounds check in rzg2l_du_crtc_create() and the
now unused num_planes field, aligning with rcar_du_crtc_create().
- Updated commit message accordingly.
v7->v8:
- New patch.
drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c | 4 +---
drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c | 19 ++-----------------
drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.h | 10 +++-------
3 files changed, 6 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
index ab2f24cc7683..c57884ab5b9b 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
@@ -409,9 +409,7 @@ int rzg2l_du_crtc_create(struct rzg2l_du_device *rcdu)
init_waitqueue_head(&rcrtc->flip_wait);
rcrtc->dev = rcdu;
- primary = rzg2l_du_vsp_get_drm_plane(rcrtc, rcrtc->vsp_pipe);
- if (IS_ERR(primary))
- return PTR_ERR(primary);
+ primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe]->plane;
ret = drmm_crtc_init_with_planes(&rcdu->ddev, crtc, primary, NULL,
&crtc_funcs_rz, NULL);
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
index 944bc9ac9589..12fe35740c62 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
@@ -71,22 +71,6 @@ void rzg2l_du_vsp_atomic_flush(struct rzg2l_du_crtc *crtc)
vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
}
-struct drm_plane *rzg2l_du_vsp_get_drm_plane(struct rzg2l_du_crtc *crtc,
- unsigned int pipe_index)
-{
- struct rzg2l_du_device *rcdu = crtc->vsp->dev;
- struct drm_plane *plane = NULL;
-
- drm_for_each_plane(plane, &rcdu->ddev) {
- struct rzg2l_du_vsp_plane *vsp_plane = to_rzg2l_vsp_plane(plane);
-
- if (vsp_plane->index == pipe_index)
- break;
- }
-
- return plane ? plane : ERR_PTR(-EINVAL);
-}
-
static const u32 rzg2l_du_vsp_formats[] = {
DRM_FORMAT_RGB332,
DRM_FORMAT_ARGB4444,
@@ -303,7 +287,7 @@ int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
struct rzg2l_du_device *rcdu = vsp->dev;
struct platform_device *pdev;
unsigned int num_crtcs = hweight32(crtcs);
- unsigned int num_planes = 2;
+ unsigned int num_planes = RZG2L_DU_VSP_MAX_PLANES;
unsigned int i;
int ret;
@@ -350,6 +334,7 @@ int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
plane->vsp = vsp;
plane->index = i;
+ vsp->planes[i] = plane;
drm_plane_helper_add(&plane->plane,
&rzg2l_du_vsp_plane_helper_funcs);
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.h
index a22aaf0843ed..acb41d343297 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.h
@@ -27,11 +27,14 @@ struct rzg2l_du_vsp_plane {
unsigned int index;
};
+#define RZG2L_DU_VSP_MAX_PLANES 2
+
struct rzg2l_du_vsp {
unsigned int index;
struct device *vsp;
struct device_link *link;
struct rzg2l_du_device *dev;
+ struct rzg2l_du_vsp_plane *planes[RZG2L_DU_VSP_MAX_PLANES];
};
static inline struct rzg2l_du_vsp_plane *to_rzg2l_vsp_plane(struct drm_plane *p)
@@ -62,8 +65,6 @@ int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
void rzg2l_du_vsp_enable(struct rzg2l_du_crtc *crtc);
void rzg2l_du_vsp_disable(struct rzg2l_du_crtc *crtc);
void rzg2l_du_vsp_atomic_flush(struct rzg2l_du_crtc *crtc);
-struct drm_plane *rzg2l_du_vsp_get_drm_plane(struct rzg2l_du_crtc *crtc,
- unsigned int pipe_index);
#else
static inline int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
unsigned int crtcs)
@@ -74,11 +75,6 @@ static inline int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node
static inline void rzg2l_du_vsp_enable(struct rzg2l_du_crtc *crtc) { };
static inline void rzg2l_du_vsp_disable(struct rzg2l_du_crtc *crtc) { };
static inline void rzg2l_du_vsp_atomic_flush(struct rzg2l_du_crtc *crtc) { };
-static inline struct drm_plane *rzg2l_du_vsp_get_drm_plane(struct rzg2l_du_crtc *crtc,
- unsigned int pipe_index)
-{
- return ERR_PTR(-ENXIO);
-}
#endif
#endif /* __RZG2L_DU_VSP_H__ */
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 04/10] drm: renesas: rz-du: Reference the DRM device by pointer
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (2 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 03/10] drm: renesas: rz-du: vsp: Keep the planes in the VSP Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 05/10] drm: renesas: rz-du: Count all registered encoders for the possible clones Tommaso Merciai
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
struct rzg2l_du_device embeds the DRM device, which makes a DU instance
and the DRM device one and the same. RZ/G3E has two instances that have
to share a single DRM device.
In preparation of supporting it, reference the DRM device by pointer and
give it a container of its own. The instance is allocated with the DRM
device rather than with the platform device, as the CRTC and VSP cleanup
handlers point into it and run once the DRM device is released.
No functional change intended.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch.
drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c | 2 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c | 39 ++++++++++++-------
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h | 7 +---
.../gpu/drm/renesas/rz-du/rzg2l_du_encoder.c | 8 ++--
.../gpu/drm/renesas/rz-du/rzg2l_du_encoder.h | 1 +
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 2 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c | 4 +-
7 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
index c57884ab5b9b..398532933013 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
@@ -411,7 +411,7 @@ int rzg2l_du_crtc_create(struct rzg2l_du_device *rcdu)
primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe]->plane;
- ret = drmm_crtc_init_with_planes(&rcdu->ddev, crtc, primary, NULL,
+ ret = drmm_crtc_init_with_planes(rcdu->ddev, crtc, primary, NULL,
&crtc_funcs_rz, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
index 6c2dc86abc7d..84da5a2df8f6 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
@@ -17,6 +17,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -144,10 +145,14 @@ static const struct drm_driver rzg2l_du_driver = {
* Platform driver
*/
+struct rzg2l_du_drm {
+ struct drm_device ddev;
+};
+
static void rzg2l_du_remove(struct platform_device *pdev)
{
- struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev);
- struct drm_device *ddev = &rcdu->ddev;
+ struct rzg2l_du_drm *rzgdrm = platform_get_drvdata(pdev);
+ struct drm_device *ddev = &rzgdrm->ddev;
drm_dev_unregister(ddev);
drm_atomic_helper_shutdown(ddev);
@@ -157,29 +162,35 @@ static void rzg2l_du_remove(struct platform_device *pdev)
static void rzg2l_du_shutdown(struct platform_device *pdev)
{
- struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev);
+ struct rzg2l_du_drm *rzgdrm = platform_get_drvdata(pdev);
- drm_atomic_helper_shutdown(&rcdu->ddev);
+ drm_atomic_helper_shutdown(&rzgdrm->ddev);
}
static int rzg2l_du_probe(struct platform_device *pdev)
{
struct rzg2l_du_device *rcdu;
+ struct rzg2l_du_drm *rzgdrm;
int ret;
if (drm_firmware_drivers_only())
return -ENODEV;
/* Allocate and initialize the RZ/G2L device structure. */
- rcdu = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_driver,
- struct rzg2l_du_device, ddev);
- if (IS_ERR(rcdu))
- return PTR_ERR(rcdu);
+ rzgdrm = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_driver,
+ struct rzg2l_du_drm, ddev);
+ if (IS_ERR(rzgdrm))
+ return PTR_ERR(rzgdrm);
+
+ platform_set_drvdata(pdev, rzgdrm);
+
+ rcdu = drmm_kzalloc(&rzgdrm->ddev, sizeof(*rcdu), GFP_KERNEL);
+ if (!rcdu)
+ return -ENOMEM;
rcdu->dev = &pdev->dev;
rcdu->info = of_device_get_match_data(rcdu->dev);
-
- platform_set_drvdata(pdev, rcdu);
+ rcdu->ddev = &rzgdrm->ddev;
/* I/O resources */
rcdu->mmio = devm_platform_ioremap_resource(pdev, 0);
@@ -207,18 +218,18 @@ static int rzg2l_du_probe(struct platform_device *pdev)
* Register the DRM device with the core and the connectors with
* sysfs.
*/
- ret = drm_dev_register(&rcdu->ddev, 0);
+ ret = drm_dev_register(&rzgdrm->ddev, 0);
if (ret)
goto error;
- drm_info(&rcdu->ddev, "Device %s probed\n", dev_name(&pdev->dev));
+ drm_info(&rzgdrm->ddev, "Device %s probed\n", dev_name(&pdev->dev));
- drm_client_setup(&rcdu->ddev, NULL);
+ drm_client_setup(&rzgdrm->ddev, NULL);
return 0;
error:
- drm_kms_helper_poll_fini(&rcdu->ddev);
+ drm_kms_helper_poll_fini(&rzgdrm->ddev);
return ret;
}
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
index e9626ef37cde..47ceaf892339 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
@@ -69,7 +69,7 @@ struct rzg2l_du_device {
void __iomem *mmio;
- struct drm_device ddev;
+ struct drm_device *ddev;
struct rzg2l_du_crtc crtcs[RZG2L_DU_MAX_CRTCS];
unsigned int num_crtcs;
@@ -77,11 +77,6 @@ struct rzg2l_du_device {
struct rzg2l_du_vsp vsps[RZG2L_DU_MAX_VSPS];
};
-static inline struct rzg2l_du_device *to_rzg2l_du_device(struct drm_device *dev)
-{
- return container_of(dev, struct rzg2l_du_device, ddev);
-}
-
static inline bool rzg2l_du_has(struct rzg2l_du_device *rcdu,
unsigned int feature)
{
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
index a1b48973aa8e..5c21c5f9fbaf 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
@@ -52,8 +52,7 @@ rzg2l_du_encoder_mode_valid(struct drm_encoder *encoder,
const struct drm_display_mode *mode)
{
struct rzg2l_du_encoder *renc = to_rzg2l_encoder(encoder);
- struct rzg2l_du_device *rcdu = to_rzg2l_du_device(renc->base.dev);
- const struct rzg2l_du_device_info *info = rcdu->info;
+ const struct rzg2l_du_device_info *info = renc->dev->info;
if (renc->output != RZG2L_DU_OUTPUT_DPAD0)
return MODE_OK;
@@ -133,12 +132,13 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %s\n",
enc_node, rzg2l_du_output_name(output));
- renc = drmm_encoder_alloc(&rcdu->ddev, struct rzg2l_du_encoder, base,
+ renc = drmm_encoder_alloc(rcdu->ddev, struct rzg2l_du_encoder, base,
&rzg2l_du_encoder_funcs, DRM_MODE_ENCODER_NONE,
NULL);
if (IS_ERR(renc))
return PTR_ERR(renc);
+ renc->dev = rcdu;
renc->output = output;
drm_encoder_helper_add(&renc->base, &rzg2l_du_encoder_helper_funcs);
@@ -153,7 +153,7 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
}
/* Create the connector for the chain of bridges. */
- connector = drm_bridge_connector_init(&rcdu->ddev, &renc->base);
+ connector = drm_bridge_connector_init(rcdu->ddev, &renc->base);
if (IS_ERR(connector)) {
dev_err(rcdu->dev,
"failed to created connector for output %s (%ld)\n",
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.h
index 3e430c1f6132..dfffcc14e0a3 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.h
@@ -17,6 +17,7 @@ struct rzg2l_du_device;
struct rzg2l_du_encoder {
struct drm_encoder base;
+ struct rzg2l_du_device *dev;
enum rzg2l_du_output output;
};
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index 87f171145a23..13d14ecacba9 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -402,7 +402,7 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu)
int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
{
- struct drm_device *dev = &rcdu->ddev;
+ struct drm_device *dev = rcdu->ddev;
struct drm_encoder *encoder;
unsigned int num_encoders;
int ret;
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
index 12fe35740c62..4df4f0ff0ed5 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
@@ -298,7 +298,7 @@ int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
vsp->vsp = &pdev->dev;
- ret = drmm_add_action_or_reset(&rcdu->ddev, rzg2l_du_vsp_cleanup, vsp);
+ ret = drmm_add_action_or_reset(rcdu->ddev, rzg2l_du_vsp_cleanup, vsp);
if (ret < 0)
return ret;
@@ -324,7 +324,7 @@ int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,
: DRM_PLANE_TYPE_OVERLAY;
struct rzg2l_du_vsp_plane *plane;
- plane = drmm_universal_plane_alloc(&rcdu->ddev, struct rzg2l_du_vsp_plane,
+ plane = drmm_universal_plane_alloc(rcdu->ddev, struct rzg2l_du_vsp_plane,
plane, crtcs, &rzg2l_du_vsp_plane_funcs,
rzg2l_du_vsp_formats,
ARRAY_SIZE(rzg2l_du_vsp_formats),
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 05/10] drm: renesas: rz-du: Count all registered encoders for the possible clones
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (3 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 04/10] drm: renesas: rz-du: Reference the DRM device by pointer Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 06/10] drm: renesas: rz-du: Split the mode setting initialization Tommaso Merciai
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
rzg2l_du_modeset_init() sets the possible clones of every encoder
registered with the DRM device, but builds the mask from the number of
outputs that rzg2l_du_encoders_init() initialized successfully. An
output whose bridge fails to attach after its encoder has been allocated
is skipped and not counted, while its encoder stays registered. The
mask then misses the bit of the last encoders, and
drm_mode_config_validate() warns about bogus possible clones.
Build the mask from the number of registered encoders instead.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch.
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index 13d14ecacba9..6eb1865f43b4 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -455,7 +455,7 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
return -EINVAL;
}
- num_encoders = ret;
+ num_encoders = dev->mode_config.num_encoder;
/*
* Set the possible CRTCs and possible clones. There's always at least
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 06/10] drm: renesas: rz-du: Split the mode setting initialization
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (4 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 05/10] drm: renesas: rz-du: Count all registered encoders for the possible clones Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 07/10] drm: renesas: rz-du: Make the CRTC index relative to the DRM device Tommaso Merciai
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
rzg2l_du_modeset_init() initializes the mode configuration of the DRM
device and creates the KMS objects of the DU instance. On RZ/G3E two
instances share a DRM device, so the mode configuration is initialized
once while each instance creates its own KMS objects.
In preparation for supporting RZ/G3E SoC, split them into
rzg2l_du_modeset_init_drm(), rzg2l_du_modeset_init_du() and
rzg2l_du_modeset_init_finish(), the latter completing the DRM device
once all instances have created their KMS objects.
As it is no longer tied to an instance, take from the DRM device and
the encoders what used to be taken from the instance.
No functional change intended.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch.
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 54 +++++++++++++++-----
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.h | 3 ++
2 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index 6eb1865f43b4..287f3f9fe56f 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -400,11 +400,8 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu)
return ret;
}
-int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
+int rzg2l_du_modeset_init_drm(struct drm_device *dev)
{
- struct drm_device *dev = rcdu->ddev;
- struct drm_encoder *encoder;
- unsigned int num_encoders;
int ret;
ret = drmm_mode_config_init(dev);
@@ -424,15 +421,14 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
dev->mode_config.max_width = 1920;
dev->mode_config.max_height = 1920;
- rcdu->num_crtcs = hweight8(rcdu->info->channels_mask);
+ return 0;
+}
- /*
- * Initialize vertical blanking interrupts handling. Start with vblank
- * disabled for all CRTCs.
- */
- ret = drm_vblank_init(dev, rcdu->num_crtcs);
- if (ret < 0)
- return ret;
+int rzg2l_du_modeset_init_du(struct rzg2l_du_device *rcdu)
+{
+ int ret;
+
+ rcdu->num_crtcs = hweight8(rcdu->info->channels_mask);
/* Initialize the compositors. */
ret = rzg2l_du_vsps_init(rcdu);
@@ -455,6 +451,23 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
return -EINVAL;
}
+ return 0;
+}
+
+int rzg2l_du_modeset_init_finish(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+ unsigned int num_encoders;
+ int ret;
+
+ /*
+ * Initialize vertical blanking interrupts handling. Start with vblank
+ * disabled for all CRTCs.
+ */
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (ret < 0)
+ return ret;
+
num_encoders = dev->mode_config.num_encoder;
/*
@@ -465,7 +478,7 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct rzg2l_du_encoder *renc = to_rzg2l_encoder(encoder);
const struct rzg2l_du_output_routing *route =
- &rcdu->info->routes[renc->output];
+ &renc->dev->info->routes[renc->output];
encoder->possible_crtcs = route->possible_outputs;
encoder->possible_clones = (1 << num_encoders) - 1;
@@ -477,3 +490,18 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
return 0;
}
+
+int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
+{
+ int ret;
+
+ ret = rzg2l_du_modeset_init_drm(rcdu->ddev);
+ if (ret < 0)
+ return ret;
+
+ ret = rzg2l_du_modeset_init_du(rcdu);
+ if (ret < 0)
+ return ret;
+
+ return rzg2l_du_modeset_init_finish(rcdu->ddev);
+}
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.h
index e2c599f115c6..0de2582f6bcd 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.h
@@ -30,6 +30,9 @@ struct rzg2l_du_format_info {
const struct rzg2l_du_format_info *rzg2l_du_format_info(u32 fourcc);
int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu);
+int rzg2l_du_modeset_init_drm(struct drm_device *dev);
+int rzg2l_du_modeset_init_du(struct rzg2l_du_device *rcdu);
+int rzg2l_du_modeset_init_finish(struct drm_device *dev);
int rzg2l_du_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args);
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 07/10] drm: renesas: rz-du: Make the CRTC index relative to the DRM device
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (5 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 06/10] drm: renesas: rz-du: Split the mode setting initialization Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 08/10] drm: renesas: rz-du: Share the encoder of an output driven by several DUs Tommaso Merciai
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
The possible_crtcs masks of planes and encoders hold CRTC indices within
the DRM device, but rzg2l_du_vsps_init() and
rzg2l_du_modeset_init_finish() build them from the index of the CRTC
within the DU instance. The two only match while an instance owns the
whole DRM device.
In preparation for supporting RZ/G3E, where two instances share one,
record in each instance the index of its first CRTC and offset the masks
by it. The index is zero for instances that own their DRM device, so
their masks are unchanged.
No functional change intended.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch.
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h | 1 +
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
index 47ceaf892339..2952c9d7348b 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
@@ -70,6 +70,7 @@ struct rzg2l_du_device {
void __iomem *mmio;
struct drm_device *ddev;
+ unsigned int index;
struct rzg2l_du_crtc crtcs[RZG2L_DU_MAX_CRTCS];
unsigned int num_crtcs;
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index 287f3f9fe56f..cad378418b38 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -367,7 +367,7 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu)
else
vsps[vsps_count++].np = args.np;
- vsps[j].crtcs_mask |= BIT(i);
+ vsps[j].crtcs_mask |= BIT(rcdu->index + i);
/*
* Store the VSP pointer and pipe index in the CRTC. If the
@@ -480,7 +480,7 @@ int rzg2l_du_modeset_init_finish(struct drm_device *dev)
const struct rzg2l_du_output_routing *route =
&renc->dev->info->routes[renc->output];
- encoder->possible_crtcs = route->possible_outputs;
+ encoder->possible_crtcs = route->possible_outputs << renc->dev->index;
encoder->possible_clones = (1 << num_encoders) - 1;
}
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 08/10] drm: renesas: rz-du: Share the encoder of an output driven by several DUs
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (6 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 07/10] drm: renesas: rz-du: Make the CRTC index relative to the DRM device Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 09/10] drm: renesas: rz-du: Add RZ/G3E (R9A09G047) DU support Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 10/10] arm64: dts: renesas: r9a09g047: Add DU{0,1} and display subsystem nodes Tommaso Merciai
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
On a SoC with several DU instances an output can be reachable from more
than one of them, but a drm_bridge can only be attached to one encoder.
In preparation for supporting RZ/G3E, where the DSI and the LVDS channel
1 are reachable from both instances, let the first instance create the
encoder and the others add their CRTC to its possible_crtcs mask, which
rzg2l_du_modeset_init_finish() then extends rather than overwrites.
Without this the second drm_bridge_attach() fails with -EBUSY, leaving
behind the encoder allocated just before it.
SoCs with a single instance are unaffected, as no encoder is ever
already attached.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- New patch
drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c | 12 ++++++++++++
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
index 5c21c5f9fbaf..45f980ea3c20 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
@@ -129,6 +129,18 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
return -EPROBE_DEFER;
}
+ /*
+ * A bridge can only be attached to one encoder. If another DU instance
+ * has already attached it, add this instance's CRTC to that encoder.
+ */
+ if (bridge->dev == rcdu->ddev && bridge->encoder) {
+ const struct rzg2l_du_output_routing *route =
+ &rcdu->info->routes[output];
+
+ bridge->encoder->possible_crtcs |= route->possible_outputs << rcdu->index;
+ return 0;
+ }
+
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %s\n",
enc_node, rzg2l_du_output_name(output));
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index cad378418b38..c20c0e0188ea 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -480,7 +480,7 @@ int rzg2l_du_modeset_init_finish(struct drm_device *dev)
const struct rzg2l_du_output_routing *route =
&renc->dev->info->routes[renc->output];
- encoder->possible_crtcs = route->possible_outputs << renc->dev->index;
+ encoder->possible_crtcs |= route->possible_outputs << renc->dev->index;
encoder->possible_clones = (1 << num_encoders) - 1;
}
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 09/10] drm: renesas: rz-du: Add RZ/G3E (R9A09G047) DU support
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (7 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 08/10] drm: renesas: rz-du: Share the encoder of an output driven by several DUs Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
2026-10-23 16:47 ` [PATCH v9 10/10] arm64: dts: renesas: r9a09g047: Add DU{0,1} and display subsystem nodes Tommaso Merciai
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
The RZ/G3E (R9A09G047) has two DU instances which can both drive the
DSI encoder and channel 1 of the LVDS encoder.
Expose them through a single DRM device, owned by a new display
subsystem driver that binds the DU instances as components.
Request the LVDS duty cycle for the new LVDS channel 1 output as well.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- Added newly architetture support creating an ad hoc component
driver for RZ/G3E display subsystem that embed the 2 du instances
into single drm device.
v7->v8:
- Modelled using ports/port instead of port/ep.
- Rebased on top of RZ/G3L du support [1]
[1] https://lore.kernel.org/all/20260826174854.199139-1-biju.das.jz@bp.renesas.com/
- Added mode_clock_min, mode_clock_max for parallel output.
- Improved commit msg and commit body.
v6->v7:
- Removed feature flag usage, rebased on top of T2H/N2H LCDC series [1]
[1] https://patchwork.global.renesas.com/project/spl2-reviews/list/?series=694&state=%2A&archive=both
- Reworked commit body as now outputs routing is based on endpoint id
instead of port number.
- Fixed rzg2l_du_r9a09g047_info instead of rzg2l_du_r9a09g047_du_info.
- Added bump of RZG2L_DU_MAX_CRTCS and RZG2L_DU_MAX_VSPS to 2.
v5->v6:
- Aligned ports numbering with the bindings changes.
v4->v5:
- Fixed RG2L_DU_FEATURE_SMUX2_DSI_CLK to RZG2L_DU_FEATURE_SMUX2_DSI_CLK,
update commit body accordingly.
- Added features field documentation.
v3->v4:
- No changes.
v2->v3:
- No changes.
v1->v2:
- Instead of using clk-provider API to select the right parent clock,
based on the outputs. Just set the correct duty cycle based on the
output, this reflects at CPG lvl to select the right parent.
- Updated commit message accordingly.
drivers/gpu/drm/renesas/rz-du/Makefile | 1 +
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c | 77 +++++-
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h | 13 +-
.../gpu/drm/renesas/rz-du/rzg2l_du_encoder.c | 3 +-
.../drm/renesas/rz-du/rzg2l_du_subsystem.c | 231 ++++++++++++++++++
5 files changed, 316 insertions(+), 9 deletions(-)
create mode 100644 drivers/gpu/drm/renesas/rz-du/rzg2l_du_subsystem.c
diff --git a/drivers/gpu/drm/renesas/rz-du/Makefile b/drivers/gpu/drm/renesas/rz-du/Makefile
index 46decb7ac4f1..a3d064957c70 100644
--- a/drivers/gpu/drm/renesas/rz-du/Makefile
+++ b/drivers/gpu/drm/renesas/rz-du/Makefile
@@ -3,6 +3,7 @@ rzg2l-du-drm-y := rzg2l_du_crtc.o \
rzg2l_du_drv.o \
rzg2l_du_encoder.o \
rzg2l_du_kms.o \
+ rzg2l_du_subsystem.o \
rzg2l-du-drm-$(CONFIG_VIDEO_RENESAS_VSP1) += rzg2l_du_vsp.o
obj-$(CONFIG_DRM_RZG2L_DU) += rzg2l-du-drm.o
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
index 84da5a2df8f6..c75f05a2145a 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
@@ -76,6 +76,31 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a08g046_info = {
.mode_clock_max = 87000,
};
+static const struct rzg2l_du_device_info rzg2l_du_r9a09g047_info = {
+ .channels_mask = BIT(0),
+ .routes = {
+ [RZG2L_DU_OUTPUT_DSI0] = {
+ .possible_outputs = BIT(0),
+ .port = 0,
+ },
+ [RZG2L_DU_OUTPUT_DPAD0] = {
+ .possible_outputs = BIT(0),
+ .port = 1,
+ },
+ [RZG2L_DU_OUTPUT_LVDS0] = {
+ .possible_outputs = BIT(0),
+ .port = 2,
+ },
+ [RZG2L_DU_OUTPUT_LVDS1] = {
+ .possible_outputs = BIT(0),
+ .port = 3,
+ },
+ },
+ .features = RZG2L_DU_FEATURE_COMPONENT,
+ .mode_clock_min = 5400,
+ .mode_clock_max = 87000,
+};
+
static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
.channels_mask = BIT(0),
.routes = {
@@ -103,6 +128,7 @@ static const struct of_device_id rzg2l_du_of_table[] = {
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
{ .compatible = "renesas,r9a08g046-du", .data = &rzg2l_du_r9a08g046_info },
+ { .compatible = "renesas,r9a09g047-du", .data = &rzg2l_du_r9a09g047_info },
{ .compatible = "renesas,r9a09g057-du", .data = &rzg2l_du_r9a09g057_info },
{ .compatible = "renesas,r9a09g077-du", .data = &rzg2l_du_r9a09g077_info },
{ /* sentinel */ }
@@ -115,7 +141,8 @@ const char *rzg2l_du_output_name(enum rzg2l_du_output output)
static const char * const names[] = {
[RZG2L_DU_OUTPUT_DSI0] = "DSI0",
[RZG2L_DU_OUTPUT_DPAD0] = "DPAD0",
- [RZG2L_DU_OUTPUT_LVDS0] = "LVDS0"
+ [RZG2L_DU_OUTPUT_LVDS0] = "LVDS0",
+ [RZG2L_DU_OUTPUT_LVDS1] = "LVDS1"
};
if (output >= ARRAY_SIZE(names))
@@ -130,7 +157,7 @@ const char *rzg2l_du_output_name(enum rzg2l_du_output output)
DEFINE_DRM_GEM_DMA_FOPS(rzg2l_du_fops);
-static const struct drm_driver rzg2l_du_driver = {
+const struct drm_driver rzg2l_du_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(rzg2l_du_dumb_create),
DRM_FBDEV_DMA_DRIVER_OPS,
@@ -151,8 +178,17 @@ struct rzg2l_du_drm {
static void rzg2l_du_remove(struct platform_device *pdev)
{
- struct rzg2l_du_drm *rzgdrm = platform_get_drvdata(pdev);
- struct drm_device *ddev = &rzgdrm->ddev;
+ const struct rzg2l_du_device_info *info = of_device_get_match_data(&pdev->dev);
+ struct rzg2l_du_drm *rzgdrm;
+ struct drm_device *ddev;
+
+ if (info->features & RZG2L_DU_FEATURE_COMPONENT) {
+ rzg2l_du_instance_remove(pdev);
+ return;
+ }
+
+ rzgdrm = platform_get_drvdata(pdev);
+ ddev = &rzgdrm->ddev;
drm_dev_unregister(ddev);
drm_atomic_helper_shutdown(ddev);
@@ -162,13 +198,19 @@ static void rzg2l_du_remove(struct platform_device *pdev)
static void rzg2l_du_shutdown(struct platform_device *pdev)
{
- struct rzg2l_du_drm *rzgdrm = platform_get_drvdata(pdev);
+ const struct rzg2l_du_device_info *info = of_device_get_match_data(&pdev->dev);
+ struct rzg2l_du_drm *rzgdrm;
+
+ if (info->features & RZG2L_DU_FEATURE_COMPONENT)
+ return;
+ rzgdrm = platform_get_drvdata(pdev);
drm_atomic_helper_shutdown(&rzgdrm->ddev);
}
static int rzg2l_du_probe(struct platform_device *pdev)
{
+ const struct rzg2l_du_device_info *info;
struct rzg2l_du_device *rcdu;
struct rzg2l_du_drm *rzgdrm;
int ret;
@@ -176,8 +218,12 @@ static int rzg2l_du_probe(struct platform_device *pdev)
if (drm_firmware_drivers_only())
return -ENODEV;
+ info = of_device_get_match_data(&pdev->dev);
+ if (info->features & RZG2L_DU_FEATURE_COMPONENT)
+ return rzg2l_du_instance_probe(pdev);
+
/* Allocate and initialize the RZ/G2L device structure. */
- rzgdrm = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_driver,
+ rzgdrm = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_drm_driver,
struct rzg2l_du_drm, ddev);
if (IS_ERR(rzgdrm))
return PTR_ERR(rzgdrm);
@@ -243,7 +289,24 @@ static struct platform_driver rzg2l_du_platform_driver = {
},
};
-module_platform_driver(rzg2l_du_platform_driver);
+static struct platform_driver * const rzg2l_du_drivers[] = {
+ &rzg2l_du_platform_driver,
+ &rzg2l_du_subsystem_driver,
+};
+
+static int __init rzg2l_du_init(void)
+{
+ return platform_register_drivers(rzg2l_du_drivers,
+ ARRAY_SIZE(rzg2l_du_drivers));
+}
+module_init(rzg2l_du_init);
+
+static void __exit rzg2l_du_exit(void)
+{
+ platform_unregister_drivers(rzg2l_du_drivers,
+ ARRAY_SIZE(rzg2l_du_drivers));
+}
+module_exit(rzg2l_du_exit);
MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
MODULE_DESCRIPTION("Renesas RZ/G2L Display Unit DRM Driver");
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
index 2952c9d7348b..ede398269d10 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
@@ -19,13 +19,17 @@
struct device;
struct drm_property;
+struct platform_device;
+struct platform_driver;
#define RZG2L_DU_FEATURE_DPIO_OE BIT(0) /* Has DPIO output enable control */
+#define RZG2L_DU_FEATURE_COMPONENT BIT(1) /* Bound as a display subsystem component */
enum rzg2l_du_output {
RZG2L_DU_OUTPUT_DSI0,
RZG2L_DU_OUTPUT_DPAD0,
RZG2L_DU_OUTPUT_LVDS0,
+ RZG2L_DU_OUTPUT_LVDS1,
RZG2L_DU_OUTPUT_MAX,
};
@@ -34,7 +38,7 @@ enum rzg2l_du_output {
* @possible_outputs: bitmask of possible outputs
* @port: device tree port number corresponding to this output route
*
- * The DU has 3 possible outputs (DPAD0, DSI0, LVDS0). Output routing data
+ * The DU has 4 possible outputs (DPAD0, DSI0, LVDS0/1). Output routing data
* specify the valid SoC outputs, which CRTC can drive the output, and the type
* of in-SoC encoder for the output.
*/
@@ -86,4 +90,11 @@ static inline bool rzg2l_du_has(struct rzg2l_du_device *rcdu,
const char *rzg2l_du_output_name(enum rzg2l_du_output output);
+extern const struct drm_driver rzg2l_du_drm_driver;
+
+int rzg2l_du_instance_probe(struct platform_device *pdev);
+void rzg2l_du_instance_remove(struct platform_device *pdev);
+
+extern struct platform_driver rzg2l_du_subsystem_driver;
+
#endif /* __RZG2L_DU_DRV_H__ */
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
index 45f980ea3c20..60709e0fc601 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
@@ -80,7 +80,8 @@ static void rzg2l_du_encoder_atomic_mode_set(struct drm_encoder *encoder,
* - LVDS path has DUTY H/L=4/3, 4/7 duty cycle.
* - DSI/RGB path has symmetric 50% duty cycle.
*/
- if (renc->output == RZG2L_DU_OUTPUT_LVDS0)
+ if (renc->output == RZG2L_DU_OUTPUT_LVDS0 ||
+ renc->output == RZG2L_DU_OUTPUT_LVDS1)
clk_set_duty_cycle(clk_parent, 4, 7);
else
clk_set_duty_cycle(clk_parent, 1, 2);
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_subsystem.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_subsystem.c
new file mode 100644
index 000000000000..9edd0ab3e1dd
--- /dev/null
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_subsystem.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RZ/G2L Display Unit subsystem DRM driver
+ *
+ * The DU instances of a display subsystem are bound as components of a single
+ * DRM device, owned by the display subsystem driver.
+ *
+ * Copyright (C) 2026 Renesas Electronics Corporation
+ */
+
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#include "rzg2l_du_drv.h"
+#include "rzg2l_du_kms.h"
+
+/* -----------------------------------------------------------------------------
+ * DU instance
+ */
+
+struct rzg2l_du_instance {
+ struct device *dev;
+ const struct rzg2l_du_device_info *info;
+ void __iomem *mmio;
+};
+
+static int rzg2l_du_instance_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct rzg2l_du_instance *du = dev_get_drvdata(dev);
+ struct drm_device *ddev = data;
+ struct rzg2l_du_device *rcdu;
+ int ret;
+
+ rcdu = drmm_kzalloc(ddev, sizeof(*rcdu), GFP_KERNEL);
+ if (!rcdu)
+ return -ENOMEM;
+
+ rcdu->dev = du->dev;
+ rcdu->info = du->info;
+ rcdu->mmio = du->mmio;
+ rcdu->ddev = ddev;
+
+ rcdu->index = ddev->mode_config.num_crtc;
+
+ if (!rcdu->index)
+ drm_dev_set_dma_dev(ddev, dev);
+
+ ret = rzg2l_du_modeset_init_du(rcdu);
+ if (ret < 0)
+ return ret;
+
+ if (WARN_ON(drm_crtc_index(&rcdu->crtcs[0].crtc) != rcdu->index))
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct component_ops rzg2l_du_instance_ops = {
+ .bind = rzg2l_du_instance_bind,
+};
+
+int rzg2l_du_instance_probe(struct platform_device *pdev)
+{
+ struct rzg2l_du_instance *du;
+ int ret;
+
+ du = devm_kzalloc(&pdev->dev, sizeof(*du), GFP_KERNEL);
+ if (!du)
+ return -ENOMEM;
+
+ du->dev = &pdev->dev;
+ du->info = of_device_get_match_data(du->dev);
+
+ du->mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(du->mmio))
+ return PTR_ERR(du->mmio);
+
+ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, du);
+
+ return component_add(&pdev->dev, &rzg2l_du_instance_ops);
+}
+
+void rzg2l_du_instance_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &rzg2l_du_instance_ops);
+}
+
+/* -----------------------------------------------------------------------------
+ * Display subsystem
+ */
+
+static int rzg2l_du_subsystem_bind(struct device *dev)
+{
+ struct drm_device *ddev;
+ int ret;
+
+ ddev = drm_dev_alloc(&rzg2l_du_drm_driver, dev);
+ if (IS_ERR(ddev))
+ return PTR_ERR(ddev);
+
+ dev_set_drvdata(dev, ddev);
+
+ ret = rzg2l_du_modeset_init_drm(ddev);
+ if (ret < 0)
+ goto error;
+
+ ret = component_bind_all(dev, ddev);
+ if (ret < 0)
+ goto error;
+
+ ret = rzg2l_du_modeset_init_finish(ddev);
+ if (ret < 0)
+ goto error_unbind;
+
+ ret = drm_dev_register(ddev, 0);
+ if (ret)
+ goto error_unbind;
+
+ drm_info(ddev, "Device %s probed with %u CRTCs\n",
+ dev_name(dev), ddev->mode_config.num_crtc);
+
+ drm_client_setup(ddev, NULL);
+
+ return 0;
+
+error_unbind:
+ drm_kms_helper_poll_fini(ddev);
+ component_unbind_all(dev, ddev);
+error:
+ dev_set_drvdata(dev, NULL);
+ drm_dev_put(ddev);
+ return ret;
+}
+
+static void rzg2l_du_subsystem_unbind(struct device *dev)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+
+ drm_dev_unregister(ddev);
+ drm_atomic_helper_shutdown(ddev);
+ drm_kms_helper_poll_fini(ddev);
+
+ component_unbind_all(dev, ddev);
+
+ dev_set_drvdata(dev, NULL);
+ drm_dev_put(ddev);
+}
+
+static const struct component_master_ops rzg2l_du_subsystem_ops = {
+ .bind = rzg2l_du_subsystem_bind,
+ .unbind = rzg2l_du_subsystem_unbind,
+};
+
+static int rzg2l_du_subsystem_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &pdev->dev;
+ unsigned int i;
+
+ if (drm_firmware_drivers_only())
+ return -ENODEV;
+
+ /* Each ports entry references the ports node of a DU instance. */
+ for (i = 0; ; i++) {
+ struct device_node *ports;
+
+ ports = of_parse_phandle(dev->of_node, "ports", i);
+ if (!ports)
+ break;
+
+ if (of_device_is_available(ports->parent))
+ drm_of_component_match_add(dev, &match,
+ component_compare_of,
+ ports->parent);
+
+ of_node_put(ports);
+ }
+
+ if (IS_ERR(match))
+ return dev_err_probe(dev, PTR_ERR(match), "failed to build the component match\n");
+
+ if (!match)
+ return dev_err_probe(dev, -ENODEV, "no enabled DU instance in ports\n");
+
+ return component_master_add_with_match(dev, &rzg2l_du_subsystem_ops,
+ match);
+}
+
+static void rzg2l_du_subsystem_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &rzg2l_du_subsystem_ops);
+}
+
+static void rzg2l_du_subsystem_shutdown(struct platform_device *pdev)
+{
+ drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
+}
+
+static const struct of_device_id rzg2l_du_subsystem_of_table[] = {
+ { .compatible = "renesas,r9a09g047-display-subsystem" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rzg2l_du_subsystem_of_table);
+
+struct platform_driver rzg2l_du_subsystem_driver = {
+ .probe = rzg2l_du_subsystem_probe,
+ .remove = rzg2l_du_subsystem_remove,
+ .shutdown = rzg2l_du_subsystem_shutdown,
+ .driver = {
+ .name = "rzg2l-du-subsystem",
+ .of_match_table = rzg2l_du_subsystem_of_table,
+ },
+};
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v9 10/10] arm64: dts: renesas: r9a09g047: Add DU{0,1} and display subsystem nodes
2026-10-23 16:47 [PATCH v9 00/10] drm: renesas: rz-du: Add RZ/G3E support Tommaso Merciai
` (8 preceding siblings ...)
2026-10-23 16:47 ` [PATCH v9 09/10] drm: renesas: rz-du: Add RZ/G3E (R9A09G047) DU support Tommaso Merciai
@ 2026-10-23 16:47 ` Tommaso Merciai
9 siblings, 0 replies; 14+ messages in thread
From: Tommaso Merciai @ 2026-10-23 16:47 UTC (permalink / raw)
To: tomm.merciai, prabhakar.mahadev-lad.rj
Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Geert Uytterhoeven, Magnus Damm, Laurent Pinchart,
dri-devel, devicetree, linux-kernel
Add DU{0,1} and the display subsystem nodes to RZ/G3E SoC DTSI.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
v8->v9:
- Split du into du0 and du1 node and added newly display_subsystem node.
v7->v8
- New patch
arch/arm64/boot/dts/renesas/r9a09g047.dtsi | 80 ++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi
index 737bf1c60451..0d03121a37e1 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi
@@ -153,6 +153,12 @@ opp-19687500 {
};
};
+ display_subsystem: display-subsystem {
+ compatible = "renesas,r9a09g047-display-subsystem";
+ ports = <&du0_ports>, <&du1_ports>;
+ status = "disabled";
+ };
+
psci {
compatible = "arm,psci-1.0", "arm,psci-0.2";
method = "smc";
@@ -2239,6 +2245,80 @@ csi2cru: endpoint@0 {
};
};
+ du0: display@16460000 {
+ compatible = "renesas,r9a09g047-du";
+ reg = <0 0x16460000 0 0x10000>;
+ interrupts = <GIC_SPI 882 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 0xed>,
+ <&cpg CPG_MOD 0xee>,
+ <&cpg CPG_MOD 0xef>;
+ clock-names = "aclk", "pclk", "vclk";
+ power-domains = <&cpg>;
+ resets = <&cpg 0xdc>;
+ renesas,vsps = <&vspd0 0>;
+ status = "disabled";
+
+ du0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du0_out_dsi: endpoint {
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ du0_out_lvds0: endpoint {
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ du0_out_lvds1: endpoint {
+ };
+ };
+ };
+ };
+
+ du1: display@16490000 {
+ compatible = "renesas,r9a09g047-du";
+ reg = <0 0x16490000 0 0x10000>;
+ interrupts = <GIC_SPI 922 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 0x1a8>,
+ <&cpg CPG_MOD 0x1a9>,
+ <&cpg CPG_MOD 0x1aa>;
+ clock-names = "aclk", "pclk", "vclk";
+ power-domains = <&cpg>;
+ resets = <&cpg 0x11e>;
+ renesas,vsps = <&vspd1 0>;
+ status = "disabled";
+
+ du1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du1_out_dsi: endpoint {
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ du1_out_rgb: endpoint {
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ du1_out_lvds1: endpoint {
+ };
+ };
+ };
+ };
+
fcpvd0: fcp@16470000 {
compatible = "renesas,r9a09g047-fcpvd",
"renesas,fcpv";
--
2.54.0
^ permalink raw reply [flat|nested] 14+ messages in thread