aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Reichel <sre@kernel.org>2020-01-18 23:35:33 +0100
committerSebastian Reichel <sre@kernel.org>2020-02-17 14:54:20 +0100
commitb9fa5336b7cb210d5000636a0f1a155494b74700 (patch)
tree8c61deecec976cc68b222793488170a1b894475c
parent964310fb5faaae5fa9a04b0acb18742acdd0c9f8 (diff)
downloadlinux-n900-omapdrm-dsi-drm-panel-5.6-rc1-wip.tar.gz
drm/omap: handle encoder/connector in DSI codeomapdrm-dsi-drm-panel-5.6-rc1-wip
Add direct support for drm_encoder and drm_connector in the DSI code. This makes it possible to properly expose the encoder as DSI type and implement sane hotplug handling (e.g. due to removing the panel module). This is also the first step to merge omapdrm with the dss sub-driver, which would simplify the driver by removing one (mostly useless) layer of abstraction. Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c185
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c11
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c32
4 files changed, 208 insertions, 24 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index f1597b967d75aa..e9849a2a3a7e9d 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -39,6 +39,9 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_atomic_state_helper.h>
#include "omapdss.h"
#include "dss.h"
@@ -333,6 +336,9 @@ struct dsi_of_data {
};
struct dsi_data {
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+
struct device *dev;
void __iomem *proto_base;
void __iomem *phy_base;
@@ -443,9 +449,11 @@ struct dsi_data {
struct omap_dss_device output;
struct drm_device *drm_dev;
- struct drm_connector *connector;
};
+#define to_dsi_data_encoder(x) container_of(x, struct dsi_data, encoder)
+#define to_dsi_data_connector(c) container_of(c, struct dsi_data, connector)
+
struct dsi_packet_sent_handler_data {
struct dsi_data *dsi;
struct completion *completion;
@@ -5049,6 +5057,18 @@ static void dsi_disconnect(struct omap_dss_device *src,
omapdss_device_disconnect(dst, dst->next);
}
+static struct drm_encoder* dsi_get_encoder(struct omap_dss_device *dssdev)
+{
+ struct dsi_data *dsi = to_dsi_data(dssdev);
+ return &dsi->encoder;
+}
+
+static struct drm_connector* dsi_get_connector(struct omap_dss_device *dssdev)
+{
+ struct dsi_data *dsi = to_dsi_data(dssdev);
+ return &dsi->connector;
+}
+
static const struct omap_dss_device_ops dsi_ops = {
.connect = dsi_connect,
.disconnect = dsi_disconnect,
@@ -5058,6 +5078,9 @@ static const struct omap_dss_device_ops dsi_ops = {
.check_timings = dsi_check_timings,
.set_timings = dsi_set_timings,
+ .get_encoder = dsi_get_encoder,
+ .get_connector = dsi_get_connector,
+
.dsi = {
.update = dsi_update_all,
.is_video_mode = dsi_is_video_mode,
@@ -5195,10 +5218,8 @@ int omap_dsi_host_attach(struct mipi_dsi_host *host,
dssdev->panel = panel;
- if (dsi->connector) {
- dsi->connector->status = connector_status_connected;
- drm_panel_attach(panel, dsi->connector);
- }
+ dsi->connector.status = connector_status_connected;
+ drm_panel_attach(panel, &dsi->connector);
dsi_bus_unlock(dsi);
@@ -5226,11 +5247,9 @@ int omap_dsi_host_detach(struct mipi_dsi_host *host,
dsi_bus_lock(dsi);
- if (dsi->connector) {
- dsi->connector->status = connector_status_disconnected;
- drm_panel_detach(dssdev->panel);
- dssdev->panel = NULL;
- }
+ dsi->connector.status = connector_status_disconnected;
+ drm_panel_detach(dssdev->panel);
+ dssdev->panel = NULL;
omap_dsi_unregister_te_irq(dsi);
dsi->vc[channel].dest = NULL;
@@ -5366,6 +5385,126 @@ static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi)
return 0;
}
+static void omap_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dsi_data *dsi = to_dsi_data_encoder(encoder);
+ struct omap_dss_device *dssdev = &dsi->output;
+ struct videomode vm = { 0 };
+
+ drm_display_mode_to_videomode(adjusted_mode, &vm);
+ dss_mgr_set_timings(dssdev, &vm);
+
+ dsi_set_timings(dssdev, adjusted_mode);
+}
+
+
+static void omap_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct dsi_data *dsi = to_dsi_data_encoder(encoder);
+ struct omap_dss_device *dssdev = &dsi->output;
+ struct drm_device *dev = encoder->dev;
+
+ 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);
+ }
+
+ dsi_disable_video_outputs(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void omap_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct dsi_data *dsi = to_dsi_data_encoder(encoder);
+ struct omap_dss_device *dssdev = &dsi->output;
+ struct drm_device *dev = encoder->dev;
+
+ dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
+
+ dsi_enable_video_outputs(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ /* Enable the panel if present. */
+ if (dssdev->panel) {
+ drm_panel_prepare(dssdev->panel);
+ drm_panel_enable(dssdev->panel);
+ }
+}
+
+static int omap_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct dsi_data *dsi = to_dsi_data_encoder(encoder);
+ struct omap_dss_device *dssdev = &dsi->output;
+ const struct drm_display_mode *mode = &crtc_state->mode;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ int ret;
+
+ drm_mode_copy(adjusted_mode, mode);
+
+ ret = dsi_check_timings(dssdev, adjusted_mode);
+ if (ret) {
+ dev_err(encoder->dev->dev, "invalid timings: %d\n", ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct drm_encoder_funcs omap_dsi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static const struct drm_encoder_helper_funcs omap_dsi_encoder_helper_funcs = {
+ .mode_set = omap_dsi_encoder_mode_set,
+ .disable = omap_dsi_encoder_disable,
+ .enable = omap_dsi_encoder_enable,
+ .atomic_check = omap_dsi_encoder_atomic_check,
+};
+
+static enum drm_connector_status
+omap_dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector->status;
+}
+
+static void omap_dsi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+ connector->dev = NULL;
+}
+
+static const struct drm_connector_funcs omap_dsi_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = omap_dsi_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = omap_dsi_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int omap_dsi_get_modes(struct drm_connector *connector)
+{
+ struct dsi_data *dsi = to_dsi_data_connector(connector);
+ struct omap_dss_device *dssdev = &dsi->output;
+
+ if (dssdev->panel)
+ return drm_panel_get_modes(dssdev->panel, connector);
+
+ return 0;
+}
+
+static const struct drm_connector_helper_funcs omap_dsi_connector_helper_funcs = {
+ .get_modes = omap_dsi_get_modes,
+};
+
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
@@ -5374,6 +5513,8 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
{
struct dss_device *dss = dss_get_device(master);
struct dsi_data *dsi = dev_get_drvdata(dev);
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_connector *connector = &dsi->connector;
struct drm_device *drm_dev = data;
char name[10];
u32 rev;
@@ -5382,7 +5523,29 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
dsi->dss = dss;
dsi->drm_dev = drm_dev;
- /* drm->connector = TODO */
+ r = drm_encoder_init(drm_dev, encoder, &omap_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
+ if (r) {
+ dev_err(dev, "Failed to initialize encoder\n");
+ return r;
+ }
+ drm_encoder_helper_add(encoder, &omap_dsi_encoder_helper_funcs);
+
+ r = drm_connector_init(drm_dev, connector, &omap_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (r) {
+ dev_err(dev, "Failed to initialize connector with drm\n");
+ return r;
+ }
+ connector->status = connector_status_disconnected;
+
+ drm_connector_helper_add(connector, &omap_dsi_connector_helper_funcs);
+ drm_connector_attach_encoder(connector, encoder);
+
+#if 0
+ if (!drm->registered)
+ return 0;
+#endif
dsi_init_pll_data(dss, dsi);
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index ead0522213c400..3e2072f2e1d632 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -58,6 +58,7 @@ struct snd_aes_iec958;
struct snd_cea_861_aud_if;
struct hdmi_avi_infoframe;
struct drm_connector;
+struct drm_encoder;
enum omap_display_type {
OMAP_DISPLAY_TYPE_NONE = 0,
@@ -287,6 +288,9 @@ struct omapdss_dsi_ops {
};
struct omap_dss_device_ops {
+ struct drm_encoder* (*get_encoder)(struct omap_dss_device *dssdev);
+ struct drm_connector* (*get_connector)(struct omap_dss_device *dssdev);
+
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index 94cded3871746e..87e50c8382b37e 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -70,6 +70,10 @@ void omap_connector_enable_hpd(struct drm_connector *connector)
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *hpd = omap_connector->hpd;
+ /* DSI is connector is not omap_connector */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_DSI)
+ return;
+
if (hpd)
hpd->ops->register_hpd_cb(hpd, omap_connector_hpd_cb,
omap_connector);
@@ -80,6 +84,10 @@ void omap_connector_disable_hpd(struct drm_connector *connector)
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *hpd = omap_connector->hpd;
+ /* DSI is connector is not omap_connector */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_DSI)
+ return;
+
if (hpd)
hpd->ops->unregister_hpd_cb(hpd);
}
@@ -126,7 +134,6 @@ static enum drm_connector_status omap_connector_detect(
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DPI:
case DRM_MODE_CONNECTOR_LVDS:
- case DRM_MODE_CONNECTOR_DSI:
status = connector_status_connected;
break;
default:
@@ -312,8 +319,6 @@ static int omap_connector_get_type(struct omap_dss_device *output)
return DRM_MODE_CONNECTOR_HDMIA;
case OMAP_DISPLAY_TYPE_DVI:
return DRM_MODE_CONNECTOR_DVID;
- case OMAP_DISPLAY_TYPE_DSI:
- return DRM_MODE_CONNECTOR_DSI;
case OMAP_DISPLAY_TYPE_DPI:
case OMAP_DISPLAY_TYPE_DBI:
return DRM_MODE_CONNECTOR_DPI;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 34c901aadbb4e3..354fde07b6393c 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -289,15 +289,21 @@ static int omap_modeset_init(struct drm_device *dev)
struct omap_drm_pipeline *pipe = &priv->pipes[i];
int id;
- pipe->encoder = omap_encoder_init(dev, pipe->output);
- if (!pipe->encoder)
- return -ENOMEM;
-
- if (pipe->output->bridge) {
- ret = drm_bridge_attach(pipe->encoder,
- pipe->output->bridge, NULL);
- if (ret < 0)
- return ret;
+ if (pipe->output->ops->get_encoder) {
+ pipe->encoder = pipe->output->ops->get_encoder(pipe->output);
+ if (!pipe->encoder)
+ return -ENODEV;
+ } else {
+ pipe->encoder = omap_encoder_init(dev, pipe->output);
+ if (!pipe->encoder)
+ return -ENOMEM;
+
+ 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);
@@ -328,7 +334,13 @@ static int omap_modeset_init(struct drm_device *dev)
struct drm_encoder *encoder = pipe->encoder;
struct drm_crtc *crtc;
- if (!pipe->output->bridge) {
+ if (!pipe->connector && pipe->output->ops->get_connector) {
+ pipe->connector = pipe->output->ops->get_connector(pipe->output);
+ if (!pipe->connector)
+ return -ENODEV;
+ }
+
+ if (!pipe->connector && !pipe->output->bridge) {
pipe->connector = omap_connector_init(dev, pipe->output,
encoder);
if (!pipe->connector)