summaryrefslogtreecommitdiff
path: root/drivers/video/omap2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c99
-rw-r--r--drivers/video/omap2/dss/core.c9
-rw-r--r--drivers/video/omap2/dss/display.c74
-rw-r--r--drivers/video/omap2/dss/dpi.c3
-rw-r--r--drivers/video/omap2/dss/dss_features.c6
-rw-r--r--drivers/video/omap2/omapfb/Kconfig2
6 files changed, 190 insertions, 3 deletions
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 687c9c7d219..851833669fe 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -33,6 +33,8 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "../../edid.h"
#include <plat/panel-generic-dpi.h>
@@ -380,6 +382,100 @@ static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
return dpi_check_timings(dssdev, timings);
}
+/* i2c / edid support */
+
+#define DDC_ADDR 0x50
+
+static int do_probe_ddc_edid(struct i2c_adapter *adapter,
+ unsigned char *buf, int block, int len)
+{
+ unsigned char start = block * EDID_LENGTH;
+ int i;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = &start,
+ }, {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = buf,
+ }
+ };
+
+ /* try at least 3 times, avoid miss for time-out */
+ for (i = 0; i < 3; i++) {
+ if (i2c_transfer(adapter, msgs, 2) == 2)
+ return 0;
+ }
+
+ return -1;
+}
+
+static int generic_dpi_panel_get_edid(struct omap_dss_device *dssdev,
+ u8 *buf, int len)
+{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ struct i2c_adapter *adapter;
+ int i;
+ u8 *edid, *new;
+
+ adapter = i2c_get_adapter(panel_data->i2c_bus_num);
+ if (!adapter) {
+ printk(KERN_ERR "Invalid I2C adapter, bus number: %d\n",
+ panel_data->i2c_bus_num);
+ return -EINVAL;
+ }
+
+ if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
+ return -EINVAL;
+
+ if (do_probe_ddc_edid(adapter, edid, 0, EDID_LENGTH))
+ goto out;
+
+ /* if there are extensions, probe more */
+ if (edid[0x7e] != 0) {
+ new = krealloc(edid, (edid[0x7e] + 1) * EDID_LENGTH,
+ GFP_KERNEL);
+ if (!new)
+ goto out;
+ edid = new;
+
+ for (i = 1; i <= edid[0x7e]; i++) {
+ if (do_probe_ddc_edid(adapter,
+ edid + i * EDID_LENGTH,
+ i, EDID_LENGTH))
+ goto out;
+ }
+ }
+
+ if (edid) {
+ memcpy(buf, edid, len);
+ kfree(edid);
+ return 0;
+ }
+
+out:
+ kfree(edid);
+ return -EINVAL;
+}
+
+static bool generic_dpi_panel_is_detected(struct omap_dss_device *dssdev)
+{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ struct i2c_adapter *adapter;
+ unsigned char out;
+
+ adapter = i2c_get_adapter(panel_data->i2c_bus_num);
+ if (!adapter) {
+ return omapdss_default_is_detected(dssdev);
+ }
+
+ return (do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
+}
+
static struct omap_dss_driver dpi_driver = {
.probe = generic_dpi_panel_probe,
.remove = generic_dpi_panel_remove,
@@ -393,6 +489,9 @@ static struct omap_dss_driver dpi_driver = {
.get_timings = generic_dpi_panel_get_timings,
.check_timings = generic_dpi_panel_check_timings,
+ .get_edid = generic_dpi_panel_get_edid,
+ .is_detected = generic_dpi_panel_is_detected,
+
.driver = {
.name = "generic_dpi_panel",
.owner = THIS_MODULE,
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 1aa2ed1e786..7d1b9fecc43 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -434,6 +434,12 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
if (dssdriver->get_recommended_bpp == NULL)
dssdriver->get_recommended_bpp =
omapdss_default_get_recommended_bpp;
+ if (!dssdriver->check_timings)
+ dssdriver->check_timings = omapdss_default_check_timings;
+ if (!dssdriver->get_timings)
+ dssdriver->get_timings = omapdss_default_get_timings;
+ if (!dssdriver->is_detected)
+ dssdriver->is_detected = omapdss_default_is_detected;
return driver_register(&dssdriver->driver);
}
@@ -491,6 +497,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..b1466d8d388 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"
@@ -312,6 +313,32 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_default_get_resolution);
+void omapdss_default_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+EXPORT_SYMBOL(omapdss_default_get_timings);
+
+int omapdss_default_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ return memcmp(&dssdev->panel.timings, timings, sizeof(*timings));
+}
+EXPORT_SYMBOL(omapdss_default_check_timings);
+
+bool omapdss_default_is_detected(struct omap_dss_device *dssdev)
+{
+ if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
+ /* show resume info for suspended displays */
+ return dssdev->activate_after_resume;
+ } else {
+ return dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
+ }
+}
+EXPORT_SYMBOL(omapdss_default_is_detected);
+
+
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high)
@@ -614,3 +641,50 @@ 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/dpi.c b/drivers/video/omap2/dss/dpi.c
index 2d3ca4ca4a0..6b0c0299527 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -145,6 +145,9 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
{
bool is_tft;
+ if (!dssdev->manager)
+ return -ENODEV;
+
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
dispc_set_parallel_interface_mode(dssdev->manager->id,
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 179a7a4f63b..b4f63d01180 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -165,9 +165,11 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
- OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
+ OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBA32 |
+ OMAP_DSS_COLOR_RGBX32,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index aa33386c81f..231f568b9f9 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -1,6 +1,6 @@
menuconfig FB_OMAP2
tristate "OMAP2+ frame buffer support (EXPERIMENTAL)"
- depends on FB && OMAP2_DSS
+ depends on FB && OMAP2_DSS && !DRM_OMAP
select OMAP2_VRAM
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3