Re: [PATCH v8 3/4] drm/atmel-hlcdc: iterate over all output endpoints
From: Rob Herring
Date: Tue Aug 14 2018 - 10:33:19 EST
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.
> 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.
Rob