Skip to content

Commit

Permalink
drm/sun4i: tcon: Find matching display backend by device node matching
Browse files Browse the repository at this point in the history
With Allwinner's Display Engine 1.0, each TCON's input is tied to a
specific display backend, and the 2 comprise what is known as a crtc
in DRM KMS land: The layer, framebuffer, and compositing functions are
provided by the backend, while the TCON provides the display timing
signals and vblank interrupts. This 1 to 1 relationship is represented
in the device tree. On some systems there is an intermediate DRC
component.

Pointers to both matching components must be provided when initializing
the crtc. As the backend is always registered before the associated
tcon, we can recursively search upwards through the of_graph to find
the matching backend.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
  • Loading branch information
Chen-Yu Tsai authored and Maxime Ripard committed May 14, 2017
1 parent 2c03e2f commit b317fa3
Showing 1 changed file with 51 additions and 4 deletions.
55 changes: 51 additions & 4 deletions drivers/gpu/drm/sun4i/sun4i_tcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,53 @@ static int sun4i_tcon_init_regmap(struct device *dev,
return 0;
}

/*
* On SoCs with the old display pipeline design (Display Engine 1.0),
* the TCON is always tied to just one backend. Hence we can traverse
* the of_graph upwards to find the backend our tcon is connected to,
* and take its ID as our own.
*
* We can either identify backends from their compatible strings, which
* means maintaining a large list of them. Or, since the backend is
* registered and binded before the TCON, we can just go through the
* list of registered backends and compare the device node.
*/
static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv,
struct device_node *node)
{
struct device_node *port, *ep, *remote;
struct sun4i_backend *backend;

port = of_graph_get_port_by_id(node, 0);
if (!port)
return ERR_PTR(-EINVAL);

for_each_available_child_of_node(port, ep) {
remote = of_graph_get_remote_port_parent(ep);
if (!remote)
continue;

/* does this node match any registered backends? */
list_for_each_entry(backend, &drv->backend_list, list) {
if (remote == backend->node) {
of_node_put(remote);
of_node_put(port);
return backend;
}
}

/* keep looking through upstream ports */
backend = sun4i_tcon_find_backend(drv, remote);
if (!IS_ERR(backend)) {
of_node_put(remote);
of_node_put(port);
return backend;
}
}

return ERR_PTR(-EINVAL);
}

static int sun4i_tcon_bind(struct device *dev, struct device *master,
void *data)
{
Expand All @@ -412,9 +459,11 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
struct sun4i_tcon *tcon;
int ret;

/* Wait for a backend to be registered */
if (list_empty(&drv->backend_list))
backend = sun4i_tcon_find_backend(drv, dev->of_node);
if (IS_ERR(backend)) {
dev_err(dev, "Couldn't find matching backend\n");
return -EPROBE_DEFER;
}

tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
if (!tcon)
Expand Down Expand Up @@ -464,8 +513,6 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
goto err_free_dotclock;
}

backend = list_first_entry(&drv->backend_list,
struct sun4i_backend, list);
tcon->crtc = sun4i_crtc_init(drm, backend, tcon);
if (IS_ERR(tcon->crtc)) {
dev_err(dev, "Couldn't create our CRTC\n");
Expand Down

0 comments on commit b317fa3

Please sign in to comment.