Skip to content

Commit

Permalink
drm/omap: Add support for drm_bridge
Browse files Browse the repository at this point in the history
Hook up drm_bridge support in the omapdrm driver. Despite the recent
extensive preparation work, this is a rather intrusive change, as the
management of outputs needs to be adapted through the driver to handle
both omap_dss_device and drm_bridge.

Connector creation is skipped when using a drm_bridge, as the bridge
creates the connector internally. This creates issues with systems that
split connector operations (such as modes retrieval and hot-plug
detection) across different bridges. These systems can't be supported
using drm_bridge for now (their support through the omap_dss_device
infrastructure is not affected), this will be fixed in subsequent
changes.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Tested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
  • Loading branch information
Laurent Pinchart authored and Tomi Valkeinen committed Mar 18, 2019
1 parent 163f7a3 commit 79107f2
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 62 deletions.
27 changes: 24 additions & 3 deletions drivers/gpu/drm/omapdrm/dss/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>

#include "dss.h"
#include "omapdss.h"
Expand Down Expand Up @@ -156,7 +157,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
goto done;
}

if (dssdev->id && dssdev->next)
if (dssdev->id && (dssdev->next || dssdev->bridge))
goto done;
}

Expand Down Expand Up @@ -184,7 +185,18 @@ int omapdss_device_connect(struct dss_device *dss,
{
int ret;

dev_dbg(dst->dev, "connect\n");
dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
src ? dev_name(src->dev) : "NULL",
dst ? dev_name(dst->dev) : "NULL");

if (!dst) {
/*
* The destination is NULL when the source is connected to a
* bridge instead of a DSS device. Stop here, we will attach the
* bridge later when we will have a DRM encoder.
*/
return src && src->bridge ? 0 : -EINVAL;
}

if (omapdss_device_is_connected(dst))
return -EBUSY;
Expand All @@ -204,7 +216,16 @@ EXPORT_SYMBOL_GPL(omapdss_device_connect);
void omapdss_device_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
dev_dbg(dst->dev, "disconnect\n");
struct dss_device *dss = src ? src->dss : dst->dss;

dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
src ? dev_name(src->dev) : "NULL",
dst ? dev_name(dst->dev) : "NULL");

if (!dst) {
WARN_ON(!src->bridge);
return;
}

if (!dst->id && !omapdss_device_is_connected(dst)) {
WARN_ON(!dst->display);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/omapdrm/dss/omapdss.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ struct omap_dss_device {

struct dss_device *dss;
struct omap_dss_device *next;
struct drm_bridge *bridge;

struct list_head list;

Expand Down
21 changes: 15 additions & 6 deletions drivers/gpu/drm/omapdrm/dss/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,34 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_graph.h>

#include "dss.h"
#include "omapdss.h"

int omapdss_device_init_output(struct omap_dss_device *out)
{
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
struct device_node *remote_node;

remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0);
if (!remote_node) {
dev_dbg(out->dev, "failed to find video sink\n");
return 0;
}

out->next = omapdss_find_device_by_node(remote_node);
out->bridge = of_drm_find_bridge(remote_node);

of_node_put(remote_node);

if (out->next && out->type != out->next->type) {
dev_err(out->dev, "output type and display type don't match\n");
omapdss_device_put(out->next);
out->next = NULL;
return -EINVAL;
}

return 0;
return out->next || out->bridge ? 0 : -EPROBE_DEFER;
}
EXPORT_SYMBOL(omapdss_device_init_output);

Expand Down
16 changes: 11 additions & 5 deletions drivers/gpu/drm/omapdrm/omap_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,16 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
.mode_valid = omap_connector_mode_valid,
};

