summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/synopsys/dw-hdmi.c')
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index e7c7c9b9c646..f08d0fded61f 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -143,6 +143,7 @@ struct dw_hdmi_phy_data {
struct dw_hdmi {
struct drm_connector connector;
struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
unsigned int version;
@@ -2775,7 +2776,8 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
struct dw_hdmi *hdmi = bridge->driver_private;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
- return 0;
+ return drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ bridge, flags);
return dw_hdmi_connector_create(hdmi);
}
@@ -3160,6 +3162,52 @@ static void dw_hdmi_init_hw(struct dw_hdmi *hdmi)
/* -----------------------------------------------------------------------------
* Probe/remove API, used from platforms based on the DRM bridge API.
*/
+
+static int dw_hdmi_parse_dt(struct dw_hdmi *hdmi)
+{
+ struct device_node *endpoint;
+ struct device_node *remote;
+
+ if (!hdmi->plat_data->output_port)
+ return 0;
+
+ endpoint = of_graph_get_endpoint_by_regs(hdmi->dev->of_node,
+ hdmi->plat_data->output_port,
+ -1);
+ if (!endpoint) {
+ /*
+ * On platforms whose bindings don't make the output port
+ * mandatory (such as Rockchip) the plat_data->output_port
+ * field isn't set, so it's safe to make this a fatal error.
+ */
+ dev_err(hdmi->dev, "Missing endpoint in port@%u\n",
+ hdmi->plat_data->output_port);
+ return -ENODEV;
+ }
+
+ remote = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+ if (!remote) {
+ dev_err(hdmi->dev, "Endpoint in port@%u unconnected\n",
+ hdmi->plat_data->output_port);
+ return -ENODEV;
+ }
+
+ if (!of_device_is_available(remote)) {
+ dev_err(hdmi->dev, "port@%u remote device is disabled\n",
+ hdmi->plat_data->output_port);
+ of_node_put(remote);
+ return -ENODEV;
+ }
+
+ hdmi->next_bridge = of_drm_find_bridge(remote);
+ of_node_put(remote);
+ if (!hdmi->next_bridge)
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data)
{
@@ -3196,6 +3244,10 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
mutex_init(&hdmi->cec_notifier_mutex);
spin_lock_init(&hdmi->audio_lock);
+ ret = dw_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@@ -3474,7 +3526,6 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
if (ret) {
dw_hdmi_remove(hdmi);
- DRM_ERROR("Failed to initialize bridge with drm\n");
return ERR_PTR(ret);
}