[PATCH 4/8] drm/sun4i: tcon: get TCON ID and matching engine with remote endpoint ID
Maxime Ripard
maxime.ripard at free-electrons.com
Sat Sep 9 08:42:57 PDT 2017
Hi,
On Fri, Sep 08, 2017 at 03:50:12PM +0800, Chen-Yu Tsai wrote:
> The device tree binding for sun4i-drm says:
>
> For all connections between components up to the TCONs in the display
> pipeline, when there are multiple components of the same type at the
> same depth, the local endpoint ID must be the same as the remote
> component's index. For example, if the remote endpoint is Frontend 1,
> then the local endpoint ID must be 1.
>
> We should be able to get the TCON's ID directly from any of the remote
> endpoints from its input port. With the ID, we can then go through the
> list of registered engines and find a matching one by ID.
>
> However the A31 device tree is incorrect. We assumed that there were no
> cross pipeline connections between the backends and TCONs. As a result,
> in all the endpoints between the backends and TCONs of the second
> display pipeline, the endpoint IDs were incorrectly set to 0, when in
> fact they should've been set to 1.
>
> To maintain compatibility with this incorrect device tree, we first
> check if the TCON's input port has 1 or many endpoints. If there are
> more than 1, then it is likely a fixed version, and we can proceed
> with the new method. If there is only 1 endpoint, then it is possibly
> an incorrect version, or it could be the SoC only has one pipeline.
> In either case we fall back to using the old method of traversing
> the input connections to find a matching engine, and then get its
> ID.
>
> Signed-off-by: Chen-Yu Tsai <wens at csie.org>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 121 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 118 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 065654dbfb2c..33c20d2f9fb1 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -463,8 +463,9 @@ static int sun4i_tcon_init_regmap(struct device *dev,
> * function in fact searches the corresponding engine, and the ID is
> * requested via the get_id function of the engine.
> */
> -static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
> - struct device_node *node)
> +static struct sunxi_engine *
> +sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,
> + struct device_node *node)
> {
> struct device_node *port, *ep, *remote;
> struct sunxi_engine *engine;
> @@ -502,7 +503,7 @@ static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
> }
>
> /* keep looking through upstream ports */
> - engine = sun4i_tcon_find_engine(drv, remote);
> + engine = sun4i_tcon_find_engine_traverse(drv, remote);
> if (!IS_ERR(engine)) {
> of_node_put(remote);
> of_node_put(port);
> @@ -513,6 +514,120 @@ static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
> return ERR_PTR(-EINVAL);
> }
>
> +/*
> + * The device tree binding says that the remote endpoint ID of any
> + * connection between components, up to and including the TCON, of
> + * the display pipeline should be equal to the actual ID of the local
> + * component. Thus we can look at any one of the input connections of
> + * the TCONs, and use that connection's remote endpoint ID as our own.
> + *
> + * Since the user of this function already finds the input port,
> + * the port is passed in directly without further checks.
> + */
> +static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
> +{
> + struct device_node *ep;
> + int ret = -EINVAL;
> +
> + /* try finding an upstream endpoint */
> + for_each_available_child_of_node(port, ep) {
> + struct device_node *remote;
> + u32 reg;
> +
> + remote = of_graph_get_remote_endpoint(ep);
> + if (!remote)
> + continue;
> +
> + ret = of_property_read_u32(remote, "reg", ®);
> + if (ret)
> + continue;
> +
> + ret = reg;
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Once we know the TCON's id, we can look through the list of
> + * engines to find a matching one. We assume all engines have
> + * been probed and added to the list.
> + */
> +static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
> + int id)
> +{
> + struct sunxi_engine *engine;
> +
> + list_for_each_entry(engine, &drv->engine_list, list)
> + if (engine->id == id)
> + return engine;
> +
> + return ERR_PTR(-EINVAL);
> +}
> +
> +/*
> + * On SoCs with the old display pipeline design (Display Engine 1.0),
> + * we assumed the TCON was always tied to just one backend. However
> + * this proved not to be the case. On the A31, the TCON can select
> + * either backend as its source. On the A20 (and likely on the A10),
> + * the backend can choose which TCON to output to.
> + *
> + * The device tree binding says that the remote endpoint ID of any
> + * connection between components, up to and including the TCON, of
> + * the display pipeline should be equal to the actual ID of the local
> + * component. Thus we should be able to look at any one of the input
> + * connections of the TCONs, and use that connection's remote endpoint
> + * ID as our own.
> + *
> + * However the connections between the backend and TCON were assumed
> + * to be always singular, and their endpoit IDs were all incorrectly
> + * set to 0. This means for these old device trees, we cannot just look
> + * up the remote endpoint ID of a TCON input endpoint. TCON1 would be
> + * incorrectly identified as TCON0.
> + *
> + * This function first checks if the TCON node has 2 input endpoints.
> + * If so, then the device tree is a corrected version, and it will use
> + * sun4i_tcon_of_get_id() and sun4i_tcon_get_engine_by_id() from above
> + * to fetch the ID and engine directly. If not, then it is likely an
> + * old device trees, where the endpoint IDs were incorrect, but did not
> + * have endpoint connections between the backend and TCON across
> + * different display pipelines. It will fall back to the old method of
> + * traversing the of_graph to try and find a matching engine by device
> + * node.
> + *
> + * In the case of single display pipeline device trees, either method
> + * works.
> + */
> +static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
> + struct device_node *node)
> +{
> + struct device_node *port;
> + struct sunxi_engine *engine;
> +
> + port = of_graph_get_port_by_id(node, 0);
> + if (!port)
> + return ERR_PTR(-EINVAL);
> +
> + /*
> + * Is this a corrected device tree with cross pipeline
> + * connections between the backend and TCON?
> + */
> + if (of_get_child_count(port) > 1) {
> + /* Get our ID directly from an upstream endpoint */
> + int id = sun4i_tcon_of_get_id_from_port(port);
> +
> + /* Get our engine by matching our ID */
> + engine = sun4i_tcon_get_engine_by_id(drv, id);
> +
> + of_node_put(port);
> + return engine;
> + }
> +
> + /* Fallback to old method by traversing input endpoints */
> + of_node_put(port);
> + return sun4i_tcon_find_engine_traverse(drv, node);
In the old DT case, I'd like to have a warning displayed in the log
saying that the DT is too old and we won't be able to support the
dual-pipeline properly, so that the users can at least know that they
should update.
Can you add it in a follow-up?
Thanks!
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170909/624f613a/attachment.sig>
More information about the linux-arm-kernel
mailing list