summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorSebastien Jan <s-jan@ti.com>2011-04-07 08:38:42 +0100
committerAndy Green <andy.green@linaro.org>2011-04-07 08:38:42 +0100
commitecfaee825b9df66c99c65c678eff3e399a82848e (patch)
tree32c439c649b82a718907e5ac8bf2ab88df2e0155 /drivers/video
parent49da1a9af916aea045cd523822904406856dc387 (diff)
OMAP4: DSS: add generic notifier mechanism
A callback can be registered by the dssdev client in order to be notified of resolution changes, for example an external monitor that is hot-plugged. Multiple clients can now register for notification from one dssdev, and the notification mechanism can be extended in the future to add other events. This is a port of Rob Clark's <rob@ti.com> original patch. Signed-off-by: Sebastien Jan <s-jan@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/core.c3
-rw-r--r--drivers/video/omap2/dss/display.c49
-rw-r--r--drivers/video/omap2/dss/hdmi.c9
3 files changed, 60 insertions, 1 deletions
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 1aa2ed1e786..19075085f96 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -491,6 +491,9 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
dssdev->dev.parent = &dss_bus;
dssdev->dev.release = omap_dss_dev_release;
dev_set_name(&dssdev->dev, "display%d", dev_num++);
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&dssdev->notifier);
+
return device_register(&dssdev->dev);
}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index a85a6f38b40..fa9df604387 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <plat/display.h>
#include "dss.h"
@@ -614,3 +615,51 @@ void omap_dss_stop_device(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omap_dss_stop_device);
+/* since omap_dss_update_size can be called in irq context, schedule work from
+ * work-queue to deliver notification to client..
+ */
+struct notify_work {
+ struct work_struct work;
+ struct omap_dss_device *dssdev;
+ enum omap_dss_event evt;
+};
+
+static void notify_worker(struct work_struct *work)
+{
+ struct notify_work *nw =
+ container_of(work, struct notify_work, work);
+ struct omap_dss_device *dssdev = nw->dssdev;
+ blocking_notifier_call_chain(&dssdev->notifier, nw->evt, dssdev);
+ kfree(work);
+}
+
+/**
+ * Called by lower level driver to notify about a change in resolution, etc.
+ */
+void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt)
+{
+ struct notify_work *nw =
+ kmalloc(sizeof(struct notify_work), GFP_KERNEL);
+ if (nw) {
+ INIT_WORK(&nw->work, notify_worker);
+ nw->dssdev = dssdev;
+ nw->evt = evt;
+ schedule_work(&nw->work);
+ }
+}
+EXPORT_SYMBOL(omap_dss_notify);
+
+void omap_dss_add_notify(struct omap_dss_device *dssdev,
+ struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&dssdev->notifier, nb);
+}
+EXPORT_SYMBOL(omap_dss_add_notify);
+
+void omap_dss_remove_notify(struct omap_dss_device *dssdev,
+ struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&dssdev->notifier, nb);
+}
+EXPORT_SYMBOL(omap_dss_remove_notify);
+
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 0d44f070ef3..71900d44a4f 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1104,6 +1104,7 @@ static void hdmi_enable_clocks(int enable)
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r, code = 0;
+ int dirty = true;
struct hdmi_pll_info pll_data;
struct omap_video_timings *p;
int clkin, n, phy;
@@ -1119,8 +1120,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dssdev->panel.timings.y_res);
if (!hdmi.custom_set) {
+ code = get_timings_index();
DSSDBG("Read EDID as no EDID is not set on poweron\n");
hdmi_read_edid(p);
+ dirty = get_timings_index() != code;
}
code = get_timings_index();
dssdev->panel.timings = cea_vesa_timings[code].timings;
@@ -1134,7 +1137,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
hdmi_wp_video_start(0);
- /* config the PLL and PHY first */
+ if (dirty) {
+ omap_dss_notify(dssdev, OMAP_DSS_SIZE_CHANGE);
+ }
+
+ /* config the PLL and PHY first */
r = hdmi_pll_program(&pll_data);
if (r) {
DSSDBG("Failed to lock PLL\n");