diff options
Diffstat (limited to 'drivers/video/omap2/dss')
23 files changed, 1376 insertions, 666 deletions
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index cb0f145c707..8f70a8300b8 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -1,5 +1,6 @@ menuconfig OMAP2_DSS tristate "OMAP2+ Display Subsystem support" + select VIDEOMODE_HELPERS help OMAP2+ Display Subsystem support. diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index a4b356a9780..d6212d63cfb 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -420,16 +420,26 @@ static void wait_pending_extra_info_updates(void) DSSWARN("timeout in wait_pending_extra_info_updates\n"); } -static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) +static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) { - return ovl->manager ? - (ovl->manager->output ? ovl->manager->output->device : NULL) : - NULL; + struct omap_dss_device *dssdev; + + dssdev = mgr->output; + if (dssdev == NULL) + return NULL; + + while (dssdev->device) + dssdev = dssdev->device; + + if (dssdev->driver) + return dssdev; + else + return NULL; } -static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) +static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) { - return mgr->output ? mgr->output->device : NULL; + return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL; } static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) @@ -792,6 +802,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_device *dst) +{ + return mgr->set_output(mgr, dst); +} + +static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr, + struct omap_dss_device *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); @@ -1156,7 +1178,7 @@ static void dss_mgr_get_info(struct omap_overlay_manager *mgr, } static int dss_mgr_set_output(struct omap_overlay_manager *mgr, - struct omap_dss_output *output) + struct omap_dss_device *output) { int r; @@ -1554,6 +1576,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, @@ -1569,7 +1593,6 @@ static DEFINE_MUTEX(compat_init_lock); int omapdss_compat_init(void) { struct platform_device *pdev = dss_get_core_pdev(); - struct omap_dss_device *dssdev = NULL; int i, r; mutex_lock(&compat_init_lock); @@ -1579,7 +1602,7 @@ int omapdss_compat_init(void) apply_init_priv(); - dss_init_overlay_managers(pdev); + dss_init_overlay_managers_sysfs(pdev); dss_init_overlays(pdev); for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { @@ -1615,12 +1638,9 @@ int omapdss_compat_init(void) if (r) goto err_mgr_ops; - for_each_dss_dev(dssdev) { - r = display_init_sysfs(pdev, dssdev); - /* XXX uninit sysfs files on error */ - if (r) - goto err_disp_sysfs; - } + r = display_init_sysfs(pdev); + if (r) + goto err_disp_sysfs; dispc_runtime_get(); @@ -1637,12 +1657,13 @@ out: err_init_irq: dispc_runtime_put(); + display_uninit_sysfs(pdev); err_disp_sysfs: dss_uninstall_mgr_ops(); err_mgr_ops: - dss_uninit_overlay_managers(pdev); + dss_uninit_overlay_managers_sysfs(pdev); dss_uninit_overlays(pdev); compat_refcnt--; @@ -1656,7 +1677,6 @@ EXPORT_SYMBOL(omapdss_compat_init); void omapdss_compat_uninit(void) { struct platform_device *pdev = dss_get_core_pdev(); - struct omap_dss_device *dssdev = NULL; mutex_lock(&compat_init_lock); @@ -1665,12 +1685,11 @@ void omapdss_compat_uninit(void) dss_dispc_uninitialize_irq(); - for_each_dss_dev(dssdev) - display_uninit_sysfs(pdev, dssdev); + display_uninit_sysfs(pdev); dss_uninstall_mgr_ops(); - dss_uninit_overlay_managers(pdev); + dss_uninit_overlay_managers_sysfs(pdev); dss_uninit_overlays(pdev); out: mutex_unlock(&compat_init_lock); diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index c9c2252e371..1aeb274e30f 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -88,7 +88,7 @@ struct regulator *dss_get_vdds_dsi(void) if (core.vdds_dsi_reg != NULL) return core.vdds_dsi_reg; - reg = regulator_get(&core.pdev->dev, "vdds_dsi"); + reg = devm_regulator_get(&core.pdev->dev, "vdds_dsi"); if (!IS_ERR(reg)) core.vdds_dsi_reg = reg; @@ -102,7 +102,7 @@ struct regulator *dss_get_vdds_sdi(void) if (core.vdds_sdi_reg != NULL) return core.vdds_sdi_reg; - reg = regulator_get(&core.pdev->dev, "vdds_sdi"); + reg = devm_regulator_get(&core.pdev->dev, "vdds_sdi"); if (!IS_ERR(reg)) core.vdds_sdi_reg = reg; @@ -243,6 +243,8 @@ static int __init omap_dss_probe(struct platform_device *pdev) if (def_disp_name) core.default_display_name = def_disp_name; + else if (pdata->default_display_name) + core.default_display_name = pdata->default_display_name; else if (pdata->default_device) core.default_display_name = pdata->default_device->name; @@ -290,37 +292,9 @@ static int dss_bus_match(struct device *dev, struct device_driver *driver) return strcmp(dssdev->driver_name, driver->name) == 0; } -static ssize_t device_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - dssdev->name ? - dssdev->name : ""); -} - -static struct device_attribute default_dev_attrs[] = { - __ATTR(name, S_IRUGO, device_name_show, NULL), - __ATTR_NULL, -}; - -static ssize_t driver_name_show(struct device_driver *drv, char *buf) -{ - struct omap_dss_driver *dssdrv = to_dss_driver(drv); - return snprintf(buf, PAGE_SIZE, "%s\n", - dssdrv->driver.name ? - dssdrv->driver.name : ""); -} -static struct driver_attribute default_drv_attrs[] = { - __ATTR(name, S_IRUGO, driver_name_show, NULL), - __ATTR_NULL, -}; - static struct bus_type dss_bus_type = { .name = "omapdss", .match = dss_bus_match, - .dev_attrs = default_dev_attrs, - .drv_attrs = default_drv_attrs, }; static void dss_bus_release(struct device *dev) @@ -377,6 +351,46 @@ static int dss_driver_remove(struct device *dev) return 0; } +static int omapdss_default_connect(struct omap_dss_device *dssdev) +{ + struct omap_dss_device *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_device *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; @@ -390,6 +404,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); } @@ -419,29 +437,33 @@ struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) if (!dssdev) return NULL; - dssdev->dev.bus = &dss_bus_type; - dssdev->dev.parent = parent; - dssdev->dev.release = omap_dss_dev_release; - dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); + dssdev->old_dev.bus = &dss_bus_type; + dssdev->old_dev.parent = parent; + dssdev->old_dev.release = omap_dss_dev_release; + dev_set_name(&dssdev->old_dev, "display%d", disp_num_counter++); - device_initialize(&dssdev->dev); + device_initialize(&dssdev->old_dev); return dssdev; } int dss_add_device(struct omap_dss_device *dssdev) { - return device_add(&dssdev->dev); + dssdev->dev = &dssdev->old_dev; + + omapdss_register_display(dssdev); + return device_add(&dssdev->old_dev); } void dss_put_device(struct omap_dss_device *dssdev) { - put_device(&dssdev->dev); + put_device(&dssdev->old_dev); } void dss_unregister_device(struct omap_dss_device *dssdev) { - device_unregister(&dssdev->dev); + device_unregister(&dssdev->old_dev); + omapdss_unregister_display(dssdev); } static int dss_unregister_dss_dev(struct device *dev, void *data) @@ -618,16 +640,6 @@ static int __init omap_dss_init(void) static void __exit omap_dss_exit(void) { - if (core.vdds_dsi_reg != NULL) { - regulator_put(core.vdds_dsi_reg); - core.vdds_dsi_reg = NULL; - } - - if (core.vdds_sdi_reg != NULL) { - regulator_put(core.vdds_sdi_reg); - core.vdds_sdi_reg = NULL; - } - omap_dss_unregister_drivers(); omap_dss_bus_unregister(); diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c index 928884c9a0a..83779c2b292 100644 --- a/drivers/video/omap2/dss/dispc-compat.c +++ b/drivers/video/omap2/dss/dispc-compat.c @@ -360,8 +360,7 @@ static void dispc_error_worker(struct work_struct *work) if (bit & errors) { DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", ovl->name); - dispc_ovl_enable(ovl->id, false); - dispc_mgr_go(ovl->manager->id); + ovl->disable(ovl); msleep(50); } } diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b33b0169bb3..02a7340111d 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -103,6 +103,7 @@ static struct { int irq; unsigned long core_clk_rate; + unsigned long tv_pclk_rate; u32 fifo_size[DISPC_MAX_NR_FIFOS]; /* maps which plane is using a fifo. fifo-id -> plane-id */ @@ -3071,22 +3072,15 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) return r / pcd; } else { - enum dss_hdmi_venc_clk_source_select source; - - source = dss_get_hdmi_venc_clk_source(); - - switch (source) { - case DSS_VENC_TV_CLK: - return venc_get_pixel_clock(); - case DSS_HDMI_M_PCLK: - return hdmi_get_pixel_clock(); - default: - BUG(); - return 0; - } + return dispc.tv_pclk_rate; } } +void dispc_set_tv_pclk(unsigned long pclk) +{ + dispc.tv_pclk_rate = pclk; +} + unsigned long dispc_core_clk_rate(void) { return dispc.core_clk_rate; @@ -3710,6 +3704,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc_runtime_put(); + dss_init_overlay_managers(); + dss_debugfs_create_file("dispc", dispc_dump_regs); return 0; @@ -3723,6 +3719,8 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); + dss_uninit_overlay_managers(); + return 0; } diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c index 18211a9ab35..21d7f77df70 100644 --- a/drivers/video/omap2/dss/display-sysfs.c +++ b/drivers/video/omap2/dss/display-sysfs.c @@ -22,42 +22,69 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/sysfs.h> #include <video/omapdss.h> #include "dss.h" -#include "dss_features.h" + +static struct omap_dss_device *to_dss_device_sysfs(struct device *dev) +{ + struct omap_dss_device *dssdev = NULL; + + for_each_dss_dev(dssdev) { + if (dssdev->dev == dev) { + omap_dss_put_device(dssdev); + return dssdev; + } + } + + return NULL; +} + +static ssize_t display_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); + + return snprintf(buf, PAGE_SIZE, "%s\n", + dssdev->name ? + dssdev->name : ""); +} 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; + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); - 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, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(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; @@ -66,7 +93,7 @@ static ssize_t display_enabled_store(struct device *dev, static ssize_t display_tear_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); return snprintf(buf, PAGE_SIZE, "%d\n", dssdev->driver->get_te ? dssdev->driver->get_te(dssdev) : 0); @@ -75,7 +102,7 @@ static ssize_t display_tear_show(struct device *dev, static ssize_t display_tear_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); int r; bool te; @@ -96,7 +123,7 @@ static ssize_t display_tear_store(struct device *dev, static ssize_t display_timings_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); struct omap_video_timings t; if (!dssdev->driver->get_timings) @@ -113,7 +140,7 @@ static ssize_t display_timings_show(struct device *dev, static ssize_t display_timings_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); struct omap_video_timings t = dssdev->panel.timings; int r, found; @@ -152,7 +179,7 @@ static ssize_t display_timings_store(struct device *dev, static ssize_t display_rotate_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); int rotate; if (!dssdev->driver->get_rotate) return -ENOENT; @@ -163,7 +190,7 @@ static ssize_t display_rotate_show(struct device *dev, static ssize_t display_rotate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); int rot, r; if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) @@ -183,7 +210,7 @@ static ssize_t display_rotate_store(struct device *dev, static ssize_t display_mirror_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); int mirror; if (!dssdev->driver->get_mirror) return -ENOENT; @@ -194,7 +221,7 @@ static ssize_t display_mirror_show(struct device *dev, static ssize_t display_mirror_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); int r; bool mirror; @@ -215,7 +242,7 @@ static ssize_t display_mirror_store(struct device *dev, static ssize_t display_wss_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); unsigned int wss; if (!dssdev->driver->get_wss) @@ -229,7 +256,7 @@ static ssize_t display_wss_show(struct device *dev, static ssize_t display_wss_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = to_dss_device_sysfs(dev); u32 wss; int r; @@ -250,6 +277,7 @@ static ssize_t display_wss_store(struct device *dev, return size; } +static DEVICE_ATTR(name, S_IRUGO, display_name_show, NULL); static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, display_enabled_show, display_enabled_store); static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, @@ -263,59 +291,55 @@ static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, display_wss_show, display_wss_store); -static struct device_attribute *display_sysfs_attrs[] = { - &dev_attr_enabled, - &dev_attr_tear_elim, - &dev_attr_timings, - &dev_attr_rotate, - &dev_attr_mirror, - &dev_attr_wss, +static const struct attribute *display_sysfs_attrs[] = { + &dev_attr_name.attr, + &dev_attr_enabled.attr, + &dev_attr_tear_elim.attr, + &dev_attr_timings.attr, + &dev_attr_rotate.attr, + &dev_attr_mirror.attr, + &dev_attr_wss.attr, NULL }; -int display_init_sysfs(struct platform_device *pdev, - struct omap_dss_device *dssdev) +int display_init_sysfs(struct platform_device *pdev) { - struct device_attribute *attr; - int i, r; + struct omap_dss_device *dssdev = NULL; + int r; - /* create device sysfs files */ - i = 0; - while ((attr = display_sysfs_attrs[i++]) != NULL) { - r = device_create_file(&dssdev->dev, attr); - if (r) { - for (i = i - 2; i >= 0; i--) { - attr = display_sysfs_attrs[i]; - device_remove_file(&dssdev->dev, attr); - } + for_each_dss_dev(dssdev) { + struct kobject *kobj = &dssdev->dev->kobj; - DSSERR("failed to create sysfs file\n"); - return r; + r = sysfs_create_files(kobj, display_sysfs_attrs); + if (r) { + DSSERR("failed to create sysfs files\n"); + goto err; } - } - /* create display? sysfs links */ - r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, - dev_name(&dssdev->dev)); - if (r) { - while ((attr = display_sysfs_attrs[i++]) != NULL) - device_remove_file(&dssdev->dev, attr); + r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias); + if (r) { + sysfs_remove_files(kobj, display_sysfs_attrs); - DSSERR("failed to create sysfs display link\n"); - return r; + DSSERR("failed to create sysfs display link\n"); + goto err; + } } return 0; + +err: + display_uninit_sysfs(pdev); + + return r; } -void display_uninit_sysfs(struct platform_device *pdev, - struct omap_dss_device *dssdev) +void display_uninit_sysfs(struct platform_device *pdev) { - struct device_attribute *attr; - int i = 0; - - sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); + struct omap_dss_device *dssdev = NULL; - while ((attr = display_sysfs_attrs[i++]) != NULL) - device_remove_file(&dssdev->dev, attr); + for_each_dss_dev(dssdev) { + sysfs_remove_link(&pdev->dev.kobj, dssdev->alias); + sysfs_remove_files(&dssdev->dev->kobj, + display_sysfs_attrs); + } } diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 0aa8ad8f966..fafe7c941a6 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -61,6 +61,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: case OMAP_DISPLAY_TYPE_HDMI: + case OMAP_DISPLAY_TYPE_DVI: return 24; default: BUG(); @@ -76,110 +77,154 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -static int dss_suspend_device(struct device *dev, void *data) +int dss_suspend_all_devices(void) { - struct omap_dss_device *dssdev = to_dss_device(dev); - - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { - dssdev->activate_after_resume = false; - return 0; - } - - dssdev->driver->disable(dssdev); - - dssdev->activate_after_resume = true; + struct omap_dss_device *dssdev = NULL; - return 0; -} + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; -int dss_suspend_all_devices(void) -{ - int r; - struct bus_type *bus = dss_get_bus(); - - r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device); - if (r) { - /* resume all displays that were suspended */ - dss_resume_all_devices(); - return r; + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + dssdev->driver->disable(dssdev); + dssdev->activate_after_resume = true; + } else { + dssdev->activate_after_resume = false; + } } return 0; } -static int dss_resume_device(struct device *dev, void *data) +int dss_resume_all_devices(void) { - int r; - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_device *dssdev = NULL; - if (dssdev->activate_after_resume) { - r = dssdev->driver->enable(dssdev); - if (r) - return r; - } + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; - dssdev->activate_after_resume = false; + if (dssdev->activate_after_resume) { + dssdev->driver->enable(dssdev); + dssdev->activate_after_resume = false; + } + } return 0; } -int dss_resume_all_devices(void) +void dss_disable_all_devices(void) { - struct bus_type *bus = dss_get_bus(); + struct omap_dss_device *dssdev = NULL; + + for_each_dss_dev(dssdev) { + if (!dssdev->driver) + continue; - return bus_for_each_dev(bus, NULL, NULL, dss_resume_device); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + dssdev->driver->disable(dssdev); + } } -static int dss_disable_device(struct device *dev, void *data) +static LIST_HEAD(panel_list); +static DEFINE_MUTEX(panel_list_mutex); +static int disp_num_counter; + +int omapdss_register_display(struct omap_dss_device *dssdev) { - struct omap_dss_device *dssdev = to_dss_device(dev); + struct omap_dss_driver *drv = dssdev->driver; - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) - dssdev->driver->disable(dssdev); + snprintf(dssdev->alias, sizeof(dssdev->alias), + "display%d", disp_num_counter++); + if (drv && drv->get_resolution == NULL) + drv->get_resolution = omapdss_default_get_resolution; + if (drv && drv->get_recommended_bpp == NULL) + drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; + if (drv && drv->get_timings == NULL) + drv->get_timings = omapdss_default_get_timings; + + mutex_lock(&panel_list_mutex); + list_add_tail(&dssdev->panel_list, &panel_list); + mutex_unlock(&panel_list_mutex); return 0; } +EXPORT_SYMBOL(omapdss_register_display); -void dss_disable_all_devices(void) +void omapdss_unregister_display(struct omap_dss_device *dssdev) { - struct bus_type *bus = dss_get_bus(); - bus_for_each_dev(bus, NULL, NULL, dss_disable_device); + mutex_lock(&panel_list_mutex); + list_del(&dssdev->panel_list); + mutex_unlock(&panel_list_mutex); } +EXPORT_SYMBOL(omapdss_unregister_display); - -void omap_dss_get_device(struct omap_dss_device *dssdev) +struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev) { - get_device(&dssdev->dev); + if (!try_module_get(dssdev->owner)) + return NULL; + + if (get_device(dssdev->dev) == NULL) { + module_put(dssdev->owner); + return NULL; + } + + return dssdev; } EXPORT_SYMBOL(omap_dss_get_device); void omap_dss_put_device(struct omap_dss_device *dssdev) { - put_device(&dssdev->dev); + put_device(dssdev->dev); + module_put(dssdev->owner); } EXPORT_SYMBOL(omap_dss_put_device); -/* ref count of the found device is incremented. ref count - * of from-device is decremented. */ +/* + * ref count of the found device is incremented. + * ref count of from-device is decremented. + */ struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) { - struct device *dev; - struct device *dev_start = NULL; - struct omap_dss_device *dssdev = NULL; + struct list_head *l; + struct omap_dss_device *dssdev; + + mutex_lock(&panel_list_mutex); - int match(struct device *dev, void *data) - { - return 1; + if (list_empty(&panel_list)) { + dssdev = NULL; + goto out; } - if (from) - dev_start = &from->dev; - dev = bus_find_device(dss_get_bus(), dev_start, NULL, match); - if (dev) - dssdev = to_dss_device(dev); - if (from) - put_device(&from->dev); + if (from == NULL) { + dssdev = list_first_entry(&panel_list, struct omap_dss_device, + panel_list); + omap_dss_get_device(dssdev); + goto out; + } + + omap_dss_put_device(from); + + list_for_each(l, &panel_list) { + dssdev = list_entry(l, struct omap_dss_device, panel_list); + if (dssdev == from) { + if (list_is_last(l, &panel_list)) { + dssdev = NULL; + goto out; + } + + dssdev = list_entry(l->next, struct omap_dss_device, + panel_list); + omap_dss_get_device(dssdev); + goto out; + } + } + WARN(1, "'from' dssdev not found\n"); + + dssdev = NULL; +out: + mutex_unlock(&panel_list_mutex); return dssdev; } EXPORT_SYMBOL(omap_dss_get_next_device); @@ -198,24 +243,72 @@ struct omap_dss_device *omap_dss_find_device(void *data, } EXPORT_SYMBOL(omap_dss_find_device); -int omap_dss_start_device(struct omap_dss_device *dssdev) +void videomode_to_omap_video_timings(const struct videomode *vm, + struct omap_video_timings *ovt) { - if (!dssdev->driver) { - DSSDBG("no driver\n"); - return -ENODEV; - } - - if (!try_module_get(dssdev->dev.driver->owner)) { - return -ENODEV; - } - - return 0; + memset(ovt, 0, sizeof(*ovt)); + + ovt->pixel_clock = vm->pixelclock / 1000; + ovt->x_res = vm->hactive; + ovt->hbp = vm->hback_porch; + ovt->hfp = vm->hfront_porch; + ovt->hsw = vm->hsync_len; + ovt->y_res = vm->vactive; + ovt->vbp = vm->vback_porch; + ovt->vfp = vm->vfront_porch; + ovt->vsw = vm->vsync_len; + + ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ? + OMAPDSS_SIG_ACTIVE_HIGH : + OMAPDSS_SIG_ACTIVE_LOW; + ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ? + OMAPDSS_SIG_ACTIVE_HIGH : + OMAPDSS_SIG_ACTIVE_LOW; + ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ? + OMAPDSS_SIG_ACTIVE_HIGH : + OMAPDSS_SIG_ACTIVE_HIGH; + ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ? + OMAPDSS_DRIVE_SIG_RISING_EDGE : + OMAPDSS_DRIVE_SIG_FALLING_EDGE; + + ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; } -EXPORT_SYMBOL(omap_dss_start_device); +EXPORT_SYMBOL(videomode_to_omap_video_timings); -void omap_dss_stop_device(struct omap_dss_device *dssdev) +void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, + struct videomode *vm) { - module_put(dssdev->dev.driver->owner); + memset(vm, 0, sizeof(*vm)); + + vm->pixelclock = ovt->pixel_clock * 1000; + + vm->hactive = ovt->x_res; + vm->hback_porch = ovt->hbp; + vm->hfront_porch = ovt->hfp; + vm->hsync_len = ovt->hsw; + vm->vactive = ovt->y_res; + vm->vback_porch = ovt->vbp; + vm->vfront_porch = ovt->vfp; + vm->vsync_len = ovt->vsw; + + if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) + vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; + else + vm->flags |= DISPLAY_FLAGS_HSYNC_LOW; + + if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH) + vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; + else + vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; + + if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH) + vm->flags |= DISPLAY_FLAGS_DE_HIGH; + else + vm->flags |= DISPLAY_FLAGS_DE_LOW; + + if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE) + vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; + else + vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; } -EXPORT_SYMBOL(omap_dss_stop_device); - +EXPORT_SYMBOL(omap_video_timings_to_videomode); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 757b57f7275..a6b331ef776 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -37,6 +37,8 @@ #include "dss_features.h" static struct { + struct platform_device *pdev; + struct regulator *vdds_dsi_reg; struct platform_device *dsidev; @@ -46,7 +48,7 @@ static struct { struct dss_lcd_mgr_config mgr_config; int data_lines; - struct omap_dss_output output; + struct omap_dss_device output; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_channel channel) @@ -129,7 +131,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, * shifted. So skip all odd dividers when the pixel clock is on the * higher side. */ - if (ctx->pck_min >= 1000000) { + if (ctx->pck_min >= 100000000) { if (lckd > 1 && lckd % 2 != 0) return false; @@ -156,7 +158,7 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, * shifted. So skip all odd dividers when the pixel clock is on the * higher side. */ - if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000) + if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000) return false; ctx->dsi_cinfo.regm_dispc = regm_dispc; @@ -345,7 +347,7 @@ static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = &dpi.output; + struct omap_dss_device *out = &dpi.output; int r; mutex_lock(&dpi.lock); @@ -362,12 +364,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_no_out_mgr; } - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err_start_dev; - } - if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) @@ -422,8 +418,6 @@ err_get_dispc: if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); err_reg_enable: - omap_dss_stop_device(dssdev); -err_start_dev: err_no_out_mgr: err_no_reg: mutex_unlock(&dpi.lock); @@ -450,8 +444,6 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); - omap_dss_stop_device(dssdev); - mutex_unlock(&dpi.lock); } EXPORT_SYMBOL(omapdss_dpi_display_disable); @@ -469,6 +461,16 @@ void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_dpi_set_timings); +static void dpi_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + mutex_lock(&dpi.lock); + + *timings = dpi.timings; + + mutex_unlock(&dpi.lock); +} + int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { @@ -542,6 +544,50 @@ static int dpi_verify_dsi_pll(struct platform_device *dsidev) return 0; } +static int dpi_init_regulator(void) +{ + struct regulator *vdds_dsi; + + if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) + return 0; + + if (dpi.vdds_dsi_reg) + return 0; + + vdds_dsi = dss_get_vdds_dsi(); + + if (IS_ERR(vdds_dsi)) { + vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi"); + if (IS_ERR(vdds_dsi)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(vdds_dsi); + } + } + + dpi.vdds_dsi_reg = vdds_dsi; + + return 0; +} + +static void dpi_init_pll(void) +{ + struct platform_device *dsidev; + + if (dpi.dsidev) + return; + + dsidev = dpi_get_dsidev(dpi.output.dispc_channel); + if (!dsidev) + return; + + if (dpi_verify_dsi_pll(dsidev)) { + DSSWARN("DSI PLL not operational\n"); + return; + } + + dpi.dsidev = dsidev; +} + /* * Return a hardcoded channel for the DPI output. This should work for * current use cases, but this can be later expanded to either resolve @@ -572,41 +618,6 @@ static enum omap_channel dpi_get_channel(void) } } -static int dpi_init_display(struct omap_dss_device *dssdev) -{ - struct platform_device *dsidev; - - DSSDBG("init_display\n"); - - if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && - dpi.vdds_dsi_reg == NULL) { - struct regulator *vdds_dsi; - - vdds_dsi = dss_get_vdds_dsi(); - - if (IS_ERR(vdds_dsi)) { - DSSERR("can't get VDDS_DSI regulator\n"); - return PTR_ERR(vdds_dsi); - } - - dpi.vdds_dsi_reg = vdds_dsi; - } - - dsidev = dpi_get_dsidev(dpi.output.dispc_channel); - - if (dsidev && dpi_verify_dsi_pll(dsidev)) { - dsidev = NULL; - DSSWARN("DSI PLL not operational\n"); - } - - if (dsidev) - DSSDBG("using DSI PLL for DPI clock\n"); - - dpi.dsidev = dsidev; - - return 0; -} - static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; @@ -646,19 +657,18 @@ static int dpi_probe_pdata(struct platform_device *dpidev) if (!plat_dssdev) return 0; + r = dpi_init_regulator(); + if (r) + return r; + + dpi_init_pll(); + dssdev = dss_alloc_and_init_device(&dpidev->dev); if (!dssdev) return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); - r = dpi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - dss_put_device(dssdev); - return r; - } - r = omapdss_output_set_device(&dpi.output, dssdev); if (r) { DSSERR("failed to connect output to new device: %s\n", @@ -678,41 +688,108 @@ static int dpi_probe_pdata(struct platform_device *dpidev) return 0; } +static int dpi_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + struct omap_overlay_manager *mgr; + int r; + + r = dpi_init_regulator(); + if (r) + return r; + + dpi_init_pll(); + + mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); + if (!mgr) + return -ENODEV; + + r = dss_mgr_connect(mgr, dssdev); + if (r) + return r; + + r = omapdss_output_set_device(dssdev, dst); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dst->name); + dss_mgr_disconnect(mgr, dssdev); + return r; + } + + return 0; +} + +static void dpi_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + WARN_ON(dst != dssdev->device); + + if (dst != dssdev->device) + return; + + omapdss_output_unset_device(dssdev); + + if (dssdev->manager) + dss_mgr_disconnect(dssdev->manager, dssdev); +} + +static const struct omapdss_dpi_ops dpi_ops = { + .connect = dpi_connect, + .disconnect = dpi_disconnect, + + .enable = omapdss_dpi_display_enable, + .disable = omapdss_dpi_display_disable, + + .check_timings = dpi_check_timings, + .set_timings = omapdss_dpi_set_timings, + .get_timings = dpi_get_timings, + + .set_data_lines = omapdss_dpi_set_data_lines, +}; + static void dpi_init_output(struct platform_device *pdev) { - struct omap_dss_output *out = &dpi.output; + struct omap_dss_device *out = &dpi.output; - out->pdev = pdev; + out->dev = &pdev->dev; out->id = OMAP_DSS_OUTPUT_DPI; - out->type = OMAP_DISPLAY_TYPE_DPI; + out->output_type = OMAP_DISPLAY_TYPE_DPI; out->name = "dpi.0"; out->dispc_channel = dpi_get_channel(); + out->ops.dpi = &dpi_ops; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void __exit dpi_uninit_output(struct platform_device *pdev) { - struct omap_dss_output *out = &dpi.output; + struct omap_dss_device *out = &dpi.output; - dss_unregister_output(out); + omapdss_unregister_output(out); } static int omap_dpi_probe(struct platform_device *pdev) { int r; + dpi.pdev = pdev; + mutex_init(&dpi.lock); dpi_init_output(pdev); - r = dpi_probe_pdata(pdev); - if (r) { - dpi_uninit_output(pdev); - return r; + if (pdev->dev.platform_data) { + r = dpi_probe_pdata(pdev); + if (r) + goto err_probe; } return 0; + +err_probe: + dpi_uninit_output(pdev); + return r; } static int __exit omap_dpi_remove(struct platform_device *pdev) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index a73dedc3310..99a043b08f0 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -363,7 +363,7 @@ struct dsi_data { enum omap_dss_dsi_mode mode; struct omap_dss_dsi_videomode_timings vm_timings; - struct omap_dss_output output; + struct omap_dss_device output; }; struct dsi_packet_sent_handler_data { @@ -383,12 +383,21 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) { - return dssdev->output->pdev; + /* HACK: dssdev can be either the panel device, when using old API, or + * the dsi device itself, when using the new API. So we solve this for + * now by checking the dssdev->id. This will be removed when the old API + * is removed. + */ + if (dssdev->id == OMAP_DSS_OUTPUT_DSI1 || + dssdev->id == OMAP_DSS_OUTPUT_DSI2) + return to_platform_device(dssdev->dev); + + return to_platform_device(dssdev->output->dev); } struct platform_device *dsi_get_dsidev_from_id(int module) { - struct omap_dss_output *out; + struct omap_dss_device *out; enum omap_dss_output_id id; switch (module) { @@ -404,7 +413,7 @@ struct platform_device *dsi_get_dsidev_from_id(int module) out = omap_dss_get_output(id); - return out ? out->pdev : NULL; + return out ? to_platform_device(out->dev) : NULL; } static inline void dsi_write_reg(struct platform_device *dsidev, @@ -1114,6 +1123,30 @@ void dsi_runtime_put(struct platform_device *dsidev) WARN_ON(r < 0 && r != -ENOSYS); } +static int dsi_regulator_init(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct regulator *vdds_dsi; + + if (dsi->vdds_dsi_reg != NULL) + return 0; + + vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); + + /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ + if (IS_ERR(vdds_dsi)) + vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO"); + + if (IS_ERR(vdds_dsi)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(vdds_dsi); + } + + dsi->vdds_dsi_reg = vdds_dsi; + + return 0; +} + /* source clock for DSI PLL. this could also be PCLKFREE */ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, bool enable) @@ -1592,22 +1625,9 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, */ enable_hsclk = enable_hsdiv = true; - if (dsi->vdds_dsi_reg == NULL) { - struct regulator *vdds_dsi; - - vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); - - /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ - if (IS_ERR(vdds_dsi)) - vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); - - if (IS_ERR(vdds_dsi)) { - DSSERR("can't get VDDS_DSI regulator\n"); - return PTR_ERR(vdds_dsi); - } - - dsi->vdds_dsi_reg = vdds_dsi; - } + r = dsi_regulator_init(dsidev); + if (r) + return r; dsi_enable_pll_clock(dsidev, 1); /* @@ -4122,7 +4142,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_overlay_manager *mgr = dsi->output.manager; int bpp = dsi_get_pixel_size(dsi->pix_fmt); - struct omap_dss_output *out = &dsi->output; + struct omap_dss_device *out = &dsi->output; u8 data_type; u16 word_count; int r; @@ -4581,12 +4601,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err_start_dev; - } - r = dsi_runtime_get(dsidev); if (r) goto err_get_dsi; @@ -4607,8 +4621,6 @@ err_init_dsi: dsi_enable_pll_clock(dsidev, 0); dsi_runtime_put(dsidev); err_get_dsi: - omap_dss_stop_device(dssdev); -err_start_dev: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); return r; @@ -4637,8 +4649,6 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); - omap_dss_stop_device(dssdev); - mutex_unlock(&dsi->lock); } EXPORT_SYMBOL(omapdss_dsi_display_disable); @@ -5225,34 +5235,6 @@ static enum omap_channel dsi_get_channel(int module_id) } } -static int dsi_init_display(struct omap_dss_device *dssdev) -{ - struct platform_device *dsidev = - dsi_get_dsidev_from_id(dssdev->phy.dsi.module); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - DSSDBG("DSI init\n"); - - if (dsi->vdds_dsi_reg == NULL) { - struct regulator *vdds_dsi; - - vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); - - /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ - if (IS_ERR(vdds_dsi)) - vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); - - if (IS_ERR(vdds_dsi)) { - DSSERR("can't get VDDS_DSI regulator\n"); - return PTR_ERR(vdds_dsi); - } - - dsi->vdds_dsi_reg = vdds_dsi; - } - - return 0; -} - int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -5410,19 +5392,16 @@ static int dsi_probe_pdata(struct platform_device *dsidev) if (!plat_dssdev) return 0; + r = dsi_regulator_init(dsidev); + if (r) + return r; + dssdev = dss_alloc_and_init_device(&dsidev->dev); if (!dssdev) return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); - r = dsi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - dss_put_device(dssdev); - return r; - } - r = omapdss_output_set_device(&dsi->output, dssdev); if (r) { DSSERR("failed to connect output to new device: %s\n", @@ -5442,28 +5421,113 @@ static int dsi_probe_pdata(struct platform_device *dsidev) return 0; } +static int dsi_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct omap_overlay_manager *mgr; + int r; + + r = dsi_regulator_init(dsidev); + if (r) + return r; + + mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); + if (!mgr) + return -ENODEV; + + r = dss_mgr_connect(mgr, dssdev); + if (r) + return r; + + r = omapdss_output_set_device(dssdev, dst); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_mgr_disconnect(mgr, dssdev); + return r; + } + + return 0; +} + +static void dsi_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + WARN_ON(dst != dssdev->device); + + if (dst != dssdev->device) + return; + + omapdss_output_unset_device(dssdev); + + if (dssdev->manager) + dss_mgr_disconnect(dssdev->manager, dssdev); +} + +static const struct omapdss_dsi_ops dsi_ops = { + .connect = dsi_connect, + .disconnect = dsi_disconnect, + + .bus_lock = dsi_bus_lock, + .bus_unlock = dsi_bus_unlock, + + .enable = omapdss_dsi_display_enable, + .disable = omapdss_dsi_display_disable, + + .enable_hs = omapdss_dsi_vc_enable_hs, + + .configure_pins = omapdss_dsi_configure_pins, + .set_config = omapdss_dsi_set_config, + + .enable_video_output = dsi_enable_video_output, + .disable_video_output = dsi_disable_video_output, + + .update = omap_dsi_update, + + .enable_te = omapdss_dsi_enable_te, + + .request_vc = omap_dsi_request_vc, + .set_vc_id = omap_dsi_set_vc_id, + .release_vc = omap_dsi_release_vc, + + .dcs_write = dsi_vc_dcs_write, + .dcs_write_nosync = dsi_vc_dcs_write_nosync, + .dcs_read = dsi_vc_dcs_read, + + .gen_write = dsi_vc_generic_write, + .gen_write_nosync = dsi_vc_generic_write_nosync, + .gen_read = dsi_vc_generic_read, + + .bta_sync = dsi_vc_send_bta_sync, + + .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size, +}; + static void dsi_init_output(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_output *out = &dsi->output; + struct omap_dss_device *out = &dsi->output; - out->pdev = dsidev; + out->dev = &dsidev->dev; out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; - out->type = OMAP_DISPLAY_TYPE_DSI; + out->output_type = OMAP_DISPLAY_TYPE_DSI; out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; out->dispc_channel = dsi_get_channel(dsi->module_id); + out->ops.dsi = &dsi_ops; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void dsi_uninit_output(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_output *out = &dsi->output; + struct omap_dss_device *out = &dsi->output; - dss_unregister_output(out); + omapdss_unregister_output(out); } /* DSI1 HW IP initialisation */ @@ -5563,12 +5627,10 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dsi_init_output(dsidev); - r = dsi_probe_pdata(dsidev); - if (r) { - dsi_runtime_put(dsidev); - dsi_uninit_output(dsidev); - pm_runtime_disable(&dsidev->dev); - return r; + if (dsidev->dev.platform_data) { + r = dsi_probe_pdata(dsidev); + if (r) + goto err_probe; } dsi_runtime_put(dsidev); @@ -5586,6 +5648,9 @@ static int omap_dsihw_probe(struct platform_device *dsidev) #endif return 0; +err_probe: + dsi_runtime_put(dsidev); + dsi_uninit_output(dsidev); err_runtime_get: pm_runtime_disable(&dsidev->dev); return r; @@ -5603,14 +5668,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) pm_runtime_disable(&dsidev->dev); - if (dsi->vdds_dsi_reg != NULL) { - if (dsi->vdds_dsi_enabled) { - regulator_disable(dsi->vdds_dsi_reg); - dsi->vdds_dsi_enabled = false; - } - - regulator_put(dsi->vdds_dsi_reg); - dsi->vdds_dsi_reg = NULL; + if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) { + regulator_disable(dsi->vdds_dsi_reg); + dsi->vdds_dsi_enabled = false; } return 0; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 94f66f9f10a..bd01608e67e 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -157,7 +157,8 @@ static void dss_restore_context(void) int dss_get_ctx_loss_count(void) { - struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; + struct platform_device *core_pdev = dss_get_core_pdev(); + struct omap_dss_board_info *board_data = core_pdev->dev.platform_data; int cnt; if (!board_data->get_context_loss_count) diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 84758936429..50a2362ef8f 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -179,23 +179,19 @@ void dss_put_device(struct omap_dss_device *dssdev); void dss_copy_device_pdata(struct omap_dss_device *dst, const struct omap_dss_device *src); -/* output */ -void dss_register_output(struct omap_dss_output *out); -void dss_unregister_output(struct omap_dss_output *out); - /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); void dss_disable_all_devices(void); -int display_init_sysfs(struct platform_device *pdev, - struct omap_dss_device *dssdev); -void display_uninit_sysfs(struct platform_device *pdev, - struct omap_dss_device *dssdev); +int display_init_sysfs(struct platform_device *pdev); +void display_uninit_sysfs(struct platform_device *pdev); /* manager */ -int dss_init_overlay_managers(struct platform_device *pdev); -void dss_uninit_overlay_managers(struct platform_device *pdev); +int dss_init_overlay_managers(void); +void dss_uninit_overlay_managers(void); +int dss_init_overlay_managers_sysfs(struct platform_device *pdev); +void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev); int dss_mgr_simple_check(struct omap_overlay_manager *mgr, const struct omap_overlay_manager_info *info); int dss_mgr_check_timings(struct omap_overlay_manager *mgr, @@ -426,6 +422,7 @@ void dispc_mgr_set_clock_div(enum omap_channel channel, const struct dispc_clock_info *cinfo); int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); +void dispc_set_tv_pclk(unsigned long pclk); u32 dispc_wb_get_framedone_irq(void); bool dispc_wb_go_busy(void); @@ -437,17 +434,8 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, bool mem_to_mem, const struct omap_video_timings *timings); /* VENC */ -#ifdef CONFIG_OMAP2_DSS_VENC int venc_init_platform_driver(void) __init; void venc_uninit_platform_driver(void) __exit; -unsigned long venc_get_pixel_clock(void); -#else -static inline unsigned long venc_get_pixel_clock(void) -{ - WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); - return 0; -} -#endif int omapdss_venc_display_enable(struct omap_dss_device *dssdev); void omapdss_venc_display_disable(struct omap_dss_device *dssdev); void omapdss_venc_set_timings(struct omap_dss_device *dssdev, @@ -464,17 +452,8 @@ int venc_panel_init(void); void venc_panel_exit(void); /* HDMI */ -#ifdef CONFIG_OMAP4_DSS_HDMI int hdmi_init_platform_driver(void) __init; void hdmi_uninit_platform_driver(void) __exit; -unsigned long hdmi_get_pixel_clock(void); -#else -static inline unsigned long hdmi_get_pixel_clock(void) -{ - WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); - return 0; -} -#endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 77dbe0cfb34..b9cfebb378a 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -797,7 +797,6 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { .phy_enable = ti_hdmi_4xxx_phy_enable, .phy_disable = ti_hdmi_4xxx_phy_disable, .read_edid = ti_hdmi_4xxx_read_edid, - .detect = ti_hdmi_4xxx_detect, .pll_enable = ti_hdmi_4xxx_pll_enable, .pll_disable = ti_hdmi_4xxx_pll_disable, .video_enable = ti_hdmi_4xxx_wp_video_start, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a109934c047..44a885b9282 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -70,7 +70,9 @@ static struct { int ls_oe_gpio; int hpd_gpio; - struct omap_dss_output output; + bool core_enabled; + + struct omap_dss_device output; } hdmi; /* @@ -328,6 +330,29 @@ static void hdmi_runtime_put(void) WARN_ON(r < 0 && r != -ENOSYS); } +static int hdmi_init_regulator(void) +{ + struct regulator *reg; + + if (hdmi.vdda_hdmi_dac_reg != NULL) + return 0; + + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + + /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ + if (IS_ERR(reg)) + reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); + + if (IS_ERR(reg)) { + DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + return PTR_ERR(reg); + } + + hdmi.vdda_hdmi_dac_reg = reg; + + return 0; +} + static int hdmi_init_display(struct omap_dss_device *dssdev) { int r; @@ -342,22 +367,9 @@ static int hdmi_init_display(struct omap_dss_device *dssdev) dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); - if (hdmi.vdda_hdmi_dac_reg == NULL) { - struct regulator *reg; - - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); - - /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ - if (IS_ERR(reg)) - reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); - - if (IS_ERR(reg)) { - DSSERR("can't get VDDA_HDMI_DAC regulator\n"); - return PTR_ERR(reg); - } - - hdmi.vdda_hdmi_dac_reg = reg; - } + r = hdmi_init_regulator(); + if (r) + return r; r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); if (r) @@ -455,12 +467,6 @@ end: return cm; } -unsigned long hdmi_get_pixel_clock(void) -{ - /* HDMI Pixel Clock in Mhz */ - return hdmi.ip_data.cfg.timings.pixel_clock * 1000; -} - static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, struct hdmi_pll_info *pi) { @@ -511,8 +517,10 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) { int r; - gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); - gpio_set_value(hdmi.ls_oe_gpio, 1); + if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) + gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); + if (gpio_is_valid(hdmi.ls_oe_gpio)) + gpio_set_value(hdmi.ls_oe_gpio, 1); /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ udelay(300); @@ -528,29 +536,37 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + hdmi.core_enabled = true; + return 0; err_runtime_get: regulator_disable(hdmi.vdda_hdmi_dac_reg); err_vdac_enable: - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + if (gpio_is_valid(hdmi.ls_oe_gpio)) + gpio_set_value(hdmi.ls_oe_gpio, 0); return r; } static void hdmi_power_off_core(struct omap_dss_device *dssdev) { + hdmi.core_enabled = false; + hdmi_runtime_put(); regulator_disable(hdmi.vdda_hdmi_dac_reg); - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + if (gpio_is_valid(hdmi.ls_oe_gpio)) + gpio_set_value(hdmi.ls_oe_gpio, 0); } static int hdmi_power_on_full(struct omap_dss_device *dssdev) { int r; struct omap_video_timings *p; - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = hdmi.output.manager; unsigned long phy; r = hdmi_power_on_core(dssdev); @@ -613,7 +629,7 @@ err_pll_enable: static void hdmi_power_off_full(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = hdmi.output.manager; dss_mgr_disable(mgr); @@ -653,9 +669,23 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, if (t != NULL) hdmi.ip_data.cfg = *t; + dispc_set_tv_pclk(t->timings.pixel_clock * 1000); + mutex_unlock(&hdmi.lock); } +static void omapdss_hdmi_display_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + const struct hdmi_config *cfg; + + cfg = hdmi_get_timings(); + if (cfg == NULL) + cfg = &vesa_timings[0]; + + memcpy(timings, &cfg->timings, sizeof(cfg->timings)); +} + static void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); @@ -700,7 +730,7 @@ bool omapdss_hdmi_detect(void) r = hdmi_runtime_get(); BUG_ON(r); - r = hdmi.ip_data.ops->detect(&hdmi.ip_data); + r = gpio_get_value(hdmi.hpd_gpio); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); @@ -710,7 +740,7 @@ bool omapdss_hdmi_detect(void) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_device *out = &hdmi.output; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); @@ -723,25 +753,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; - - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err0; - } - r = hdmi_power_on_full(dssdev); if (r) { DSSERR("failed to power on device\n"); - goto err1; + goto err0; } mutex_unlock(&hdmi.lock); return 0; -err1: - omap_dss_stop_device(dssdev); err0: mutex_unlock(&hdmi.lock); return r; @@ -755,8 +775,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) hdmi_power_off_full(dssdev); - omap_dss_stop_device(dssdev); - mutex_unlock(&hdmi.lock); } @@ -768,8 +786,6 @@ int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; - r = hdmi_power_on_core(dssdev); if (r) { DSSERR("failed to power on device\n"); @@ -1033,24 +1049,219 @@ static int hdmi_probe_pdata(struct platform_device *pdev) return 0; } +static int hdmi_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + struct omap_overlay_manager *mgr; + int r; + + dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); + + r = hdmi_init_regulator(); + if (r) + return r; + + mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); + if (!mgr) + return -ENODEV; + + r = dss_mgr_connect(mgr, dssdev); + if (r) + return r; + + r = omapdss_output_set_device(dssdev, dst); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dst->name); + dss_mgr_disconnect(mgr, dssdev); + return r; + } + + return 0; +} + +static void hdmi_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + WARN_ON(dst != dssdev->device); + + if (dst != dssdev->device) + return; + + omapdss_output_unset_device(dssdev); + + if (dssdev->manager) + dss_mgr_disconnect(dssdev->manager, dssdev); +} + +static int hdmi_read_edid(struct omap_dss_device *dssdev, + u8 *edid, int len) +{ + bool need_enable; + int r; + + need_enable = hdmi.core_enabled == false; + + if (need_enable) { + r = omapdss_hdmi_core_enable(dssdev); + if (r) + return r; + } + + r = omapdss_hdmi_read_edid(edid, len); + + if (need_enable) + omapdss_hdmi_core_disable(dssdev); + + return r; +} + +#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) +static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&hdmi.lock); + + if (!hdmi_mode_has_audio()) { + r = -EPERM; + goto err; + } + + r = hdmi_audio_enable(); + if (r) + goto err; + + mutex_unlock(&hdmi.lock); + return 0; + +err: + mutex_unlock(&hdmi.lock); + return r; +} + +static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) +{ + hdmi_audio_disable(); +} + +static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) +{ + return hdmi_audio_start(); +} + +static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) +{ + hdmi_audio_stop(); +} + +static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) +{ + bool r; + + mutex_lock(&hdmi.lock); + + r = hdmi_mode_has_audio(); + + mutex_unlock(&hdmi.lock); + return r; +} + +static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, + struct omap_dss_audio *audio) +{ + int r; + + mutex_lock(&hdmi.lock); + + if (!hdmi_mode_has_audio()) { + r = -EPERM; + goto err; + } + + r = hdmi_audio_config(audio); + if (r) + goto err; + + mutex_unlock(&hdmi.lock); + return 0; + +err: + mutex_unlock(&hdmi.lock); + return r; +} +#else +static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) +{ + return -EPERM; +} + +static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) +{ +} + +static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) +{ + return -EPERM; +} + +static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) +{ +} + +static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) +{ + return false; +} + +static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, + struct omap_dss_audio *audio) +{ + return -EPERM; +} +#endif + +static const struct omapdss_hdmi_ops hdmi_ops = { + .connect = hdmi_connect, + .disconnect = hdmi_disconnect, + + .enable = omapdss_hdmi_display_enable, + .disable = omapdss_hdmi_display_disable, + + .check_timings = omapdss_hdmi_display_check_timing, + .set_timings = omapdss_hdmi_display_set_timing, + .get_timings = omapdss_hdmi_display_get_timings, + + .read_edid = hdmi_read_edid, + + .audio_enable = omapdss_hdmi_audio_enable, + .audio_disable = omapdss_hdmi_audio_disable, + .audio_start = omapdss_hdmi_audio_start, + .audio_stop = omapdss_hdmi_audio_stop, + .audio_supported = omapdss_hdmi_audio_supported, + .audio_config = omapdss_hdmi_audio_config, +}; + static void hdmi_init_output(struct platform_device *pdev) { - struct omap_dss_output *out = &hdmi.output; + struct omap_dss_device *out = &hdmi.output; - out->pdev = pdev; + out->dev = &pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; - out->type = OMAP_DISPLAY_TYPE_HDMI; + out->output_type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; + out->ops.hdmi = &hdmi_ops; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void __exit hdmi_uninit_output(struct platform_device *pdev) { - struct omap_dss_output *out = &hdmi.output; + struct omap_dss_device *out = &hdmi.output; - dss_unregister_output(out); + omapdss_unregister_output(out); } /* HDMI HW IP initialisation */ @@ -1071,6 +1282,12 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) if (IS_ERR(hdmi.ip_data.base_wp)) return PTR_ERR(hdmi.ip_data.base_wp); + hdmi.ip_data.irq = platform_get_irq(pdev, 0); + if (hdmi.ip_data.irq < 0) { + DSSERR("platform_get_irq failed\n"); + return -ENODEV; + } + r = hdmi_get_clocks(pdev); if (r) { DSSERR("can't get clocks\n"); @@ -1084,6 +1301,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; + hdmi.ct_cp_hpd_gpio = -1; + hdmi.ls_oe_gpio = -1; + hdmi.hpd_gpio = -1; + hdmi_init_output(pdev); r = hdmi_panel_init(); @@ -1094,15 +1315,19 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) dss_debugfs_create_file("hdmi", hdmi_dump_regs); - r = hdmi_probe_pdata(pdev); - if (r) { - hdmi_panel_exit(); - hdmi_uninit_output(pdev); - pm_runtime_disable(&pdev->dev); - return r; + if (pdev->dev.platform_data) { + r = hdmi_probe_pdata(pdev); + if (r) + goto err_probe; } return 0; + +err_probe: + hdmi_panel_exit(); + hdmi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return r; } static int __exit hdmi_remove_child(struct device *dev, void *data) diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c index 9a2fb59b6f8..de7e7b5b1b7 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,32 +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 = dssdev->output; - - /* - * a registered device should have an output connected to it - * already - */ - if (!out) { - DSSERR("device has no output connected to it\n"); + 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; } - r = mgr->set_output(mgr, out); + old_dssdev->driver->disconnect(old_dssdev); + } + + if (dssdev) { + r = dssdev->driver->connect(dssdev); if (r) { - DSSERR("failed to set manager output\n"); + DSSERR("failed to connect new device\n"); + goto put_device; + } + + 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; } @@ -509,4 +522,6 @@ void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) { kobject_del(&mgr->kobj); kobject_put(&mgr->kobj); + + memset(&mgr->kobj, 0, sizeof(mgr->kobj)); } diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 2551eaa14c4..1aac9b4191a 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -36,9 +36,9 @@ static int num_managers; static struct omap_overlay_manager *managers; -int dss_init_overlay_managers(struct platform_device *pdev) +int dss_init_overlay_managers(void) { - int i, r; + int i; num_managers = dss_feat_get_num_mgrs(); @@ -76,6 +76,17 @@ int dss_init_overlay_managers(struct platform_device *pdev) dss_feat_get_supported_outputs(mgr->id); INIT_LIST_HEAD(&mgr->overlays); + } + + return 0; +} + +int dss_init_overlay_managers_sysfs(struct platform_device *pdev) +{ + int i, r; + + for (i = 0; i < num_managers; ++i) { + struct omap_overlay_manager *mgr = &managers[i]; r = dss_manager_kobj_init(mgr, pdev); if (r) @@ -85,18 +96,22 @@ int dss_init_overlay_managers(struct platform_device *pdev) return 0; } -void dss_uninit_overlay_managers(struct platform_device *pdev) +void dss_uninit_overlay_managers(void) +{ + kfree(managers); + managers = NULL; + num_managers = 0; +} + +void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev) { int i; for (i = 0; i < num_managers; ++i) { struct omap_overlay_manager *mgr = &managers[i]; + dss_manager_kobj_uninit(mgr); } - - kfree(managers); - managers = NULL; - num_managers = 0; } int omap_dss_get_num_overlay_managers(void) diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 5214df63e0a..3f5c0a758b3 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c @@ -27,7 +27,7 @@ static LIST_HEAD(output_list); static DEFINE_MUTEX(output_lock); -int omapdss_output_set_device(struct omap_dss_output *out, +int omapdss_output_set_device(struct omap_dss_device *out, struct omap_dss_device *dssdev) { int r; @@ -41,7 +41,7 @@ int omapdss_output_set_device(struct omap_dss_output *out, goto err; } - if (out->type != dssdev->type) { + if (out->output_type != dssdev->type) { DSSERR("output type and display type don't match\n"); r = -EINVAL; goto err; @@ -60,7 +60,7 @@ err: } EXPORT_SYMBOL(omapdss_output_set_device); -int omapdss_output_unset_device(struct omap_dss_output *out) +int omapdss_output_unset_device(struct omap_dss_device *out) { int r; @@ -92,19 +92,22 @@ err: } EXPORT_SYMBOL(omapdss_output_unset_device); -void dss_register_output(struct omap_dss_output *out) +int omapdss_register_output(struct omap_dss_device *out) { list_add_tail(&out->list, &output_list); + return 0; } +EXPORT_SYMBOL(omapdss_register_output); -void dss_unregister_output(struct omap_dss_output *out) +void omapdss_unregister_output(struct omap_dss_device *out) { list_del(&out->list); } +EXPORT_SYMBOL(omapdss_unregister_output); -struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) +struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id) { - struct omap_dss_output *out; + struct omap_dss_device *out; list_for_each_entry(out, &output_list, list) { if (out->id == id) @@ -115,6 +118,62 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) } EXPORT_SYMBOL(omap_dss_get_output); +struct omap_dss_device *omap_dss_find_output(const char *name) +{ + struct omap_dss_device *out; + + list_for_each_entry(out, &output_list, list) { + if (strcmp(out->name, name) == 0) + return omap_dss_get_device(out); + } + + return NULL; +} +EXPORT_SYMBOL(omap_dss_find_output); + +struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node) +{ + struct omap_dss_device *out; + + list_for_each_entry(out, &output_list, list) { + if (out->dev->of_node == node) + return omap_dss_get_device(out); + } + + return NULL; +} +EXPORT_SYMBOL(omap_dss_find_output_by_node); + +struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) +{ + while (dssdev->output) + dssdev = dssdev->output; + + if (dssdev->id != 0) + return omap_dss_get_device(dssdev); + + return NULL; +} +EXPORT_SYMBOL(omapdss_find_output_from_display); + +struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) +{ + struct omap_dss_device *out; + struct omap_overlay_manager *mgr; + + out = omapdss_find_output_from_display(dssdev); + + if (out == NULL) + return NULL; + + mgr = out->manager; + + omap_dss_put_device(out); + + return mgr; +} +EXPORT_SYMBOL(omapdss_find_mgr_from_display); + static const struct dss_mgr_ops *dss_mgr_ops; int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) @@ -134,6 +193,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_device *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_device *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/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1a17dd1447d..fdfe6e6f25d 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -117,7 +117,7 @@ static struct { int data_lines; struct rfbi_timings intf_timings; - struct omap_dss_output output; + struct omap_dss_device output; } rfbi; static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) @@ -312,7 +312,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev, { u32 l; int r; - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = rfbi.output.manager; u16 width = rfbi.timings.x_res; u16 height = rfbi.timings.y_res; @@ -852,7 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = rfbi.output.manager; struct dss_lcd_mgr_config mgr_config; mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; @@ -890,7 +890,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_device *out = &rfbi.output; int r; if (out == NULL || out->manager == NULL) { @@ -902,12 +902,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) if (r) return r; - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err0; - } - r = dss_mgr_register_framedone_handler(out->manager, framedone_callback, NULL); if (r) { @@ -924,8 +918,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) return 0; err1: - omap_dss_stop_device(dssdev); -err0: rfbi_runtime_put(); return r; } @@ -933,11 +925,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable); void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_device *out = &rfbi.output; dss_mgr_unregister_framedone_handler(out->manager, framedone_callback, NULL); - omap_dss_stop_device(dssdev); rfbi_runtime_put(); } @@ -1022,22 +1013,23 @@ static int rfbi_probe_pdata(struct platform_device *rfbidev) static void rfbi_init_output(struct platform_device *pdev) { - struct omap_dss_output *out = &rfbi.output; + struct omap_dss_device *out = &rfbi.output; - out->pdev = pdev; + out->dev = &pdev->dev; out->id = OMAP_DSS_OUTPUT_DBI; - out->type = OMAP_DISPLAY_TYPE_DBI; + out->output_type = OMAP_DISPLAY_TYPE_DBI; out->name = "rfbi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_LCD; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void __exit rfbi_uninit_output(struct platform_device *pdev) { - struct omap_dss_output *out = &rfbi.output; + struct omap_dss_device *out = &rfbi.output; - dss_unregister_output(out); + omapdss_unregister_output(out); } /* RFBI HW IP initialisation */ @@ -1093,15 +1085,16 @@ static int omap_rfbihw_probe(struct platform_device *pdev) rfbi_init_output(pdev); - r = rfbi_probe_pdata(pdev); - if (r) { - rfbi_uninit_output(pdev); - pm_runtime_disable(&pdev->dev); - return r; + if (pdev->dev.platform_data) { + r = rfbi_probe_pdata(pdev); + if (r) + goto err_probe; } return 0; +err_probe: + rfbi_uninit_output(pdev); err_runtime_get: pm_runtime_disable(&pdev->dev); return r; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 0bcd30272f6..856af2e8976 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -31,6 +31,8 @@ #include "dss.h" static struct { + struct platform_device *pdev; + bool update_enabled; struct regulator *vdds_sdi_reg; @@ -38,7 +40,7 @@ static struct { struct omap_video_timings timings; int datapairs; - struct omap_dss_output output; + struct omap_dss_device output; } sdi; struct sdi_clk_calc_ctx { @@ -109,7 +111,7 @@ static int sdi_calc_clock_div(unsigned long pclk, static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = sdi.output.manager; sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; @@ -124,7 +126,7 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_device *out = &sdi.output; struct omap_video_timings *t = &sdi.timings; struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; @@ -136,12 +138,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) return -ENODEV; } - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err_start_dev; - } - r = regulator_enable(sdi.vdds_sdi_reg); if (r) goto err_reg_enable; @@ -213,15 +209,13 @@ err_calc_clock_div: err_get_dispc: regulator_disable(sdi.vdds_sdi_reg); err_reg_enable: - omap_dss_stop_device(dssdev); -err_start_dev: return r; } EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = sdi.output.manager; dss_mgr_disable(mgr); @@ -230,8 +224,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) dispc_runtime_put(); regulator_disable(sdi.vdds_sdi_reg); - - omap_dss_stop_device(dssdev); } EXPORT_SYMBOL(omapdss_sdi_display_disable); @@ -242,29 +234,51 @@ void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_sdi_set_timings); +static void sdi_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = sdi.timings; +} + +static int sdi_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct omap_overlay_manager *mgr = sdi.output.manager; + + if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) + return -EINVAL; + + if (timings->pixel_clock == 0) + return -EINVAL; + + return 0; +} + void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) { sdi.datapairs = datapairs; } EXPORT_SYMBOL(omapdss_sdi_set_datapairs); -static int sdi_init_display(struct omap_dss_device *dssdev) +static int sdi_init_regulator(void) { - DSSDBG("SDI init\n"); + struct regulator *vdds_sdi; - if (sdi.vdds_sdi_reg == NULL) { - struct regulator *vdds_sdi; + if (sdi.vdds_sdi_reg) + return 0; - vdds_sdi = dss_get_vdds_sdi(); + vdds_sdi = dss_get_vdds_sdi(); + if (IS_ERR(vdds_sdi)) { + vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi"); if (IS_ERR(vdds_sdi)) { DSSERR("can't get VDDS_SDI regulator\n"); return PTR_ERR(vdds_sdi); } - - sdi.vdds_sdi_reg = vdds_sdi; } + sdi.vdds_sdi_reg = vdds_sdi; + return 0; } @@ -313,7 +327,7 @@ static int sdi_probe_pdata(struct platform_device *sdidev) dss_copy_device_pdata(dssdev, plat_dssdev); - r = sdi_init_display(dssdev); + r = sdi_init_regulator(); if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); @@ -339,39 +353,104 @@ static int sdi_probe_pdata(struct platform_device *sdidev) return 0; } +static int sdi_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + struct omap_overlay_manager *mgr; + int r; + + r = sdi_init_regulator(); + if (r) + return r; + + mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); + if (!mgr) + return -ENODEV; + + r = dss_mgr_connect(mgr, dssdev); + if (r) + return r; + + r = omapdss_output_set_device(dssdev, dst); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dst->name); + dss_mgr_disconnect(mgr, dssdev); + return r; + } + + return 0; +} + +static void sdi_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + WARN_ON(dst != dssdev->device); + + if (dst != dssdev->device) + return; + + omapdss_output_unset_device(dssdev); + + if (dssdev->manager) + dss_mgr_disconnect(dssdev->manager, dssdev); +} + +static const struct omapdss_sdi_ops sdi_ops = { + .connect = sdi_connect, + .disconnect = sdi_disconnect, + + .enable = omapdss_sdi_display_enable, + .disable = omapdss_sdi_display_disable, + + .check_timings = sdi_check_timings, + .set_timings = omapdss_sdi_set_timings, + .get_timings = sdi_get_timings, + + .set_datapairs = omapdss_sdi_set_datapairs, +}; + static void sdi_init_output(struct platform_device *pdev) { - struct omap_dss_output *out = &sdi.output; + struct omap_dss_device *out = &sdi.output; - out->pdev = pdev; + out->dev = &pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; - out->type = OMAP_DISPLAY_TYPE_SDI; + out->output_type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_LCD; + out->ops.sdi = &sdi_ops; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void __exit sdi_uninit_output(struct platform_device *pdev) { - struct omap_dss_output *out = &sdi.output; + struct omap_dss_device *out = &sdi.output; - dss_unregister_output(out); + omapdss_unregister_output(out); } static int omap_sdi_probe(struct platform_device *pdev) { int r; + sdi.pdev = pdev; + sdi_init_output(pdev); - r = sdi_probe_pdata(pdev); - if (r) { - sdi_uninit_output(pdev); - return r; + if (pdev->dev.platform_data) { + r = sdi_probe_pdata(pdev); + if (r) + goto err_probe; } return 0; + +err_probe: + sdi_uninit_output(pdev); + return r; } static int __exit omap_sdi_remove(struct platform_device *pdev) diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 216aa704f9d..45215f44617 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -73,8 +73,6 @@ struct ti_hdmi_ip_ops { int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); - bool (*detect)(struct hdmi_ip_data *ip_data); - int (*pll_enable)(struct hdmi_ip_data *ip_data); void (*pll_disable)(struct hdmi_ip_data *ip_data); @@ -155,19 +153,18 @@ struct hdmi_ip_data { unsigned long core_av_offset; unsigned long pll_offset; unsigned long phy_offset; + int irq; const struct ti_hdmi_ip_ops *ops; struct hdmi_config cfg; struct hdmi_pll_info pll_data; struct hdmi_core_infoframe_avi avi_cfg; /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ - int hpd_gpio; struct mutex lock; }; int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); -bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e18b222ed73..e242ed85cb0 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/seq_file.h> -#include <linux/gpio.h> #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) #include <sound/asound.h> #include <sound/asoundef.h> @@ -38,6 +37,9 @@ #include "dss.h" #include "dss_features.h" +#define HDMI_IRQ_LINK_CONNECT (1 << 25) +#define HDMI_IRQ_LINK_DISCONNECT (1 << 26) + static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx, u32 val) { @@ -233,37 +235,39 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); } -static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) +static irqreturn_t hdmi_irq_handler(int irq, void *data) { - bool hpd; - int r; - - mutex_lock(&ip_data->lock); - - hpd = gpio_get_value(ip_data->hpd_gpio); + struct hdmi_ip_data *ip_data = data; + void __iomem *wp_base = hdmi_wp_base(ip_data); + u32 irqstatus; + + irqstatus = hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); + hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, irqstatus); + /* flush posted write */ + hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); + + if ((irqstatus & HDMI_IRQ_LINK_CONNECT) && + irqstatus & HDMI_IRQ_LINK_DISCONNECT) { + /* + * If we get both connect and disconnect interrupts at the same + * time, turn off the PHY, clear interrupts, and restart, which + * raises connect interrupt if a cable is connected, or nothing + * if cable is not connected. + */ + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); - if (hpd) - r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); - else - r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); + /* flush posted write */ + hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS); - if (r) { - DSSERR("Failed to %s PHY TX power\n", - hpd ? "enable" : "disable"); - goto err; + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); + } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) { + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); } -err: - mutex_unlock(&ip_data->lock); - return r; -} - -static irqreturn_t hpd_irq_handler(int irq, void *data) -{ - struct hdmi_ip_data *ip_data = data; - - hdmi_check_hpd_state(ip_data); - return IRQ_HANDLED; } @@ -272,6 +276,12 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) u16 r = 0; void __iomem *phy_base = hdmi_phy_base(ip_data); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_CLR, + 0xffffffff); + + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQSTATUS, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); if (r) return r; @@ -297,29 +307,23 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) /* Write to phy address 3 to change the polarity control */ REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); - r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), - NULL, hpd_irq_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, "hpd", ip_data); + r = request_threaded_irq(ip_data->irq, NULL, hdmi_irq_handler, + IRQF_ONESHOT, "OMAP HDMI", ip_data); if (r) { - DSSERR("HPD IRQ request failed\n"); + DSSERR("HDMI IRQ request failed\n"); hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); return r; } - r = hdmi_check_hpd_state(ip_data); - if (r) { - free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); - hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); - return r; - } + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_SET, + HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; } void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) { - free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); + free_irq(ip_data->irq, ip_data); hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); } @@ -476,11 +480,6 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, return l; } -bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) -{ - return gpio_get_value(ip_data->hpd_gpio); -} - static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, struct hdmi_core_infoframe_avi *avi_cfg, struct hdmi_core_packet_enable_repeat *repeat_cfg) diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 8366ae19e82..6ef2f929a76 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h @@ -33,6 +33,7 @@ #define HDMI_WP_IRQSTATUS 0x28 #define HDMI_WP_PWR_CTRL 0x40 #define HDMI_WP_IRQENABLE_SET 0x2C +#define HDMI_WP_IRQENABLE_CLR 0x30 #define HDMI_WP_VIDEO_CFG 0x50 #define HDMI_WP_VIDEO_SIZE 0x60 #define HDMI_WP_VIDEO_TIMING_H 0x68 diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 74fdb3ee209..496a106fe82 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -304,7 +304,7 @@ static struct { enum omap_dss_venc_type type; bool invert_polarity; - struct omap_dss_output output; + struct omap_dss_device output; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -429,7 +429,7 @@ static const struct venc_config *venc_timings_to_config( static int venc_power_on(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = venc.output.manager; u32 l; int r; @@ -480,7 +480,7 @@ err0: static void venc_power_off(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = venc.output.manager; venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); @@ -492,15 +492,9 @@ static void venc_power_off(struct omap_dss_device *dssdev) venc_runtime_put(); } -unsigned long venc_get_pixel_clock(void) -{ - /* VENC Pixel Clock in Mhz */ - return 13500000; -} - int omapdss_venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_device *out = &venc.output; int r; DSSDBG("venc_display_enable\n"); @@ -513,23 +507,15 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) goto err0; } - r = omap_dss_start_device(dssdev); - if (r) { - DSSERR("failed to start device\n"); - goto err0; - } - r = venc_power_on(dssdev); if (r) - goto err1; + goto err0; venc.wss_data = 0; mutex_unlock(&venc.venc_lock); return 0; -err1: - omap_dss_stop_device(dssdev); err0: mutex_unlock(&venc.venc_lock); return r; @@ -543,8 +529,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev) venc_power_off(dssdev); - omap_dss_stop_device(dssdev); - mutex_unlock(&venc.venc_lock); } @@ -561,6 +545,8 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev, venc.timings = *timings; + dispc_set_tv_pclk(13500000); + mutex_unlock(&venc.venc_lock); } @@ -578,6 +564,16 @@ int omapdss_venc_check_timings(struct omap_dss_device *dssdev, return -EINVAL; } +static void venc_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + mutex_lock(&venc.venc_lock); + + *timings = venc.timings; + + mutex_unlock(&venc.venc_lock); +} + u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) { /* Invert due to VENC_L21_WC_CTL:INV=1 */ @@ -633,23 +629,22 @@ void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, mutex_unlock(&venc.venc_lock); } -static int venc_init_display(struct omap_dss_device *dssdev) +static int venc_init_regulator(void) { - DSSDBG("init_display\n"); - - if (venc.vdda_dac_reg == NULL) { - struct regulator *vdda_dac; + struct regulator *vdda_dac; - vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac"); + if (venc.vdda_dac_reg != NULL) + return 0; - if (IS_ERR(vdda_dac)) { - DSSERR("can't get VDDA_DAC regulator\n"); - return PTR_ERR(vdda_dac); - } + vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); - venc.vdda_dac_reg = vdda_dac; + if (IS_ERR(vdda_dac)) { + DSSERR("can't get VDDA_DAC regulator\n"); + return PTR_ERR(vdda_dac); } + venc.vdda_dac_reg = vdda_dac; + return 0; } @@ -765,19 +760,16 @@ static int venc_probe_pdata(struct platform_device *vencdev) if (!plat_dssdev) return 0; + r = venc_init_regulator(); + if (r) + return r; + dssdev = dss_alloc_and_init_device(&vencdev->dev); if (!dssdev) return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); - r = venc_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - dss_put_device(dssdev); - return r; - } - r = omapdss_output_set_device(&venc.output, dssdev); if (r) { DSSERR("failed to connect output to new device: %s\n", @@ -797,24 +789,87 @@ static int venc_probe_pdata(struct platform_device *vencdev) return 0; } +static int venc_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + struct omap_overlay_manager *mgr; + int r; + + r = venc_init_regulator(); + if (r) + return r; + + mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); + if (!mgr) + return -ENODEV; + + r = dss_mgr_connect(mgr, dssdev); + if (r) + return r; + + r = omapdss_output_set_device(dssdev, dst); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dst->name); + dss_mgr_disconnect(mgr, dssdev); + return r; + } + + return 0; +} + +static void venc_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) +{ + WARN_ON(dst != dssdev->device); + + if (dst != dssdev->device) + return; + + omapdss_output_unset_device(dssdev); + + if (dssdev->manager) + dss_mgr_disconnect(dssdev->manager, dssdev); +} + +static const struct omapdss_atv_ops venc_ops = { + .connect = venc_connect, + .disconnect = venc_disconnect, + + .enable = omapdss_venc_display_enable, + .disable = omapdss_venc_display_disable, + + .check_timings = omapdss_venc_check_timings, + .set_timings = omapdss_venc_set_timings, + .get_timings = venc_get_timings, + + .set_type = omapdss_venc_set_type, + .invert_vid_out_polarity = omapdss_venc_invert_vid_out_polarity, + + .set_wss = omapdss_venc_set_wss, + .get_wss = omapdss_venc_get_wss, +}; + static void venc_init_output(struct platform_device *pdev) { - struct omap_dss_output *out = &venc.output; + struct omap_dss_device *out = &venc.output; - out->pdev = pdev; + out->dev = &pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; - out->type = OMAP_DISPLAY_TYPE_VENC; + out->output_type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; + out->ops.atv = &venc_ops; + out->owner = THIS_MODULE; - dss_register_output(out); + omapdss_register_output(out); } static void __exit venc_uninit_output(struct platform_device *pdev) { - struct omap_dss_output *out = &venc.output; + struct omap_dss_device *out = &venc.output; - dss_unregister_output(out); + omapdss_unregister_output(out); } /* VENC HW IP initialisation */ @@ -866,16 +921,17 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_init_output(pdev); - r = venc_probe_pdata(pdev); - if (r) { - venc_panel_exit(); - venc_uninit_output(pdev); - pm_runtime_disable(&pdev->dev); - return r; + if (pdev->dev.platform_data) { + r = venc_probe_pdata(pdev); + if (r) + goto err_probe; } return 0; +err_probe: + venc_panel_exit(); + venc_uninit_output(pdev); err_panel_init: err_runtime_get: pm_runtime_disable(&pdev->dev); @@ -886,11 +942,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev) { dss_unregister_child_devices(&pdev->dev); - if (venc.vdda_dac_reg != NULL) { - regulator_put(venc.vdda_dac_reg); - venc.vdda_dac_reg = NULL; - } - venc_panel_exit(); venc_uninit_output(pdev); diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c index 0d2b1a0834a..f7d92c57bd7 100644 --- a/drivers/video/omap2/dss/venc_panel.c +++ b/drivers/video/omap2/dss/venc_panel.c @@ -107,19 +107,19 @@ static int venc_panel_probe(struct omap_dss_device *dssdev) dssdev->panel.timings = default_timings; - return device_create_file(&dssdev->dev, &dev_attr_output_type); + return device_create_file(dssdev->dev, &dev_attr_output_type); } static void venc_panel_remove(struct omap_dss_device *dssdev) { - device_remove_file(&dssdev->dev, &dev_attr_output_type); + device_remove_file(dssdev->dev, &dev_attr_output_type); } static int venc_panel_enable(struct omap_dss_device *dssdev) { int r; - dev_dbg(&dssdev->dev, "venc_panel_enable\n"); + dev_dbg(dssdev->dev, "venc_panel_enable\n"); mutex_lock(&venc_panel.lock); @@ -150,7 +150,7 @@ err: static void venc_panel_disable(struct omap_dss_device *dssdev) { - dev_dbg(&dssdev->dev, "venc_panel_disable\n"); + dev_dbg(dssdev->dev, "venc_panel_disable\n"); mutex_lock(&venc_panel.lock); @@ -167,7 +167,7 @@ end: static void venc_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); + dev_dbg(dssdev->dev, "venc_panel_set_timings\n"); mutex_lock(&venc_panel.lock); @@ -180,21 +180,21 @@ static void venc_panel_set_timings(struct omap_dss_device *dssdev, static int venc_panel_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); + dev_dbg(dssdev->dev, "venc_panel_check_timings\n"); return omapdss_venc_check_timings(dssdev, timings); } static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) { - dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); + dev_dbg(dssdev->dev, "venc_panel_get_wss\n"); return omapdss_venc_get_wss(dssdev); } static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) { - dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); + dev_dbg(dssdev->dev, "venc_panel_set_wss\n"); return omapdss_venc_set_wss(dssdev, wss); } |