static int omap_connector_get_type(struct omap_dss_device *display)
static int omap_connector_get_type(struct omap_dss_device *output)
{
switch (display->type) {
struct omap_dss_device *display;
enum omap_display_type type;

display = omapdss_display_get(output);
type = display->type;
omapdss_device_put(display);

switch (type) {
case OMAP_DISPLAY_TYPE_HDMI:
return DRM_MODE_CONNECTOR_HDMIA;
case OMAP_DISPLAY_TYPE_DVI:
Expand All @@ -324,14 +331,13 @@ static int omap_connector_get_type(struct omap_dss_device *display)
/* initialize connector */
struct drm_connector *omap_connector_init(struct drm_device *dev,
struct omap_dss_device *output,
struct omap_dss_device *display,
struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
struct omap_connector *omap_connector;
struct omap_dss_device *dssdev;

DBG("%s", display->name);
DBG("%s", output->name);

omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
if (!omap_connector)
Expand All @@ -344,7 +350,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
connector->doublescan_allowed = 0;

drm_connector_init(dev, connector, &omap_connector_funcs,
omap_connector_get_type(display));
omap_connector_get_type(output));
drm_connector_helper_add(connector, &omap_connector_helper_funcs);

/*
Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/omapdrm/omap_connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ struct omap_dss_device;

struct drm_connector *omap_connector_init(struct drm_device *dev,
struct omap_dss_device *output,
struct omap_dss_device *display,
struct drm_encoder *encoder);
bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
void omap_connector_enable_hpd(struct drm_connector *connector);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/omapdrm/omap_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
&omap_crtc_funcs, NULL);
if (ret < 0) {
dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
__func__, pipe->display->name);
__func__, pipe->output->name);
kfree(omap_crtc);
return ERR_PTR(ret);
}
Expand Down
69 changes: 51 additions & 18 deletions drivers/gpu/drm/omapdrm/omap_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,7 @@ static void omap_disconnect_pipelines(struct drm_device *ddev)
omapdss_device_disconnect(NULL, pipe->output);

omapdss_device_put(pipe->output);
omapdss_device_put(pipe->display);
pipe->output = NULL;
pipe->display = NULL;
}

memset(&priv->channels, 0, sizeof(priv->channels));
Expand All @@ -169,7 +167,6 @@ static int omap_connect_pipelines(struct drm_device *ddev)

pipe = &priv->pipes[priv->num_pipes++];
pipe->output = omapdss_device_get(output);
pipe->display = omapdss_display_get(output);

if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) {
/* To balance the 'for_each_dss_output' loop */
Expand Down Expand Up @@ -207,6 +204,28 @@ static int omap_modeset_init_properties(struct drm_device *dev)
return 0;
}

static int omap_display_id(struct omap_dss_device *output)
{
struct device_node *node = NULL;

if (output->next) {
struct omap_dss_device *display;

display = omapdss_display_get(output);
node = display->dev->of_node;
omapdss_device_put(display);
} else {
struct drm_bridge *bridge = output->bridge;

while (bridge->next)
bridge = bridge->next;

node = bridge->of_node;
}

return node ? of_alias_get_id(node, "display") : -ENODEV;
}

static int omap_modeset_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
Expand Down Expand Up @@ -262,7 +281,10 @@ static int omap_modeset_init(struct drm_device *dev)
priv->planes[priv->num_planes++] = plane;
}

/* Create the encoders and get the pipelines aliases. */
/*
* Create the encoders, attach the bridges and get the pipeline alias
* IDs.
*/
for (i = 0; i < priv->num_pipes; i++) {
struct omap_drm_pipeline *pipe = &priv->pipes[i];
int id;
Expand All @@ -271,7 +293,14 @@ static int omap_modeset_init(struct drm_device *dev)
if (!pipe->encoder)
return -ENOMEM;

id = of_alias_get_id(pipe->display->dev->of_node, "display");
if (pipe->output->bridge) {
ret = drm_bridge_attach(pipe->encoder,
pipe->output->bridge, NULL);
if (ret < 0)
return ret;
}

id = omap_display_id(pipe->output);
pipe->alias_id = id >= 0 ? id : i;
}

Expand All @@ -297,16 +326,16 @@ static int omap_modeset_init(struct drm_device *dev)
for (i = 0; i < priv->num_pipes; i++) {
struct omap_drm_pipeline *pipe = &priv->pipes[i];
struct drm_encoder *encoder = pipe->encoder;
struct drm_connector *connector;
struct drm_crtc *crtc;

connector = omap_connector_init(dev, pipe->output,
pipe->display, encoder);
if (!connector)
return -ENOMEM;
if (!pipe->output->bridge) {
pipe->connector = omap_connector_init(dev, pipe->output,
encoder);
if (!pipe->connector)
return -ENOMEM;

drm_connector_attach_encoder(connector, encoder);
pipe->connector = connector;
drm_connector_attach_encoder(pipe->connector, encoder);
}

crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
if (IS_ERR(crtc))
Expand Down Expand Up @@ -350,10 +379,12 @@ static int omap_modeset_init(struct drm_device *dev)
static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
{
struct omap_drm_private *priv = ddev->dev_private;
int i;
unsigned int i;

for (i = 0; i < priv->num_pipes; i++)
omap_connector_enable_hpd(priv->pipes[i].connector);
for (i = 0; i < priv->num_pipes; i++) {
if (priv->pipes[i].connector)
omap_connector_enable_hpd(priv->pipes[i].connector);
}
}

/*
Expand All @@ -362,10 +393,12 @@ static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
{
struct omap_drm_private *priv = ddev->dev_private;
int i;
unsigned int i;

for (i = 0; i < priv->num_pipes; i++)
omap_connector_disable_hpd(priv->pipes[i].connector);
for (i = 0; i < priv->num_pipes; i++) {
if (priv->pipes[i].connector)
omap_connector_disable_hpd(priv->pipes[i].connector);
}
}

/*
Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/omapdrm/omap_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ struct omap_drm_pipeline {
struct drm_encoder *encoder;
struct drm_connector *connector;
struct omap_dss_device *output;
struct omap_dss_device *display;
unsigned int alias_id;
};

Expand Down
Loading

0 comments on commit 79107f2

Please sign in to comment.