diff options
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r-- | drivers/video/omap2/displays/panel-generic-dpi.c | 99 | ||||
-rw-r--r-- | drivers/video/omap2/dss/core.c | 9 | ||||
-rw-r--r-- | drivers/video/omap2/dss/display.c | 74 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dpi.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/Kconfig | 2 |
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 |