On RZ/G3E all outputs of a DU instance share a single port and are
distinguished by endpoint id, unlike the port-per-output layout on
RZ/G2L.

Auto-detect the routing mode by checking whether any port exposes more
than one endpoint (rzg2l_du_ep_routing()). Add an 'ep' field in a union
with 'port' in rzg2l_du_output_routing to cover both conventions, and
update rzg2l_du_encoders_init() to match routes by ep.id when endpoint
routing is detected. Track a linked_outputs bitmask to skip duplicate
encoder creation when the same output type appears under multiple
DU-channel ports.

No functional change for existing platforms.

Signed-off-by: Tommaso Merciai <[email protected]>
---
v6->v7:
 - New patch.

 drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h |  6 ++-
 drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 57 +++++++++++++++++---
 2 files changed, 55 insertions(+), 8 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 d0e59b787cd7..eed8e1215f08 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
@@ -32,6 +32,7 @@ enum rzg2l_du_output {
  * struct rzg2l_du_output_routing - Output routing specification
  * @possible_outputs: bitmask of possible outputs
  * @port: device tree port number corresponding to this output route
+ * @ep: device tree endpoint id corresponding to this output route
  *
  * The DU has 2 possible outputs (DPAD0, DSI0). Output routing data
  * specify the valid SoC outputs, which CRTC can drive the output, and the type
@@ -39,7 +40,10 @@ enum rzg2l_du_output {
  */
 struct rzg2l_du_output_routing {
        unsigned int possible_outputs;
-       unsigned int port;
+       union {
+               unsigned int port;
+               unsigned int ep;
+       };
 };
 
 /*
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 fc5ce8c7eea0..01b037594926 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -266,15 +266,37 @@ static int rzg2l_du_encoders_init_one(struct 
rzg2l_du_device *rcdu,
        return ret;
 }
 
+static bool rzg2l_du_ep_routing(const struct device_node *np)
+{
+       for_each_of_graph_port(np, port) {
+               unsigned int count = 0;
+
+               for_each_of_graph_port_endpoint(port, ep)
+                       count++;
+
+               if (count > 1)
+                       return true;
+       }
+       return false;
+}
+
 static int rzg2l_du_encoders_init(struct rzg2l_du_device *rcdu)
 {
        struct device_node *np = rcdu->dev->of_node;
+       bool ep_routing = rzg2l_du_ep_routing(np);
+       unsigned int linked_outputs = 0;
        struct device_node *ep_node;
        unsigned int num_encoders = 0;
 
        /*
         * Iterate over the endpoints and create one encoder for each output
         * pipeline.
+        *
+        * Two routing modes are supported:
+        * - Port-based (default): each output lives on its own port, routes
+        *   are matched by ep.port.
+        * - Endpoint-based: all outputs share a single port, each output lives
+        *   on its own endpoint, routes are matched by ep.id.
         */
        for_each_endpoint_of_node(np, ep_node) {
                enum rzg2l_du_output output;
@@ -288,19 +310,39 @@ static int rzg2l_du_encoders_init(struct rzg2l_du_device 
*rcdu)
                        return ret;
                }
 
-               /* Find the output route corresponding to the port number. */
+               /* Find the output route corresponding to the port/endpoint. */
                for (i = 0; i < RZG2L_DU_OUTPUT_MAX; ++i) {
-                       if (rcdu->info->routes[i].possible_outputs &&
-                           rcdu->info->routes[i].port == ep.port) {
-                               output = i;
+                       const struct rzg2l_du_output_routing *route =
+                               &rcdu->info->routes[i];
+
+                       if (!route->possible_outputs)
+                               continue;
+
+                       if (ep_routing ? route->ep == ep.id :
+                           route->port == ep.port)
                                break;
-                       }
                }
 
                if (i == RZG2L_DU_OUTPUT_MAX) {
                        dev_warn(rcdu->dev,
-                                "port %u references unexisting output, 
skipping\n",
-                                ep.port);
+                                "port %u endpoint %u references unexisting 
output, skipping\n",
+                                ep.port, ep.id);
+                       continue;
+               }
+
+               output = i;
+
+               /*
+                * With endpoint-based routing the same output type can appear
+                * under multiple DU-channel ports (e.g. DSI on both port@0 and
+                * port@1). Only create one encoder per output the encoder's
+                * possible_crtcs mask already covers all channels that can
+                * drive it.
+                */
+               if (ep_routing && (linked_outputs & BIT(output))) {
+                       dev_dbg(rcdu->dev,
+                               "output %s already linked, skipping port %u 
endpoint %u\n",
+                               rzg2l_du_output_name(output), ep.port, ep.id);
                        continue;
                }
 
@@ -315,6 +357,7 @@ static int rzg2l_du_encoders_init(struct rzg2l_du_device 
*rcdu)
                        continue;
                }
 
+               linked_outputs |= BIT(output);
                num_encoders++;
        }
 
-- 
2.54.0

Reply via email to