2009-11-03 09:23:50 +00:00
|
|
|
/*
|
|
|
|
* linux/drivers/video/omap2/dss/core.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Nokia Corporation
|
|
|
|
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
|
|
|
*
|
|
|
|
* Some code and ideas taken from drivers/video/omap/ driver
|
|
|
|
* by Imre Deak.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define DSS_SUBSYS_NAME "CORE"
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
#include <linux/debugfs.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/device.h>
|
2010-02-04 15:03:41 +00:00
|
|
|
#include <linux/regulator/consumer.h>
|
OMAPDSS: Use PM notifiers for system suspend
The current way how omapdss handles system suspend and resume is that
omapdss device (a platform device, which is not part of the device
hierarchy of the DSS HW devices, like DISPC and DSI, or panels.) uses
the suspend and resume callbacks from platform_driver to handle system
suspend. It does this by disabling all enabled panels on suspend, and
resuming the previously disabled panels on resume.
This presents a few problems.
One is that as omapdss device is not related to the panel devices or the
DSS HW devices, there's no ordering in the suspend process. This means
that suspend could be first ran for DSS HW devices and panels, and only
then for omapdss device. Currently this is not a problem, as DSS HW
devices and panels do not handle suspend.
Another, more pressing problem, is that when suspending or resuming, the
runtime PM functions return -EACCES as runtime PM is disabled during
system suspend. This causes the driver to print warnings, and operations
to fail as they think that they failed to bring up the HW.
This patch changes the omapdss suspend handling to use PM notifiers,
which are called before suspend and after resume. This way we have a
normally functioning system when we are suspending and resuming the
panels.
This patch, I believe, creates a problem that somebody could enable or
disable a panel between PM_SUSPEND_PREPARE and the system suspend, and
similarly the other way around in resume. I choose to ignore the problem
for now, as it sounds rather unlikely, and if it happens, it's not
fatal.
In the long run the system suspend handling of omapdss and panels should
be thought out properly. The current approach feels rather hacky.
Perhaps the panel drivers should handle system suspend, or the users of
omapdss (omapfb, omapdrm) should handle system suspend.
Note that after this patch we could probably revert
0eaf9f52e94f756147dbfe1faf1f77a02378dbf9 (OMAPDSS: use sync versions of
pm_runtime_put). But as I said, this patch may be temporary, so let's
leave the sync version still in place.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Reported-by: Jassi Brar <jaswinder.singh@linaro.org>
Tested-by: Jassi Brar <jaswinder.singh@linaro.org>
Tested-by: Joe Woodward <jw@terrafix.co.uk>
Signed-off-by: Archit Taneja <archit@ti.com>
[fts: fixed 2 brace coding style issues]
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
2012-07-04 12:43:48 +00:00
|
|
|
#include <linux/suspend.h>
|
2012-09-10 10:58:29 +00:00
|
|
|
#include <linux/slab.h>
|
2009-11-03 09:23:50 +00:00
|
|
|
|
2011-05-11 11:05:07 +00:00
|
|
|
#include <video/omapdss.h>
|
2009-11-03 09:23:50 +00:00
|
|
|
|
|
|
|
#include "dss.h"
|
2010-09-15 13:50:00 +00:00
|
|
|
#include "dss_features.h"
|
2009-11-03 09:23:50 +00:00
|
|
|
|
|
|
|
static struct {
|
|
|
|
struct platform_device *pdev;
|
2010-02-04 15:03:41 +00:00
|
|
|
|
2012-02-23 11:00:51 +00:00
|
|
|
const char *default_display_name;
|
2009-11-03 09:23:50 +00:00
|
|
|
} core;
|
|
|
|
|
|
|
|
static char *def_disp_name;
|
|
|
|
module_param_named(def_disp, def_disp_name, charp, 0);
|
2011-02-16 10:53:44 +00:00
|
|
|
MODULE_PARM_DESC(def_disp, "default display name");
|
2009-11-03 09:23:50 +00:00
|
|
|
|
2012-10-29 10:40:46 +00:00
|
|
|
const char *omapdss_get_default_display_name(void)
|
2012-09-06 11:26:10 +00:00
|
|
|
{
|
|
|
|
return core.default_display_name;
|
|
|
|
}
|
2012-10-29 10:40:46 +00:00
|
|
|
EXPORT_SYMBOL(omapdss_get_default_display_name);
|
2012-09-06 11:26:10 +00:00
|
|
|
|
2012-10-18 10:46:29 +00:00
|
|
|
enum omapdss_version omapdss_get_version(void)
|
|
|
|
{
|
|
|
|
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
|
|
|
|
return pdata->version;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(omapdss_get_version);
|
|
|
|
|
2012-10-10 07:46:06 +00:00
|
|
|
struct platform_device *dss_get_core_pdev(void)
|
|
|
|
{
|
|
|
|
return core.pdev;
|
|
|
|
}
|
|
|
|
|
2012-02-20 09:50:06 +00:00
|
|
|
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
|
|
|
|
{
|
|
|
|
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
|
|
|
|
|
|
|
|
if (!board_data->dsi_enable_pads)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
return board_data->dsi_enable_pads(dsi_id, lane_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
|
|
|
|
{
|
|
|
|
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
|
|
|
|
|
2012-10-16 11:51:21 +00:00
|
|
|
if (!board_data->dsi_disable_pads)
|
2012-02-20 09:50:06 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
return board_data->dsi_disable_pads(dsi_id, lane_mask);
|
|
|
|
}
|
|
|
|
|
2012-03-08 10:52:38 +00:00
|
|
|
int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
|
|
|
|
{
|
|
|
|
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
|
|
|
|
|
|
|
|
if (pdata->set_min_bus_tput)
|
|
|
|
return pdata->set_min_bus_tput(dev, tput);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-29 05:55:42 +00:00
|
|
|
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
|
2009-11-03 09:23:50 +00:00
|
|
|
static int dss_debug_show(struct seq_file *s, void *unused)
|
|
|
|
{
|
|
|
|
void (*func)(struct seq_file *) = s->private;
|
|
|
|
func(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dss_debug_open(struct inode *inode, struct file *file)
|
|
|
|
{
|
|
|
|
return single_open(file, dss_debug_show, inode->i_private);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct file_operations dss_debug_fops = {
|
|
|
|
.open = dss_debug_open,
|
|
|
|
.read = seq_read,
|
|
|
|
.llseek = seq_lseek,
|
|
|
|
.release = single_release,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct dentry *dss_debugfs_dir;
|
|
|
|
|
|
|
|
static int dss_initialize_debugfs(void)
|
|
|
|
{
|
|
|
|
dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
|
|
|
|
if (IS_ERR(dss_debugfs_dir)) {
|
|
|
|
int err = PTR_ERR(dss_debugfs_dir);
|
|
|
|
dss_debugfs_dir = NULL;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
|
|
|
|
&dss_debug_dump_clocks, &dss_debug_fops);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dss_uninitialize_debugfs(void)
|
|
|
|
{
|
|
|
|
if (dss_debugfs_dir)
|
|
|
|
debugfs_remove_recursive(dss_debugfs_dir);
|
|
|
|
}
|
2012-03-02 16:01:07 +00:00
|
|
|
|
|
|
|
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
|
|
|
|
{
|
|
|
|
struct dentry *d;
|
|
|
|
|
|
|
|
d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
|
|
|
|
write, &dss_debug_fops);
|
|
|
|
|
2013-07-15 01:50:32 +00:00
|
|
|
return PTR_ERR_OR_ZERO(d);
|
2012-03-02 16:01:07 +00:00
|
|
|
}
|
2012-09-29 05:55:42 +00:00
|
|
|
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
|
2010-05-07 09:58:41 +00:00
|
|
|
static inline int dss_initialize_debugfs(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static inline void dss_uninitialize_debugfs(void)
|
|
|
|
{
|
|
|
|
}
|
2012-05-23 13:45:09 +00:00
|
|
|
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
|
2012-03-02 16:01:07 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-29 05:55:42 +00:00
|
|
|
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
|
2009-11-03 09:23:50 +00:00
|
|
|
|
|
|
|
/* PLATFORM DEVICE */
|
OMAPDSS: Use PM notifiers for system suspend
The current way how omapdss handles system suspend and resume is that
omapdss device (a platform device, which is not part of the device
hierarchy of the DSS HW devices, like DISPC and DSI, or panels.) uses
the suspend and resume callbacks from platform_driver to handle system
suspend. It does this by disabling all enabled panels on suspend, and
resuming the previously disabled panels on resume.
This presents a few problems.
One is that as omapdss device is not related to the panel devices or the
DSS HW devices, there's no ordering in the suspend process. This means
that suspend could be first ran for DSS HW devices and panels, and only
then for omapdss device. Currently this is not a problem, as DSS HW
devices and panels do not handle suspend.
Another, more pressing problem, is that when suspending or resuming, the
runtime PM functions return -EACCES as runtime PM is disabled during
system suspend. This causes the driver to print warnings, and operations
to fail as they think that they failed to bring up the HW.
This patch changes the omapdss suspend handling to use PM notifiers,
which are called before suspend and after resume. This way we have a
normally functioning system when we are suspending and resuming the
panels.
This patch, I believe, creates a problem that somebody could enable or
disable a panel between PM_SUSPEND_PREPARE and the system suspend, and
similarly the other way around in resume. I choose to ignore the problem
for now, as it sounds rather unlikely, and if it happens, it's not
fatal.
In the long run the system suspend handling of omapdss and panels should
be thought out properly. The current approach feels rather hacky.
Perhaps the panel drivers should handle system suspend, or the users of
omapdss (omapfb, omapdrm) should handle system suspend.
Note that after this patch we could probably revert
0eaf9f52e94f756147dbfe1faf1f77a02378dbf9 (OMAPDSS: use sync versions of
pm_runtime_put). But as I said, this patch may be temporary, so let's
leave the sync version still in place.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Reported-by: Jassi Brar <jaswinder.singh@linaro.org>
Tested-by: Jassi Brar <jaswinder.singh@linaro.org>
Tested-by: Joe Woodward <jw@terrafix.co.uk>
Signed-off-by: Archit Taneja <archit@ti.com>
[fts: fixed 2 brace coding style issues]
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
2012-07-04 12:43:48 +00:00
|
|
|
|
2016-02-19 16:05:14 +00:00
|
|
|
static void dss_disable_all_devices(void)
|
|
|
|
{
|
|
|
|
struct omap_dss_device *dssdev = NULL;
|
|
|
|
|
|
|
|
for_each_dss_dev(dssdev) {
|
|
|
|
if (!dssdev->driver)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
|
|
|
dssdev->driver->disable(dssdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 15:41:13 +00:00
|
|
|
static int __init omap_dss_probe(struct platform_device *pdev)
|
2009-11-03 09:23:50 +00:00
|
|
|
{
|
|
|
|
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
core.pdev = pdev;
|
|
|
|
|
2012-10-18 10:46:29 +00:00
|
|
|
dss_features_init(omapdss_get_version());
|
2010-09-15 13:50:00 +00:00
|
|
|
|
2009-11-03 09:23:50 +00:00
|
|
|
r = dss_initialize_debugfs();
|
|
|
|
if (r)
|
2010-05-07 09:58:42 +00:00
|
|
|
goto err_debugfs;
|
2009-11-03 09:23:50 +00:00
|
|
|
|
2012-02-23 11:00:51 +00:00
|
|
|
if (def_disp_name)
|
|
|
|
core.default_display_name = def_disp_name;
|
2012-11-16 12:59:56 +00:00
|
|
|
else if (pdata->default_display_name)
|
|
|
|
core.default_display_name = pdata->default_display_name;
|
2012-02-23 11:00:51 +00:00
|
|
|
else if (pdata->default_device)
|
|
|
|
core.default_display_name = pdata->default_device->name;
|
|
|
|
|
2009-11-03 09:23:50 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-05-07 09:58:42 +00:00
|
|
|
err_debugfs:
|
|
|
|
|
2009-11-03 09:23:50 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int omap_dss_remove(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
dss_uninitialize_debugfs();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void omap_dss_shutdown(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
DSSDBG("shutdown\n");
|
|
|
|
dss_disable_all_devices();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct platform_driver omap_dss_driver = {
|
|
|
|
.remove = omap_dss_remove,
|
|
|
|
.shutdown = omap_dss_shutdown,
|
|
|
|
.driver = {
|
|
|
|
.name = "omapdss",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
/* INIT */
|
2012-03-02 15:37:53 +00:00
|
|
|
static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
|
2015-06-04 11:44:49 +00:00
|
|
|
dss_init_platform_driver,
|
|
|
|
dispc_init_platform_driver,
|
2012-10-22 12:57:25 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_DSI
|
|
|
|
dsi_init_platform_driver,
|
|
|
|
#endif
|
2012-03-02 15:37:53 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_DPI
|
|
|
|
dpi_init_platform_driver,
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OMAP2_DSS_SDI
|
|
|
|
sdi_init_platform_driver,
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OMAP2_DSS_RFBI
|
|
|
|
rfbi_init_platform_driver,
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OMAP2_DSS_VENC
|
|
|
|
venc_init_platform_driver,
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OMAP4_DSS_HDMI
|
2013-09-12 12:15:57 +00:00
|
|
|
hdmi4_init_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
#endif
|
2014-03-13 10:44:14 +00:00
|
|
|
#ifdef CONFIG_OMAP5_DSS_HDMI
|
|
|
|
hdmi5_init_platform_driver,
|
|
|
|
#endif
|
2012-03-02 15:37:53 +00:00
|
|
|
};
|
|
|
|
|
2015-06-04 11:44:49 +00:00
|
|
|
static void (*dss_output_drv_unreg_funcs[])(void) = {
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP5_DSS_HDMI
|
|
|
|
hdmi5_uninit_platform_driver,
|
2012-10-22 12:57:25 +00:00
|
|
|
#endif
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP4_DSS_HDMI
|
|
|
|
hdmi4_uninit_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
#endif
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_VENC
|
|
|
|
venc_uninit_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OMAP2_DSS_RFBI
|
|
|
|
rfbi_uninit_platform_driver,
|
|
|
|
#endif
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_SDI
|
|
|
|
sdi_uninit_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
#endif
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_DPI
|
|
|
|
dpi_uninit_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
#endif
|
2015-06-04 11:31:36 +00:00
|
|
|
#ifdef CONFIG_OMAP2_DSS_DSI
|
|
|
|
dsi_uninit_platform_driver,
|
2014-03-13 10:44:14 +00:00
|
|
|
#endif
|
2015-06-04 11:44:49 +00:00
|
|
|
dispc_uninit_platform_driver,
|
|
|
|
dss_uninit_platform_driver,
|
2012-03-02 15:37:53 +00:00
|
|
|
};
|
|
|
|
|
2012-11-20 09:58:47 +00:00
|
|
|
static int __init omap_dss_init(void)
|
2012-03-19 13:05:02 +00:00
|
|
|
{
|
|
|
|
int r;
|
2012-03-02 15:37:53 +00:00
|
|
|
int i;
|
2012-03-19 13:05:02 +00:00
|
|
|
|
2012-03-07 10:53:18 +00:00
|
|
|
r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
|
2012-03-19 13:05:02 +00:00
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
|
2012-03-02 15:37:53 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
|
|
|
|
r = dss_output_drv_reg_funcs[i]();
|
2015-06-04 11:44:49 +00:00
|
|
|
if (r)
|
|
|
|
goto err_reg;
|
2012-03-19 13:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2015-06-04 11:44:49 +00:00
|
|
|
err_reg:
|
|
|
|
for (i = ARRAY_SIZE(dss_output_drv_reg_funcs) - i;
|
|
|
|
i < ARRAY_SIZE(dss_output_drv_reg_funcs);
|
|
|
|
++i)
|
|
|
|
dss_output_drv_unreg_funcs[i]();
|
|
|
|
|
2012-03-19 13:05:02 +00:00
|
|
|
platform_driver_unregister(&omap_dss_driver);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-11-20 09:58:47 +00:00
|
|
|
static void __exit omap_dss_exit(void)
|
2012-03-19 13:05:02 +00:00
|
|
|
{
|
2012-03-02 15:37:53 +00:00
|
|
|
int i;
|
|
|
|
|
2015-06-04 11:44:49 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i)
|
|
|
|
dss_output_drv_unreg_funcs[i]();
|
2012-03-19 13:05:02 +00:00
|
|
|
|
|
|
|
platform_driver_unregister(&omap_dss_driver);
|
|
|
|
}
|
|
|
|
|
2009-11-03 09:23:50 +00:00
|
|
|
module_init(omap_dss_init);
|
|
|
|
module_exit(omap_dss_exit);
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
|
|
|
|
MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
|