Message ID | 463d18493ac508708ed764e71d11c2b89662544c.1478103726.git.jsarha@ti.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Jyri, Thank you for the patch. On Wednesday 02 Nov 2016 18:32:17 Jyri Sarha wrote: > Adds drm bride support for attaching drm bridge drivers to tilcdc. The > decision whether a video port leads to an external encoder or bridge > is made simply based on remote device's compatible string. The code > has been tested with BeagleBone-Black with and without BeagleBone > DVI-D Cape Rev A3 using ti-tfp410 driver. > > Signed-off-by: Jyri Sarha <jsarha@ti.com> > --- > .../devicetree/bindings/display/tilcdc/tilcdc.txt | 7 +- > drivers/gpu/drm/tilcdc/tilcdc_drv.c | 7 +- > drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 + > drivers/gpu/drm/tilcdc/tilcdc_external.c | 140 ++++++++++++++--- > drivers/gpu/drm/tilcdc/tilcdc_external.h | 1 + > 5 files changed, 135 insertions(+), 22 deletions(-) > > diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt index > 6fddb4f..ae7a942 100644 > --- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > @@ -34,9 +34,10 @@ Optional properties: > > Optional nodes: > > - - port/ports: to describe a connection to an external encoder. The > - binding follows Documentation/devicetree/bindings/graph.txt and > - suppors a single port with a single endpoint. > + - port/ports: to describe a connection to an external encoder or > + bridge. The binding follows What's the difference between encoder and bridge here ? drm_bridge and drm_encoder are irrelevant to DT bindings, we should only care about the hardware view of the system here. > + Documentation/devicetree/bindings/graph.txt and suppors a single > + port with a single endpoint. > > - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and > Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for > connecting diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c > b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index dcc9621..ec22576 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c > +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c > @@ -384,9 +384,14 @@ static int tilcdc_init(struct drm_driver *ddrv, struct > device *dev) ret = tilcdc_add_external_encoders(ddev); > if (ret < 0) > goto init_failed; > + } else { > + ret = tilcdc_attach_remote_device(ddev); > + if (ret) > + goto init_failed; > } > > - if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { > + if (!priv->remote_encoder && > + ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { > dev_err(dev, "no encoders/connectors found\n"); > ret = -ENXIO; > goto init_failed; > diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h > b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index d31fe5d..283ff28 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h > +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h > @@ -90,6 +90,8 @@ struct tilcdc_drm_private { > struct drm_connector *connectors[8]; > const struct drm_connector_helper_funcs *connector_funcs[8]; > > + struct drm_encoder *remote_encoder; > + > bool is_registered; > bool is_componentized; > }; > diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c > b/drivers/gpu/drm/tilcdc/tilcdc_external.c index 06a4c58..bcb1324 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c > +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c > @@ -28,6 +28,18 @@ > .raster_order = 0, > }; > > +static const struct tilcdc_panel_info panel_info_default = { > + .ac_bias = 255, > + .ac_bias_intrpt = 0, > + .dma_burst_sz = 16, > + .bpp = 16, > + .fdd = 0x80, > + .tft_alt_mode = 0, > + .sync_edge = 0, > + .sync_ctrl = 1, > + .raster_order = 0, > +}; > + > static int tilcdc_external_mode_valid(struct drm_connector *connector, > struct drm_display_mode *mode) > { > @@ -130,6 +142,101 @@ void tilcdc_remove_external_encoders(struct drm_device > *dev) priv->connector_funcs[i]); > } > > +static struct drm_encoder_funcs tilcdc_remote_encoder_funcs = { > + .destroy = drm_encoder_cleanup, > +}; > + > +static > +int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge > *bridge) +{ > + struct tilcdc_drm_private *priv = ddev->dev_private; > + int ret; > + > + priv->remote_encoder->possible_crtcs = BIT(0); > + priv->remote_encoder->bridge = bridge; > + bridge->encoder = priv->remote_encoder; > + > + ret = drm_bridge_attach(ddev, bridge); > + if (ret) { > + dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret); > + return ret; > + } > + > + tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default); > + > + return 0; > +} > + > +static int tilcdc_node_has_port(struct device_node *dev_node) > +{ > + struct device_node *node; > + > + node = of_get_child_by_name(dev_node, "ports"); > + if (!node) > + node = of_get_child_by_name(dev_node, "port"); > + if (!node) > + return 0; > + of_node_put(node); > + > + return 1; > +} > + > +static > +struct device_node *tilcdc_get_remote_node(struct device_node *node) > +{ > + struct device_node *ep; > + struct device_node *parent; > + > + if (!tilcdc_node_has_port(node)) > + return NULL; > + > + ep = of_graph_get_next_endpoint(node, NULL); > + if (!ep) > + return NULL; > + > + parent = of_graph_get_remote_port_parent(ep); > + of_node_put(ep); > + > + return parent; > +} > + > +int tilcdc_attach_remote_device(struct drm_device *ddev) > +{ > + struct tilcdc_drm_private *priv = ddev->dev_private; > + struct device_node *remote_node; > + struct drm_bridge *bridge; > + int ret; > + > + remote_node = tilcdc_get_remote_node(ddev->dev->of_node); > + if (!remote_node) > + return 0; > + > + bridge = of_drm_find_bridge(remote_node); > + of_node_put(remote_node); > + if (!bridge) > + return -EPROBE_DEFER; > + > + priv->remote_encoder = devm_kzalloc(ddev->dev, > + sizeof(*priv->remote_encoder), > + GFP_KERNEL); > + if (!priv->remote_encoder) > + return -ENOMEM; > + > + ret = drm_encoder_init(ddev, priv->remote_encoder, > + &tilcdc_remote_encoder_funcs, > + DRM_MODE_ENCODER_NONE, NULL); > + if (ret) { > + dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret); > + return ret; > + } > + > + ret = tilcdc_attach_bridge(ddev, bridge); > + if (ret) > + drm_encoder_cleanup(priv->remote_encoder); > + > + return ret; > +} > + > static int dev_match_of(struct device *dev, void *data) > { > return dev->of_node == data; > @@ -141,16 +248,10 @@ int tilcdc_get_external_components(struct device *dev, > struct device_node *node; > struct device_node *ep = NULL; > int count = 0; > + int ret = 0; > > - /* Avoid error print by of_graph_get_next_endpoint() if there > - * is no ports present. > - */ > - node = of_get_child_by_name(dev->of_node, "ports"); > - if (!node) > - node = of_get_child_by_name(dev->of_node, "port"); > - if (!node) > + if (!tilcdc_node_has_port(dev->of_node)) > return 0; > - of_node_put(node); > > while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) { > node = of_graph_get_remote_port_parent(ep); > @@ -160,17 +261,20 @@ int tilcdc_get_external_components(struct device *dev, > } > > dev_dbg(dev, "Subdevice node '%s' found\n", node->name); > - if (match) > - drm_of_component_match_add(dev, match, dev_match_of, > - node); > - of_node_put(node); > - count++; > - } > > - if (count > 1) { > - dev_err(dev, "Only one external encoder is supported\n"); > - return -EINVAL; > + if (of_device_is_compatible(node, "nxp,tda998x")) { > + if (match) > + drm_of_component_match_add(dev, match, > + dev_match_of, node); > + ret = 1; > + } > + > + of_node_put(node); > + if (count++ > 1) { > + dev_err(dev, "Only one port is supported\n"); > + return -EINVAL; > + } > } > > - return count; > + return ret; > } > diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h > b/drivers/gpu/drm/tilcdc/tilcdc_external.h index c700e0c..a27c365 100644 > --- a/drivers/gpu/drm/tilcdc/tilcdc_external.h > +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h > @@ -22,4 +22,5 @@ > void tilcdc_remove_external_encoders(struct drm_device *dev); > int tilcdc_get_external_components(struct device *dev, > struct component_match **match); > +int tilcdc_attach_remote_device(struct drm_device *ddev); > #endif /* __TILCDC_SLAVE_H__ */
On Wed, Nov 02, 2016 at 06:32:17PM +0200, Jyri Sarha wrote: > Adds drm bride support for attaching drm bridge drivers to tilcdc. The > decision whether a video port leads to an external encoder or bridge > is made simply based on remote device's compatible string. The code > has been tested with BeagleBone-Black with and without BeagleBone > DVI-D Cape Rev A3 using ti-tfp410 driver. > > Signed-off-by: Jyri Sarha <jsarha@ti.com> > --- > .../devicetree/bindings/display/tilcdc/tilcdc.txt | 7 +- > drivers/gpu/drm/tilcdc/tilcdc_drv.c | 7 +- > drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 + > drivers/gpu/drm/tilcdc/tilcdc_external.c | 140 ++++++++++++++++++--- > drivers/gpu/drm/tilcdc/tilcdc_external.h | 1 + > 5 files changed, 135 insertions(+), 22 deletions(-) > > diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > index 6fddb4f..ae7a942 100644 > --- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt > @@ -34,9 +34,10 @@ Optional properties: > > Optional nodes: > > - - port/ports: to describe a connection to an external encoder. The > - binding follows Documentation/devicetree/bindings/graph.txt and > - suppors a single port with a single endpoint. > + - port/ports: to describe a connection to an external encoder or > + bridge. The binding follows > + Documentation/devicetree/bindings/graph.txt and suppors a single > + port with a single endpoint. I don't think a DT change is needed here. Bridge vs. encoder is all DRM terminology. > > - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and > Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt index 6fddb4f..ae7a942 100644 --- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt +++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt @@ -34,9 +34,10 @@ Optional properties: Optional nodes: - - port/ports: to describe a connection to an external encoder. The - binding follows Documentation/devicetree/bindings/graph.txt and - suppors a single port with a single endpoint. + - port/ports: to describe a connection to an external encoder or + bridge. The binding follows + Documentation/devicetree/bindings/graph.txt and suppors a single + port with a single endpoint. - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index dcc9621..ec22576 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -384,9 +384,14 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev) ret = tilcdc_add_external_encoders(ddev); if (ret < 0) goto init_failed; + } else { + ret = tilcdc_attach_remote_device(ddev); + if (ret) + goto init_failed; } - if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { + if (!priv->remote_encoder && + ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); ret = -ENXIO; goto init_failed; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index d31fe5d..283ff28 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -90,6 +90,8 @@ struct tilcdc_drm_private { struct drm_connector *connectors[8]; const struct drm_connector_helper_funcs *connector_funcs[8]; + struct drm_encoder *remote_encoder; + bool is_registered; bool is_componentized; }; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index 06a4c58..bcb1324 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -28,6 +28,18 @@ .raster_order = 0, }; +static const struct tilcdc_panel_info panel_info_default = { + .ac_bias = 255, + .ac_bias_intrpt = 0, + .dma_burst_sz = 16, + .bpp = 16, + .fdd = 0x80, + .tft_alt_mode = 0, + .sync_edge = 0, + .sync_ctrl = 1, + .raster_order = 0, +}; + static int tilcdc_external_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { @@ -130,6 +142,101 @@ void tilcdc_remove_external_encoders(struct drm_device *dev) priv->connector_funcs[i]); } +static struct drm_encoder_funcs tilcdc_remote_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static +int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge) +{ + struct tilcdc_drm_private *priv = ddev->dev_private; + int ret; + + priv->remote_encoder->possible_crtcs = BIT(0); + priv->remote_encoder->bridge = bridge; + bridge->encoder = priv->remote_encoder; + + ret = drm_bridge_attach(ddev, bridge); + if (ret) { + dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret); + return ret; + } + + tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default); + + return 0; +} + +static int tilcdc_node_has_port(struct device_node *dev_node) +{ + struct device_node *node; + + node = of_get_child_by_name(dev_node, "ports"); + if (!node) + node = of_get_child_by_name(dev_node, "port"); + if (!node) + return 0; + of_node_put(node); + + return 1; +} + +static +struct device_node *tilcdc_get_remote_node(struct device_node *node) +{ + struct device_node *ep; + struct device_node *parent; + + if (!tilcdc_node_has_port(node)) + return NULL; + + ep = of_graph_get_next_endpoint(node, NULL); + if (!ep) + return NULL; + + parent = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + + return parent; +} + +int tilcdc_attach_remote_device(struct drm_device *ddev) +{ + struct tilcdc_drm_private *priv = ddev->dev_private; + struct device_node *remote_node; + struct drm_bridge *bridge; + int ret; + + remote_node = tilcdc_get_remote_node(ddev->dev->of_node); + if (!remote_node) + return 0; + + bridge = of_drm_find_bridge(remote_node); + of_node_put(remote_node); + if (!bridge) + return -EPROBE_DEFER; + + priv->remote_encoder = devm_kzalloc(ddev->dev, + sizeof(*priv->remote_encoder), + GFP_KERNEL); + if (!priv->remote_encoder) + return -ENOMEM; + + ret = drm_encoder_init(ddev, priv->remote_encoder, + &tilcdc_remote_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) { + dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret); + return ret; + } + + ret = tilcdc_attach_bridge(ddev, bridge); + if (ret) + drm_encoder_cleanup(priv->remote_encoder); + + return ret; +} + static int dev_match_of(struct device *dev, void *data) { return dev->of_node == data; @@ -141,16 +248,10 @@ int tilcdc_get_external_components(struct device *dev, struct device_node *node; struct device_node *ep = NULL; int count = 0; + int ret = 0; - /* Avoid error print by of_graph_get_next_endpoint() if there - * is no ports present. - */ - node = of_get_child_by_name(dev->of_node, "ports"); - if (!node) - node = of_get_child_by_name(dev->of_node, "port"); - if (!node) + if (!tilcdc_node_has_port(dev->of_node)) return 0; - of_node_put(node); while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) { node = of_graph_get_remote_port_parent(ep); @@ -160,17 +261,20 @@ int tilcdc_get_external_components(struct device *dev, } dev_dbg(dev, "Subdevice node '%s' found\n", node->name); - if (match) - drm_of_component_match_add(dev, match, dev_match_of, - node); - of_node_put(node); - count++; - } - if (count > 1) { - dev_err(dev, "Only one external encoder is supported\n"); - return -EINVAL; + if (of_device_is_compatible(node, "nxp,tda998x")) { + if (match) + drm_of_component_match_add(dev, match, + dev_match_of, node); + ret = 1; + } + + of_node_put(node); + if (count++ > 1) { + dev_err(dev, "Only one port is supported\n"); + return -EINVAL; + } } - return count; + return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h index c700e0c..a27c365 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h @@ -22,4 +22,5 @@ void tilcdc_remove_external_encoders(struct drm_device *dev); int tilcdc_get_external_components(struct device *dev, struct component_match **match); +int tilcdc_attach_remote_device(struct drm_device *ddev); #endif /* __TILCDC_SLAVE_H__ */
Adds drm bride support for attaching drm bridge drivers to tilcdc. The decision whether a video port leads to an external encoder or bridge is made simply based on remote device's compatible string. The code has been tested with BeagleBone-Black with and without BeagleBone DVI-D Cape Rev A3 using ti-tfp410 driver. Signed-off-by: Jyri Sarha <jsarha@ti.com> --- .../devicetree/bindings/display/tilcdc/tilcdc.txt | 7 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 7 +- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 + drivers/gpu/drm/tilcdc/tilcdc_external.c | 140 ++++++++++++++++++--- drivers/gpu/drm/tilcdc/tilcdc_external.h | 1 + 5 files changed, 135 insertions(+), 22 deletions(-)