[PATCH v7 07/13] drm: renesas: rz-du: kms: Enable multi CRTC creation

From: Tommaso Merciai

Date: Thu May 07 2026 - 05:24:42 EST


Replace the hardcoded rzg2l_du_crtc_create(rcdu, 0, 0) call with a
loop over channels_mask using for_each_set_bit(), passing the correct
software and hardware indices to each invocation.

Iterate the registered CRTCs by their hardware index when building
encoder possible_crtcs masks, so that the DRM software CRTC index
correctly maps to the hardware channel.

No functional changes intended.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@xxxxxxxxxxxxxx>
---
v6->v7:
- New patch.

drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 28 ++++++++++++++++----
1 file changed, 23 insertions(+), 5 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 7cbdf146788e..fc5ce8c7eea0 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -404,7 +404,10 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
{
struct drm_device *dev = &rcdu->ddev;
struct drm_encoder *encoder;
+ unsigned long channels_mask;
unsigned int num_encoders;
+ unsigned int swindex = 0;
+ unsigned int hwindex;
int ret;

ret = drmm_mode_config_init(dev);
@@ -424,7 +427,8 @@ 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);
+ channels_mask = rcdu->info->channels_mask;
+ rcdu->num_crtcs = hweight8(channels_mask);

/*
* Initialize vertical blanking interrupts handling. Start with vblank
@@ -440,9 +444,11 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
return ret;

/* Create the CRTCs. */
- ret = rzg2l_du_crtc_create(rcdu, 0, 0);
- if (ret < 0)
- return ret;
+ for_each_set_bit(hwindex, &channels_mask, RZG2L_DU_MAX_CRTCS) {
+ ret = rzg2l_du_crtc_create(rcdu, swindex++, hwindex);
+ if (ret < 0)
+ return ret;
+ }

/* Initialize the encoders. */
ret = rzg2l_du_encoders_init(rcdu);
@@ -461,13 +467,25 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
* Set the possible CRTCs and possible clones. There's always at least
* one way for all encoders to clone each other, set all bits in the
* possible clones field.
+ *
+ * route->possible_outputs uses hardware channel indices, but DRM
+ * possible_crtcs uses the CRTC registration order. Convert by
+ * mapping each set bit in possible_outputs through the hw_index
+ * stored in each CRTC.
*/
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];
+ unsigned int possible_crtcs = 0;
+ unsigned int i;
+
+ for (i = 0; i < rcdu->num_crtcs; i++) {
+ if (route->possible_outputs & BIT(rcdu->crtcs[i].hw_index))
+ possible_crtcs |= BIT(i);
+ }

- encoder->possible_crtcs = route->possible_outputs;
+ encoder->possible_crtcs = possible_crtcs;
encoder->possible_clones = (1 << num_encoders) - 1;
}

--
2.54.0