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
