summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c24
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c12
-rw-r--r--drivers/video/omap2/dss/apply.c14
-rw-r--r--drivers/video/omap2/dss/core.c44
-rw-r--r--drivers/video/omap2/dss/display-sysfs.c28
-rw-r--r--drivers/video/omap2/dss/manager-sysfs.c45
-rw-r--r--drivers/video/omap2/dss/output.c14
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c25
-rw-r--r--include/video/omapdss.h23
9 files changed, 188 insertions, 41 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 02075bfcd8fd..b2ab2f5d3cb9 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -94,6 +94,28 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
static struct omap_crtc *omap_crtcs[8];
/* we can probably ignore these until we support command-mode panels: */
+static int omap_crtc_connect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ if (mgr->output)
+ return -EINVAL;
+
+ if ((mgr->supported_outputs & dst->id) == 0)
+ return -EINVAL;
+
+ dst->manager = mgr;
+ mgr->output = dst;
+
+ return 0;
+}
+
+static void omap_crtc_disconnect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ mgr->output->manager = NULL;
+ mgr->output = NULL;
+}
+
static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
{
}
@@ -138,6 +160,8 @@ static void omap_crtc_unregister_framedone_handler(
}
static const struct dss_mgr_ops mgr_ops = {
+ .connect = omap_crtc_connect,
+ .disconnect = omap_crtc_disconnect,
.start_update = omap_crtc_start_update,
.enable = omap_crtc_enable,
.disable = omap_crtc_disable,
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index ff9b49276b81..c65dd0d6b01d 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -97,6 +97,7 @@ static int omap_modeset_init(struct drm_device *dev)
int num_mgrs = dss_feat_get_num_mgrs();
int num_crtcs;
int i, id = 0;
+ int r;
omap_crtc_pre_init();
@@ -118,6 +119,7 @@ static int omap_modeset_init(struct drm_device *dev)
struct drm_connector *connector;
struct drm_encoder *encoder;
enum omap_channel channel;
+ struct omap_overlay_manager *mgr;
if (!dssdev->driver) {
dev_warn(dev->dev, "%s has no driver.. skipping it\n",
@@ -133,6 +135,13 @@ static int omap_modeset_init(struct drm_device *dev)
continue;
}
+ r = dssdev->driver->connect(dssdev);
+ if (r) {
+ dev_err(dev->dev, "could not connect display: %s\n",
+ dssdev->name);
+ continue;
+ }
+
encoder = omap_encoder_init(dev, dssdev);
if (!encoder) {
@@ -174,8 +183,9 @@ static int omap_modeset_init(struct drm_device *dev)
* other possible channels to which the encoder can connect are
* not considered.
*/
- channel = dssdev->output->dispc_channel;
+ mgr = omapdss_find_mgr_from_display(dssdev);
+ channel = mgr->id;
/*
* if this channel hasn't already been taken by a previously
* allocated crtc, we create a new crtc for it
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index c844071e8e28..dbd3c2f28a83 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -790,6 +790,18 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
}
}
+static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ return mgr->set_output(mgr, dst);
+}
+
+static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ mgr->unset_output(mgr);
+}
+
static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@@ -1552,6 +1564,8 @@ static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_mana
}
static const struct dss_mgr_ops apply_mgr_ops = {
+ .connect = dss_mgr_connect_compat,
+ .disconnect = dss_mgr_disconnect_compat,
.start_update = dss_mgr_start_update_compat,
.enable = dss_mgr_enable_compat,
.disable = dss_mgr_disable_compat,
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 710e9f9a4436..831abec565f2 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -379,6 +379,46 @@ static int dss_driver_remove(struct device *dev)
return 0;
}
+static int omapdss_default_connect(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_output *out;
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ out = dssdev->output;
+
+ if (out == NULL)
+ return -ENODEV;
+
+ mgr = omap_dss_get_overlay_manager(out->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, out);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void omapdss_default_disconnect(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_output *out;
+ struct omap_overlay_manager *mgr;
+
+ out = dssdev->output;
+
+ if (out == NULL)
+ return;
+
+ mgr = out->manager;
+
+ if (mgr == NULL)
+ return;
+
+ dss_mgr_disconnect(mgr, out);
+}
+
int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
{
dssdriver->driver.bus = &dss_bus_type;
@@ -392,6 +432,10 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
omapdss_default_get_recommended_bpp;
if (dssdriver->get_timings == NULL)
dssdriver->get_timings = omapdss_default_get_timings;
+ if (dssdriver->connect == NULL)
+ dssdriver->connect = omapdss_default_connect;
+ if (dssdriver->disconnect == NULL)
+ dssdriver->disconnect = omapdss_default_disconnect;
return driver_register(&dssdriver->driver);
}
diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c
index 18211a9ab354..81d5dc6e509f 100644
--- a/drivers/video/omap2/dss/display-sysfs.c
+++ b/drivers/video/omap2/dss/display-sysfs.c
@@ -33,9 +33,9 @@ static ssize_t display_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
- return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ omapdss_device_is_enabled(dssdev));
}
static ssize_t display_enabled_store(struct device *dev,
@@ -44,20 +44,24 @@ static ssize_t display_enabled_store(struct device *dev,
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
- bool enabled;
+ bool enable;
- r = strtobool(buf, &enabled);
+ r = strtobool(buf, &enable);
if (r)
return r;
- if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
- if (enabled) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- return r;
- } else {
- dssdev->driver->disable(dssdev);
- }
+ if (enable == omapdss_device_is_enabled(dssdev))
+ return size;
+
+ if (omapdss_device_is_connected(dssdev) == false)
+ return -ENODEV;
+
+ if (enable) {
+ r = dssdev->driver->enable(dssdev);
+ if (r)
+ return r;
+ } else {
+ dssdev->driver->disable(dssdev);
}
return size;
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c
index 72784b3aad27..de7e7b5b1b7c 100644
--- a/drivers/video/omap2/dss/manager-sysfs.c
+++ b/drivers/video/omap2/dss/manager-sysfs.c
@@ -50,6 +50,7 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
int r = 0;
size_t len = size;
struct omap_dss_device *dssdev = NULL;
+ struct omap_dss_device *old_dssdev;
int match(struct omap_dss_device *dssdev, void *data)
{
@@ -66,34 +67,44 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
if (len > 0 && dssdev == NULL)
return -EINVAL;
- if (dssdev)
+ if (dssdev) {
DSSDBG("display %s found\n", dssdev->name);
- if (mgr->output) {
- r = mgr->unset_output(mgr);
- if (r) {
- DSSERR("failed to unset current output\n");
+ if (omapdss_device_is_connected(dssdev)) {
+ DSSERR("new display is already connected\n");
+ r = -EINVAL;
+ goto put_device;
+ }
+
+ if (omapdss_device_is_enabled(dssdev)) {
+ DSSERR("new display is not disabled\n");
+ r = -EINVAL;
goto put_device;
}
}
- if (dssdev) {
- struct omap_dss_output *out;
+ old_dssdev = mgr->get_device(mgr);
+ if (old_dssdev) {
+ if (omapdss_device_is_enabled(old_dssdev)) {
+ DSSERR("old display is not disabled\n");
+ r = -EINVAL;
+ goto put_device;
+ }
- out = omapdss_find_output_from_display(dssdev);
+ old_dssdev->driver->disconnect(old_dssdev);
+ }
- /*
- * a registered device should have an output connected to it
- * already
- */
- if (!out) {
- DSSERR("device has no output connected to it\n");
+ if (dssdev) {
+ r = dssdev->driver->connect(dssdev);
+ if (r) {
+ DSSERR("failed to connect new device\n");
goto put_device;
}
- r = mgr->set_output(mgr, out);
- if (r) {
- DSSERR("failed to set manager output\n");
+ old_dssdev = mgr->get_device(mgr);
+ if (old_dssdev != dssdev) {
+ DSSERR("failed to connect device to this manager\n");
+ dssdev->driver->disconnect(dssdev);
goto put_device;
}
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
index ab2c0f0ab244..a53b08b2249b 100644
--- a/drivers/video/omap2/dss/output.c
+++ b/drivers/video/omap2/dss/output.c
@@ -179,6 +179,20 @@ void dss_uninstall_mgr_ops(void)
}
EXPORT_SYMBOL(dss_uninstall_mgr_ops);
+int dss_mgr_connect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ return dss_mgr_ops->connect(mgr, dst);
+}
+EXPORT_SYMBOL(dss_mgr_connect);
+
+void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst)
+{
+ dss_mgr_ops->disconnect(mgr, dst);
+}
+EXPORT_SYMBOL(dss_mgr_disconnect);
+
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings)
{
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index cc8953c4faa1..528e453e8e11 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1853,6 +1853,8 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
dssdev->driver->disable(dssdev);
+ dssdev->driver->disconnect(dssdev);
+
omap_dss_put_device(dssdev);
}
@@ -2363,22 +2365,23 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
int i, r;
struct omap_overlay_manager *mgr;
+ r = def_dssdev->driver->connect(def_dssdev);
+ if (r) {
+ dev_err(fbdev->dev, "failed to connect default display\n");
+ return r;
+ }
+
for (i = 0; i < fbdev->num_displays; ++i) {
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
- struct omap_dss_output *out;
- out = omapdss_find_output_from_display(dssdev);
- if (!out)
+ if (dssdev == def_dssdev)
continue;
- mgr = omap_dss_get_overlay_manager(out->dispc_channel);
- if (!mgr)
- continue;
-
- if (mgr->output)
- mgr->unset_output(mgr);
-
- mgr->set_output(mgr, out);
+ /*
+ * We don't care if the connect succeeds or not. We just want to
+ * connect as many displays as possible.
+ */
+ dssdev->driver->connect(dssdev);
}
mgr = omapdss_find_mgr_from_display(def_dssdev);
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 898f81247859..4f52f523fba4 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -689,6 +689,9 @@ struct omap_dss_driver {
int (*probe)(struct omap_dss_device *);
void (*remove)(struct omap_dss_device *);
+ int (*connect)(struct omap_dss_device *dssdev);
+ void (*disconnect)(struct omap_dss_device *dssdev);
+
int (*enable)(struct omap_dss_device *display);
void (*disable)(struct omap_dss_device *display);
int (*run_test)(struct omap_dss_device *display, int test);
@@ -889,6 +892,11 @@ int omapdss_compat_init(void);
void omapdss_compat_uninit(void);
struct dss_mgr_ops {
+ int (*connect)(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst);
+ void (*disconnect)(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst);
+
void (*start_update)(struct omap_overlay_manager *mgr);
int (*enable)(struct omap_overlay_manager *mgr);
void (*disable)(struct omap_overlay_manager *mgr);
@@ -905,6 +913,10 @@ struct dss_mgr_ops {
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
void dss_uninstall_mgr_ops(void);
+int dss_mgr_connect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst);
+void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *dst);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
@@ -916,4 +928,15 @@ int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
+
+static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
+{
+ return dssdev->output;
+}
+
+static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
+{
+ return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
+}
+
#endif