Commit 73eb5476 authored by Laurent Pinchart's avatar Laurent Pinchart

drm: rcar-du: Support panels connected directly to the DPAD outputs

The R-Car DU driver assumes that a bridge is always connected to the DU
output. This is valid for the LVDS and HDMI outputs, but the DPAD
outputs can be connected directly to a panel, in which case no bridge is
available.

To support this use case, detect whether the entities connected to the
DU DPAD outputs are encoders or panels based on the number of ports of
their DT node, and retrieve the corresponding type of DRM objects. For
panels, additionally create panel bridge instances.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: default avatarKevin Key <kevin.key@gentex.com>
Reviewed-by: default avatarKieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
parent 0bec6219
...@@ -28,13 +28,33 @@ static const struct drm_encoder_funcs encoder_funcs = { ...@@ -28,13 +28,33 @@ static const struct drm_encoder_funcs encoder_funcs = {
.destroy = drm_encoder_cleanup, .destroy = drm_encoder_cleanup,
}; };
static unsigned int rcar_du_encoder_count_ports(struct device_node *node)
{
struct device_node *ports;
struct device_node *port;
unsigned int num_ports = 0;
ports = of_get_child_by_name(node, "ports");
if (!ports)
ports = of_node_get(node);
for_each_child_of_node(ports, port) {
if (of_node_name_eq(port, "port"))
num_ports++;
}
of_node_put(ports);
return num_ports;
}
int rcar_du_encoder_init(struct rcar_du_device *rcdu, int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output, enum rcar_du_output output,
struct device_node *enc_node) struct device_node *enc_node)
{ {
struct rcar_du_encoder *renc; struct rcar_du_encoder *renc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_bridge *bridge = NULL; struct drm_bridge *bridge;
int ret; int ret;
renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
...@@ -48,12 +68,34 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, ...@@ -48,12 +68,34 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n", dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
enc_node, output); enc_node, output);
/* Locate the DRM bridge from the encoder DT node. */ /*
* Locate the DRM bridge from the DT node. For the DPAD outputs, if the
* DT node has a single port, assume that it describes a panel and
* create a panel bridge.
*/
if ((output == RCAR_DU_OUTPUT_DPAD0 ||
output == RCAR_DU_OUTPUT_DPAD1) &&
rcar_du_encoder_count_ports(enc_node) == 1) {
struct drm_panel *panel = of_drm_find_panel(enc_node);
if (IS_ERR(panel)) {
ret = PTR_ERR(panel);
goto done;
}
bridge = devm_drm_panel_bridge_add(rcdu->dev, panel,
DRM_MODE_CONNECTOR_DPI);
if (IS_ERR(bridge)) {
ret = PTR_ERR(bridge);
goto done;
}
} else {
bridge = of_drm_find_bridge(enc_node); bridge = of_drm_find_bridge(enc_node);
if (!bridge) { if (!bridge) {
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto done; goto done;
} }
}
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
DRM_MODE_ENCODER_NONE, NULL); DRM_MODE_ENCODER_NONE, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment