From 30b71761957c541cd9dfd6cd10e3feb21a8ddca1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 7 Dec 2018 23:08:35 +0200 Subject: [PATCH] drm/omap: Add support for drm_panel Hook up drm_panel support in the omapdrm driver. The change is relatively simply as the way has been paved by drm_bridge support already. In addition to looking up, attaching to and detaching from the panel, we only need to add panel support in the connector .get_modes() handler, take connector bus flags (set by the panel) into account, and enable/disable the panel in the encoder enable/disable operations handlers. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Tested-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/base.c | 12 ++++--- drivers/gpu/drm/omapdrm/dss/omapdss.h | 1 + drivers/gpu/drm/omapdrm/dss/output.c | 7 +++- drivers/gpu/drm/omapdrm/omap_connector.c | 9 ++++++ drivers/gpu/drm/omapdrm/omap_drv.c | 15 ++++++++- drivers/gpu/drm/omapdrm/omap_encoder.c | 41 ++++++++++++++++-------- 6 files changed, 65 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 09c9f2971aa2..3c088cd2ceab 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -157,7 +157,8 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) goto done; } - if (dssdev->id && (dssdev->next || dssdev->bridge)) + if (dssdev->id && + (dssdev->next || dssdev->bridge || dssdev->panel)) goto done; } @@ -192,10 +193,11 @@ int omapdss_device_connect(struct dss_device *dss, 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. + * bridge or panel instead of a DSS device. Stop here, we will + * attach the bridge or panel later when we will have a DRM + * encoder. */ - return src && src->bridge ? 0 : -EINVAL; + return src && (src->bridge || src->panel) ? 0 : -EINVAL; } if (omapdss_device_is_connected(dst)) @@ -223,7 +225,7 @@ void omapdss_device_disconnect(struct omap_dss_device *src, dst ? dev_name(dst->dev) : "NULL"); if (!dst) { - WARN_ON(!src->bridge); + WARN_ON(!src->bridge && !src->panel); return; } diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index f47e9b94288f..0c734d1f89e1 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -411,6 +411,7 @@ struct omap_dss_device { struct dss_device *dss; struct omap_dss_device *next; struct drm_bridge *bridge; + struct drm_panel *panel; struct list_head list; diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 2a53025c2fde..10a9ee5cdc61 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -22,6 +22,8 @@ #include #include +#include + #include "dss.h" #include "omapdss.h" @@ -37,6 +39,9 @@ int omapdss_device_init_output(struct omap_dss_device *out) out->next = omapdss_find_device_by_node(remote_node); out->bridge = of_drm_find_bridge(remote_node); + out->panel = of_drm_find_panel(remote_node); + if (IS_ERR(out->panel)) + out->panel = NULL; of_node_put(remote_node); @@ -47,7 +52,7 @@ int omapdss_device_init_output(struct omap_dss_device *out) return -EINVAL; } - return out->next || out->bridge ? 0 : -EPROBE_DEFER; + return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; } EXPORT_SYMBOL(omapdss_device_init_output); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index f711a267e2b6..5967283934e1 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -17,6 +17,7 @@ #include #include +#include #include #include "omap_drv.h" @@ -211,6 +212,7 @@ static int omap_connector_get_modes_edid(struct drm_connector *connector, static int omap_connector_get_modes(struct drm_connector *connector) { + struct omap_connector *omap_connector = to_omap_connector(connector); struct omap_dss_device *dssdev; DBG("%s", connector->name); @@ -233,6 +235,13 @@ static int omap_connector_get_modes(struct drm_connector *connector) if (dssdev) return dssdev->ops->get_modes(dssdev, connector); + /* + * Otherwise if the display pipeline uses a drm_panel, we delegate the + * operation to the panel API. + */ + if (omap_connector->output->panel) + return drm_panel_get_modes(omap_connector->output->panel); + /* * We can't retrieve modes, which can happen for instance for a DVI or * VGA output with the DDC bus unconnected. The KMS core will add the diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index f3a36f7b3c4d..1b9b6f5e48e1 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "omap_dmm_tiler.h" #include "omap_drv.h" @@ -137,6 +138,9 @@ static void omap_disconnect_pipelines(struct drm_device *ddev) for (i = 0; i < priv->num_pipes; i++) { struct omap_drm_pipeline *pipe = &priv->pipes[i]; + if (pipe->output->panel) + drm_panel_detach(pipe->output->panel); + omapdss_device_disconnect(NULL, pipe->output); omapdss_device_put(pipe->output); @@ -214,13 +218,15 @@ static int omap_display_id(struct omap_dss_device *output) display = omapdss_display_get(output); node = display->dev->of_node; omapdss_device_put(display); - } else { + } else if (output->bridge) { struct drm_bridge *bridge = output->bridge; while (bridge->next) bridge = bridge->next; node = bridge->of_node; + } else if (output->panel) { + node = output->panel->dev->of_node; } return node ? of_alias_get_id(node, "display") : -ENODEV; @@ -335,6 +341,13 @@ static int omap_modeset_init(struct drm_device *dev) return -ENOMEM; drm_connector_attach_encoder(pipe->connector, encoder); + + if (pipe->output->panel) { + ret = drm_panel_attach(pipe->output->panel, + pipe->connector); + if (ret < 0) + return ret; + } } crtc = omap_crtc_init(dev, pipe, priv->planes[i]); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 9eb3db9ba23f..40512419642b 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "omap_drv.h" @@ -79,22 +80,15 @@ static void omap_encoder_update_videomode_flags(struct videomode *vm, } } -static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder, +static void omap_encoder_hdmi_mode_set(struct drm_connector *connector, + struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; struct omap_encoder *omap_encoder = to_omap_encoder(encoder); struct omap_dss_device *dssdev = omap_encoder->output; - struct drm_connector *connector; bool hdmi_mode; - hdmi_mode = false; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - hdmi_mode = omap_connector_get_hdmi_mode(connector); - break; - } - } + hdmi_mode = omap_connector_get_hdmi_mode(connector); if (dssdev->ops->hdmi.set_hdmi_mode) dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); @@ -117,8 +111,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, struct omap_encoder *omap_encoder = to_omap_encoder(encoder); struct omap_dss_device *output = omap_encoder->output; struct omap_dss_device *dssdev; + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; struct drm_bridge *bridge; struct videomode vm = { 0 }; + u32 bus_flags; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) + break; + } drm_display_mode_to_videomode(adjusted_mode, &vm); @@ -135,8 +137,6 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags); for (bridge = output->bridge; bridge; bridge = bridge->next) { - u32 bus_flags; - if (!bridge->timings) continue; @@ -144,6 +144,9 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, omap_encoder_update_videomode_flags(&vm, bus_flags); } + bus_flags = connector->display_info.bus_flags; + omap_encoder_update_videomode_flags(&vm, bus_flags); + /* Set timings for all devices in the display pipeline. */ dss_mgr_set_timings(output, &vm); @@ -154,7 +157,7 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, /* Set the HDMI mode and HDMI infoframe if applicable. */ if (output->type == OMAP_DISPLAY_TYPE_HDMI) - omap_encoder_hdmi_mode_set(encoder, adjusted_mode); + omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode); } static void omap_encoder_disable(struct drm_encoder *encoder) @@ -165,6 +168,12 @@ static void omap_encoder_disable(struct drm_encoder *encoder) dev_dbg(dev->dev, "disable(%s)\n", dssdev->name); + /* Disable the panel if present. */ + if (dssdev->panel) { + drm_panel_disable(dssdev->panel); + drm_panel_unprepare(dssdev->panel); + } + /* * Disable the chain of external devices, starting at the one at the * internal encoder's output. @@ -214,6 +223,12 @@ static void omap_encoder_enable(struct drm_encoder *encoder) * internal encoder's output. */ omapdss_device_enable(dssdev->next); + + /* Enable the panel if present. */ + if (dssdev->panel) { + drm_panel_prepare(dssdev->panel); + drm_panel_enable(dssdev->panel); + } } static int omap_encoder_atomic_check(struct drm_encoder *encoder,