On 2018-08-14 16:33, Rob Herring wrote: > On Tue, Aug 14, 2018 at 12:36 AM Peter Rosin <peda@xxxxxxxxxx> wrote: >> >> On 2018-08-13 22:52, Rob Herring wrote: >>> On Mon, Aug 13, 2018 at 8:25 AM Peter Rosin <peda@xxxxxxxxxx> wrote: >>>> >>>> On 2018-08-13 15:59, jacopo mondi wrote: >>>>> Hi Peter, >>>>> >>>>> On Fri, Aug 10, 2018 at 03:03:58PM +0200, Peter Rosin wrote: >>>>>> This enables more flexible devicetrees. You can e.g. have two output >>>>>> nodes where one is not enabled, without the ordering affecting things. >>> >>> Your DTs are not supposed to be flexible. They should be well defined >>> by the binding. >> >> I feel the need to explain the situation with more words... >> >> We have a board with this atmel-hlcdc wired to both an LVDS encoder >> and an HDMI encoder. Depending on how we integrate this board, only >> one of these paths make sense. Hence, I would like to do the following >> in a .dtsi for that board: >> >> / { >> hlcdc-display-controller { >> ... >> port@0 { >> hlcdc_lvds: endpoint@0 { >> reg = <0>; >> remote-endpoint = <&lvds_encoder_input>; >> }; >> >> hlcdc_hdmi: endpoint@1 { >> reg = <1>; >> remote-endpoint = <&hdmi_encoder_input>; >> }; >> }; >> }; >> >> lvds_encoder: lvds-encoder { >> status = "disabled"; >> >> ... >> >> ports { >> #address-cells = <1>; >> #size-cells = <0>; >> >> port@0 { >> reg = <0>; >> >> lvds_encoder_input: endpoint { >> remote-endpoint = <&hlcdc_lvds>; >> }; >> }; >> >> port@1 { >> reg = <1>; >> >> lvds_encoder_output: endpoint { >> }; >> }; >> }; >> }; >> }; >> >> &i2c2 { >> ... >> hdmi_encoder: hdmi-encoder@70 { >> status = "disabled"; >> >> ... >> >> port { >> hdmi_encoder_input: endpoint { >> remote-endpoint = <&hlcdc_hdmi>; >> }; >> }; >> }; >> }; >> >> >> And then, depending on what components are fitted and what LVDS panel has >> been attached to the LVDS encoder output, this can be used as follows >> in the .dts file for LVDS case: >> >> / { >> panel: panel { >> compatible = "litemax,dlf2118", "panel-lvds"; >> >> ... >> >> port { >> panel_input: endpoint { >> remote-endpoint = <&lvds_encoder_output>; >> }; >> }; >> }; >> }; >> >> >> &lvds_encoder { >> status = "okay"; >> }; >> >> &lvds_encoder_output { >> remote-endpoint = <&panel_input>; >> }; >> >> >> For the HDMI case, it would be this in the .dts file: >> >> &hdmi_encoder { >> status = "okay"; >> }; >> >> >> The above seem so much better than just having the following in >> the .dtsi file >> >> / { >> hlcdc-display-controller { >> ... >> port@0 { >> hlcdc_lvds: endpoint { >> remote-endpoint = <&encoder_input>; >> }; >> }; >> }; >> }; >> >> and pushing the lvds-encoder and hdmi-encoder nodes (slightly modified) down >> to the relevant .dts files. Especially so since we have to this point >> delivered several variants with different LVDS panels. The duplication >> is ugly, and the number of different panels is expected to grow... >> >> But maybe I have misunderstood what endpoints are all about, but to me >> the actual endpoint id is not that interesting and I see nothing in the >> graph binding that suggests that endpoint id 0 has to be up and kicking >> in order for endpoint id 1 to be examined at all. > > I guess it depends if the numbering is significant. For a one to many > fan out like this, not so much. For a muxed input, then it would be. Right, the endpoint numbering certainly *can* be important for some cases, I can see that, and am not arguing against that part... >> For ports, yes, you are right that the port id needs to be defined and >> fixed for a specific function, so scratch that. It was just a "maybe" >> question anyway... >> >>>>>> >>>>>> Prior to this patch the active node had to have endpoint id zero. >>>>>> >>>>>> Signed-off-by: Peter Rosin <peda@xxxxxxxxxx> >>>>>> --- >>>>>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 32 ++++++++++++++++++------ >>>>>> 1 file changed, 25 insertions(+), 7 deletions(-) >>>>>> >>>>>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c >>>>>> index 8db51fb131db..16c1b2f54b42 100644 >>>>>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c >>>>>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c >>>>>> @@ -31,14 +31,16 @@ static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = { >>>>>> .destroy = drm_encoder_cleanup, >>>>>> }; >>>>>> >>>>>> -static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) >>>>>> +static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, >>>>>> + struct of_endpoint *endpoint) >>>>>> { >>>>>> struct drm_encoder *encoder; >>>>>> struct drm_panel *panel; >>>>>> struct drm_bridge *bridge; >>>>>> int ret; >>>>>> >>>>>> - ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint, >>>>>> + ret = drm_of_find_panel_or_bridge(dev->dev->of_node, >>>>>> + endpoint->port, endpoint->id, >>>>> >>>>> You are refusing endpoint->port != 0 in the caller, so that could be >>>>> 0. >>>> >>>> Yes, it could. However, I intentionally did not write 0 here, so that >>>> the logic related to "port has to be zero" was in one place and not >>>> scattered about. I guess it's up to Boris? >>>> >>>> Maybe the port do not actually have to be zero at all? With the old >>>> code, it was kind of understandable that the port number was fixed, >>>> but for the code in my patch it does not matter at all AFAICT. There >>>> is nothing in the binding docs (except for the example) that hints >>>> that port has to be zero, so that's one thing in favor of just getting >>>> rid of the port number checking altogether... >>> >>> The port numbering must be defined and fixed. If that is not clear in >>> the binding, fix the binding. >> >> Ok, so the code in my patch does the right thing forcing the port >> number to zero. >> >>>>>> @@ -77,13 +79,29 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) >>>>>> >>>>>> int atmel_hlcdc_create_outputs(struct drm_device *dev) >>>>>> { >>>>>> - int endpoint, ret = 0; >>>>>> - >>>>>> - for (endpoint = 0; !ret; endpoint++) >>>>>> - ret = atmel_hlcdc_attach_endpoint(dev, endpoint); >>>>>> + struct of_endpoint endpoint; >>>>>> + struct device_node *node = NULL; >>>>>> + int count = 0; >>>>>> + int ret = 0; >>>>>> + >>>>>> + for_each_endpoint_of_node(dev->dev->of_node, node) { >>>>>> + of_graph_parse_endpoint(node, &endpoint); >>> >>> I'd really like to kill off of_graph_parse_endpoint, not add more >>> users (check the git history on this code). You should know what are >>> possible port and endpoint numbers, so iterate over those. >> >> So, add a comment to that effect in the docs of the of_graph_parse_endpoint >> function. >> >> How can the hlcdc driver know the actual number of endpoints? It's a >> one-way signal path out from that port, and it can easily be routed to >> 1, 2, 3 or even more places. As shown above, forcing the endpoint id >> to start at zero is a nuisance, and I don't see the point of it. >> >> But I welcome suggestions on how to arrange the above dtsi/dts fragments >> in a world where the endpoint id absolutely has to start at zero. > > Your dts file arrangement seems fine. Can't you just not exit the loop > on -ENODEV? IOW, just iterate til you find an enabled endpoint. That would regress cases where two (or more) endpoints are enabled (which is currently supported). As I see it, the driver will have a very hard time knowing when to stop iterating with any solution not involving the equivalent of the functions for_each_endpoint_of_node and of_graph_parse_endpoint. Open-coding of_graph_parse_endpoint just to avoid it is a bit more than silly IMHO... Cheers, Peter