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

Reply via email to