Skip CRTC creation for DU channels that have no connected output in DT. Scan the device endpoint graph to determine which channels have at least one endpoint with a remote-endpoint phandle, and restrict the active channels mask to that subset.
On EP-routing platforms (RZG2L_DU_FEATURE_EP_ROUTING), port@N maps directly to DU channel N. On port-based platforms, any connected endpoint activates the single hardware channel. Update rzg2l_du_vsps_init() to compute the renesas,vsps property stride from the full hardware channel count (hweight8(channels_mask)) rather than the narrowed connected count, so the correct DT entry is selected for each active channel. No functional change intended for existing platforms. Signed-off-by: Tommaso Merciai <[email protected]> --- v6->v7: - New patch. drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 58 +++++++++++++++++--- 1 file changed, 49 insertions(+), 9 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 01b037594926..c2cd542a8cf5 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c @@ -364,7 +364,8 @@ static int rzg2l_du_encoders_init(struct rzg2l_du_device *rcdu) return num_encoders; } -static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu) +static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu, + unsigned long channels_mask) { const struct device_node *np = rcdu->dev->of_node; const char *vsps_prop_name = "renesas,vsps"; @@ -374,6 +375,8 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu) unsigned int crtcs_mask; } vsps[RZG2L_DU_MAX_VSPS] = { { NULL, }, }; unsigned int vsps_count = 0; + unsigned int swindex = 0; + unsigned int hwindex; unsigned int cells; unsigned int i; int ret; @@ -384,15 +387,15 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu) * connected DU CRTCs. */ ret = of_property_count_u32_elems(np, vsps_prop_name); - cells = ret / rcdu->num_crtcs - 1; + cells = ret / hweight8(rcdu->info->channels_mask) - 1; if (cells != 1) return -EINVAL; - for (i = 0; i < rcdu->num_crtcs; ++i) { + for_each_set_bit(hwindex, &channels_mask, RZG2L_DU_MAX_CRTCS) { unsigned int j; ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name, - cells, i, &args); + cells, hwindex, &args); if (ret < 0) goto done; @@ -410,15 +413,16 @@ 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(swindex); /* * Store the VSP pointer and pipe index in the CRTC. If the * second cell of the 'renesas,vsps' specifier isn't present, * default to 0. */ - rcdu->crtcs[i].vsp = &rcdu->vsps[j]; - rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0; + rcdu->crtcs[swindex].vsp = &rcdu->vsps[j]; + rcdu->crtcs[swindex].vsp_pipe = cells >= 1 ? args.args[0] : 0; + swindex++; } /* @@ -443,8 +447,36 @@ static int rzg2l_du_vsps_init(struct rzg2l_du_device *rcdu) return ret; } +static unsigned int rzg2l_du_connected_channels(struct rzg2l_du_device *rcdu) +{ + struct device_node *np = rcdu->dev->of_node; + unsigned int connected = 0; + struct device_node *ep_node; + + for_each_endpoint_of_node(np, ep_node) { + struct of_endpoint ep; + struct device_node *remote; + + if (!of_device_is_available(ep_node)) + continue; + + if (of_graph_parse_endpoint(ep_node, &ep)) + continue; + + remote = of_graph_get_remote_endpoint(ep_node); + if (!remote) + continue; + of_node_put(remote); + + connected |= BIT(ep.port); + } + + return rcdu->info->channels_mask & connected; +} + int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu) { + struct device_node *np = rcdu->dev->of_node; struct drm_device *dev = &rcdu->ddev; struct drm_encoder *encoder; unsigned long channels_mask; @@ -470,7 +502,15 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu) dev->mode_config.max_width = 1920; dev->mode_config.max_height = 1920; - channels_mask = rcdu->info->channels_mask; + if (rzg2l_du_ep_routing(np)) { + channels_mask = rzg2l_du_connected_channels(rcdu); + if (!channels_mask) { + dev_err(rcdu->dev, "no connected DU channels found in DT\n"); + return -ENODEV; + } + } else { + channels_mask = rcdu->info->channels_mask; + } rcdu->num_crtcs = hweight8(channels_mask); /* @@ -482,7 +522,7 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu) return ret; /* Initialize the compositors. */ - ret = rzg2l_du_vsps_init(rcdu); + ret = rzg2l_du_vsps_init(rcdu, channels_mask); if (ret < 0) return ret; -- 2.54.0
