video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related files, directories for backlight, console, linux logo, lots of fbdev device drivers, fbdev framework files. Make some order into the chaos by creating drivers/video/fbdev directory, and move all fbdev related files there. No functionality is changed, although I guess it is possible that some subtle Makefile build order related issue could be created by this patch. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Jingoo Han <jg1.han@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
121
drivers/video/fbdev/omap2/dss/Kconfig
Normal file
121
drivers/video/fbdev/omap2/dss/Kconfig
Normal file
@@ -0,0 +1,121 @@
|
||||
menuconfig OMAP2_DSS
|
||||
tristate "OMAP2+ Display Subsystem support"
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
OMAP2+ Display Subsystem support.
|
||||
|
||||
if OMAP2_DSS
|
||||
|
||||
config OMAP2_DSS_DEBUG
|
||||
bool "Debug support"
|
||||
default n
|
||||
help
|
||||
This enables printing of debug messages. Alternatively, debug messages
|
||||
can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
|
||||
appropriate flags in <debugfs>/dynamic_debug/control.
|
||||
|
||||
config OMAP2_DSS_DEBUGFS
|
||||
bool "Debugfs filesystem support"
|
||||
depends on DEBUG_FS
|
||||
default n
|
||||
help
|
||||
This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
|
||||
querying about clock configuration and register configuration of dss,
|
||||
dispc, dsi, hdmi and rfbi.
|
||||
|
||||
config OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
bool "Collect DSS IRQ statistics"
|
||||
depends on OMAP2_DSS_DEBUGFS
|
||||
default n
|
||||
help
|
||||
Collect DSS IRQ statistics, printable via debugfs.
|
||||
|
||||
The statistics can be found from
|
||||
<debugfs>/omapdss/dispc_irq for DISPC interrupts, and
|
||||
<debugfs>/omapdss/dsi_irq for DSI interrupts.
|
||||
|
||||
config OMAP2_DSS_DPI
|
||||
bool "DPI support"
|
||||
default y
|
||||
help
|
||||
DPI Interface. This is the Parallel Display Interface.
|
||||
|
||||
config OMAP2_DSS_RFBI
|
||||
bool "RFBI support"
|
||||
depends on BROKEN
|
||||
default n
|
||||
help
|
||||
MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
|
||||
Instrument's terminology).
|
||||
|
||||
DBI is a bus between the host processor and a peripheral,
|
||||
such as a display or a framebuffer chip.
|
||||
|
||||
See http://www.mipi.org/ for DBI specifications.
|
||||
|
||||
config OMAP2_DSS_VENC
|
||||
bool "VENC support"
|
||||
default y
|
||||
help
|
||||
OMAP Video Encoder support for S-Video and composite TV-out.
|
||||
|
||||
config OMAP4_DSS_HDMI
|
||||
bool "HDMI support"
|
||||
default y
|
||||
help
|
||||
HDMI Interface. This adds the High Definition Multimedia Interface.
|
||||
See http://www.hdmi.org/ for HDMI specification.
|
||||
|
||||
config OMAP4_DSS_HDMI_AUDIO
|
||||
bool
|
||||
|
||||
config OMAP2_DSS_SDI
|
||||
bool "SDI support"
|
||||
default n
|
||||
help
|
||||
SDI (Serial Display Interface) support.
|
||||
|
||||
SDI is a high speed one-way display serial bus between the host
|
||||
processor and a display.
|
||||
|
||||
config OMAP2_DSS_DSI
|
||||
bool "DSI support"
|
||||
default n
|
||||
help
|
||||
MIPI DSI (Display Serial Interface) support.
|
||||
|
||||
DSI is a high speed half-duplex serial interface between the host
|
||||
processor and a peripheral, such as a display or a framebuffer chip.
|
||||
|
||||
See http://www.mipi.org/ for DSI specifications.
|
||||
|
||||
config OMAP2_DSS_MIN_FCK_PER_PCK
|
||||
int "Minimum FCK/PCK ratio (for scaling)"
|
||||
range 0 32
|
||||
default 0
|
||||
help
|
||||
This can be used to adjust the minimum FCK/PCK ratio.
|
||||
|
||||
With this you can make sure that DISPC FCK is at least
|
||||
n x PCK. Video plane scaling requires higher FCK than
|
||||
normally.
|
||||
|
||||
If this is set to 0, there's no extra constraint on the
|
||||
DISPC FCK. However, the FCK will at minimum be
|
||||
2xPCK (if active matrix) or 3xPCK (if passive matrix).
|
||||
|
||||
Max FCK is 173MHz, so this doesn't work if your PCK
|
||||
is very high.
|
||||
|
||||
config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
|
||||
bool "Sleep 20ms after VENC reset"
|
||||
default y
|
||||
help
|
||||
There is a 20ms sleep after VENC reset which seemed to fix the
|
||||
reset. The reason for the bug is unclear, and it's also unclear
|
||||
on what platforms this happens.
|
||||
|
||||
This option enables the sleep, and is enabled by default. You can
|
||||
disable the sleep if it doesn't cause problems on your platform.
|
||||
|
||||
endif
|
15
drivers/video/fbdev/omap2/dss/Makefile
Normal file
15
drivers/video/fbdev/omap2/dss/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
|
||||
# Core DSS files
|
||||
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
|
||||
output.o dss-of.o
|
||||
# DSS compat layer files
|
||||
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
|
||||
dispc-compat.o display-sysfs.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
|
||||
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi_common.o hdmi_wp.o hdmi_pll.o \
|
||||
hdmi_phy.o hdmi4_core.o
|
||||
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
|
1700
drivers/video/fbdev/omap2/dss/apply.c
Normal file
1700
drivers/video/fbdev/omap2/dss/apply.c
Normal file
File diff suppressed because it is too large
Load Diff
360
drivers/video/fbdev/omap2/dss/core.c
Normal file
360
drivers/video/fbdev/omap2/dss/core.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
|
||||
const char *default_display_name;
|
||||
} core;
|
||||
|
||||
static char *def_disp_name;
|
||||
module_param_named(def_disp, def_disp_name, charp, 0);
|
||||
MODULE_PARM_DESC(def_disp, "default display name");
|
||||
|
||||
static bool dss_initialized;
|
||||
|
||||
const char *omapdss_get_default_display_name(void)
|
||||
{
|
||||
return core.default_display_name;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_get_default_display_name);
|
||||
|
||||
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);
|
||||
|
||||
bool omapdss_is_initialized(void)
|
||||
{
|
||||
return dss_initialized;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_is_initialized);
|
||||
|
||||
struct platform_device *dss_get_core_pdev(void)
|
||||
{
|
||||
return core.pdev;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!board_data->dsi_disable_pads)
|
||||
return;
|
||||
|
||||
return board_data->dsi_disable_pads(dsi_id, lane_mask);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return PTR_ERR_OR_ZERO(d);
|
||||
}
|
||||
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
|
||||
static inline int dss_initialize_debugfs(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void dss_uninitialize_debugfs(void)
|
||||
{
|
||||
}
|
||||
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
|
||||
|
||||
/* PLATFORM DEVICE */
|
||||
static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
|
||||
{
|
||||
DSSDBG("pm notif %lu\n", v);
|
||||
|
||||
switch (v) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
DSSDBG("suspending displays\n");
|
||||
return dss_suspend_all_devices();
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
DSSDBG("resuming displays\n");
|
||||
return dss_resume_all_devices();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct notifier_block omap_dss_pm_notif_block = {
|
||||
.notifier_call = omap_dss_pm_notif,
|
||||
};
|
||||
|
||||
static int __init omap_dss_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
int r;
|
||||
|
||||
core.pdev = pdev;
|
||||
|
||||
dss_features_init(omapdss_get_version());
|
||||
|
||||
r = dss_initialize_debugfs();
|
||||
if (r)
|
||||
goto err_debugfs;
|
||||
|
||||
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;
|
||||
|
||||
register_pm_notifier(&omap_dss_pm_notif_block);
|
||||
|
||||
return 0;
|
||||
|
||||
err_debugfs:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_dss_remove(struct platform_device *pdev)
|
||||
{
|
||||
unregister_pm_notifier(&omap_dss_pm_notif_block);
|
||||
|
||||
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",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
/* INIT */
|
||||
static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_init_platform_driver,
|
||||
#endif
|
||||
#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
|
||||
hdmi4_init_platform_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_uninit_platform_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
dpi_uninit_platform_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
sdi_uninit_platform_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
rfbi_uninit_platform_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
venc_uninit_platform_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP4_DSS_HDMI
|
||||
hdmi4_uninit_platform_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)];
|
||||
|
||||
static int __init omap_dss_init(void)
|
||||
{
|
||||
int r;
|
||||
int i;
|
||||
|
||||
r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dss_init_platform_driver();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DSS platform driver\n");
|
||||
goto err_dss;
|
||||
}
|
||||
|
||||
r = dispc_init_platform_driver();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize dispc platform driver\n");
|
||||
goto err_dispc;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's ok if the output-driver register fails. It happens, for example,
|
||||
* when there is no output-device (e.g. SDI for OMAP4).
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
|
||||
r = dss_output_drv_reg_funcs[i]();
|
||||
if (r == 0)
|
||||
dss_output_drv_loaded[i] = true;
|
||||
}
|
||||
|
||||
dss_initialized = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_dispc:
|
||||
dss_uninit_platform_driver();
|
||||
err_dss:
|
||||
platform_driver_unregister(&omap_dss_driver);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit omap_dss_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) {
|
||||
if (dss_output_drv_loaded[i])
|
||||
dss_output_drv_unreg_funcs[i]();
|
||||
}
|
||||
|
||||
dispc_uninit_platform_driver();
|
||||
dss_uninit_platform_driver();
|
||||
|
||||
platform_driver_unregister(&omap_dss_driver);
|
||||
}
|
||||
|
||||
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");
|
||||
|
666
drivers/video/fbdev/omap2/dss/dispc-compat.c
Normal file
666
drivers/video/fbdev/omap2/dss/dispc-compat.c
Normal file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* 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 "APPLY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
#include "dispc-compat.h"
|
||||
|
||||
#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_OCP_ERR | \
|
||||
DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_SYNC_LOST | \
|
||||
DISPC_IRQ_SYNC_LOST_DIGIT)
|
||||
|
||||
#define DISPC_MAX_NR_ISRS 8
|
||||
|
||||
struct omap_dispc_isr_data {
|
||||
omap_dispc_isr_t isr;
|
||||
void *arg;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
struct dispc_irq_stats {
|
||||
unsigned long last_reset;
|
||||
unsigned irq_count;
|
||||
unsigned irqs[32];
|
||||
};
|
||||
|
||||
static struct {
|
||||
spinlock_t irq_lock;
|
||||
u32 irq_error_mask;
|
||||
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
||||
u32 error_irqs;
|
||||
struct work_struct error_work;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spinlock_t irq_stats_lock;
|
||||
struct dispc_irq_stats irq_stats;
|
||||
#endif
|
||||
} dispc_compat;
|
||||
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
static void dispc_dump_irqs(struct seq_file *s)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dispc_irq_stats stats;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
|
||||
|
||||
stats = dispc_compat.irq_stats;
|
||||
memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
|
||||
dispc_compat.irq_stats.last_reset = jiffies;
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
|
||||
|
||||
seq_printf(s, "period %u ms\n",
|
||||
jiffies_to_msecs(jiffies - stats.last_reset));
|
||||
|
||||
seq_printf(s, "irqs %d\n", stats.irq_count);
|
||||
#define PIS(x) \
|
||||
seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
|
||||
|
||||
PIS(FRAMEDONE);
|
||||
PIS(VSYNC);
|
||||
PIS(EVSYNC_EVEN);
|
||||
PIS(EVSYNC_ODD);
|
||||
PIS(ACBIAS_COUNT_STAT);
|
||||
PIS(PROG_LINE_NUM);
|
||||
PIS(GFX_FIFO_UNDERFLOW);
|
||||
PIS(GFX_END_WIN);
|
||||
PIS(PAL_GAMMA_MASK);
|
||||
PIS(OCP_ERR);
|
||||
PIS(VID1_FIFO_UNDERFLOW);
|
||||
PIS(VID1_END_WIN);
|
||||
PIS(VID2_FIFO_UNDERFLOW);
|
||||
PIS(VID2_END_WIN);
|
||||
if (dss_feat_get_num_ovls() > 3) {
|
||||
PIS(VID3_FIFO_UNDERFLOW);
|
||||
PIS(VID3_END_WIN);
|
||||
}
|
||||
PIS(SYNC_LOST);
|
||||
PIS(SYNC_LOST_DIGIT);
|
||||
PIS(WAKEUP);
|
||||
if (dss_has_feature(FEAT_MGR_LCD2)) {
|
||||
PIS(FRAMEDONE2);
|
||||
PIS(VSYNC2);
|
||||
PIS(ACBIAS_COUNT_STAT2);
|
||||
PIS(SYNC_LOST2);
|
||||
}
|
||||
if (dss_has_feature(FEAT_MGR_LCD3)) {
|
||||
PIS(FRAMEDONE3);
|
||||
PIS(VSYNC3);
|
||||
PIS(ACBIAS_COUNT_STAT3);
|
||||
PIS(SYNC_LOST3);
|
||||
}
|
||||
#undef PIS
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dispc.irq_lock has to be locked by the caller */
|
||||
static void _omap_dispc_set_irqs(void)
|
||||
{
|
||||
u32 mask;
|
||||
int i;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
mask = dispc_compat.irq_error_mask;
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
|
||||
if (isr_data->isr == NULL)
|
||||
continue;
|
||||
|
||||
mask |= isr_data->mask;
|
||||
}
|
||||
|
||||
dispc_write_irqenable(mask);
|
||||
}
|
||||
|
||||
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
if (isr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
|
||||
/* check for duplicate entry */
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
if (isr_data->isr == isr && isr_data->arg == arg &&
|
||||
isr_data->mask == mask) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
isr_data = NULL;
|
||||
ret = -EBUSY;
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
|
||||
if (isr_data->isr != NULL)
|
||||
continue;
|
||||
|
||||
isr_data->isr = isr;
|
||||
isr_data->arg = arg;
|
||||
isr_data->mask = mask;
|
||||
ret = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dispc_register_isr);
|
||||
|
||||
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
if (isr_data->isr != isr || isr_data->arg != arg ||
|
||||
isr_data->mask != mask)
|
||||
continue;
|
||||
|
||||
/* found the correct isr */
|
||||
|
||||
isr_data->isr = NULL;
|
||||
isr_data->arg = NULL;
|
||||
isr_data->mask = 0;
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dispc_unregister_isr);
|
||||
|
||||
static void print_irq_status(u32 status)
|
||||
{
|
||||
if ((status & dispc_compat.irq_error_mask) == 0)
|
||||
return;
|
||||
|
||||
#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
|
||||
|
||||
pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
|
||||
status,
|
||||
PIS(OCP_ERR),
|
||||
PIS(GFX_FIFO_UNDERFLOW),
|
||||
PIS(VID1_FIFO_UNDERFLOW),
|
||||
PIS(VID2_FIFO_UNDERFLOW),
|
||||
dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
|
||||
PIS(SYNC_LOST),
|
||||
PIS(SYNC_LOST_DIGIT),
|
||||
dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
|
||||
dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
|
||||
#undef PIS
|
||||
}
|
||||
|
||||
/* Called from dss.c. Note that we don't touch clocks here,
|
||||
* but we presume they are on because we got an IRQ. However,
|
||||
* an irq handler may turn the clocks off, so we may not have
|
||||
* clock later in the function. */
|
||||
static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
|
||||
{
|
||||
int i;
|
||||
u32 irqstatus, irqenable;
|
||||
u32 handledirqs = 0;
|
||||
u32 unhandled_errors;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
||||
|
||||
spin_lock(&dispc_compat.irq_lock);
|
||||
|
||||
irqstatus = dispc_read_irqstatus();
|
||||
irqenable = dispc_read_irqenable();
|
||||
|
||||
/* IRQ is not for us */
|
||||
if (!(irqstatus & irqenable)) {
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spin_lock(&dispc_compat.irq_stats_lock);
|
||||
dispc_compat.irq_stats.irq_count++;
|
||||
dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
|
||||
spin_unlock(&dispc_compat.irq_stats_lock);
|
||||
#endif
|
||||
|
||||
print_irq_status(irqstatus);
|
||||
|
||||
/* Ack the interrupt. Do it here before clocks are possibly turned
|
||||
* off */
|
||||
dispc_clear_irqstatus(irqstatus);
|
||||
/* flush posted write */
|
||||
dispc_read_irqstatus();
|
||||
|
||||
/* make a copy and unlock, so that isrs can unregister
|
||||
* themselves */
|
||||
memcpy(registered_isr, dispc_compat.registered_isr,
|
||||
sizeof(registered_isr));
|
||||
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = ®istered_isr[i];
|
||||
|
||||
if (!isr_data->isr)
|
||||
continue;
|
||||
|
||||
if (isr_data->mask & irqstatus) {
|
||||
isr_data->isr(isr_data->arg, irqstatus);
|
||||
handledirqs |= isr_data->mask;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&dispc_compat.irq_lock);
|
||||
|
||||
unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
|
||||
|
||||
if (unhandled_errors) {
|
||||
dispc_compat.error_irqs |= unhandled_errors;
|
||||
|
||||
dispc_compat.irq_error_mask &= ~unhandled_errors;
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
schedule_work(&dispc_compat.error_work);
|
||||
}
|
||||
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dispc_error_worker(struct work_struct *work)
|
||||
{
|
||||
int i;
|
||||
u32 errors;
|
||||
unsigned long flags;
|
||||
static const unsigned fifo_underflow_bits[] = {
|
||||
DISPC_IRQ_GFX_FIFO_UNDERFLOW,
|
||||
DISPC_IRQ_VID1_FIFO_UNDERFLOW,
|
||||
DISPC_IRQ_VID2_FIFO_UNDERFLOW,
|
||||
DISPC_IRQ_VID3_FIFO_UNDERFLOW,
|
||||
};
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
errors = dispc_compat.error_irqs;
|
||||
dispc_compat.error_irqs = 0;
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
dispc_runtime_get();
|
||||
|
||||
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
|
||||
struct omap_overlay *ovl;
|
||||
unsigned bit;
|
||||
|
||||
ovl = omap_dss_get_overlay(i);
|
||||
bit = fifo_underflow_bits[i];
|
||||
|
||||
if (bit & errors) {
|
||||
DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
|
||||
ovl->name);
|
||||
ovl->disable(ovl);
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
struct omap_overlay_manager *mgr;
|
||||
unsigned bit;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
bit = dispc_mgr_get_sync_lost_irq(i);
|
||||
|
||||
if (bit & errors) {
|
||||
int j;
|
||||
|
||||
DSSERR("SYNC_LOST on channel %s, restarting the output "
|
||||
"with video overlays disabled\n",
|
||||
mgr->name);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
|
||||
struct omap_overlay *ovl;
|
||||
ovl = omap_dss_get_overlay(j);
|
||||
|
||||
if (ovl->id != OMAP_DSS_GFX &&
|
||||
ovl->manager == mgr)
|
||||
ovl->disable(ovl);
|
||||
}
|
||||
|
||||
dss_mgr_enable(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors & DISPC_IRQ_OCP_ERR) {
|
||||
DSSERR("OCP_ERR\n");
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
dss_mgr_disable(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
dispc_compat.irq_error_mask |= errors;
|
||||
_omap_dispc_set_irqs();
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
dispc_runtime_put();
|
||||
}
|
||||
|
||||
int dss_dispc_initialize_irq(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spin_lock_init(&dispc_compat.irq_stats_lock);
|
||||
dispc_compat.irq_stats.last_reset = jiffies;
|
||||
dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
|
||||
#endif
|
||||
|
||||
spin_lock_init(&dispc_compat.irq_lock);
|
||||
|
||||
memset(dispc_compat.registered_isr, 0,
|
||||
sizeof(dispc_compat.registered_isr));
|
||||
|
||||
dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
|
||||
if (dss_has_feature(FEAT_MGR_LCD2))
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
|
||||
if (dss_has_feature(FEAT_MGR_LCD3))
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
|
||||
if (dss_feat_get_num_ovls() > 3)
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
|
||||
|
||||
/*
|
||||
* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
|
||||
* so clear it
|
||||
*/
|
||||
dispc_clear_irqstatus(dispc_read_irqstatus());
|
||||
|
||||
INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
|
||||
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
|
||||
if (r) {
|
||||
DSSERR("dispc_request_irq failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_dispc_uninitialize_irq(void)
|
||||
{
|
||||
dispc_free_irq(&dispc_compat);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_isr(void *data, u32 mask)
|
||||
{
|
||||
struct completion *compl = data;
|
||||
complete(compl);
|
||||
}
|
||||
|
||||
static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
|
||||
{
|
||||
dispc_mgr_enable(channel, true);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
||||
int r;
|
||||
u32 irq;
|
||||
|
||||
if (dispc_mgr_is_enabled(channel) == false)
|
||||
return;
|
||||
|
||||
/*
|
||||
* When we disable LCD output, we need to wait for FRAMEDONE to know
|
||||
* that DISPC has finished with the LCD output.
|
||||
*/
|
||||
|
||||
irq = dispc_mgr_get_framedone_irq(channel);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq);
|
||||
if (r)
|
||||
DSSERR("failed to register FRAMEDONE isr\n");
|
||||
|
||||
dispc_mgr_enable(channel, false);
|
||||
|
||||
/* if we couldn't register for framedone, just sleep and exit */
|
||||
if (r) {
|
||||
msleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&framedone_compl,
|
||||
msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for FRAME DONE\n");
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq);
|
||||
if (r)
|
||||
DSSERR("failed to unregister FRAMEDONE isr\n");
|
||||
}
|
||||
|
||||
static void dispc_digit_out_enable_isr(void *data, u32 mask)
|
||||
{
|
||||
struct completion *compl = data;
|
||||
|
||||
/* ignore any sync lost interrupts */
|
||||
if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
|
||||
complete(compl);
|
||||
}
|
||||
|
||||
static void dispc_mgr_enable_digit_out(void)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(vsync_compl);
|
||||
int r;
|
||||
u32 irq_mask;
|
||||
|
||||
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Digit output produces some sync lost interrupts during the first
|
||||
* frame when enabling. Those need to be ignored, so we register for the
|
||||
* sync lost irq to prevent the error handler from triggering.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
|
||||
dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
||||
irq_mask);
|
||||
if (r) {
|
||||
DSSERR("failed to register %x isr\n", irq_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
|
||||
|
||||
/* wait for the first evsync */
|
||||
if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for digit out to start\n");
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to unregister %x isr\n", irq_mask);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_digit_out(void)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
||||
int r, i;
|
||||
u32 irq_mask;
|
||||
int num_irqs;
|
||||
|
||||
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
|
||||
return;
|
||||
|
||||
/*
|
||||
* When we disable the digit output, we need to wait for FRAMEDONE to
|
||||
* know that DISPC has finished with the output.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
num_irqs = 1;
|
||||
|
||||
if (!irq_mask) {
|
||||
/*
|
||||
* omap 2/3 don't have framedone irq for TV, so we need to use
|
||||
* vsyncs for this.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
/*
|
||||
* We need to wait for both even and odd vsyncs. Note that this
|
||||
* is not totally reliable, as we could get a vsync interrupt
|
||||
* before we disable the output, which leads to timeout in the
|
||||
* wait_for_completion.
|
||||
*/
|
||||
num_irqs = 2;
|
||||
}
|
||||
|
||||
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to register %x isr\n", irq_mask);
|
||||
|
||||
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
|
||||
|
||||
/* if we couldn't register the irq, just sleep and exit */
|
||||
if (r) {
|
||||
msleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_irqs; ++i) {
|
||||
if (!wait_for_completion_timeout(&framedone_compl,
|
||||
msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for digit out to stop\n");
|
||||
}
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to unregister %x isr\n", irq_mask);
|
||||
}
|
||||
|
||||
void dispc_mgr_enable_sync(enum omap_channel channel)
|
||||
{
|
||||
if (dss_mgr_is_lcd(channel))
|
||||
dispc_mgr_enable_lcd_out(channel);
|
||||
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
||||
dispc_mgr_enable_digit_out();
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
void dispc_mgr_disable_sync(enum omap_channel channel)
|
||||
{
|
||||
if (dss_mgr_is_lcd(channel))
|
||||
dispc_mgr_disable_lcd_out(channel);
|
||||
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
||||
dispc_mgr_disable_digit_out();
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
||||
unsigned long timeout)
|
||||
{
|
||||
void dispc_irq_wait_handler(void *data, u32 mask)
|
||||
{
|
||||
complete((struct completion *)data);
|
||||
}
|
||||
|
||||
int r;
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
|
||||
irqmask);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&completion,
|
||||
timeout);
|
||||
|
||||
omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
|
||||
|
||||
if (timeout == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (timeout == -ERESTARTSYS)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
return 0;
|
||||
}
|
30
drivers/video/fbdev/omap2/dss/dispc-compat.h
Normal file
30
drivers/video/fbdev/omap2/dss/dispc-compat.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DSS_DISPC_COMPAT_H
|
||||
#define __OMAP2_DSS_DISPC_COMPAT_H
|
||||
|
||||
void dispc_mgr_enable_sync(enum omap_channel channel);
|
||||
void dispc_mgr_disable_sync(enum omap_channel channel);
|
||||
|
||||
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
||||
unsigned long timeout);
|
||||
|
||||
int dss_dispc_initialize_irq(void);
|
||||
void dss_dispc_uninitialize_irq(void);
|
||||
|
||||
#endif
|
3853
drivers/video/fbdev/omap2/dss/dispc.c
Normal file
3853
drivers/video/fbdev/omap2/dss/dispc.c
Normal file
File diff suppressed because it is too large
Load Diff
917
drivers/video/fbdev/omap2/dss/dispc.h
Normal file
917
drivers/video/fbdev/omap2/dss/dispc.h
Normal file
@@ -0,0 +1,917 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dispc.h
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
* Author: Archit Taneja <archit@ti.com>
|
||||
*
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DISPC_REG_H
|
||||
#define __OMAP2_DISPC_REG_H
|
||||
|
||||
/* DISPC common registers */
|
||||
#define DISPC_REVISION 0x0000
|
||||
#define DISPC_SYSCONFIG 0x0010
|
||||
#define DISPC_SYSSTATUS 0x0014
|
||||
#define DISPC_IRQSTATUS 0x0018
|
||||
#define DISPC_IRQENABLE 0x001C
|
||||
#define DISPC_CONTROL 0x0040
|
||||
#define DISPC_CONFIG 0x0044
|
||||
#define DISPC_CAPABLE 0x0048
|
||||
#define DISPC_LINE_STATUS 0x005C
|
||||
#define DISPC_LINE_NUMBER 0x0060
|
||||
#define DISPC_GLOBAL_ALPHA 0x0074
|
||||
#define DISPC_CONTROL2 0x0238
|
||||
#define DISPC_CONFIG2 0x0620
|
||||
#define DISPC_DIVISOR 0x0804
|
||||
#define DISPC_GLOBAL_BUFFER 0x0800
|
||||
#define DISPC_CONTROL3 0x0848
|
||||
#define DISPC_CONFIG3 0x084C
|
||||
#define DISPC_MSTANDBY_CTRL 0x0858
|
||||
#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C
|
||||
|
||||
/* DISPC overlay registers */
|
||||
#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_BA0_OFFSET(n))
|
||||
#define DISPC_OVL_BA1(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_BA1_OFFSET(n))
|
||||
#define DISPC_OVL_BA0_UV(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_BA0_UV_OFFSET(n))
|
||||
#define DISPC_OVL_BA1_UV(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_BA1_UV_OFFSET(n))
|
||||
#define DISPC_OVL_POSITION(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_POS_OFFSET(n))
|
||||
#define DISPC_OVL_SIZE(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_SIZE_OFFSET(n))
|
||||
#define DISPC_OVL_ATTRIBUTES(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ATTR_OFFSET(n))
|
||||
#define DISPC_OVL_ATTRIBUTES2(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ATTR2_OFFSET(n))
|
||||
#define DISPC_OVL_FIFO_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIFO_THRESH_OFFSET(n))
|
||||
#define DISPC_OVL_FIFO_SIZE_STATUS(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIFO_SIZE_STATUS_OFFSET(n))
|
||||
#define DISPC_OVL_ROW_INC(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ROW_INC_OFFSET(n))
|
||||
#define DISPC_OVL_PIXEL_INC(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_PIX_INC_OFFSET(n))
|
||||
#define DISPC_OVL_WINDOW_SKIP(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_WINDOW_SKIP_OFFSET(n))
|
||||
#define DISPC_OVL_TABLE_BA(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_TABLE_BA_OFFSET(n))
|
||||
#define DISPC_OVL_FIR(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_OFFSET(n))
|
||||
#define DISPC_OVL_FIR2(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR2_OFFSET(n))
|
||||
#define DISPC_OVL_PICTURE_SIZE(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_PIC_SIZE_OFFSET(n))
|
||||
#define DISPC_OVL_ACCU0(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ACCU0_OFFSET(n))
|
||||
#define DISPC_OVL_ACCU1(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ACCU1_OFFSET(n))
|
||||
#define DISPC_OVL_ACCU2_0(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ACCU2_0_OFFSET(n))
|
||||
#define DISPC_OVL_ACCU2_1(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_ACCU2_1_OFFSET(n))
|
||||
#define DISPC_OVL_FIR_COEF_H(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_H_OFFSET(n, i))
|
||||
#define DISPC_OVL_FIR_COEF_HV(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_HV_OFFSET(n, i))
|
||||
#define DISPC_OVL_FIR_COEF_H2(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_H2_OFFSET(n, i))
|
||||
#define DISPC_OVL_FIR_COEF_HV2(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_HV2_OFFSET(n, i))
|
||||
#define DISPC_OVL_CONV_COEF(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_CONV_COEF_OFFSET(n, i))
|
||||
#define DISPC_OVL_FIR_COEF_V(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_V_OFFSET(n, i))
|
||||
#define DISPC_OVL_FIR_COEF_V2(n, i) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_FIR_COEF_V2_OFFSET(n, i))
|
||||
#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_PRELOAD_OFFSET(n))
|
||||
#define DISPC_OVL_MFLAG_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
|
||||
DISPC_MFLAG_THRESHOLD_OFFSET(n))
|
||||
|
||||
/* DISPC up/downsampling FIR filter coefficient structure */
|
||||
struct dispc_coef {
|
||||
s8 hc4_vc22;
|
||||
s8 hc3_vc2;
|
||||
u8 hc2_vc1;
|
||||
s8 hc1_vc0;
|
||||
s8 hc0_vc00;
|
||||
};
|
||||
|
||||
const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
|
||||
|
||||
/* DISPC manager/channel specific registers */
|
||||
static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x004C;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
return 0x0050;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03AC;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0814;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0054;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
return 0x0058;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03B0;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0818;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_TIMING_H(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0064;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x0400;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0840;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_TIMING_V(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0068;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x0404;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0844;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x006C;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x0408;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x083C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_DIVISORo(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0070;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x040C;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0838;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
|
||||
static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x007C;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
return 0x0078;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03CC;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0834;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x01D4;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03C0;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0828;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x01D8;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03C4;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x082C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x01DC;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03C8;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0830;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0220;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03BC;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0824;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0224;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03B8;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x0820;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return 0x0228;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return 0x03B4;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return 0x081C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* DISPC overlay register base addresses */
|
||||
static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0080;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x00BC;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x014C;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0300;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0500;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* DISPC overlay register offsets */
|
||||
static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0000;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0008;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0004;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x000C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0544;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x04BC;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0310;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0118;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0548;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x04C0;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0314;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x011C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0008;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x009C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x000C;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x00A8;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0020;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0010;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0070;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0568;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x04DC;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x032C;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0310;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0024;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0014;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x008C;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0028;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0018;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0088;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x002C;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x001C;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x00A4;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0030;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0020;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0098;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0034;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
case OMAP_DSS_VIDEO3:
|
||||
BUG();
|
||||
return 0;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0038;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
case OMAP_DSS_VIDEO3:
|
||||
BUG();
|
||||
return 0;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0024;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0090;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0580;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x055C;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0424;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x290;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0028;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0094;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x002C;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0000;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0584;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0560;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0428;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0294;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0030;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0004;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0588;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0564;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x042C;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0298;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0034 + i * 0x8;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0010 + i * 0x8;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x058C + i * 0x8;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0568 + i * 0x8;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0430 + i * 0x8;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x02A0 + i * 0x8;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0038 + i * 0x8;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0014 + i * 0x8;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0590 + i * 8;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x056C + i * 0x8;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0434 + i * 0x8;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x02A4 + i * 0x8;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4,} */
|
||||
static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
case OMAP_DSS_VIDEO2:
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0074 + i * 0x4;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0124 + i * 0x4;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x00B4 + i * 0x4;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
case OMAP_DSS_WB:
|
||||
return 0x0050 + i * 0x4;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
|
||||
static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
BUG();
|
||||
return 0;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x05CC + i * 0x4;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x05A8 + i * 0x4;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x0470 + i * 0x4;
|
||||
case OMAP_DSS_WB:
|
||||
return 0x02E0 + i * 0x4;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x01AC;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0174;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x00E8;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x00A0;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
|
||||
{
|
||||
switch (plane) {
|
||||
case OMAP_DSS_GFX:
|
||||
return 0x0860;
|
||||
case OMAP_DSS_VIDEO1:
|
||||
return 0x0864;
|
||||
case OMAP_DSS_VIDEO2:
|
||||
return 0x0868;
|
||||
case OMAP_DSS_VIDEO3:
|
||||
return 0x086c;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
325
drivers/video/fbdev/omap2/dss/dispc_coefs.c
Normal file
325
drivers/video/fbdev/omap2/dss/dispc_coefs.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dispc_coefs.c
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
* Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dispc.h"
|
||||
|
||||
static const struct dispc_coef coef3_M8[8] = {
|
||||
{ 0, 0, 128, 0, 0 },
|
||||
{ 0, -4, 123, 9, 0 },
|
||||
{ 0, -4, 108, 24, 0 },
|
||||
{ 0, -2, 87, 43, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 43, 87, -2, 0 },
|
||||
{ 0, 24, 108, -4, 0 },
|
||||
{ 0, 9, 123, -4, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M9[8] = {
|
||||
{ 0, 6, 116, 6, 0 },
|
||||
{ 0, 0, 112, 16, 0 },
|
||||
{ 0, -2, 100, 30, 0 },
|
||||
{ 0, -2, 83, 47, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 47, 83, -2, 0 },
|
||||
{ 0, 30, 100, -2, 0 },
|
||||
{ 0, 16, 112, 0, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M10[8] = {
|
||||
{ 0, 10, 108, 10, 0 },
|
||||
{ 0, 3, 104, 21, 0 },
|
||||
{ 0, 0, 94, 34, 0 },
|
||||
{ 0, -1, 80, 49, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 49, 80, -1, 0 },
|
||||
{ 0, 34, 94, 0, 0 },
|
||||
{ 0, 21, 104, 3, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M11[8] = {
|
||||
{ 0, 14, 100, 14, 0 },
|
||||
{ 0, 6, 98, 24, 0 },
|
||||
{ 0, 2, 90, 36, 0 },
|
||||
{ 0, 0, 78, 50, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 50, 78, 0, 0 },
|
||||
{ 0, 36, 90, 2, 0 },
|
||||
{ 0, 24, 98, 6, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M12[8] = {
|
||||
{ 0, 16, 96, 16, 0 },
|
||||
{ 0, 9, 93, 26, 0 },
|
||||
{ 0, 4, 86, 38, 0 },
|
||||
{ 0, 1, 76, 51, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 51, 76, 1, 0 },
|
||||
{ 0, 38, 86, 4, 0 },
|
||||
{ 0, 26, 93, 9, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M13[8] = {
|
||||
{ 0, 18, 92, 18, 0 },
|
||||
{ 0, 10, 90, 28, 0 },
|
||||
{ 0, 5, 83, 40, 0 },
|
||||
{ 0, 1, 75, 52, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 52, 75, 1, 0 },
|
||||
{ 0, 40, 83, 5, 0 },
|
||||
{ 0, 28, 90, 10, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M14[8] = {
|
||||
{ 0, 20, 88, 20, 0 },
|
||||
{ 0, 12, 86, 30, 0 },
|
||||
{ 0, 6, 81, 41, 0 },
|
||||
{ 0, 2, 74, 52, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 52, 74, 2, 0 },
|
||||
{ 0, 41, 81, 6, 0 },
|
||||
{ 0, 30, 86, 12, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M16[8] = {
|
||||
{ 0, 22, 84, 22, 0 },
|
||||
{ 0, 14, 82, 32, 0 },
|
||||
{ 0, 8, 78, 42, 0 },
|
||||
{ 0, 3, 72, 53, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 53, 72, 3, 0 },
|
||||
{ 0, 42, 78, 8, 0 },
|
||||
{ 0, 32, 82, 14, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M19[8] = {
|
||||
{ 0, 24, 80, 24, 0 },
|
||||
{ 0, 16, 79, 33, 0 },
|
||||
{ 0, 9, 76, 43, 0 },
|
||||
{ 0, 4, 70, 54, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 54, 70, 4, 0 },
|
||||
{ 0, 43, 76, 9, 0 },
|
||||
{ 0, 33, 79, 16, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M22[8] = {
|
||||
{ 0, 25, 78, 25, 0 },
|
||||
{ 0, 17, 77, 34, 0 },
|
||||
{ 0, 10, 74, 44, 0 },
|
||||
{ 0, 5, 69, 54, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 54, 69, 5, 0 },
|
||||
{ 0, 44, 74, 10, 0 },
|
||||
{ 0, 34, 77, 17, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M26[8] = {
|
||||
{ 0, 26, 76, 26, 0 },
|
||||
{ 0, 19, 74, 35, 0 },
|
||||
{ 0, 11, 72, 45, 0 },
|
||||
{ 0, 5, 69, 54, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 54, 69, 5, 0 },
|
||||
{ 0, 45, 72, 11, 0 },
|
||||
{ 0, 35, 74, 19, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef3_M32[8] = {
|
||||
{ 0, 27, 74, 27, 0 },
|
||||
{ 0, 19, 73, 36, 0 },
|
||||
{ 0, 12, 71, 45, 0 },
|
||||
{ 0, 6, 68, 54, 0 },
|
||||
{ 0, 64, 64, 0, 0 },
|
||||
{ 0, 54, 68, 6, 0 },
|
||||
{ 0, 45, 71, 12, 0 },
|
||||
{ 0, 36, 73, 19, 0 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M8[8] = {
|
||||
{ 0, 0, 128, 0, 0 },
|
||||
{ -2, 14, 125, -10, 1 },
|
||||
{ -6, 33, 114, -15, 2 },
|
||||
{ -10, 55, 98, -16, 1 },
|
||||
{ 0, -14, 78, 78, -14 },
|
||||
{ 1, -16, 98, 55, -10 },
|
||||
{ 2, -15, 114, 33, -6 },
|
||||
{ 1, -10, 125, 14, -2 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M9[8] = {
|
||||
{ -3, 10, 114, 10, -3 },
|
||||
{ -6, 24, 111, 0, -1 },
|
||||
{ -8, 40, 103, -7, 0 },
|
||||
{ -11, 58, 91, -11, 1 },
|
||||
{ 0, -12, 76, 76, -12 },
|
||||
{ 1, -11, 91, 58, -11 },
|
||||
{ 0, -7, 103, 40, -8 },
|
||||
{ -1, 0, 111, 24, -6 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M10[8] = {
|
||||
{ -4, 18, 100, 18, -4 },
|
||||
{ -6, 30, 99, 8, -3 },
|
||||
{ -8, 44, 93, 0, -1 },
|
||||
{ -9, 58, 84, -5, 0 },
|
||||
{ 0, -8, 72, 72, -8 },
|
||||
{ 0, -5, 84, 58, -9 },
|
||||
{ -1, 0, 93, 44, -8 },
|
||||
{ -3, 8, 99, 30, -6 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M11[8] = {
|
||||
{ -5, 23, 92, 23, -5 },
|
||||
{ -6, 34, 90, 13, -3 },
|
||||
{ -6, 45, 85, 6, -2 },
|
||||
{ -6, 57, 78, 0, -1 },
|
||||
{ 0, -4, 68, 68, -4 },
|
||||
{ -1, 0, 78, 57, -6 },
|
||||
{ -2, 6, 85, 45, -6 },
|
||||
{ -3, 13, 90, 34, -6 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M12[8] = {
|
||||
{ -4, 26, 84, 26, -4 },
|
||||
{ -5, 36, 82, 18, -3 },
|
||||
{ -4, 46, 78, 10, -2 },
|
||||
{ -3, 55, 72, 5, -1 },
|
||||
{ 0, 0, 64, 64, 0 },
|
||||
{ -1, 5, 72, 55, -3 },
|
||||
{ -2, 10, 78, 46, -4 },
|
||||
{ -3, 18, 82, 36, -5 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M13[8] = {
|
||||
{ -3, 28, 78, 28, -3 },
|
||||
{ -3, 37, 76, 21, -3 },
|
||||
{ -2, 45, 73, 14, -2 },
|
||||
{ 0, 53, 68, 8, -1 },
|
||||
{ 0, 3, 61, 61, 3 },
|
||||
{ -1, 8, 68, 53, 0 },
|
||||
{ -2, 14, 73, 45, -2 },
|
||||
{ -3, 21, 76, 37, -3 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M14[8] = {
|
||||
{ -2, 30, 72, 30, -2 },
|
||||
{ -1, 37, 71, 23, -2 },
|
||||
{ 0, 45, 69, 16, -2 },
|
||||
{ 3, 52, 64, 10, -1 },
|
||||
{ 0, 6, 58, 58, 6 },
|
||||
{ -1, 10, 64, 52, 3 },
|
||||
{ -2, 16, 69, 45, 0 },
|
||||
{ -2, 23, 71, 37, -1 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M16[8] = {
|
||||
{ 0, 31, 66, 31, 0 },
|
||||
{ 1, 38, 65, 25, -1 },
|
||||
{ 3, 44, 62, 20, -1 },
|
||||
{ 6, 49, 59, 14, 0 },
|
||||
{ 0, 10, 54, 54, 10 },
|
||||
{ 0, 14, 59, 49, 6 },
|
||||
{ -1, 20, 62, 44, 3 },
|
||||
{ -1, 25, 65, 38, 1 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M19[8] = {
|
||||
{ 3, 32, 58, 32, 3 },
|
||||
{ 4, 38, 58, 27, 1 },
|
||||
{ 7, 42, 55, 23, 1 },
|
||||
{ 10, 46, 54, 18, 0 },
|
||||
{ 0, 14, 50, 50, 14 },
|
||||
{ 0, 18, 54, 46, 10 },
|
||||
{ 1, 23, 55, 42, 7 },
|
||||
{ 1, 27, 58, 38, 4 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M22[8] = {
|
||||
{ 4, 33, 54, 33, 4 },
|
||||
{ 6, 37, 54, 28, 3 },
|
||||
{ 9, 41, 53, 24, 1 },
|
||||
{ 12, 45, 51, 20, 0 },
|
||||
{ 0, 16, 48, 48, 16 },
|
||||
{ 0, 20, 51, 45, 12 },
|
||||
{ 1, 24, 53, 41, 9 },
|
||||
{ 3, 28, 54, 37, 6 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M26[8] = {
|
||||
{ 6, 33, 50, 33, 6 },
|
||||
{ 8, 36, 51, 29, 4 },
|
||||
{ 11, 40, 50, 25, 2 },
|
||||
{ 14, 43, 48, 22, 1 },
|
||||
{ 0, 18, 46, 46, 18 },
|
||||
{ 1, 22, 48, 43, 14 },
|
||||
{ 2, 25, 50, 40, 11 },
|
||||
{ 4, 29, 51, 36, 8 },
|
||||
};
|
||||
|
||||
static const struct dispc_coef coef5_M32[8] = {
|
||||
{ 7, 33, 48, 33, 7 },
|
||||
{ 10, 36, 48, 29, 5 },
|
||||
{ 13, 39, 47, 26, 3 },
|
||||
{ 16, 42, 46, 23, 1 },
|
||||
{ 0, 19, 45, 45, 19 },
|
||||
{ 1, 23, 46, 42, 16 },
|
||||
{ 3, 26, 47, 39, 13 },
|
||||
{ 5, 29, 48, 36, 10 },
|
||||
};
|
||||
|
||||
const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
|
||||
{
|
||||
int i;
|
||||
static const struct {
|
||||
int Mmin;
|
||||
int Mmax;
|
||||
const struct dispc_coef *coef_3;
|
||||
const struct dispc_coef *coef_5;
|
||||
} coefs[] = {
|
||||
{ 27, 32, coef3_M32, coef5_M32 },
|
||||
{ 23, 26, coef3_M26, coef5_M26 },
|
||||
{ 20, 22, coef3_M22, coef5_M22 },
|
||||
{ 17, 19, coef3_M19, coef5_M19 },
|
||||
{ 15, 16, coef3_M16, coef5_M16 },
|
||||
{ 14, 14, coef3_M14, coef5_M14 },
|
||||
{ 13, 13, coef3_M13, coef5_M13 },
|
||||
{ 12, 12, coef3_M12, coef5_M12 },
|
||||
{ 11, 11, coef3_M11, coef5_M11 },
|
||||
{ 10, 10, coef3_M10, coef5_M10 },
|
||||
{ 9, 9, coef3_M9, coef5_M9 },
|
||||
{ 4, 8, coef3_M8, coef5_M8 },
|
||||
/*
|
||||
* When upscaling more than two times, blockiness and outlines
|
||||
* around the image are observed when M8 tables are used. M11,
|
||||
* M16 and M19 tables are used to prevent this.
|
||||
*/
|
||||
{ 3, 3, coef3_M11, coef5_M11 },
|
||||
{ 2, 2, coef3_M16, coef5_M16 },
|
||||
{ 0, 1, coef3_M19, coef5_M19 },
|
||||
};
|
||||
|
||||
inc /= 128;
|
||||
for (i = 0; i < ARRAY_SIZE(coefs); ++i)
|
||||
if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
|
||||
return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
|
||||
return NULL;
|
||||
}
|
345
drivers/video/fbdev/omap2/dss/display-sysfs.c
Normal file
345
drivers/video/fbdev/omap2/dss/display-sysfs.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* 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 "DISPLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.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_sysfs(dev);
|
||||
|
||||
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_sysfs(dev);
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static ssize_t display_tear_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, "%d\n",
|
||||
dssdev->driver->get_te ?
|
||||
dssdev->driver->get_te(dssdev) : 0);
|
||||
}
|
||||
|
||||
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_sysfs(dev);
|
||||
int r;
|
||||
bool te;
|
||||
|
||||
if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
|
||||
return -ENOENT;
|
||||
|
||||
r = strtobool(buf, &te);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->enable_te(dssdev, te);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_timings_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
struct omap_video_timings t;
|
||||
|
||||
if (!dssdev->driver->get_timings)
|
||||
return -ENOENT;
|
||||
|
||||
dssdev->driver->get_timings(dssdev, &t);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
|
||||
t.pixelclock,
|
||||
t.x_res, t.hfp, t.hbp, t.hsw,
|
||||
t.y_res, t.vfp, t.vbp, t.vsw);
|
||||
}
|
||||
|
||||
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_sysfs(dev);
|
||||
struct omap_video_timings t = dssdev->panel.timings;
|
||||
int r, found;
|
||||
|
||||
if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
|
||||
return -ENOENT;
|
||||
|
||||
found = 0;
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
if (strncmp("pal", buf, 3) == 0) {
|
||||
t = omap_dss_pal_timings;
|
||||
found = 1;
|
||||
} else if (strncmp("ntsc", buf, 4) == 0) {
|
||||
t = omap_dss_ntsc_timings;
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
|
||||
&t.pixelclock,
|
||||
&t.x_res, &t.hfp, &t.hbp, &t.hsw,
|
||||
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->driver->check_timings(dssdev, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->driver->disable(dssdev);
|
||||
dssdev->driver->set_timings(dssdev, &t);
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_rotate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int rotate;
|
||||
if (!dssdev->driver->get_rotate)
|
||||
return -ENOENT;
|
||||
rotate = dssdev->driver->get_rotate(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
|
||||
}
|
||||
|
||||
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_sysfs(dev);
|
||||
int rot, r;
|
||||
|
||||
if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
|
||||
return -ENOENT;
|
||||
|
||||
r = kstrtoint(buf, 0, &rot);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->set_rotate(dssdev, rot);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_mirror_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int mirror;
|
||||
if (!dssdev->driver->get_mirror)
|
||||
return -ENOENT;
|
||||
mirror = dssdev->driver->get_mirror(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
|
||||
}
|
||||
|
||||
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_sysfs(dev);
|
||||
int r;
|
||||
bool mirror;
|
||||
|
||||
if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
|
||||
return -ENOENT;
|
||||
|
||||
r = strtobool(buf, &mirror);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->set_mirror(dssdev, mirror);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_wss_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
unsigned int wss;
|
||||
|
||||
if (!dssdev->driver->get_wss)
|
||||
return -ENOENT;
|
||||
|
||||
wss = dssdev->driver->get_wss(dssdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
|
||||
}
|
||||
|
||||
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_sysfs(dev);
|
||||
u32 wss;
|
||||
int r;
|
||||
|
||||
if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
|
||||
return -ENOENT;
|
||||
|
||||
r = kstrtou32(buf, 0, &wss);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (wss > 0xfffff)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->driver->set_wss(dssdev, wss);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(display_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,
|
||||
display_tear_show, display_tear_store);
|
||||
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
|
||||
display_timings_show, display_timings_store);
|
||||
static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
|
||||
display_rotate_show, display_rotate_store);
|
||||
static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
|
||||
display_mirror_show, display_mirror_store);
|
||||
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
|
||||
display_wss_show, display_wss_store);
|
||||
|
||||
static const struct attribute *display_sysfs_attrs[] = {
|
||||
&dev_attr_display_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 = NULL;
|
||||
int r;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
struct kobject *kobj = &dssdev->dev->kobj;
|
||||
|
||||
r = sysfs_create_files(kobj, display_sysfs_attrs);
|
||||
if (r) {
|
||||
DSSERR("failed to create sysfs files\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
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");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
display_uninit_sysfs(pdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void display_uninit_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
|
||||
sysfs_remove_files(&dssdev->dev->kobj,
|
||||
display_sysfs_attrs);
|
||||
}
|
||||
}
|
338
drivers/video/fbdev/omap2/dss/display.c
Normal file
338
drivers/video/fbdev/omap2/dss/display.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/display.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 "DISPLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
|
||||
u16 *xres, u16 *yres)
|
||||
{
|
||||
*xres = dssdev->panel.timings.x_res;
|
||||
*yres = dssdev->panel.timings.y_res;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_default_get_resolution);
|
||||
|
||||
int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
|
||||
{
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
if (dssdev->phy.dpi.data_lines == 24)
|
||||
return 24;
|
||||
else
|
||||
return 16;
|
||||
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
if (dssdev->ctrl.pixel_size == 24)
|
||||
return 24;
|
||||
else
|
||||
return 16;
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
|
||||
return 24;
|
||||
else
|
||||
return 16;
|
||||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
case OMAP_DISPLAY_TYPE_HDMI:
|
||||
case OMAP_DISPLAY_TYPE_DVI:
|
||||
return 24;
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
|
||||
|
||||
void omapdss_default_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
*timings = dssdev->panel.timings;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_default_get_timings);
|
||||
|
||||
int dss_suspend_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);
|
||||
dssdev->activate_after_resume = true;
|
||||
} else {
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_resume_all_devices(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->activate_after_resume) {
|
||||
dssdev->driver->enable(dssdev);
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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_driver *drv = dssdev->driver;
|
||||
int id;
|
||||
|
||||
/*
|
||||
* Note: this presumes all the displays are either using DT or non-DT,
|
||||
* which normally should be the case. This also presumes that all
|
||||
* displays either have an DT alias, or none has.
|
||||
*/
|
||||
|
||||
if (dssdev->dev->of_node) {
|
||||
id = of_alias_get_id(dssdev->dev->of_node, "display");
|
||||
|
||||
if (id < 0)
|
||||
id = disp_num_counter++;
|
||||
} else {
|
||||
id = disp_num_counter++;
|
||||
}
|
||||
|
||||
snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
|
||||
|
||||
/* Use 'label' property for name, if it exists */
|
||||
if (dssdev->dev->of_node)
|
||||
of_property_read_string(dssdev->dev->of_node, "label",
|
||||
&dssdev->name);
|
||||
|
||||
if (dssdev->name == NULL)
|
||||
dssdev->name = dssdev->alias;
|
||||
|
||||
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 omapdss_unregister_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
mutex_lock(&panel_list_mutex);
|
||||
list_del(&dssdev->panel_list);
|
||||
mutex_unlock(&panel_list_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_unregister_display);
|
||||
|
||||
struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
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);
|
||||
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.
|
||||
*/
|
||||
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
|
||||
{
|
||||
struct list_head *l;
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
mutex_lock(&panel_list_mutex);
|
||||
|
||||
if (list_empty(&panel_list)) {
|
||||
dssdev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
struct omap_dss_device *omap_dss_find_device(void *data,
|
||||
int (*match)(struct omap_dss_device *dssdev, void *data))
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
|
||||
if (match(dssdev, data))
|
||||
return dssdev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_find_device);
|
||||
|
||||
void videomode_to_omap_video_timings(const struct videomode *vm,
|
||||
struct omap_video_timings *ovt)
|
||||
{
|
||||
memset(ovt, 0, sizeof(*ovt));
|
||||
|
||||
ovt->pixelclock = vm->pixelclock;
|
||||
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_LOW;
|
||||
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(videomode_to_omap_video_timings);
|
||||
|
||||
void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
|
||||
struct videomode *vm)
|
||||
{
|
||||
memset(vm, 0, sizeof(*vm));
|
||||
|
||||
vm->pixelclock = ovt->pixelclock;
|
||||
|
||||
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_video_timings_to_videomode);
|
774
drivers/video/fbdev/omap2/dss/dpi.c
Normal file
774
drivers/video/fbdev/omap2/dss/dpi.c
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dpi.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 "DPI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct regulator *vdds_dsi_reg;
|
||||
struct platform_device *dsidev;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
struct dss_lcd_mgr_config mgr_config;
|
||||
int data_lines;
|
||||
|
||||
struct omap_dss_device output;
|
||||
|
||||
bool port_initialized;
|
||||
} dpi;
|
||||
|
||||
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
|
||||
{
|
||||
/*
|
||||
* XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
|
||||
* would also be used for DISPC fclk. Meaning, when the DPI output is
|
||||
* disabled, DISPC clock will be disabled, and TV out will stop.
|
||||
*/
|
||||
switch (omapdss_get_version()) {
|
||||
case OMAPDSS_VER_OMAP24xx:
|
||||
case OMAPDSS_VER_OMAP34xx_ES1:
|
||||
case OMAPDSS_VER_OMAP34xx_ES3:
|
||||
case OMAPDSS_VER_OMAP3630:
|
||||
case OMAPDSS_VER_AM35xx:
|
||||
return NULL;
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return dsi_get_dsidev_from_id(0);
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return dsi_get_dsidev_from_id(1);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return dsi_get_dsidev_from_id(0);
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return dsi_get_dsidev_from_id(1);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
|
||||
default:
|
||||
/* this shouldn't happen */
|
||||
WARN_ON(1);
|
||||
return OMAP_DSS_CLK_SRC_FCK;
|
||||
}
|
||||
}
|
||||
|
||||
struct dpi_clk_calc_ctx {
|
||||
struct platform_device *dsidev;
|
||||
|
||||
/* inputs */
|
||||
|
||||
unsigned long pck_min, pck_max;
|
||||
|
||||
/* outputs */
|
||||
|
||||
struct dsi_clock_info dsi_cinfo;
|
||||
unsigned long fck;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
};
|
||||
|
||||
static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
||||
unsigned long pck, void *data)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
|
||||
/*
|
||||
* Odd dividers give us uneven duty cycle, causing problem when level
|
||||
* shifted. So skip all odd dividers when the pixel clock is on the
|
||||
* higher side.
|
||||
*/
|
||||
if (ctx->pck_min >= 100000000) {
|
||||
if (lckd > 1 && lckd % 2 != 0)
|
||||
return false;
|
||||
|
||||
if (pckd > 1 && pckd % 2 != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx->dispc_cinfo.lck_div = lckd;
|
||||
ctx->dispc_cinfo.pck_div = pckd;
|
||||
ctx->dispc_cinfo.lck = lck;
|
||||
ctx->dispc_cinfo.pck = pck;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
|
||||
void *data)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
|
||||
/*
|
||||
* Odd dividers give us uneven duty cycle, causing problem when level
|
||||
* 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 >= 100000000)
|
||||
return false;
|
||||
|
||||
ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
||||
ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
|
||||
|
||||
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
|
||||
dpi_calc_dispc_cb, ctx);
|
||||
}
|
||||
|
||||
|
||||
static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
|
||||
unsigned long pll,
|
||||
void *data)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
|
||||
ctx->dsi_cinfo.regn = regn;
|
||||
ctx->dsi_cinfo.regm = regm;
|
||||
ctx->dsi_cinfo.fint = fint;
|
||||
ctx->dsi_cinfo.clkin4ddr = pll;
|
||||
|
||||
return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
|
||||
dpi_calc_hsdiv_cb, ctx);
|
||||
}
|
||||
|
||||
static bool dpi_calc_dss_cb(unsigned long fck, void *data)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
|
||||
ctx->fck = fck;
|
||||
|
||||
return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
|
||||
dpi_calc_dispc_cb, ctx);
|
||||
}
|
||||
|
||||
static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
|
||||
{
|
||||
unsigned long clkin;
|
||||
unsigned long pll_min, pll_max;
|
||||
|
||||
clkin = dsi_get_pll_clkin(dpi.dsidev);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->dsidev = dpi.dsidev;
|
||||
ctx->pck_min = pck - 1000;
|
||||
ctx->pck_max = pck + 1000;
|
||||
ctx->dsi_cinfo.clkin = clkin;
|
||||
|
||||
pll_min = 0;
|
||||
pll_max = 0;
|
||||
|
||||
return dsi_pll_calc(dpi.dsidev, clkin,
|
||||
pll_min, pll_max,
|
||||
dpi_calc_pll_cb, ctx);
|
||||
}
|
||||
|
||||
static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* DSS fck gives us very few possibilities, so finding a good pixel
|
||||
* clock may not be possible. We try multiple times to find the clock,
|
||||
* each time widening the pixel clock range we look for, up to
|
||||
* +/- ~15MHz.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 25; ++i) {
|
||||
bool ok;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
if (pck > 1000 * i * i * i)
|
||||
ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
|
||||
else
|
||||
ctx->pck_min = 0;
|
||||
ctx->pck_max = pck + 1000 * i * i * i;
|
||||
|
||||
ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
|
||||
if (ok)
|
||||
return ok;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dpi_set_dsi_clk(enum omap_channel channel,
|
||||
unsigned long pck_req, unsigned long *fck, int *lck_div,
|
||||
int *pck_div)
|
||||
{
|
||||
struct dpi_clk_calc_ctx ctx;
|
||||
int r;
|
||||
bool ok;
|
||||
|
||||
ok = dpi_dsi_clk_calc(pck_req, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss_select_lcd_clk_source(channel,
|
||||
dpi_get_alt_clk_src(channel));
|
||||
|
||||
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
|
||||
|
||||
*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
||||
*lck_div = ctx.dispc_cinfo.lck_div;
|
||||
*pck_div = ctx.dispc_cinfo.pck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
||||
int *lck_div, int *pck_div)
|
||||
{
|
||||
struct dpi_clk_calc_ctx ctx;
|
||||
int r;
|
||||
bool ok;
|
||||
|
||||
ok = dpi_dss_clk_calc(pck_req, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
r = dss_set_fck_rate(ctx.fck);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
|
||||
|
||||
*fck = ctx.fck;
|
||||
*lck_div = ctx.dispc_cinfo.lck_div;
|
||||
*pck_div = ctx.dispc_cinfo.pck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_set_mode(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
struct omap_video_timings *t = &dpi.timings;
|
||||
int lck_div = 0, pck_div = 0;
|
||||
unsigned long fck = 0;
|
||||
unsigned long pck;
|
||||
int r = 0;
|
||||
|
||||
if (dpi.dsidev)
|
||||
r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
else
|
||||
r = dpi_set_dispc_clk(t->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pck = fck / lck_div / pck_div;
|
||||
|
||||
if (pck != t->pixelclock) {
|
||||
DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
|
||||
t->pixelclock, pck);
|
||||
|
||||
t->pixelclock = pck;
|
||||
}
|
||||
|
||||
dss_mgr_set_timings(mgr, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
dpi.mgr_config.stallmode = false;
|
||||
dpi.mgr_config.fifohandcheck = false;
|
||||
|
||||
dpi.mgr_config.video_port_width = dpi.data_lines;
|
||||
|
||||
dpi.mgr_config.lcden_sig_polarity = 0;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
|
||||
}
|
||||
|
||||
static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
int r;
|
||||
|
||||
mutex_lock(&dpi.lock);
|
||||
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
|
||||
DSSERR("no VDSS_DSI regulator\n");
|
||||
r = -ENODEV;
|
||||
goto err_no_reg;
|
||||
}
|
||||
|
||||
if (out == NULL || out->manager == NULL) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err_no_out_mgr;
|
||||
}
|
||||
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
|
||||
r = regulator_enable(dpi.vdds_dsi_reg);
|
||||
if (r)
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
r = dss_dpi_select_source(out->manager->id);
|
||||
if (r)
|
||||
goto err_src_sel;
|
||||
|
||||
if (dpi.dsidev) {
|
||||
r = dsi_runtime_get(dpi.dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
||||
r = dsi_pll_init(dpi.dsidev, 0, 1);
|
||||
if (r)
|
||||
goto err_dsi_pll_init;
|
||||
}
|
||||
|
||||
r = dpi_set_mode(out->manager);
|
||||
if (r)
|
||||
goto err_set_mode;
|
||||
|
||||
dpi_config_lcd_manager(out->manager);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
r = dss_mgr_enable(out->manager);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
err_set_mode:
|
||||
if (dpi.dsidev)
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
err_dsi_pll_init:
|
||||
if (dpi.dsidev)
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
err_get_dsi:
|
||||
err_src_sel:
|
||||
dispc_runtime_put();
|
||||
err_get_dispc:
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
err_reg_enable:
|
||||
err_no_out_mgr:
|
||||
err_no_reg:
|
||||
mutex_unlock(&dpi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dpi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dpi.output.manager;
|
||||
|
||||
mutex_lock(&dpi.lock);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
if (dpi.dsidev) {
|
||||
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
}
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
}
|
||||
|
||||
static void dpi_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("dpi_set_timings\n");
|
||||
|
||||
mutex_lock(&dpi.lock);
|
||||
|
||||
dpi.timings = *timings;
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dpi.output.manager;
|
||||
int lck_div, pck_div;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
struct dpi_clk_calc_ctx ctx;
|
||||
bool ok;
|
||||
|
||||
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->pixelclock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dpi.dsidev) {
|
||||
ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
||||
} else {
|
||||
ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
fck = ctx.fck;
|
||||
}
|
||||
|
||||
lck_div = ctx.dispc_cinfo.lck_div;
|
||||
pck_div = ctx.dispc_cinfo.pck_div;
|
||||
|
||||
pck = fck / lck_div / pck_div;
|
||||
|
||||
timings->pixelclock = pck;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
|
||||
{
|
||||
mutex_lock(&dpi.lock);
|
||||
|
||||
dpi.data_lines = data_lines;
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
}
|
||||
|
||||
static int dpi_verify_dsi_pll(struct platform_device *dsidev)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* do initial setup with the PLL to see if it is operational */
|
||||
|
||||
r = dsi_runtime_get(dsidev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dsi_pll_init(dsidev, 0, 1);
|
||||
if (r) {
|
||||
dsi_runtime_put(dsidev);
|
||||
return r;
|
||||
}
|
||||
|
||||
dsi_pll_uninit(dsidev, true);
|
||||
dsi_runtime_put(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 = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
|
||||
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
|
||||
* the channel in some more dynamic manner, or get the channel as a user
|
||||
* parameter.
|
||||
*/
|
||||
static enum omap_channel dpi_get_channel(void)
|
||||
{
|
||||
switch (omapdss_get_version()) {
|
||||
case OMAPDSS_VER_OMAP24xx:
|
||||
case OMAPDSS_VER_OMAP34xx_ES1:
|
||||
case OMAPDSS_VER_OMAP34xx_ES3:
|
||||
case OMAPDSS_VER_OMAP3630:
|
||||
case OMAPDSS_VER_AM35xx:
|
||||
return OMAP_DSS_CHANNEL_LCD;
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
return OMAP_DSS_CHANNEL_LCD2;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
return OMAP_DSS_CHANNEL_LCD3;
|
||||
|
||||
default:
|
||||
DSSWARN("unsupported DSS version\n");
|
||||
return OMAP_DSS_CHANNEL_LCD;
|
||||
}
|
||||
}
|
||||
|
||||
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->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
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 = dpi_display_enable,
|
||||
.disable = dpi_display_disable,
|
||||
|
||||
.check_timings = dpi_check_timings,
|
||||
.set_timings = dpi_set_timings,
|
||||
.get_timings = dpi_get_timings,
|
||||
|
||||
.set_data_lines = dpi_set_data_lines,
|
||||
};
|
||||
|
||||
static void dpi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_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;
|
||||
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit dpi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
static int omap_dpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
dpi.pdev = pdev;
|
||||
|
||||
mutex_init(&dpi.lock);
|
||||
|
||||
dpi_init_output(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit omap_dpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
dpi_uninit_output(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver omap_dpi_driver = {
|
||||
.probe = omap_dpi_probe,
|
||||
.remove = __exit_p(omap_dpi_remove),
|
||||
.driver = {
|
||||
.name = "omapdss_dpi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int __init dpi_init_platform_driver(void)
|
||||
{
|
||||
return platform_driver_register(&omap_dpi_driver);
|
||||
}
|
||||
|
||||
void __exit dpi_uninit_platform_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_dpi_driver);
|
||||
}
|
||||
|
||||
int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
{
|
||||
struct device_node *ep;
|
||||
u32 datalines;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
r = of_property_read_u32(ep, "data-lines", &datalines);
|
||||
if (r) {
|
||||
DSSERR("failed to parse datalines\n");
|
||||
goto err_datalines;
|
||||
}
|
||||
|
||||
dpi.data_lines = datalines;
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
dpi.pdev = pdev;
|
||||
|
||||
mutex_init(&dpi.lock);
|
||||
|
||||
dpi_init_output(pdev);
|
||||
|
||||
dpi.port_initialized = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_datalines:
|
||||
of_node_put(ep);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void __exit dpi_uninit_port(void)
|
||||
{
|
||||
if (!dpi.port_initialized)
|
||||
return;
|
||||
|
||||
dpi_uninit_output(dpi.pdev);
|
||||
}
|
5751
drivers/video/fbdev/omap2/dss/dsi.c
Normal file
5751
drivers/video/fbdev/omap2/dss/dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
159
drivers/video/fbdev/omap2/dss/dss-of.c
Normal file
159
drivers/video/fbdev/omap2/dss/dss-of.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_port(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *port = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
if (!prev) {
|
||||
struct device_node *ports;
|
||||
/*
|
||||
* It's the first call, we have to find a port subnode
|
||||
* within this node or within an optional 'ports' node.
|
||||
*/
|
||||
ports = of_get_child_by_name(parent, "ports");
|
||||
if (ports)
|
||||
parent = ports;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
|
||||
/* release the 'ports' node */
|
||||
of_node_put(ports);
|
||||
} else {
|
||||
struct device_node *ports;
|
||||
|
||||
ports = of_get_parent(prev);
|
||||
if (!ports)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
port = of_get_next_child(ports, prev);
|
||||
if (!port) {
|
||||
of_node_put(ports);
|
||||
return NULL;
|
||||
}
|
||||
prev = port;
|
||||
} while (of_node_cmp(port->name, "port") != 0);
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *ep = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
ep = of_get_next_child(parent, prev);
|
||||
if (!ep)
|
||||
return NULL;
|
||||
prev = ep;
|
||||
} while (of_node_cmp(ep->name, "endpoint") != 0);
|
||||
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
|
||||
|
||||
static struct device_node *
|
||||
omapdss_of_get_remote_device_node(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
int i;
|
||||
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
np = of_get_next_parent(np);
|
||||
|
||||
for (i = 0; i < 3 && np; ++i) {
|
||||
struct property *prop;
|
||||
|
||||
prop = of_find_property(np, "compatible", NULL);
|
||||
|
||||
if (prop)
|
||||
return np;
|
||||
|
||||
np = of_get_next_parent(np);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_first_endpoint(const struct device_node *parent)
|
||||
{
|
||||
struct device_node *port, *ep;
|
||||
|
||||
port = omapdss_of_get_next_port(parent, NULL);
|
||||
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
|
||||
of_node_put(port);
|
||||
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
|
||||
|
||||
struct omap_dss_device *
|
||||
omapdss_of_find_source_for_first_ep(struct device_node *node)
|
||||
{
|
||||
struct device_node *ep;
|
||||
struct device_node *src_node;
|
||||
struct omap_dss_device *src;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
if (!ep)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
src_node = omapdss_of_get_remote_device_node(ep);
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
if (!src_node)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
src = omap_dss_find_output_by_node(src_node);
|
||||
|
||||
of_node_put(src_node);
|
||||
|
||||
if (!src)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
return src;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
|
972
drivers/video/fbdev/omap2/dss/dss.c
Normal file
972
drivers/video/fbdev/omap2/dss/dss.c
Normal file
@@ -0,0 +1,972 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss.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 "DSS"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
#define DSS_SZ_REGS SZ_512
|
||||
|
||||
struct dss_reg {
|
||||
u16 idx;
|
||||
};
|
||||
|
||||
#define DSS_REG(idx) ((const struct dss_reg) { idx })
|
||||
|
||||
#define DSS_REVISION DSS_REG(0x0000)
|
||||
#define DSS_SYSCONFIG DSS_REG(0x0010)
|
||||
#define DSS_SYSSTATUS DSS_REG(0x0014)
|
||||
#define DSS_CONTROL DSS_REG(0x0040)
|
||||
#define DSS_SDI_CONTROL DSS_REG(0x0044)
|
||||
#define DSS_PLL_CONTROL DSS_REG(0x0048)
|
||||
#define DSS_SDI_STATUS DSS_REG(0x005C)
|
||||
|
||||
#define REG_GET(idx, start, end) \
|
||||
FLD_GET(dss_read_reg(idx), start, end)
|
||||
|
||||
#define REG_FLD_MOD(idx, val, start, end) \
|
||||
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
|
||||
|
||||
static int dss_runtime_get(void);
|
||||
static void dss_runtime_put(void);
|
||||
|
||||
struct dss_features {
|
||||
u8 fck_div_max;
|
||||
u8 dss_fck_multiplier;
|
||||
const char *parent_clk_name;
|
||||
int (*dpi_select_source)(enum omap_channel channel);
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *parent_clk;
|
||||
struct clk *dss_clk;
|
||||
unsigned long dss_clk_rate;
|
||||
|
||||
unsigned long cache_req_pck;
|
||||
unsigned long cache_prate;
|
||||
struct dispc_clock_info cache_dispc_cinfo;
|
||||
|
||||
enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
|
||||
enum omap_dss_clk_source dispc_clk_source;
|
||||
enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
|
||||
|
||||
bool ctx_valid;
|
||||
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
|
||||
|
||||
const struct dss_features *feat;
|
||||
} dss;
|
||||
|
||||
static const char * const dss_generic_clk_source_names[] = {
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
|
||||
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
|
||||
};
|
||||
|
||||
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
|
||||
{
|
||||
__raw_writel(val, dss.base + idx.idx);
|
||||
}
|
||||
|
||||
static inline u32 dss_read_reg(const struct dss_reg idx)
|
||||
{
|
||||
return __raw_readl(dss.base + idx.idx);
|
||||
}
|
||||
|
||||
#define SR(reg) \
|
||||
dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
|
||||
#define RR(reg) \
|
||||
dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
|
||||
|
||||
static void dss_save_context(void)
|
||||
{
|
||||
DSSDBG("dss_save_context\n");
|
||||
|
||||
SR(CONTROL);
|
||||
|
||||
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
||||
OMAP_DISPLAY_TYPE_SDI) {
|
||||
SR(SDI_CONTROL);
|
||||
SR(PLL_CONTROL);
|
||||
}
|
||||
|
||||
dss.ctx_valid = true;
|
||||
|
||||
DSSDBG("context saved\n");
|
||||
}
|
||||
|
||||
static void dss_restore_context(void)
|
||||
{
|
||||
DSSDBG("dss_restore_context\n");
|
||||
|
||||
if (!dss.ctx_valid)
|
||||
return;
|
||||
|
||||
RR(CONTROL);
|
||||
|
||||
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
||||
OMAP_DISPLAY_TYPE_SDI) {
|
||||
RR(SDI_CONTROL);
|
||||
RR(PLL_CONTROL);
|
||||
}
|
||||
|
||||
DSSDBG("context restored\n");
|
||||
}
|
||||
|
||||
#undef SR
|
||||
#undef RR
|
||||
|
||||
void dss_sdi_init(int datapairs)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
BUG_ON(datapairs > 3 || datapairs < 1);
|
||||
|
||||
l = dss_read_reg(DSS_SDI_CONTROL);
|
||||
l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
|
||||
l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
|
||||
l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
|
||||
dss_write_reg(DSS_SDI_CONTROL, l);
|
||||
|
||||
l = dss_read_reg(DSS_PLL_CONTROL);
|
||||
l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
|
||||
l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
|
||||
l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
|
||||
dss_write_reg(DSS_PLL_CONTROL, l);
|
||||
}
|
||||
|
||||
int dss_sdi_enable(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
dispc_pck_free_enable(1);
|
||||
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
udelay(1); /* wait 2x PCLK */
|
||||
|
||||
/* Lock SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
|
||||
|
||||
/* Waiting for PLL lock request to complete */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("PLL lock request timed out\n");
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clearing PLL_GO bit */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
|
||||
|
||||
/* Waiting for PLL to lock */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("PLL lock timed out\n");
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
dispc_lcd_enable_signal(1);
|
||||
|
||||
/* Waiting for SDI reset to complete */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("SDI reset timed out\n");
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dispc_lcd_enable_signal(0);
|
||||
err1:
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
|
||||
dispc_pck_free_enable(0);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void dss_sdi_disable(void)
|
||||
{
|
||||
dispc_lcd_enable_signal(0);
|
||||
|
||||
dispc_pck_free_enable(0);
|
||||
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
}
|
||||
|
||||
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
return dss_generic_clk_source_names[clk_src];
|
||||
}
|
||||
|
||||
void dss_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
const char *fclk_name, *fclk_real_name;
|
||||
unsigned long fclk_rate;
|
||||
|
||||
if (dss_runtime_get())
|
||||
return;
|
||||
|
||||
seq_printf(s, "- DSS -\n");
|
||||
|
||||
fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
||||
fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
||||
fclk_rate = clk_get_rate(dss.dss_clk);
|
||||
|
||||
seq_printf(s, "%s (%s) = %lu\n",
|
||||
fclk_name, fclk_real_name,
|
||||
fclk_rate);
|
||||
|
||||
dss_runtime_put();
|
||||
}
|
||||
|
||||
static void dss_dump_regs(struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
|
||||
|
||||
if (dss_runtime_get())
|
||||
return;
|
||||
|
||||
DUMPREG(DSS_REVISION);
|
||||
DUMPREG(DSS_SYSCONFIG);
|
||||
DUMPREG(DSS_SYSSTATUS);
|
||||
DUMPREG(DSS_CONTROL);
|
||||
|
||||
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
||||
OMAP_DISPLAY_TYPE_SDI) {
|
||||
DUMPREG(DSS_SDI_CONTROL);
|
||||
DUMPREG(DSS_PLL_CONTROL);
|
||||
DUMPREG(DSS_SDI_STATUS);
|
||||
}
|
||||
|
||||
dss_runtime_put();
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b;
|
||||
u8 start, end;
|
||||
|
||||
switch (clk_src) {
|
||||
case OMAP_DSS_CLK_SRC_FCK:
|
||||
b = 0;
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
b = 2;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
|
||||
|
||||
REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
|
||||
|
||||
dss.dispc_clk_source = clk_src;
|
||||
}
|
||||
|
||||
void dss_select_dsi_clk_source(int dsi_module,
|
||||
enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b, pos;
|
||||
|
||||
switch (clk_src) {
|
||||
case OMAP_DSS_CLK_SRC_FCK:
|
||||
b = 0;
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
|
||||
BUG_ON(dsi_module != 0);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dsi_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
|
||||
BUG_ON(dsi_module != 1);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dsi_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
pos = dsi_module == 0 ? 1 : 10;
|
||||
REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */
|
||||
|
||||
dss.dsi_clk_source[dsi_module] = clk_src;
|
||||
}
|
||||
|
||||
void dss_select_lcd_clk_source(enum omap_channel channel,
|
||||
enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b, ix, pos;
|
||||
|
||||
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
|
||||
dss_select_dispc_clk_source(clk_src);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (clk_src) {
|
||||
case OMAP_DSS_CLK_SRC_FCK:
|
||||
b = 0;
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
|
||||
channel != OMAP_DSS_CHANNEL_LCD3);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
|
||||
(channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
|
||||
REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
|
||||
|
||||
ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
|
||||
(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
|
||||
dss.lcd_clk_source[ix] = clk_src;
|
||||
}
|
||||
|
||||
enum omap_dss_clk_source dss_get_dispc_clk_source(void)
|
||||
{
|
||||
return dss.dispc_clk_source;
|
||||
}
|
||||
|
||||
enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
|
||||
{
|
||||
return dss.dsi_clk_source[dsi_module];
|
||||
}
|
||||
|
||||
enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
|
||||
{
|
||||
if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
|
||||
int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
|
||||
(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
|
||||
return dss.lcd_clk_source[ix];
|
||||
} else {
|
||||
/* LCD_CLK source is the same as DISPC_FCLK source for
|
||||
* OMAP2 and OMAP3 */
|
||||
return dss.dispc_clk_source;
|
||||
}
|
||||
}
|
||||
|
||||
bool dss_div_calc(unsigned long pck, unsigned long fck_min,
|
||||
dss_div_calc_func func, void *data)
|
||||
{
|
||||
int fckd, fckd_start, fckd_stop;
|
||||
unsigned long fck;
|
||||
unsigned long fck_hw_max;
|
||||
unsigned long fckd_hw_max;
|
||||
unsigned long prate;
|
||||
unsigned m;
|
||||
|
||||
fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
||||
|
||||
if (dss.parent_clk == NULL) {
|
||||
unsigned pckd;
|
||||
|
||||
pckd = fck_hw_max / pck;
|
||||
|
||||
fck = pck * pckd;
|
||||
|
||||
fck = clk_round_rate(dss.dss_clk, fck);
|
||||
|
||||
return func(fck, data);
|
||||
}
|
||||
|
||||
fckd_hw_max = dss.feat->fck_div_max;
|
||||
|
||||
m = dss.feat->dss_fck_multiplier;
|
||||
prate = clk_get_rate(dss.parent_clk);
|
||||
|
||||
fck_min = fck_min ? fck_min : 1;
|
||||
|
||||
fckd_start = min(prate * m / fck_min, fckd_hw_max);
|
||||
fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
|
||||
|
||||
for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
|
||||
fck = DIV_ROUND_UP(prate, fckd) * m;
|
||||
|
||||
if (func(fck, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int dss_set_fck_rate(unsigned long rate)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("set fck to %lu\n", rate);
|
||||
|
||||
r = clk_set_rate(dss.dss_clk, rate);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
|
||||
|
||||
WARN_ONCE(dss.dss_clk_rate != rate,
|
||||
"clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
|
||||
rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long dss_get_dispc_clk_rate(void)
|
||||
{
|
||||
return dss.dss_clk_rate;
|
||||
}
|
||||
|
||||
static int dss_setup_default_clock(void)
|
||||
{
|
||||
unsigned long max_dss_fck, prate;
|
||||
unsigned long fck;
|
||||
unsigned fck_div;
|
||||
int r;
|
||||
|
||||
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
||||
|
||||
if (dss.parent_clk == NULL) {
|
||||
fck = clk_round_rate(dss.dss_clk, max_dss_fck);
|
||||
} else {
|
||||
prate = clk_get_rate(dss.parent_clk);
|
||||
|
||||
fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
|
||||
max_dss_fck);
|
||||
fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
|
||||
}
|
||||
|
||||
r = dss_set_fck_rate(fck);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_set_venc_output(enum omap_dss_venc_type type)
|
||||
{
|
||||
int l = 0;
|
||||
|
||||
if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
|
||||
l = 0;
|
||||
else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
|
||||
l = 1;
|
||||
else
|
||||
BUG();
|
||||
|
||||
/* venc out selection. 0 = comp, 1 = svideo */
|
||||
REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
|
||||
}
|
||||
|
||||
void dss_set_dac_pwrdn_bgz(bool enable)
|
||||
{
|
||||
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
|
||||
}
|
||||
|
||||
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
|
||||
{
|
||||
enum omap_display_type dp;
|
||||
dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
|
||||
|
||||
/* Complain about invalid selections */
|
||||
WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
|
||||
WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
|
||||
|
||||
/* Select only if we have options */
|
||||
if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
|
||||
REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
|
||||
}
|
||||
|
||||
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
|
||||
{
|
||||
enum omap_display_type displays;
|
||||
|
||||
displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
|
||||
if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
|
||||
return DSS_VENC_TV_CLK;
|
||||
|
||||
if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
|
||||
return DSS_HDMI_M_PCLK;
|
||||
|
||||
return REG_GET(DSS_CONTROL, 15, 15);
|
||||
}
|
||||
|
||||
static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
|
||||
{
|
||||
if (channel != OMAP_DSS_CHANNEL_LCD)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_dpi_select_source_omap4(enum omap_channel channel)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
val = 0;
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
val = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_dpi_select_source_omap5(enum omap_channel channel)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
val = 1;
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
val = 2;
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
val = 3;
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_DIGIT:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_dpi_select_source(enum omap_channel channel)
|
||||
{
|
||||
return dss.feat->dpi_select_source(channel);
|
||||
}
|
||||
|
||||
static int dss_get_clocks(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = devm_clk_get(&dss.pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get clock fck\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
dss.dss_clk = clk;
|
||||
|
||||
if (dss.feat->parent_clk_name) {
|
||||
clk = clk_get(NULL, dss.feat->parent_clk_name);
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
} else {
|
||||
clk = NULL;
|
||||
}
|
||||
|
||||
dss.parent_clk = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dss_put_clocks(void)
|
||||
{
|
||||
if (dss.parent_clk)
|
||||
clk_put(dss.parent_clk);
|
||||
}
|
||||
|
||||
static int dss_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("dss_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&dss.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void dss_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("dss_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put_sync(&dss.pdev->dev);
|
||||
WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
|
||||
}
|
||||
|
||||
/* DEBUGFS */
|
||||
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
|
||||
void dss_debug_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
dss_dump_clocks(s);
|
||||
dispc_dump_clocks(s);
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_dump_clocks(s);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dss_features omap24xx_dss_feats __initconst = {
|
||||
/*
|
||||
* fck div max is really 16, but the divider range has gaps. The range
|
||||
* from 1 to 6 has no gaps, so let's use that as a max.
|
||||
*/
|
||||
.fck_div_max = 6,
|
||||
.dss_fck_multiplier = 2,
|
||||
.parent_clk_name = "core_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
|
||||
};
|
||||
|
||||
static const struct dss_features omap34xx_dss_feats __initconst = {
|
||||
.fck_div_max = 16,
|
||||
.dss_fck_multiplier = 2,
|
||||
.parent_clk_name = "dpll4_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
|
||||
};
|
||||
|
||||
static const struct dss_features omap3630_dss_feats __initconst = {
|
||||
.fck_div_max = 32,
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll4_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
|
||||
};
|
||||
|
||||
static const struct dss_features omap44xx_dss_feats __initconst = {
|
||||
.fck_div_max = 32,
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll_per_x2_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_omap4,
|
||||
};
|
||||
|
||||
static const struct dss_features omap54xx_dss_feats __initconst = {
|
||||
.fck_div_max = 64,
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll_per_x2_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_omap5,
|
||||
};
|
||||
|
||||
static int __init dss_init_features(struct platform_device *pdev)
|
||||
{
|
||||
const struct dss_features *src;
|
||||
struct dss_features *dst;
|
||||
|
||||
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
|
||||
if (!dst) {
|
||||
dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
switch (omapdss_get_version()) {
|
||||
case OMAPDSS_VER_OMAP24xx:
|
||||
src = &omap24xx_dss_feats;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP34xx_ES1:
|
||||
case OMAPDSS_VER_OMAP34xx_ES3:
|
||||
case OMAPDSS_VER_AM35xx:
|
||||
src = &omap34xx_dss_feats;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP3630:
|
||||
src = &omap3630_dss_feats;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
src = &omap44xx_dss_feats;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
src = &omap54xx_dss_feats;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
dss.feat = dst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init dss_init_ports(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *parent = pdev->dev.of_node;
|
||||
struct device_node *port;
|
||||
int r;
|
||||
|
||||
if (parent == NULL)
|
||||
return 0;
|
||||
|
||||
port = omapdss_of_get_next_port(parent, NULL);
|
||||
if (!port) {
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
dpi_init_port(pdev, parent);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
u32 reg;
|
||||
|
||||
r = of_property_read_u32(port, "reg", ®);
|
||||
if (r)
|
||||
reg = 0;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
if (reg == 0)
|
||||
dpi_init_port(pdev, port);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
if (reg == 1)
|
||||
sdi_init_port(pdev, port);
|
||||
#endif
|
||||
|
||||
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dss_uninit_ports(void)
|
||||
{
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
dpi_uninit_port();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
sdi_uninit_port();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* DSS HW IP initialisation */
|
||||
static int __init omap_dsshw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *dss_mem;
|
||||
u32 rev;
|
||||
int r;
|
||||
|
||||
dss.pdev = pdev;
|
||||
|
||||
r = dss_init_features(dss.pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
|
||||
if (!dss_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM DSS\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
|
||||
resource_size(dss_mem));
|
||||
if (!dss.base) {
|
||||
DSSERR("can't ioremap DSS\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = dss_get_clocks();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dss_setup_default_clock();
|
||||
if (r)
|
||||
goto err_setup_clocks;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
goto err_runtime_get;
|
||||
|
||||
dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
|
||||
|
||||
/* Select DPLL */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
|
||||
|
||||
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
|
||||
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
|
||||
#endif
|
||||
dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
|
||||
|
||||
dss_init_ports(pdev);
|
||||
|
||||
rev = dss_read_reg(DSS_REVISION);
|
||||
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
|
||||
dss_runtime_put();
|
||||
|
||||
dss_debugfs_create_file("dss", dss_dump_regs);
|
||||
|
||||
return 0;
|
||||
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_setup_clocks:
|
||||
dss_put_clocks();
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit omap_dsshw_remove(struct platform_device *pdev)
|
||||
{
|
||||
dss_uninit_ports();
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
dss_put_clocks();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_runtime_suspend(struct device *dev)
|
||||
{
|
||||
dss_save_context();
|
||||
dss_set_min_bus_tput(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
/*
|
||||
* Set an arbitrarily high tput request to ensure OPP100.
|
||||
* What we should really do is to make a request to stay in OPP100,
|
||||
* without any tput requirements, but that is not currently possible
|
||||
* via the PM layer.
|
||||
*/
|
||||
|
||||
r = dss_set_min_bus_tput(dev, 1000000000);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss_restore_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dss_pm_ops = {
|
||||
.runtime_suspend = dss_runtime_suspend,
|
||||
.runtime_resume = dss_runtime_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id dss_of_match[] = {
|
||||
{ .compatible = "ti,omap2-dss", },
|
||||
{ .compatible = "ti,omap3-dss", },
|
||||
{ .compatible = "ti,omap4-dss", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, dss_of_match);
|
||||
|
||||
static struct platform_driver omap_dsshw_driver = {
|
||||
.remove = __exit_p(omap_dsshw_remove),
|
||||
.driver = {
|
||||
.name = "omapdss_dss",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dss_pm_ops,
|
||||
.of_match_table = dss_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
int __init dss_init_platform_driver(void)
|
||||
{
|
||||
return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe);
|
||||
}
|
||||
|
||||
void dss_uninit_platform_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_dsshw_driver);
|
||||
}
|
438
drivers/video/fbdev/omap2/dss/dss.h
Normal file
438
drivers/video/fbdev/omap2/dss/dss.h
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss.h
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DSS_H
|
||||
#define __OMAP2_DSS_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt
|
||||
#else
|
||||
#define pr_fmt(fmt) fmt
|
||||
#endif
|
||||
|
||||
#define DSSDBG(format, ...) \
|
||||
pr_debug(format, ## __VA_ARGS__)
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSERR(format, ...) \
|
||||
printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSERR(format, ...) \
|
||||
printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSINFO(format, ...) \
|
||||
printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSINFO(format, ...) \
|
||||
printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSWARN(format, ...) \
|
||||
printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSWARN(format, ...) \
|
||||
printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* OMAP TRM gives bitfields as start:end, where start is the higher bit
|
||||
number. For example 7:0 */
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
|
||||
#define FLD_MOD(orig, val, start, end) \
|
||||
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
|
||||
|
||||
enum dss_io_pad_mode {
|
||||
DSS_IO_PAD_MODE_RESET,
|
||||
DSS_IO_PAD_MODE_RFBI,
|
||||
DSS_IO_PAD_MODE_BYPASS,
|
||||
};
|
||||
|
||||
enum dss_hdmi_venc_clk_source_select {
|
||||
DSS_VENC_TV_CLK = 0,
|
||||
DSS_HDMI_M_PCLK = 1,
|
||||
};
|
||||
|
||||
enum dss_dsi_content_type {
|
||||
DSS_DSI_CONTENT_DCS,
|
||||
DSS_DSI_CONTENT_GENERIC,
|
||||
};
|
||||
|
||||
enum dss_writeback_channel {
|
||||
DSS_WB_LCD1_MGR = 0,
|
||||
DSS_WB_LCD2_MGR = 1,
|
||||
DSS_WB_TV_MGR = 2,
|
||||
DSS_WB_OVL0 = 3,
|
||||
DSS_WB_OVL1 = 4,
|
||||
DSS_WB_OVL2 = 5,
|
||||
DSS_WB_OVL3 = 6,
|
||||
DSS_WB_LCD3_MGR = 7,
|
||||
};
|
||||
|
||||
struct dispc_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long lck;
|
||||
unsigned long pck;
|
||||
|
||||
/* dividers */
|
||||
u16 lck_div;
|
||||
u16 pck_div;
|
||||
};
|
||||
|
||||
struct dsi_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long fint;
|
||||
unsigned long clkin4ddr;
|
||||
unsigned long clkin;
|
||||
unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK
|
||||
* OMAP4: PLLx_CLK1 */
|
||||
unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK
|
||||
* OMAP4: PLLx_CLK2 */
|
||||
unsigned long lp_clk;
|
||||
|
||||
/* dividers */
|
||||
u16 regn;
|
||||
u16 regm;
|
||||
u16 regm_dispc; /* OMAP3: REGM3
|
||||
* OMAP4: REGM4 */
|
||||
u16 regm_dsi; /* OMAP3: REGM4
|
||||
* OMAP4: REGM5 */
|
||||
u16 lp_clk_div;
|
||||
};
|
||||
|
||||
struct dss_lcd_mgr_config {
|
||||
enum dss_io_pad_mode io_pad_mode;
|
||||
|
||||
bool stallmode;
|
||||
bool fifohandcheck;
|
||||
|
||||
struct dispc_clock_info clock_info;
|
||||
|
||||
int video_port_width;
|
||||
|
||||
int lcden_sig_polarity;
|
||||
};
|
||||
|
||||
struct seq_file;
|
||||
struct platform_device;
|
||||
|
||||
/* core */
|
||||
struct platform_device *dss_get_core_pdev(void);
|
||||
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
|
||||
void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
|
||||
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
|
||||
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
|
||||
|
||||
/* 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);
|
||||
void display_uninit_sysfs(struct platform_device *pdev);
|
||||
|
||||
/* manager */
|
||||
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,
|
||||
const struct omap_video_timings *timings);
|
||||
int dss_mgr_check(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info,
|
||||
const struct omap_video_timings *mgr_timings,
|
||||
const struct dss_lcd_mgr_config *config,
|
||||
struct omap_overlay_info **overlay_infos);
|
||||
|
||||
static inline bool dss_mgr_is_lcd(enum omap_channel id)
|
||||
{
|
||||
if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 ||
|
||||
id == OMAP_DSS_CHANNEL_LCD3)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
|
||||
struct platform_device *pdev);
|
||||
void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
|
||||
|
||||
/* overlay */
|
||||
void dss_init_overlays(struct platform_device *pdev);
|
||||
void dss_uninit_overlays(struct platform_device *pdev);
|
||||
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
|
||||
int dss_ovl_simple_check(struct omap_overlay *ovl,
|
||||
const struct omap_overlay_info *info);
|
||||
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
|
||||
const struct omap_video_timings *mgr_timings);
|
||||
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
|
||||
enum omap_color_mode mode);
|
||||
int dss_overlay_kobj_init(struct omap_overlay *ovl,
|
||||
struct platform_device *pdev);
|
||||
void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
|
||||
|
||||
/* DSS */
|
||||
int dss_init_platform_driver(void) __init;
|
||||
void dss_uninit_platform_driver(void);
|
||||
|
||||
unsigned long dss_get_dispc_clk_rate(void);
|
||||
int dss_dpi_select_source(enum omap_channel channel);
|
||||
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
|
||||
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
|
||||
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
|
||||
void dss_dump_clocks(struct seq_file *s);
|
||||
|
||||
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
|
||||
void dss_debug_dump_clocks(struct seq_file *s);
|
||||
#endif
|
||||
|
||||
void dss_sdi_init(int datapairs);
|
||||
int dss_sdi_enable(void);
|
||||
void dss_sdi_disable(void);
|
||||
|
||||
void dss_select_dsi_clk_source(int dsi_module,
|
||||
enum omap_dss_clk_source clk_src);
|
||||
void dss_select_lcd_clk_source(enum omap_channel channel,
|
||||
enum omap_dss_clk_source clk_src);
|
||||
enum omap_dss_clk_source dss_get_dispc_clk_source(void);
|
||||
enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
|
||||
enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
|
||||
|
||||
void dss_set_venc_output(enum omap_dss_venc_type type);
|
||||
void dss_set_dac_pwrdn_bgz(bool enable);
|
||||
|
||||
int dss_set_fck_rate(unsigned long rate);
|
||||
|
||||
typedef bool (*dss_div_calc_func)(unsigned long fck, void *data);
|
||||
bool dss_div_calc(unsigned long pck, unsigned long fck_min,
|
||||
dss_div_calc_func func, void *data);
|
||||
|
||||
/* SDI */
|
||||
int sdi_init_platform_driver(void) __init;
|
||||
void sdi_uninit_platform_driver(void) __exit;
|
||||
|
||||
int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
|
||||
void sdi_uninit_port(void) __exit;
|
||||
|
||||
/* DSI */
|
||||
|
||||
typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
|
||||
unsigned long pll, void *data);
|
||||
typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
|
||||
void *data);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
|
||||
struct dentry;
|
||||
struct file_operations;
|
||||
|
||||
int dsi_init_platform_driver(void) __init;
|
||||
void dsi_uninit_platform_driver(void) __exit;
|
||||
|
||||
int dsi_runtime_get(struct platform_device *dsidev);
|
||||
void dsi_runtime_put(struct platform_device *dsidev);
|
||||
|
||||
void dsi_dump_clocks(struct seq_file *s);
|
||||
|
||||
void dsi_irq_handler(void);
|
||||
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
|
||||
|
||||
unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
|
||||
|
||||
bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
|
||||
unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
|
||||
bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
|
||||
unsigned long pll_min, unsigned long pll_max,
|
||||
dsi_pll_calc_func func, void *data);
|
||||
|
||||
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
|
||||
int dsi_pll_set_clock_div(struct platform_device *dsidev,
|
||||
struct dsi_clock_info *cinfo);
|
||||
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
|
||||
bool enable_hsdiv);
|
||||
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
|
||||
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
|
||||
void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
|
||||
struct platform_device *dsi_get_dsidev_from_id(int module);
|
||||
#else
|
||||
static inline int dsi_runtime_get(struct platform_device *dsidev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void dsi_runtime_put(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
|
||||
{
|
||||
WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
|
||||
{
|
||||
WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
|
||||
struct dsi_clock_info *cinfo)
|
||||
{
|
||||
WARN("%s: DSI not compiled in\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int dsi_pll_init(struct platform_device *dsidev,
|
||||
bool enable_hsclk, bool enable_hsdiv)
|
||||
{
|
||||
WARN("%s: DSI not compiled in\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void dsi_pll_uninit(struct platform_device *dsidev,
|
||||
bool disconnect_lanes)
|
||||
{
|
||||
}
|
||||
static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
static inline struct platform_device *dsi_get_dsidev_from_id(int module)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
|
||||
unsigned long pll, unsigned long out_min,
|
||||
dsi_hsdiv_calc_func func, void *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool dsi_pll_calc(struct platform_device *dsidev,
|
||||
unsigned long clkin,
|
||||
unsigned long pll_min, unsigned long pll_max,
|
||||
dsi_pll_calc_func func, void *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* DPI */
|
||||
int dpi_init_platform_driver(void) __init;
|
||||
void dpi_uninit_platform_driver(void) __exit;
|
||||
|
||||
int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
|
||||
void dpi_uninit_port(void) __exit;
|
||||
|
||||
/* DISPC */
|
||||
int dispc_init_platform_driver(void) __init;
|
||||
void dispc_uninit_platform_driver(void) __exit;
|
||||
void dispc_dump_clocks(struct seq_file *s);
|
||||
|
||||
void dispc_enable_sidle(void);
|
||||
void dispc_disable_sidle(void);
|
||||
|
||||
void dispc_lcd_enable_signal(bool enable);
|
||||
void dispc_pck_free_enable(bool enable);
|
||||
void dispc_enable_fifomerge(bool enable);
|
||||
void dispc_enable_gamma_table(bool enable);
|
||||
void dispc_set_loadmode(enum omap_dss_load_mode mode);
|
||||
|
||||
typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
|
||||
unsigned long pck, void *data);
|
||||
bool dispc_div_calc(unsigned long dispc,
|
||||
unsigned long pck_min, unsigned long pck_max,
|
||||
dispc_div_calc_func func, void *data);
|
||||
|
||||
bool dispc_mgr_timings_ok(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
unsigned long dispc_fclk_rate(void);
|
||||
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
|
||||
struct dispc_clock_info *cinfo);
|
||||
|
||||
|
||||
void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
|
||||
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
|
||||
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
|
||||
bool manual_update);
|
||||
|
||||
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
|
||||
unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
|
||||
unsigned long dispc_core_clk_rate(void);
|
||||
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);
|
||||
void dispc_wb_go(void);
|
||||
void dispc_wb_enable(bool enable);
|
||||
bool dispc_wb_is_enabled(void);
|
||||
void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
|
||||
int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
|
||||
bool mem_to_mem, const struct omap_video_timings *timings);
|
||||
|
||||
/* VENC */
|
||||
int venc_init_platform_driver(void) __init;
|
||||
void venc_uninit_platform_driver(void) __exit;
|
||||
|
||||
/* HDMI */
|
||||
int hdmi4_init_platform_driver(void) __init;
|
||||
void hdmi4_uninit_platform_driver(void) __exit;
|
||||
|
||||
/* RFBI */
|
||||
int rfbi_init_platform_driver(void) __init;
|
||||
void rfbi_uninit_platform_driver(void) __exit;
|
||||
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
|
||||
{
|
||||
int b;
|
||||
for (b = 0; b < 32; ++b) {
|
||||
if (irqstatus & (1 << b))
|
||||
irq_arr[b]++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
935
drivers/video/fbdev/omap2/dss/dss_features.c
Normal file
935
drivers/video/fbdev/omap2/dss/dss_features.c
Normal file
@@ -0,0 +1,935 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss_features.c
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
* Author: Archit Taneja <archit@ti.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
/* Defines a generic omap register field */
|
||||
struct dss_reg_field {
|
||||
u8 start, end;
|
||||
};
|
||||
|
||||
struct dss_param_range {
|
||||
int min, max;
|
||||
};
|
||||
|
||||
struct omap_dss_features {
|
||||
const struct dss_reg_field *reg_fields;
|
||||
const int num_reg_fields;
|
||||
|
||||
const enum dss_feat_id *features;
|
||||
const int num_features;
|
||||
|
||||
const int num_mgrs;
|
||||
const int num_ovls;
|
||||
const int num_wbs;
|
||||
const enum omap_display_type *supported_displays;
|
||||
const enum omap_dss_output_id *supported_outputs;
|
||||
const enum omap_color_mode *supported_color_modes;
|
||||
const enum omap_overlay_caps *overlay_caps;
|
||||
const char * const *clksrc_names;
|
||||
const struct dss_param_range *dss_params;
|
||||
|
||||
const enum omap_dss_rotation_type supported_rotation_types;
|
||||
|
||||
const u32 buffer_size_unit;
|
||||
const u32 burst_size_unit;
|
||||
};
|
||||
|
||||
/* This struct is assigned to one of the below during initialization */
|
||||
static const struct omap_dss_features *omap_current_dss_features;
|
||||
|
||||
static const struct dss_reg_field omap2_dss_reg_fields[] = {
|
||||
[FEAT_REG_FIRHINC] = { 11, 0 },
|
||||
[FEAT_REG_FIRVINC] = { 27, 16 },
|
||||
[FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
|
||||
[FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
|
||||
[FEAT_REG_FIFOSIZE] = { 8, 0 },
|
||||
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 25, 16 },
|
||||
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
|
||||
[FEAT_REG_DSIPLL_REGN] = { 0, 0 },
|
||||
[FEAT_REG_DSIPLL_REGM] = { 0, 0 },
|
||||
[FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
|
||||
[FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
|
||||
};
|
||||
|
||||
static const struct dss_reg_field omap3_dss_reg_fields[] = {
|
||||
[FEAT_REG_FIRHINC] = { 12, 0 },
|
||||
[FEAT_REG_FIRVINC] = { 28, 16 },
|
||||
[FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
|
||||
[FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
|
||||
[FEAT_REG_FIFOSIZE] = { 10, 0 },
|
||||
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 25, 16 },
|
||||
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
|
||||
[FEAT_REG_DSIPLL_REGN] = { 7, 1 },
|
||||
[FEAT_REG_DSIPLL_REGM] = { 18, 8 },
|
||||
[FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
|
||||
[FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
|
||||
};
|
||||
|
||||
static const struct dss_reg_field omap4_dss_reg_fields[] = {
|
||||
[FEAT_REG_FIRHINC] = { 12, 0 },
|
||||
[FEAT_REG_FIRVINC] = { 28, 16 },
|
||||
[FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
|
||||
[FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
|
||||
[FEAT_REG_FIFOSIZE] = { 15, 0 },
|
||||
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 26, 16 },
|
||||
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
|
||||
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
|
||||
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
|
||||
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
|
||||
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
|
||||
};
|
||||
|
||||
static const struct dss_reg_field omap5_dss_reg_fields[] = {
|
||||
[FEAT_REG_FIRHINC] = { 12, 0 },
|
||||
[FEAT_REG_FIRVINC] = { 28, 16 },
|
||||
[FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
|
||||
[FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
|
||||
[FEAT_REG_FIFOSIZE] = { 15, 0 },
|
||||
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 26, 16 },
|
||||
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
|
||||
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
|
||||
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
|
||||
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
|
||||
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
|
||||
};
|
||||
|
||||
static const enum omap_display_type omap2_dss_supported_displays[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DISPLAY_TYPE_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_display_type omap3430_dss_supported_displays[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
|
||||
OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DISPLAY_TYPE_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_display_type omap3630_dss_supported_displays[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
|
||||
OMAP_DISPLAY_TYPE_DSI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DISPLAY_TYPE_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_display_type omap4_dss_supported_displays[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD2 */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
|
||||
OMAP_DISPLAY_TYPE_DSI,
|
||||
};
|
||||
|
||||
static const enum omap_display_type omap5_dss_supported_displays[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
|
||||
OMAP_DISPLAY_TYPE_DSI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD2 */
|
||||
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
|
||||
OMAP_DISPLAY_TYPE_DSI,
|
||||
};
|
||||
|
||||
static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_DSI1,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_VENC,
|
||||
};
|
||||
|
||||
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD2 */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_DSI2,
|
||||
};
|
||||
|
||||
static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
|
||||
/* OMAP_DSS_CHANNEL_LCD */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD2 */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_DSI1,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD3 */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
OMAP_DSS_OUTPUT_DSI2,
|
||||
};
|
||||
|
||||
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
|
||||
OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
|
||||
OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
|
||||
OMAP_DSS_COLOR_UYVY,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
|
||||
OMAP_DSS_COLOR_UYVY,
|
||||
};
|
||||
|
||||
static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
|
||||
OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
|
||||
OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
|
||||
};
|
||||
|
||||
static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
|
||||
OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
|
||||
OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 |
|
||||
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
|
||||
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
|
||||
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
|
||||
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
|
||||
OMAP_DSS_COLOR_RGBX32,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
|
||||
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
|
||||
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
|
||||
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
|
||||
OMAP_DSS_COLOR_RGBX32,
|
||||
|
||||
/* OMAP_DSS_VIDEO3 */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
|
||||
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
|
||||
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
|
||||
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
|
||||
OMAP_DSS_COLOR_RGBX32,
|
||||
|
||||
/* OMAP_DSS_WB */
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
|
||||
OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
|
||||
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
|
||||
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
|
||||
OMAP_DSS_COLOR_RGBX32,
|
||||
};
|
||||
|
||||
static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
};
|
||||
|
||||
static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
};
|
||||
|
||||
static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
};
|
||||
|
||||
static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
|
||||
/* OMAP_DSS_GFX */
|
||||
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
|
||||
OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO1 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO2 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
|
||||
/* OMAP_DSS_VIDEO3 */
|
||||
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
|
||||
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
|
||||
OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
|
||||
};
|
||||
|
||||
static const char * const omap2_dss_clk_source_names[] = {
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
|
||||
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK1",
|
||||
};
|
||||
|
||||
static const char * const omap3_dss_clk_source_names[] = {
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
|
||||
[OMAP_DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
|
||||
};
|
||||
|
||||
static const char * const omap4_dss_clk_source_names[] = {
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
|
||||
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
|
||||
};
|
||||
|
||||
static const char * const omap5_dss_clk_source_names[] = {
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
|
||||
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
|
||||
[OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
|
||||
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
|
||||
};
|
||||
|
||||
static const struct dss_param_range omap2_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
|
||||
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
|
||||
[FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
|
||||
[FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
|
||||
[FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
|
||||
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 2 },
|
||||
/*
|
||||
* Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
|
||||
* scaler cannot scale a image with width more than 768.
|
||||
*/
|
||||
[FEAT_PARAM_LINEWIDTH] = { 1, 768 },
|
||||
};
|
||||
|
||||
static const struct dss_param_range omap3_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
|
||||
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
|
||||
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
|
||||
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
|
||||
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
|
||||
};
|
||||
|
||||
static const struct dss_param_range omap4_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
|
||||
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
|
||||
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
|
||||
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
|
||||
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
|
||||
};
|
||||
|
||||
static const struct dss_param_range omap5_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
|
||||
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
|
||||
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
|
||||
[FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
|
||||
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
|
||||
[FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap2_dss_feat_list[] = {
|
||||
FEAT_LCDENABLEPOL,
|
||||
FEAT_LCDENABLESIGNAL,
|
||||
FEAT_PCKFREEENABLE,
|
||||
FEAT_FUNCGATED,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap3430_dss_feat_list[] = {
|
||||
FEAT_LCDENABLEPOL,
|
||||
FEAT_LCDENABLESIGNAL,
|
||||
FEAT_PCKFREEENABLE,
|
||||
FEAT_FUNCGATED,
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FIXED_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_OMAP3_DSI_FIFO_BUG,
|
||||
FEAT_DPI_USES_VDDS_DSI,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id am35xx_dss_feat_list[] = {
|
||||
FEAT_LCDENABLEPOL,
|
||||
FEAT_LCDENABLESIGNAL,
|
||||
FEAT_PCKFREEENABLE,
|
||||
FEAT_FUNCGATED,
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FIXED_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_OMAP3_DSI_FIFO_BUG,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap3630_dss_feat_list[] = {
|
||||
FEAT_LCDENABLEPOL,
|
||||
FEAT_LCDENABLESIGNAL,
|
||||
FEAT_PCKFREEENABLE,
|
||||
FEAT_FUNCGATED,
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_PWR_BUG,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FIXED_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_OMAP3_DSI_FIFO_BUG,
|
||||
FEAT_DPI_USES_VDDS_DSI,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
|
||||
FEAT_MGR_LCD2,
|
||||
FEAT_CORE_CLK_DIV,
|
||||
FEAT_LCD_CLK_SRC,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_GNQ,
|
||||
FEAT_HANDLE_UV_SEPARATE,
|
||||
FEAT_ATTR2,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_BURST_2D,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
|
||||
FEAT_MGR_LCD2,
|
||||
FEAT_CORE_CLK_DIV,
|
||||
FEAT_LCD_CLK_SRC,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_GNQ,
|
||||
FEAT_HDMI_CTS_SWMODE,
|
||||
FEAT_HANDLE_UV_SEPARATE,
|
||||
FEAT_ATTR2,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_BURST_2D,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap4_dss_feat_list[] = {
|
||||
FEAT_MGR_LCD2,
|
||||
FEAT_CORE_CLK_DIV,
|
||||
FEAT_LCD_CLK_SRC,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_GNQ,
|
||||
FEAT_HDMI_CTS_SWMODE,
|
||||
FEAT_HDMI_AUDIO_USE_MCLK,
|
||||
FEAT_HANDLE_UV_SEPARATE,
|
||||
FEAT_ATTR2,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_BURST_2D,
|
||||
};
|
||||
|
||||
static const enum dss_feat_id omap5_dss_feat_list[] = {
|
||||
FEAT_MGR_LCD2,
|
||||
FEAT_CORE_CLK_DIV,
|
||||
FEAT_LCD_CLK_SRC,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_GNQ,
|
||||
FEAT_HDMI_CTS_SWMODE,
|
||||
FEAT_HDMI_AUDIO_USE_MCLK,
|
||||
FEAT_HANDLE_UV_SEPARATE,
|
||||
FEAT_ATTR2,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_BURST_2D,
|
||||
FEAT_DSI_PLL_SELFREQDCO,
|
||||
FEAT_DSI_PLL_REFSEL,
|
||||
FEAT_DSI_PHY_DCC,
|
||||
FEAT_MFLAG,
|
||||
};
|
||||
|
||||
/* OMAP2 DSS Features */
|
||||
static const struct omap_dss_features omap2_dss_features = {
|
||||
.reg_fields = omap2_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
|
||||
|
||||
.features = omap2_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap2_dss_feat_list),
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
.supported_displays = omap2_dss_supported_displays,
|
||||
.supported_outputs = omap2_dss_supported_outputs,
|
||||
.supported_color_modes = omap2_dss_supported_color_modes,
|
||||
.overlay_caps = omap2_dss_overlay_caps,
|
||||
.clksrc_names = omap2_dss_clk_source_names,
|
||||
.dss_params = omap2_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
/* OMAP3 DSS Features */
|
||||
static const struct omap_dss_features omap3430_dss_features = {
|
||||
.reg_fields = omap3_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
|
||||
|
||||
.features = omap3430_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap3430_dss_feat_list),
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
.supported_displays = omap3430_dss_supported_displays,
|
||||
.supported_outputs = omap3430_dss_supported_outputs,
|
||||
.supported_color_modes = omap3_dss_supported_color_modes,
|
||||
.overlay_caps = omap3430_dss_overlay_caps,
|
||||
.clksrc_names = omap3_dss_clk_source_names,
|
||||
.dss_params = omap3_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
* AM35xx DSS Features. This is basically OMAP3 DSS Features without the
|
||||
* vdds_dsi regulator.
|
||||
*/
|
||||
static const struct omap_dss_features am35xx_dss_features = {
|
||||
.reg_fields = omap3_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
|
||||
|
||||
.features = am35xx_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(am35xx_dss_feat_list),
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
.supported_displays = omap3430_dss_supported_displays,
|
||||
.supported_outputs = omap3430_dss_supported_outputs,
|
||||
.supported_color_modes = omap3_dss_supported_color_modes,
|
||||
.overlay_caps = omap3430_dss_overlay_caps,
|
||||
.clksrc_names = omap3_dss_clk_source_names,
|
||||
.dss_params = omap3_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
static const struct omap_dss_features omap3630_dss_features = {
|
||||
.reg_fields = omap3_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
|
||||
|
||||
.features = omap3630_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap3630_dss_feat_list),
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
.supported_displays = omap3630_dss_supported_displays,
|
||||
.supported_outputs = omap3630_dss_supported_outputs,
|
||||
.supported_color_modes = omap3_dss_supported_color_modes,
|
||||
.overlay_caps = omap3630_dss_overlay_caps,
|
||||
.clksrc_names = omap3_dss_clk_source_names,
|
||||
.dss_params = omap3_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
/* OMAP4 DSS Features */
|
||||
/* For OMAP4430 ES 1.0 revision */
|
||||
static const struct omap_dss_features omap4430_es1_0_dss_features = {
|
||||
.reg_fields = omap4_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
|
||||
|
||||
.features = omap4430_es1_0_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list),
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 4,
|
||||
.num_wbs = 1,
|
||||
.supported_displays = omap4_dss_supported_displays,
|
||||
.supported_outputs = omap4_dss_supported_outputs,
|
||||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.overlay_caps = omap4_dss_overlay_caps,
|
||||
.clksrc_names = omap4_dss_clk_source_names,
|
||||
.dss_params = omap4_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */
|
||||
static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
|
||||
.reg_fields = omap4_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
|
||||
|
||||
.features = omap4430_es2_0_1_2_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list),
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 4,
|
||||
.num_wbs = 1,
|
||||
.supported_displays = omap4_dss_supported_displays,
|
||||
.supported_outputs = omap4_dss_supported_outputs,
|
||||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.overlay_caps = omap4_dss_overlay_caps,
|
||||
.clksrc_names = omap4_dss_clk_source_names,
|
||||
.dss_params = omap4_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* For all the other OMAP4 versions */
|
||||
static const struct omap_dss_features omap4_dss_features = {
|
||||
.reg_fields = omap4_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
|
||||
|
||||
.features = omap4_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap4_dss_feat_list),
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 4,
|
||||
.num_wbs = 1,
|
||||
.supported_displays = omap4_dss_supported_displays,
|
||||
.supported_outputs = omap4_dss_supported_outputs,
|
||||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.overlay_caps = omap4_dss_overlay_caps,
|
||||
.clksrc_names = omap4_dss_clk_source_names,
|
||||
.dss_params = omap4_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* OMAP5 DSS Features */
|
||||
static const struct omap_dss_features omap5_dss_features = {
|
||||
.reg_fields = omap5_dss_reg_fields,
|
||||
.num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
|
||||
|
||||
.features = omap5_dss_feat_list,
|
||||
.num_features = ARRAY_SIZE(omap5_dss_feat_list),
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 4,
|
||||
.supported_displays = omap5_dss_supported_displays,
|
||||
.supported_outputs = omap5_dss_supported_outputs,
|
||||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.overlay_caps = omap4_dss_overlay_caps,
|
||||
.clksrc_names = omap5_dss_clk_source_names,
|
||||
.dss_params = omap5_dss_param_range,
|
||||
.supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* Functions returning values related to a DSS feature */
|
||||
int dss_feat_get_num_mgrs(void)
|
||||
{
|
||||
return omap_current_dss_features->num_mgrs;
|
||||
}
|
||||
EXPORT_SYMBOL(dss_feat_get_num_mgrs);
|
||||
|
||||
int dss_feat_get_num_ovls(void)
|
||||
{
|
||||
return omap_current_dss_features->num_ovls;
|
||||
}
|
||||
EXPORT_SYMBOL(dss_feat_get_num_ovls);
|
||||
|
||||
int dss_feat_get_num_wbs(void)
|
||||
{
|
||||
return omap_current_dss_features->num_wbs;
|
||||
}
|
||||
|
||||
unsigned long dss_feat_get_param_min(enum dss_range_param param)
|
||||
{
|
||||
return omap_current_dss_features->dss_params[param].min;
|
||||
}
|
||||
|
||||
unsigned long dss_feat_get_param_max(enum dss_range_param param)
|
||||
{
|
||||
return omap_current_dss_features->dss_params[param].max;
|
||||
}
|
||||
|
||||
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
|
||||
{
|
||||
return omap_current_dss_features->supported_displays[channel];
|
||||
}
|
||||
EXPORT_SYMBOL(dss_feat_get_supported_displays);
|
||||
|
||||
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
|
||||
{
|
||||
return omap_current_dss_features->supported_outputs[channel];
|
||||
}
|
||||
EXPORT_SYMBOL(dss_feat_get_supported_outputs);
|
||||
|
||||
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
|
||||
{
|
||||
return omap_current_dss_features->supported_color_modes[plane];
|
||||
}
|
||||
EXPORT_SYMBOL(dss_feat_get_supported_color_modes);
|
||||
|
||||
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
|
||||
{
|
||||
return omap_current_dss_features->overlay_caps[plane];
|
||||
}
|
||||
|
||||
bool dss_feat_color_mode_supported(enum omap_plane plane,
|
||||
enum omap_color_mode color_mode)
|
||||
{
|
||||
return omap_current_dss_features->supported_color_modes[plane] &
|
||||
color_mode;
|
||||
}
|
||||
|
||||
const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
|
||||
{
|
||||
return omap_current_dss_features->clksrc_names[id];
|
||||
}
|
||||
|
||||
u32 dss_feat_get_buffer_size_unit(void)
|
||||
{
|
||||
return omap_current_dss_features->buffer_size_unit;
|
||||
}
|
||||
|
||||
u32 dss_feat_get_burst_size_unit(void)
|
||||
{
|
||||
return omap_current_dss_features->burst_size_unit;
|
||||
}
|
||||
|
||||
/* DSS has_feature check */
|
||||
bool dss_has_feature(enum dss_feat_id id)
|
||||
{
|
||||
int i;
|
||||
const enum dss_feat_id *features = omap_current_dss_features->features;
|
||||
const int num_features = omap_current_dss_features->num_features;
|
||||
|
||||
for (i = 0; i < num_features; i++) {
|
||||
if (features[i] == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
|
||||
{
|
||||
if (id >= omap_current_dss_features->num_reg_fields)
|
||||
BUG();
|
||||
|
||||
*start = omap_current_dss_features->reg_fields[id].start;
|
||||
*end = omap_current_dss_features->reg_fields[id].end;
|
||||
}
|
||||
|
||||
bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
|
||||
{
|
||||
return omap_current_dss_features->supported_rotation_types & rot_type;
|
||||
}
|
||||
|
||||
void dss_features_init(enum omapdss_version version)
|
||||
{
|
||||
switch (version) {
|
||||
case OMAPDSS_VER_OMAP24xx:
|
||||
omap_current_dss_features = &omap2_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP34xx_ES1:
|
||||
case OMAPDSS_VER_OMAP34xx_ES3:
|
||||
omap_current_dss_features = &omap3430_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP3630:
|
||||
omap_current_dss_features = &omap3630_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
omap_current_dss_features = &omap4430_es1_0_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
omap_current_dss_features = &omap4_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
omap_current_dss_features = &omap5_dss_features;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_AM35xx:
|
||||
omap_current_dss_features = &am35xx_dss_features;
|
||||
break;
|
||||
|
||||
default:
|
||||
DSSWARN("Unsupported OMAP version");
|
||||
break;
|
||||
}
|
||||
}
|
117
drivers/video/fbdev/omap2/dss/dss_features.h
Normal file
117
drivers/video/fbdev/omap2/dss/dss_features.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss_features.h
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
* Author: Archit Taneja <archit@ti.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DSS_FEATURES_H
|
||||
#define __OMAP2_DSS_FEATURES_H
|
||||
|
||||
#define MAX_DSS_MANAGERS 4
|
||||
#define MAX_DSS_OVERLAYS 4
|
||||
#define MAX_DSS_LCD_MANAGERS 3
|
||||
#define MAX_NUM_DSI 2
|
||||
|
||||
/* DSS has feature id */
|
||||
enum dss_feat_id {
|
||||
FEAT_LCDENABLEPOL,
|
||||
FEAT_LCDENABLESIGNAL,
|
||||
FEAT_PCKFREEENABLE,
|
||||
FEAT_FUNCGATED,
|
||||
FEAT_MGR_LCD2,
|
||||
FEAT_MGR_LCD3,
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
/* Independent core clk divider */
|
||||
FEAT_CORE_CLK_DIV,
|
||||
FEAT_LCD_CLK_SRC,
|
||||
/* DSI-PLL power command 0x3 is not working */
|
||||
FEAT_DSI_PLL_PWR_BUG,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_DSI_GNQ,
|
||||
FEAT_DPI_USES_VDDS_DSI,
|
||||
FEAT_HDMI_CTS_SWMODE,
|
||||
FEAT_HDMI_AUDIO_USE_MCLK,
|
||||
FEAT_HANDLE_UV_SEPARATE,
|
||||
FEAT_ATTR2,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
FEAT_ALPHA_FIXED_ZORDER,
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
/* An unknown HW bug causing the normal FIFO thresholds not to work */
|
||||
FEAT_OMAP3_DSI_FIFO_BUG,
|
||||
FEAT_BURST_2D,
|
||||
FEAT_DSI_PLL_SELFREQDCO,
|
||||
FEAT_DSI_PLL_REFSEL,
|
||||
FEAT_DSI_PHY_DCC,
|
||||
FEAT_MFLAG,
|
||||
};
|
||||
|
||||
/* DSS register field id */
|
||||
enum dss_feat_reg_field {
|
||||
FEAT_REG_FIRHINC,
|
||||
FEAT_REG_FIRVINC,
|
||||
FEAT_REG_FIFOHIGHTHRESHOLD,
|
||||
FEAT_REG_FIFOLOWTHRESHOLD,
|
||||
FEAT_REG_FIFOSIZE,
|
||||
FEAT_REG_HORIZONTALACCU,
|
||||
FEAT_REG_VERTICALACCU,
|
||||
FEAT_REG_DISPC_CLK_SWITCH,
|
||||
FEAT_REG_DSIPLL_REGN,
|
||||
FEAT_REG_DSIPLL_REGM,
|
||||
FEAT_REG_DSIPLL_REGM_DISPC,
|
||||
FEAT_REG_DSIPLL_REGM_DSI,
|
||||
};
|
||||
|
||||
enum dss_range_param {
|
||||
FEAT_PARAM_DSS_FCK,
|
||||
FEAT_PARAM_DSS_PCD,
|
||||
FEAT_PARAM_DSIPLL_REGN,
|
||||
FEAT_PARAM_DSIPLL_REGM,
|
||||
FEAT_PARAM_DSIPLL_REGM_DISPC,
|
||||
FEAT_PARAM_DSIPLL_REGM_DSI,
|
||||
FEAT_PARAM_DSIPLL_FINT,
|
||||
FEAT_PARAM_DSIPLL_LPDIV,
|
||||
FEAT_PARAM_DSI_FCK,
|
||||
FEAT_PARAM_DOWNSCALE,
|
||||
FEAT_PARAM_LINEWIDTH,
|
||||
};
|
||||
|
||||
/* DSS Feature Functions */
|
||||
int dss_feat_get_num_wbs(void);
|
||||
unsigned long dss_feat_get_param_min(enum dss_range_param param);
|
||||
unsigned long dss_feat_get_param_max(enum dss_range_param param);
|
||||
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
|
||||
bool dss_feat_color_mode_supported(enum omap_plane plane,
|
||||
enum omap_color_mode color_mode);
|
||||
const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
|
||||
|
||||
u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
|
||||
u32 dss_feat_get_burst_size_unit(void); /* in bytes */
|
||||
|
||||
bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
|
||||
|
||||
bool dss_has_feature(enum dss_feat_id id);
|
||||
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
|
||||
void dss_features_init(enum omapdss_version version);
|
||||
#endif
|
444
drivers/video/fbdev/omap2/dss/hdmi.h
Normal file
444
drivers/video/fbdev/omap2/dss/hdmi.h
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* HDMI driver definition for TI OMAP4 Processor.
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _HDMI_H
|
||||
#define _HDMI_H
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
/* HDMI Wrapper */
|
||||
|
||||
#define HDMI_WP_REVISION 0x0
|
||||
#define HDMI_WP_SYSCONFIG 0x10
|
||||
#define HDMI_WP_IRQSTATUS_RAW 0x24
|
||||
#define HDMI_WP_IRQSTATUS 0x28
|
||||
#define HDMI_WP_IRQENABLE_SET 0x2C
|
||||
#define HDMI_WP_IRQENABLE_CLR 0x30
|
||||
#define HDMI_WP_IRQWAKEEN 0x34
|
||||
#define HDMI_WP_PWR_CTRL 0x40
|
||||
#define HDMI_WP_DEBOUNCE 0x44
|
||||
#define HDMI_WP_VIDEO_CFG 0x50
|
||||
#define HDMI_WP_VIDEO_SIZE 0x60
|
||||
#define HDMI_WP_VIDEO_TIMING_H 0x68
|
||||
#define HDMI_WP_VIDEO_TIMING_V 0x6C
|
||||
#define HDMI_WP_CLK 0x70
|
||||
#define HDMI_WP_AUDIO_CFG 0x80
|
||||
#define HDMI_WP_AUDIO_CFG2 0x84
|
||||
#define HDMI_WP_AUDIO_CTRL 0x88
|
||||
#define HDMI_WP_AUDIO_DATA 0x8C
|
||||
|
||||
/* HDMI WP IRQ flags */
|
||||
#define HDMI_IRQ_CORE (1 << 0)
|
||||
#define HDMI_IRQ_OCP_TIMEOUT (1 << 4)
|
||||
#define HDMI_IRQ_AUDIO_FIFO_UNDERFLOW (1 << 8)
|
||||
#define HDMI_IRQ_AUDIO_FIFO_OVERFLOW (1 << 9)
|
||||
#define HDMI_IRQ_AUDIO_FIFO_SAMPLE_REQ (1 << 10)
|
||||
#define HDMI_IRQ_VIDEO_VSYNC (1 << 16)
|
||||
#define HDMI_IRQ_VIDEO_FRAME_DONE (1 << 17)
|
||||
#define HDMI_IRQ_PHY_LINE5V_ASSERT (1 << 24)
|
||||
#define HDMI_IRQ_LINK_CONNECT (1 << 25)
|
||||
#define HDMI_IRQ_LINK_DISCONNECT (1 << 26)
|
||||
#define HDMI_IRQ_PLL_LOCK (1 << 29)
|
||||
#define HDMI_IRQ_PLL_UNLOCK (1 << 30)
|
||||
#define HDMI_IRQ_PLL_RECAL (1 << 31)
|
||||
|
||||
/* HDMI PLL */
|
||||
|
||||
#define PLLCTRL_PLL_CONTROL 0x0
|
||||
#define PLLCTRL_PLL_STATUS 0x4
|
||||
#define PLLCTRL_PLL_GO 0x8
|
||||
#define PLLCTRL_CFG1 0xC
|
||||
#define PLLCTRL_CFG2 0x10
|
||||
#define PLLCTRL_CFG3 0x14
|
||||
#define PLLCTRL_SSC_CFG1 0x18
|
||||
#define PLLCTRL_SSC_CFG2 0x1C
|
||||
#define PLLCTRL_CFG4 0x20
|
||||
|
||||
/* HDMI PHY */
|
||||
|
||||
#define HDMI_TXPHY_TX_CTRL 0x0
|
||||
#define HDMI_TXPHY_DIGITAL_CTRL 0x4
|
||||
#define HDMI_TXPHY_POWER_CTRL 0x8
|
||||
#define HDMI_TXPHY_PAD_CFG_CTRL 0xC
|
||||
|
||||
enum hdmi_pll_pwr {
|
||||
HDMI_PLLPWRCMD_ALLOFF = 0,
|
||||
HDMI_PLLPWRCMD_PLLONLY = 1,
|
||||
HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
|
||||
HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
|
||||
};
|
||||
|
||||
enum hdmi_phy_pwr {
|
||||
HDMI_PHYPWRCMD_OFF = 0,
|
||||
HDMI_PHYPWRCMD_LDOON = 1,
|
||||
HDMI_PHYPWRCMD_TXON = 2
|
||||
};
|
||||
|
||||
enum hdmi_core_hdmi_dvi {
|
||||
HDMI_DVI = 0,
|
||||
HDMI_HDMI = 1
|
||||
};
|
||||
|
||||
enum hdmi_clk_refsel {
|
||||
HDMI_REFSEL_PCLK = 0,
|
||||
HDMI_REFSEL_REF1 = 1,
|
||||
HDMI_REFSEL_REF2 = 2,
|
||||
HDMI_REFSEL_SYSCLK = 3
|
||||
};
|
||||
|
||||
enum hdmi_packing_mode {
|
||||
HDMI_PACK_10b_RGB_YUV444 = 0,
|
||||
HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
|
||||
HDMI_PACK_20b_YUV422 = 2,
|
||||
HDMI_PACK_ALREADYPACKED = 7
|
||||
};
|
||||
|
||||
enum hdmi_stereo_channels {
|
||||
HDMI_AUDIO_STEREO_NOCHANNELS = 0,
|
||||
HDMI_AUDIO_STEREO_ONECHANNEL = 1,
|
||||
HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
|
||||
HDMI_AUDIO_STEREO_THREECHANNELS = 3,
|
||||
HDMI_AUDIO_STEREO_FOURCHANNELS = 4
|
||||
};
|
||||
|
||||
enum hdmi_audio_type {
|
||||
HDMI_AUDIO_TYPE_LPCM = 0,
|
||||
HDMI_AUDIO_TYPE_IEC = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_justify {
|
||||
HDMI_AUDIO_JUSTIFY_LEFT = 0,
|
||||
HDMI_AUDIO_JUSTIFY_RIGHT = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_sample_order {
|
||||
HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
|
||||
HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_samples_perword {
|
||||
HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
|
||||
HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_sample_size {
|
||||
HDMI_AUDIO_SAMPLE_16BITS = 0,
|
||||
HDMI_AUDIO_SAMPLE_24BITS = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_transf_mode {
|
||||
HDMI_AUDIO_TRANSF_DMA = 0,
|
||||
HDMI_AUDIO_TRANSF_IRQ = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_blk_strt_end_sig {
|
||||
HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
|
||||
HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
|
||||
};
|
||||
|
||||
enum hdmi_core_audio_layout {
|
||||
HDMI_AUDIO_LAYOUT_2CH = 0,
|
||||
HDMI_AUDIO_LAYOUT_8CH = 1
|
||||
};
|
||||
|
||||
enum hdmi_core_cts_mode {
|
||||
HDMI_AUDIO_CTS_MODE_HW = 0,
|
||||
HDMI_AUDIO_CTS_MODE_SW = 1
|
||||
};
|
||||
|
||||
enum hdmi_audio_mclk_mode {
|
||||
HDMI_AUDIO_MCLK_128FS = 0,
|
||||
HDMI_AUDIO_MCLK_256FS = 1,
|
||||
HDMI_AUDIO_MCLK_384FS = 2,
|
||||
HDMI_AUDIO_MCLK_512FS = 3,
|
||||
HDMI_AUDIO_MCLK_768FS = 4,
|
||||
HDMI_AUDIO_MCLK_1024FS = 5,
|
||||
HDMI_AUDIO_MCLK_1152FS = 6,
|
||||
HDMI_AUDIO_MCLK_192FS = 7
|
||||
};
|
||||
|
||||
/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
|
||||
enum hdmi_core_infoframe {
|
||||
HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
|
||||
HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
|
||||
HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
|
||||
HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON = 1,
|
||||
HDMI_INFOFRAME_AVI_DB1B_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
|
||||
HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
|
||||
HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
|
||||
HDMI_INFOFRAME_AVI_DB1S_0 = 0,
|
||||
HDMI_INFOFRAME_AVI_DB1S_1 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB1S_2 = 2,
|
||||
HDMI_INFOFRAME_AVI_DB2C_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
|
||||
HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
|
||||
HDMI_INFOFRAME_AVI_DB2M_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB2M_43 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB2M_169 = 2,
|
||||
HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
|
||||
HDMI_INFOFRAME_AVI_DB2R_43 = 9,
|
||||
HDMI_INFOFRAME_AVI_DB2R_169 = 10,
|
||||
HDMI_INFOFRAME_AVI_DB2R_149 = 11,
|
||||
HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
|
||||
HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
|
||||
HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
|
||||
HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
|
||||
HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
|
||||
HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
|
||||
HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
|
||||
HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
|
||||
HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
|
||||
};
|
||||
|
||||
struct hdmi_cm {
|
||||
int code;
|
||||
int mode;
|
||||
};
|
||||
|
||||
struct hdmi_video_format {
|
||||
enum hdmi_packing_mode packing_mode;
|
||||
u32 y_res; /* Line per panel */
|
||||
u32 x_res; /* pixel per line */
|
||||
};
|
||||
|
||||
struct hdmi_config {
|
||||
struct omap_video_timings timings;
|
||||
struct hdmi_cm cm;
|
||||
};
|
||||
|
||||
/* HDMI PLL structure */
|
||||
struct hdmi_pll_info {
|
||||
u16 regn;
|
||||
u16 regm;
|
||||
u32 regmf;
|
||||
u16 regm2;
|
||||
u16 regsd;
|
||||
u16 dcofreq;
|
||||
enum hdmi_clk_refsel refsel;
|
||||
};
|
||||
|
||||
struct hdmi_audio_format {
|
||||
enum hdmi_stereo_channels stereo_channels;
|
||||
u8 active_chnnls_msk;
|
||||
enum hdmi_audio_type type;
|
||||
enum hdmi_audio_justify justification;
|
||||
enum hdmi_audio_sample_order sample_order;
|
||||
enum hdmi_audio_samples_perword samples_per_word;
|
||||
enum hdmi_audio_sample_size sample_size;
|
||||
enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end;
|
||||
};
|
||||
|
||||
struct hdmi_audio_dma {
|
||||
u8 transfer_size;
|
||||
u8 block_size;
|
||||
enum hdmi_audio_transf_mode mode;
|
||||
u16 fifo_threshold;
|
||||
};
|
||||
|
||||
struct hdmi_core_audio_i2s_config {
|
||||
u8 in_length_bits;
|
||||
u8 justification;
|
||||
u8 sck_edge_mode;
|
||||
u8 vbit;
|
||||
u8 direction;
|
||||
u8 shift;
|
||||
u8 active_sds;
|
||||
};
|
||||
|
||||
struct hdmi_core_audio_config {
|
||||
struct hdmi_core_audio_i2s_config i2s_cfg;
|
||||
struct snd_aes_iec958 *iec60958_cfg;
|
||||
bool fs_override;
|
||||
u32 n;
|
||||
u32 cts;
|
||||
u32 aud_par_busclk;
|
||||
enum hdmi_core_audio_layout layout;
|
||||
enum hdmi_core_cts_mode cts_mode;
|
||||
bool use_mclk;
|
||||
enum hdmi_audio_mclk_mode mclk_mode;
|
||||
bool en_acr_pkt;
|
||||
bool en_dsd_audio;
|
||||
bool en_parallel_aud_input;
|
||||
bool en_spdif;
|
||||
};
|
||||
|
||||
/*
|
||||
* Refer to section 8.2 in HDMI 1.3 specification for
|
||||
* details about infoframe databytes
|
||||
*/
|
||||
struct hdmi_core_infoframe_avi {
|
||||
/* Y0, Y1 rgb,yCbCr */
|
||||
u8 db1_format;
|
||||
/* A0 Active information Present */
|
||||
u8 db1_active_info;
|
||||
/* B0, B1 Bar info data valid */
|
||||
u8 db1_bar_info_dv;
|
||||
/* S0, S1 scan information */
|
||||
u8 db1_scan_info;
|
||||
/* C0, C1 colorimetry */
|
||||
u8 db2_colorimetry;
|
||||
/* M0, M1 Aspect ratio (4:3, 16:9) */
|
||||
u8 db2_aspect_ratio;
|
||||
/* R0...R3 Active format aspect ratio */
|
||||
u8 db2_active_fmt_ar;
|
||||
/* ITC IT content. */
|
||||
u8 db3_itc;
|
||||
/* EC0, EC1, EC2 Extended colorimetry */
|
||||
u8 db3_ec;
|
||||
/* Q1, Q0 Quantization range */
|
||||
u8 db3_q_range;
|
||||
/* SC1, SC0 Non-uniform picture scaling */
|
||||
u8 db3_nup_scaling;
|
||||
/* VIC0..6 Video format identification */
|
||||
u8 db4_videocode;
|
||||
/* PR0..PR3 Pixel repetition factor */
|
||||
u8 db5_pixel_repeat;
|
||||
/* Line number end of top bar */
|
||||
u16 db6_7_line_eoftop;
|
||||
/* Line number start of bottom bar */
|
||||
u16 db8_9_line_sofbottom;
|
||||
/* Pixel number end of left bar */
|
||||
u16 db10_11_pixel_eofleft;
|
||||
/* Pixel number start of right bar */
|
||||
u16 db12_13_pixel_sofright;
|
||||
};
|
||||
|
||||
struct hdmi_wp_data {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
struct hdmi_pll_data {
|
||||
void __iomem *base;
|
||||
|
||||
struct hdmi_pll_info info;
|
||||
};
|
||||
|
||||
struct hdmi_phy_data {
|
||||
void __iomem *base;
|
||||
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct hdmi_core_data {
|
||||
void __iomem *base;
|
||||
|
||||
struct hdmi_core_infoframe_avi avi_cfg;
|
||||
};
|
||||
|
||||
static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx,
|
||||
u32 val)
|
||||
{
|
||||
__raw_writel(val, base_addr + idx);
|
||||
}
|
||||
|
||||
static inline u32 hdmi_read_reg(void __iomem *base_addr, const u16 idx)
|
||||
{
|
||||
return __raw_readl(base_addr + idx);
|
||||
}
|
||||
|
||||
#define REG_FLD_MOD(base, idx, val, start, end) \
|
||||
hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
|
||||
val, start, end))
|
||||
#define REG_GET(base, idx, start, end) \
|
||||
FLD_GET(hdmi_read_reg(base, idx), start, end)
|
||||
|
||||
static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
|
||||
const u32 idx, int b2, int b1, u32 val)
|
||||
{
|
||||
u32 t = 0, v;
|
||||
while (val != (v = REG_GET(base_addr, idx, b2, b1))) {
|
||||
if (t++ > 10000)
|
||||
return v;
|
||||
udelay(1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* HDMI wrapper funcs */
|
||||
int hdmi_wp_video_start(struct hdmi_wp_data *wp);
|
||||
void hdmi_wp_video_stop(struct hdmi_wp_data *wp);
|
||||
void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s);
|
||||
u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp);
|
||||
void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus);
|
||||
void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask);
|
||||
void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
|
||||
int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
|
||||
int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
|
||||
void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
|
||||
struct hdmi_video_format *video_fmt);
|
||||
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
|
||||
struct omap_video_timings *timings);
|
||||
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
|
||||
struct omap_video_timings *timings);
|
||||
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
|
||||
struct omap_video_timings *timings, struct hdmi_config *param);
|
||||
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
|
||||
|
||||
/* HDMI PLL funcs */
|
||||
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
|
||||
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
|
||||
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
|
||||
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
|
||||
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
|
||||
|
||||
/* HDMI PHY funcs */
|
||||
int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
|
||||
struct hdmi_config *cfg);
|
||||
void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp);
|
||||
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
|
||||
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
|
||||
|
||||
/* HDMI common funcs */
|
||||
const struct hdmi_config *hdmi_default_timing(void);
|
||||
const struct hdmi_config *hdmi_get_timings(int mode, int code);
|
||||
struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing);
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
|
||||
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
|
||||
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
|
||||
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
|
||||
struct hdmi_audio_format *aud_fmt);
|
||||
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
|
||||
struct hdmi_audio_dma *aud_dma);
|
||||
static inline bool hdmi_mode_has_audio(int mode)
|
||||
{
|
||||
return mode == HDMI_HDMI ? true : false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
703
drivers/video/fbdev/omap2/dss/hdmi4.c
Normal file
703
drivers/video/fbdev/omap2/dss/hdmi4.c
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
* HDMI interface DSS driver for TI's OMAP4 family of SoCs.
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Authors: Yong Zhi
|
||||
* Mythri pk <mythripk@ti.com>
|
||||
*
|
||||
* 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 "HDMI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "hdmi4_core.h"
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
struct mutex lock;
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct hdmi_wp_data wp;
|
||||
struct hdmi_pll_data pll;
|
||||
struct hdmi_phy_data phy;
|
||||
struct hdmi_core_data core;
|
||||
|
||||
struct hdmi_config cfg;
|
||||
|
||||
struct clk *sys_clk;
|
||||
struct regulator *vdda_hdmi_dac_reg;
|
||||
|
||||
bool core_enabled;
|
||||
|
||||
struct omap_dss_device output;
|
||||
} hdmi;
|
||||
|
||||
static int hdmi_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("hdmi_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&hdmi.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("hdmi_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put_sync(&hdmi.pdev->dev);
|
||||
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");
|
||||
|
||||
if (IS_ERR(reg)) {
|
||||
if (PTR_ERR(reg) != -EPROBE_DEFER)
|
||||
DSSERR("can't get VDDA regulator\n");
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
hdmi.vdda_hdmi_dac_reg = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_power_on_core(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_runtime_get();
|
||||
if (r)
|
||||
goto err_runtime_get;
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
unsigned long phy;
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
p = &hdmi.cfg.timings;
|
||||
|
||||
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
|
||||
|
||||
/* the functions below use kHz pixel clock. TODO: change to Hz */
|
||||
phy = p->pixelclock / 1000;
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
|
||||
|
||||
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
|
||||
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
|
||||
if (r) {
|
||||
DSSDBG("Failed to lock PLL\n");
|
||||
goto err_pll_enable;
|
||||
}
|
||||
|
||||
r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg);
|
||||
if (r) {
|
||||
DSSDBG("Failed to start PHY\n");
|
||||
goto err_phy_enable;
|
||||
}
|
||||
|
||||
hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
|
||||
|
||||
/* bypass TV gamma table */
|
||||
dispc_enable_gamma_table(0);
|
||||
|
||||
/* tv size */
|
||||
dss_mgr_set_timings(mgr, p);
|
||||
|
||||
r = hdmi_wp_video_start(&hdmi.wp);
|
||||
if (r)
|
||||
goto err_vid_enable;
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
err_vid_enable:
|
||||
hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
|
||||
err_phy_enable:
|
||||
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
err_pll_enable:
|
||||
hdmi_power_off_core(dssdev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
|
||||
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
|
||||
hdmi_power_off_core(dssdev);
|
||||
}
|
||||
|
||||
static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct hdmi_cm cm;
|
||||
const struct hdmi_config *t;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
cm = hdmi_get_code(timings);
|
||||
hdmi.cfg.cm = cm;
|
||||
|
||||
t = hdmi_get_timings(cm.mode, cm.code);
|
||||
if (t != NULL) {
|
||||
hdmi.cfg = *t;
|
||||
|
||||
dispc_set_tv_pclk(t->timings.pixelclock);
|
||||
} else {
|
||||
hdmi.cfg.timings = *timings;
|
||||
hdmi.cfg.cm.code = 0;
|
||||
hdmi.cfg.cm.mode = HDMI_DVI;
|
||||
|
||||
dispc_set_tv_pclk(timings->pixelclock);
|
||||
}
|
||||
|
||||
DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ?
|
||||
"DVI" : "HDMI", hdmi.cfg.cm.code);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
const struct hdmi_config *cfg;
|
||||
struct hdmi_cm cm = hdmi.cfg.cm;
|
||||
|
||||
cfg = hdmi_get_timings(cm.mode, cm.code);
|
||||
if (cfg == NULL)
|
||||
cfg = hdmi_default_timing();
|
||||
|
||||
memcpy(timings, &cfg->timings, sizeof(cfg->timings));
|
||||
}
|
||||
|
||||
static void hdmi_dump_regs(struct seq_file *s)
|
||||
{
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (hdmi_runtime_get()) {
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
hdmi_wp_dump(&hdmi.wp, s);
|
||||
hdmi_pll_dump(&hdmi.pll, s);
|
||||
hdmi_phy_dump(&hdmi.phy, s);
|
||||
hdmi4_core_dump(&hdmi.core, s);
|
||||
|
||||
hdmi_runtime_put();
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static int read_edid(u8 *buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
r = hdmi_runtime_get();
|
||||
BUG_ON(r);
|
||||
|
||||
r = hdmi4_read_edid(&hdmi.core, buf, len);
|
||||
|
||||
hdmi_runtime_put();
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (out == NULL || out->manager == NULL) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = hdmi_power_on_full(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("Enter hdmi_display_disable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
hdmi_power_off_full(dssdev);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static int hdmi_core_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("ENTER omapdss_hdmi_core_enable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_core_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("Enter omapdss_hdmi_core_disable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
hdmi_power_off_core(dssdev);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static int hdmi_get_clocks(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "sys_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get sys_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
hdmi.sys_clk = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
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->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
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 = hdmi_core_enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = read_edid(edid, len);
|
||||
|
||||
if (need_enable)
|
||||
hdmi_core_disable(dssdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_wp_audio_enable(&hdmi.wp, true);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
hdmi_wp_audio_enable(&hdmi.wp, false);
|
||||
}
|
||||
|
||||
static int hdmi_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
|
||||
}
|
||||
|
||||
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
|
||||
}
|
||||
|
||||
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
bool r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
r = hdmi_mode_has_audio(hdmi.cfg.cm.mode);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int hdmi_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
int r;
|
||||
u32 pclk = hdmi.cfg.timings.pixelclock;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int hdmi_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int 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 = hdmi_display_enable,
|
||||
.disable = hdmi_display_disable,
|
||||
|
||||
.check_timings = hdmi_display_check_timing,
|
||||
.set_timings = hdmi_display_set_timing,
|
||||
.get_timings = hdmi_display_get_timings,
|
||||
|
||||
.read_edid = hdmi_read_edid,
|
||||
|
||||
.audio_enable = hdmi_audio_enable,
|
||||
.audio_disable = hdmi_audio_disable,
|
||||
.audio_start = hdmi_audio_start,
|
||||
.audio_stop = hdmi_audio_stop,
|
||||
.audio_supported = hdmi_audio_supported,
|
||||
.audio_config = hdmi_audio_config,
|
||||
};
|
||||
|
||||
static void hdmi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_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;
|
||||
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit hdmi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
/* HDMI HW IP initialisation */
|
||||
static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
hdmi.pdev = pdev;
|
||||
|
||||
mutex_init(&hdmi.lock);
|
||||
|
||||
r = hdmi_wp_init(pdev, &hdmi.wp);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_init(pdev, &hdmi.pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_phy_init(pdev, &hdmi.phy);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi4_core_init(pdev, &hdmi.core);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_get_clocks(pdev);
|
||||
if (r) {
|
||||
DSSERR("can't get clocks\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
hdmi_init_output(pdev);
|
||||
|
||||
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
|
||||
{
|
||||
hdmi_uninit_output(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable_unprepare(hdmi.sys_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
clk_prepare_enable(hdmi.sys_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops hdmi_pm_ops = {
|
||||
.runtime_suspend = hdmi_runtime_suspend,
|
||||
.runtime_resume = hdmi_runtime_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id hdmi_of_match[] = {
|
||||
{ .compatible = "ti,omap4-hdmi", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver omapdss_hdmihw_driver = {
|
||||
.probe = omapdss_hdmihw_probe,
|
||||
.remove = __exit_p(omapdss_hdmihw_remove),
|
||||
.driver = {
|
||||
.name = "omapdss_hdmi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &hdmi_pm_ops,
|
||||
.of_match_table = hdmi_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
int __init hdmi4_init_platform_driver(void)
|
||||
{
|
||||
return platform_driver_register(&omapdss_hdmihw_driver);
|
||||
}
|
||||
|
||||
void __exit hdmi4_uninit_platform_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omapdss_hdmihw_driver);
|
||||
}
|
1036
drivers/video/fbdev/omap2/dss/hdmi4_core.c
Normal file
1036
drivers/video/fbdev/omap2/dss/hdmi4_core.c
Normal file
File diff suppressed because it is too large
Load Diff
276
drivers/video/fbdev/omap2/dss/hdmi4_core.h
Normal file
276
drivers/video/fbdev/omap2/dss/hdmi4_core.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* HDMI header definition for OMAP4 HDMI core IP
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _HDMI4_CORE_H_
|
||||
#define _HDMI4_CORE_H_
|
||||
|
||||
#include "hdmi.h"
|
||||
|
||||
/* OMAP4 HDMI IP Core System */
|
||||
|
||||
#define HDMI_CORE_SYS_VND_IDL 0x0
|
||||
#define HDMI_CORE_SYS_DEV_IDL 0x8
|
||||
#define HDMI_CORE_SYS_DEV_IDH 0xC
|
||||
#define HDMI_CORE_SYS_DEV_REV 0x10
|
||||
#define HDMI_CORE_SYS_SRST 0x14
|
||||
#define HDMI_CORE_SYS_SYS_CTRL1 0x20
|
||||
#define HDMI_CORE_SYS_SYS_STAT 0x24
|
||||
#define HDMI_CORE_SYS_SYS_CTRL3 0x28
|
||||
#define HDMI_CORE_SYS_DCTL 0x34
|
||||
#define HDMI_CORE_SYS_DE_DLY 0xC8
|
||||
#define HDMI_CORE_SYS_DE_CTRL 0xCC
|
||||
#define HDMI_CORE_SYS_DE_TOP 0xD0
|
||||
#define HDMI_CORE_SYS_DE_CNTL 0xD8
|
||||
#define HDMI_CORE_SYS_DE_CNTH 0xDC
|
||||
#define HDMI_CORE_SYS_DE_LINL 0xE0
|
||||
#define HDMI_CORE_SYS_DE_LINH_1 0xE4
|
||||
#define HDMI_CORE_SYS_HRES_L 0xE8
|
||||
#define HDMI_CORE_SYS_HRES_H 0xEC
|
||||
#define HDMI_CORE_SYS_VRES_L 0xF0
|
||||
#define HDMI_CORE_SYS_VRES_H 0xF4
|
||||
#define HDMI_CORE_SYS_IADJUST 0xF8
|
||||
#define HDMI_CORE_SYS_POLDETECT 0xFC
|
||||
#define HDMI_CORE_SYS_HWIDTH1 0x110
|
||||
#define HDMI_CORE_SYS_HWIDTH2 0x114
|
||||
#define HDMI_CORE_SYS_VWIDTH 0x11C
|
||||
#define HDMI_CORE_SYS_VID_CTRL 0x120
|
||||
#define HDMI_CORE_SYS_VID_ACEN 0x124
|
||||
#define HDMI_CORE_SYS_VID_MODE 0x128
|
||||
#define HDMI_CORE_SYS_VID_BLANK1 0x12C
|
||||
#define HDMI_CORE_SYS_VID_BLANK2 0x130
|
||||
#define HDMI_CORE_SYS_VID_BLANK3 0x134
|
||||
#define HDMI_CORE_SYS_DC_HEADER 0x138
|
||||
#define HDMI_CORE_SYS_VID_DITHER 0x13C
|
||||
#define HDMI_CORE_SYS_RGB2XVYCC_CT 0x140
|
||||
#define HDMI_CORE_SYS_R2Y_COEFF_LOW 0x144
|
||||
#define HDMI_CORE_SYS_R2Y_COEFF_UP 0x148
|
||||
#define HDMI_CORE_SYS_G2Y_COEFF_LOW 0x14C
|
||||
#define HDMI_CORE_SYS_G2Y_COEFF_UP 0x150
|
||||
#define HDMI_CORE_SYS_B2Y_COEFF_LOW 0x154
|
||||
#define HDMI_CORE_SYS_B2Y_COEFF_UP 0x158
|
||||
#define HDMI_CORE_SYS_R2CB_COEFF_LOW 0x15C
|
||||
#define HDMI_CORE_SYS_R2CB_COEFF_UP 0x160
|
||||
#define HDMI_CORE_SYS_G2CB_COEFF_LOW 0x164
|
||||
#define HDMI_CORE_SYS_G2CB_COEFF_UP 0x168
|
||||
#define HDMI_CORE_SYS_B2CB_COEFF_LOW 0x16C
|
||||
#define HDMI_CORE_SYS_B2CB_COEFF_UP 0x170
|
||||
#define HDMI_CORE_SYS_R2CR_COEFF_LOW 0x174
|
||||
#define HDMI_CORE_SYS_R2CR_COEFF_UP 0x178
|
||||
#define HDMI_CORE_SYS_G2CR_COEFF_LOW 0x17C
|
||||
#define HDMI_CORE_SYS_G2CR_COEFF_UP 0x180
|
||||
#define HDMI_CORE_SYS_B2CR_COEFF_LOW 0x184
|
||||
#define HDMI_CORE_SYS_B2CR_COEFF_UP 0x188
|
||||
#define HDMI_CORE_SYS_RGB_OFFSET_LOW 0x18C
|
||||
#define HDMI_CORE_SYS_RGB_OFFSET_UP 0x190
|
||||
#define HDMI_CORE_SYS_Y_OFFSET_LOW 0x194
|
||||
#define HDMI_CORE_SYS_Y_OFFSET_UP 0x198
|
||||
#define HDMI_CORE_SYS_CBCR_OFFSET_LOW 0x19C
|
||||
#define HDMI_CORE_SYS_CBCR_OFFSET_UP 0x1A0
|
||||
#define HDMI_CORE_SYS_INTR_STATE 0x1C0
|
||||
#define HDMI_CORE_SYS_INTR1 0x1C4
|
||||
#define HDMI_CORE_SYS_INTR2 0x1C8
|
||||
#define HDMI_CORE_SYS_INTR3 0x1CC
|
||||
#define HDMI_CORE_SYS_INTR4 0x1D0
|
||||
#define HDMI_CORE_SYS_INTR_UNMASK1 0x1D4
|
||||
#define HDMI_CORE_SYS_INTR_UNMASK2 0x1D8
|
||||
#define HDMI_CORE_SYS_INTR_UNMASK3 0x1DC
|
||||
#define HDMI_CORE_SYS_INTR_UNMASK4 0x1E0
|
||||
#define HDMI_CORE_SYS_INTR_CTRL 0x1E4
|
||||
#define HDMI_CORE_SYS_TMDS_CTRL 0x208
|
||||
|
||||
/* value definitions for HDMI_CORE_SYS_SYS_CTRL1 fields */
|
||||
#define HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC 0x1
|
||||
#define HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC 0x1
|
||||
#define HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS 0x1
|
||||
#define HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE 0x1
|
||||
|
||||
/* HDMI DDC E-DID */
|
||||
#define HDMI_CORE_DDC_ADDR 0x3B4
|
||||
#define HDMI_CORE_DDC_SEGM 0x3B8
|
||||
#define HDMI_CORE_DDC_OFFSET 0x3BC
|
||||
#define HDMI_CORE_DDC_COUNT1 0x3C0
|
||||
#define HDMI_CORE_DDC_COUNT2 0x3C4
|
||||
#define HDMI_CORE_DDC_STATUS 0x3C8
|
||||
#define HDMI_CORE_DDC_CMD 0x3CC
|
||||
#define HDMI_CORE_DDC_DATA 0x3D0
|
||||
|
||||
/* HDMI IP Core Audio Video */
|
||||
|
||||
#define HDMI_CORE_AV_ACR_CTRL 0x4
|
||||
#define HDMI_CORE_AV_FREQ_SVAL 0x8
|
||||
#define HDMI_CORE_AV_N_SVAL1 0xC
|
||||
#define HDMI_CORE_AV_N_SVAL2 0x10
|
||||
#define HDMI_CORE_AV_N_SVAL3 0x14
|
||||
#define HDMI_CORE_AV_CTS_SVAL1 0x18
|
||||
#define HDMI_CORE_AV_CTS_SVAL2 0x1C
|
||||
#define HDMI_CORE_AV_CTS_SVAL3 0x20
|
||||
#define HDMI_CORE_AV_CTS_HVAL1 0x24
|
||||
#define HDMI_CORE_AV_CTS_HVAL2 0x28
|
||||
#define HDMI_CORE_AV_CTS_HVAL3 0x2C
|
||||
#define HDMI_CORE_AV_AUD_MODE 0x50
|
||||
#define HDMI_CORE_AV_SPDIF_CTRL 0x54
|
||||
#define HDMI_CORE_AV_HW_SPDIF_FS 0x60
|
||||
#define HDMI_CORE_AV_SWAP_I2S 0x64
|
||||
#define HDMI_CORE_AV_SPDIF_ERTH 0x6C
|
||||
#define HDMI_CORE_AV_I2S_IN_MAP 0x70
|
||||
#define HDMI_CORE_AV_I2S_IN_CTRL 0x74
|
||||
#define HDMI_CORE_AV_I2S_CHST0 0x78
|
||||
#define HDMI_CORE_AV_I2S_CHST1 0x7C
|
||||
#define HDMI_CORE_AV_I2S_CHST2 0x80
|
||||
#define HDMI_CORE_AV_I2S_CHST4 0x84
|
||||
#define HDMI_CORE_AV_I2S_CHST5 0x88
|
||||
#define HDMI_CORE_AV_ASRC 0x8C
|
||||
#define HDMI_CORE_AV_I2S_IN_LEN 0x90
|
||||
#define HDMI_CORE_AV_HDMI_CTRL 0xBC
|
||||
#define HDMI_CORE_AV_AUDO_TXSTAT 0xC0
|
||||
#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC
|
||||
#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0
|
||||
#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4
|
||||
#define HDMI_CORE_AV_TEST_TXCTRL 0xF0
|
||||
#define HDMI_CORE_AV_DPD 0xF4
|
||||
#define HDMI_CORE_AV_PB_CTRL1 0xF8
|
||||
#define HDMI_CORE_AV_PB_CTRL2 0xFC
|
||||
#define HDMI_CORE_AV_AVI_TYPE 0x100
|
||||
#define HDMI_CORE_AV_AVI_VERS 0x104
|
||||
#define HDMI_CORE_AV_AVI_LEN 0x108
|
||||
#define HDMI_CORE_AV_AVI_CHSUM 0x10C
|
||||
#define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110)
|
||||
#define HDMI_CORE_AV_SPD_TYPE 0x180
|
||||
#define HDMI_CORE_AV_SPD_VERS 0x184
|
||||
#define HDMI_CORE_AV_SPD_LEN 0x188
|
||||
#define HDMI_CORE_AV_SPD_CHSUM 0x18C
|
||||
#define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190)
|
||||
#define HDMI_CORE_AV_AUDIO_TYPE 0x200
|
||||
#define HDMI_CORE_AV_AUDIO_VERS 0x204
|
||||
#define HDMI_CORE_AV_AUDIO_LEN 0x208
|
||||
#define HDMI_CORE_AV_AUDIO_CHSUM 0x20C
|
||||
#define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210)
|
||||
#define HDMI_CORE_AV_MPEG_TYPE 0x280
|
||||
#define HDMI_CORE_AV_MPEG_VERS 0x284
|
||||
#define HDMI_CORE_AV_MPEG_LEN 0x288
|
||||
#define HDMI_CORE_AV_MPEG_CHSUM 0x28C
|
||||
#define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290)
|
||||
#define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300)
|
||||
#define HDMI_CORE_AV_CP_BYTE1 0x37C
|
||||
#define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380)
|
||||
#define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC
|
||||
|
||||
#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4
|
||||
#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4
|
||||
#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4
|
||||
#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4
|
||||
|
||||
#define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15
|
||||
#define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27
|
||||
#define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10
|
||||
#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27
|
||||
#define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31
|
||||
#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31
|
||||
|
||||
enum hdmi_core_inputbus_width {
|
||||
HDMI_INPUT_8BIT = 0,
|
||||
HDMI_INPUT_10BIT = 1,
|
||||
HDMI_INPUT_12BIT = 2
|
||||
};
|
||||
|
||||
enum hdmi_core_dither_trunc {
|
||||
HDMI_OUTPUTTRUNCATION_8BIT = 0,
|
||||
HDMI_OUTPUTTRUNCATION_10BIT = 1,
|
||||
HDMI_OUTPUTTRUNCATION_12BIT = 2,
|
||||
HDMI_OUTPUTDITHER_8BIT = 3,
|
||||
HDMI_OUTPUTDITHER_10BIT = 4,
|
||||
HDMI_OUTPUTDITHER_12BIT = 5
|
||||
};
|
||||
|
||||
enum hdmi_core_deepcolor_ed {
|
||||
HDMI_DEEPCOLORPACKECTDISABLE = 0,
|
||||
HDMI_DEEPCOLORPACKECTENABLE = 1
|
||||
};
|
||||
|
||||
enum hdmi_core_packet_mode {
|
||||
HDMI_PACKETMODERESERVEDVALUE = 0,
|
||||
HDMI_PACKETMODE24BITPERPIXEL = 4,
|
||||
HDMI_PACKETMODE30BITPERPIXEL = 5,
|
||||
HDMI_PACKETMODE36BITPERPIXEL = 6,
|
||||
HDMI_PACKETMODE48BITPERPIXEL = 7
|
||||
};
|
||||
|
||||
enum hdmi_core_tclkselclkmult {
|
||||
HDMI_FPLL05IDCK = 0,
|
||||
HDMI_FPLL10IDCK = 1,
|
||||
HDMI_FPLL20IDCK = 2,
|
||||
HDMI_FPLL40IDCK = 3
|
||||
};
|
||||
|
||||
enum hdmi_core_packet_ctrl {
|
||||
HDMI_PACKETENABLE = 1,
|
||||
HDMI_PACKETDISABLE = 0,
|
||||
HDMI_PACKETREPEATON = 1,
|
||||
HDMI_PACKETREPEATOFF = 0
|
||||
};
|
||||
|
||||
enum hdmi_audio_i2s_config {
|
||||
HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
|
||||
HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
|
||||
HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
|
||||
HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
|
||||
HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
|
||||
HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
|
||||
HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
|
||||
HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
|
||||
HDMI_AUDIO_I2S_SD0_EN = 1,
|
||||
HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
|
||||
HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
|
||||
HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
|
||||
};
|
||||
|
||||
struct hdmi_core_video_config {
|
||||
enum hdmi_core_inputbus_width ip_bus_width;
|
||||
enum hdmi_core_dither_trunc op_dither_truc;
|
||||
enum hdmi_core_deepcolor_ed deep_color_pkt;
|
||||
enum hdmi_core_packet_mode pkt_mode;
|
||||
enum hdmi_core_hdmi_dvi hdmi_dvi;
|
||||
enum hdmi_core_tclkselclkmult tclk_sel_clkmult;
|
||||
};
|
||||
|
||||
struct hdmi_core_packet_enable_repeat {
|
||||
u32 audio_pkt;
|
||||
u32 audio_pkt_repeat;
|
||||
u32 avi_infoframe;
|
||||
u32 avi_infoframe_repeat;
|
||||
u32 gen_cntrl_pkt;
|
||||
u32 gen_cntrl_pkt_repeat;
|
||||
u32 generic_pkt;
|
||||
u32 generic_pkt_repeat;
|
||||
};
|
||||
|
||||
int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
|
||||
void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
|
||||
struct hdmi_config *cfg);
|
||||
void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
|
||||
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
|
||||
void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
|
||||
int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
|
||||
struct omap_dss_audio *audio, u32 pclk);
|
||||
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
|
||||
#endif
|
||||
|
||||
#endif
|
425
drivers/video/fbdev/omap2/dss/hdmi_common.c
Normal file
425
drivers/video/fbdev/omap2/dss/hdmi_common.c
Normal file
@@ -0,0 +1,425 @@
|
||||
|
||||
/*
|
||||
* Logic for the below structure :
|
||||
* user enters the CEA or VESA timings by specifying the HDMI/DVI code.
|
||||
* There is a correspondence between CEA/VESA timing and code, please
|
||||
* refer to section 6.3 in HDMI 1.3 specification for timing code.
|
||||
*
|
||||
* In the below structure, cea_vesa_timings corresponds to all OMAP4
|
||||
* supported CEA and VESA timing values.code_cea corresponds to the CEA
|
||||
* code, It is used to get the timing from cea_vesa_timing array.Similarly
|
||||
* with code_vesa. Code_index is used for back mapping, that is once EDID
|
||||
* is read from the TV, EDID is parsed to find the timing values and then
|
||||
* map it to corresponding CEA or VESA index.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "HDMI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "hdmi.h"
|
||||
|
||||
static const struct hdmi_config cea_timings[] = {
|
||||
{
|
||||
{ 640, 480, 25200000, 96, 16, 48, 2, 10, 33,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 1, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 720, 480, 27027000, 62, 16, 60, 6, 9, 30,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 2, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1280, 720, 74250000, 40, 110, 220, 5, 5, 20,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 4, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1920, 540, 74250000, 44, 88, 148, 5, 2, 15,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
true, },
|
||||
{ 5, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1440, 240, 27027000, 124, 38, 114, 3, 4, 15,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
true, },
|
||||
{ 6, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1920, 1080, 148500000, 44, 88, 148, 5, 4, 36,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 16, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 720, 576, 27000000, 64, 12, 68, 5, 5, 39,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 17, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1280, 720, 74250000, 40, 440, 220, 5, 5, 20,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 19, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1920, 540, 74250000, 44, 528, 148, 5, 2, 15,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
true, },
|
||||
{ 20, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1440, 288, 27000000, 126, 24, 138, 3, 2, 19,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
true, },
|
||||
{ 21, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1440, 576, 54000000, 128, 24, 136, 5, 5, 39,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 29, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1920, 1080, 148500000, 44, 528, 148, 5, 4, 36,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 31, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 1920, 1080, 74250000, 44, 638, 148, 5, 4, 36,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 32, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 2880, 480, 108108000, 248, 64, 240, 6, 9, 30,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 35, HDMI_HDMI },
|
||||
},
|
||||
{
|
||||
{ 2880, 576, 108000000, 256, 48, 272, 5, 5, 39,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 37, HDMI_HDMI },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hdmi_config vesa_timings[] = {
|
||||
/* VESA From Here */
|
||||
{
|
||||
{ 640, 480, 25175000, 96, 16, 48, 2, 11, 31,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 4, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 800, 600, 40000000, 128, 40, 88, 4, 1, 23,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 9, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 848, 480, 33750000, 112, 16, 112, 8, 6, 23,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0xE, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 768, 79500000, 128, 64, 192, 7, 3, 20,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x17, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 800, 83500000, 128, 72, 200, 6, 3, 22,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x1C, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1360, 768, 85500000, 112, 64, 256, 6, 3, 18,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x27, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 960, 108000000, 112, 96, 312, 3, 1, 36,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x20, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 1024, 108000000, 112, 48, 248, 3, 1, 38,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x23, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1024, 768, 65000000, 136, 24, 160, 6, 3, 29,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x10, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1400, 1050, 121750000, 144, 88, 232, 4, 3, 32,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x2A, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1440, 900, 106500000, 152, 80, 232, 6, 3, 25,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x2F, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1680, 1050, 146250000, 176 , 104, 280, 6, 3, 30,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
|
||||
false, },
|
||||
{ 0x3A, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1366, 768, 85500000, 143, 70, 213, 3, 3, 24,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x51, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1920, 1080, 148500000, 44, 148, 80, 5, 4, 36,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x52, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 768, 68250000, 32, 48, 80, 7, 3, 12,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x16, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1400, 1050, 101000000, 32, 48, 80, 4, 3, 23,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x29, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1680, 1050, 119000000, 32, 48, 80, 6, 3, 21,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x39, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 800, 79500000, 32, 48, 80, 6, 3, 14,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x1B, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1280, 720, 74250000, 40, 110, 220, 5, 5, 20,
|
||||
OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x55, HDMI_DVI },
|
||||
},
|
||||
{
|
||||
{ 1920, 1200, 154000000, 32, 48, 80, 6, 3, 26,
|
||||
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
false, },
|
||||
{ 0x44, HDMI_DVI },
|
||||
},
|
||||
};
|
||||
|
||||
const struct hdmi_config *hdmi_default_timing(void)
|
||||
{
|
||||
return &vesa_timings[0];
|
||||
}
|
||||
|
||||
static const struct hdmi_config *hdmi_find_timing(int code,
|
||||
const struct hdmi_config *timings_arr, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (timings_arr[i].cm.code == code)
|
||||
return &timings_arr[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct hdmi_config *hdmi_get_timings(int mode, int code)
|
||||
{
|
||||
const struct hdmi_config *arr;
|
||||
int len;
|
||||
|
||||
if (mode == HDMI_DVI) {
|
||||
arr = vesa_timings;
|
||||
len = ARRAY_SIZE(vesa_timings);
|
||||
} else {
|
||||
arr = cea_timings;
|
||||
len = ARRAY_SIZE(cea_timings);
|
||||
}
|
||||
|
||||
return hdmi_find_timing(code, arr, len);
|
||||
}
|
||||
|
||||
static bool hdmi_timings_compare(struct omap_video_timings *timing1,
|
||||
const struct omap_video_timings *timing2)
|
||||
{
|
||||
int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
|
||||
|
||||
if ((DIV_ROUND_CLOSEST(timing2->pixelclock, 1000000) ==
|
||||
DIV_ROUND_CLOSEST(timing1->pixelclock, 1000000)) &&
|
||||
(timing2->x_res == timing1->x_res) &&
|
||||
(timing2->y_res == timing1->y_res)) {
|
||||
|
||||
timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
|
||||
timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
|
||||
timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
|
||||
timing1_vsync = timing1->vfp + timing1->vsw + timing1->vbp;
|
||||
|
||||
DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
|
||||
"timing2_hsync = %d timing2_vsync = %d\n",
|
||||
timing1_hsync, timing1_vsync,
|
||||
timing2_hsync, timing2_vsync);
|
||||
|
||||
if ((timing1_hsync == timing2_hsync) &&
|
||||
(timing1_vsync == timing2_vsync)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
|
||||
{
|
||||
int i;
|
||||
struct hdmi_cm cm = {-1};
|
||||
DSSDBG("hdmi_get_code\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
|
||||
if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
|
||||
cm = cea_timings[i].cm;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
|
||||
if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
|
||||
cm = vesa_timings[i].cm;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return cm;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
|
||||
{
|
||||
u32 deep_color;
|
||||
bool deep_color_correct = false;
|
||||
|
||||
if (n == NULL || cts == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: When implemented, query deep color mode here. */
|
||||
deep_color = 100;
|
||||
|
||||
/*
|
||||
* When using deep color, the default N value (as in the HDMI
|
||||
* specification) yields to an non-integer CTS. Hence, we
|
||||
* modify it while keeping the restrictions described in
|
||||
* section 7.2.1 of the HDMI 1.4a specification.
|
||||
*/
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
case 48000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
if (deep_color == 125)
|
||||
if (pclk == 27027000 || pclk == 74250000)
|
||||
deep_color_correct = true;
|
||||
if (deep_color == 150)
|
||||
if (pclk == 27027000)
|
||||
deep_color_correct = true;
|
||||
break;
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
if (deep_color == 125)
|
||||
if (pclk == 27027000)
|
||||
deep_color_correct = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (deep_color_correct) {
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
*n = 8192;
|
||||
break;
|
||||
case 44100:
|
||||
*n = 12544;
|
||||
break;
|
||||
case 48000:
|
||||
*n = 8192;
|
||||
break;
|
||||
case 88200:
|
||||
*n = 25088;
|
||||
break;
|
||||
case 96000:
|
||||
*n = 16384;
|
||||
break;
|
||||
case 176400:
|
||||
*n = 50176;
|
||||
break;
|
||||
case 192000:
|
||||
*n = 32768;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (sample_freq) {
|
||||
case 32000:
|
||||
*n = 4096;
|
||||
break;
|
||||
case 44100:
|
||||
*n = 6272;
|
||||
break;
|
||||
case 48000:
|
||||
*n = 6144;
|
||||
break;
|
||||
case 88200:
|
||||
*n = 12544;
|
||||
break;
|
||||
case 96000:
|
||||
*n = 12288;
|
||||
break;
|
||||
case 176400:
|
||||
*n = 25088;
|
||||
break;
|
||||
case 192000:
|
||||
*n = 24576;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
|
||||
*cts = (pclk/1000) * (*n / 128) * deep_color / (sample_freq / 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
160
drivers/video/fbdev/omap2/dss/hdmi_phy.c
Normal file
160
drivers/video/fbdev/omap2/dss/hdmi_phy.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* HDMI PHY
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
|
||||
{
|
||||
#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
|
||||
hdmi_read_reg(phy->base, r))
|
||||
|
||||
DUMPPHY(HDMI_TXPHY_TX_CTRL);
|
||||
DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
|
||||
DUMPPHY(HDMI_TXPHY_POWER_CTRL);
|
||||
DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
|
||||
}
|
||||
|
||||
static irqreturn_t hdmi_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct hdmi_wp_data *wp = data;
|
||||
u32 irqstatus;
|
||||
|
||||
irqstatus = hdmi_wp_get_irqstatus(wp);
|
||||
hdmi_wp_set_irqstatus(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_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
|
||||
|
||||
hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
|
||||
HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
|
||||
} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
|
||||
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
|
||||
} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
|
||||
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
|
||||
struct hdmi_config *cfg)
|
||||
{
|
||||
u16 r = 0;
|
||||
u32 irqstatus;
|
||||
|
||||
hdmi_wp_clear_irqenable(wp, 0xffffffff);
|
||||
|
||||
irqstatus = hdmi_wp_get_irqstatus(wp);
|
||||
hdmi_wp_set_irqstatus(wp, irqstatus);
|
||||
|
||||
r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* Read address 0 in order to get the SCP reset done completed
|
||||
* Dummy access performed to make sure reset is done
|
||||
*/
|
||||
hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
|
||||
|
||||
/*
|
||||
* Write to phy address 0 to configure the clock
|
||||
* use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
|
||||
*/
|
||||
REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
|
||||
|
||||
/* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
|
||||
hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
|
||||
|
||||
/* Setup max LDO voltage */
|
||||
REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
|
||||
|
||||
/* 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(phy->irq, NULL, hdmi_irq_handler,
|
||||
IRQF_ONESHOT, "OMAP HDMI", wp);
|
||||
if (r) {
|
||||
DSSERR("HDMI IRQ request failed\n");
|
||||
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
|
||||
return r;
|
||||
}
|
||||
|
||||
hdmi_wp_set_irqenable(wp,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp)
|
||||
{
|
||||
free_irq(phy->irq, wp);
|
||||
|
||||
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
|
||||
}
|
||||
|
||||
#define PHY_OFFSET 0x300
|
||||
#define PHY_SIZE 0x100
|
||||
|
||||
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
|
||||
{
|
||||
struct resource *res;
|
||||
struct resource temp_res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
|
||||
if (!res) {
|
||||
DSSDBG("can't get PHY mem resource by name\n");
|
||||
/*
|
||||
* if hwmod/DT doesn't have the memory resource information
|
||||
* split into HDMI sub blocks by name, we try again by getting
|
||||
* the platform's first resource. this code will be removed when
|
||||
* the driver can get the mem resources by name
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
DSSERR("can't get PHY mem resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
temp_res.start = res->start + PHY_OFFSET;
|
||||
temp_res.end = temp_res.start + PHY_SIZE - 1;
|
||||
res = &temp_res;
|
||||
}
|
||||
|
||||
phy->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!phy->base) {
|
||||
DSSERR("can't ioremap TX PHY\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy->irq = platform_get_irq(pdev, 0);
|
||||
if (phy->irq < 0) {
|
||||
DSSERR("platform_get_irq failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
232
drivers/video/fbdev/omap2/dss/hdmi_pll.c
Normal file
232
drivers/video/fbdev/omap2/dss/hdmi_pll.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* HDMI PLL
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "HDMIPLL"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
#define HDMI_DEFAULT_REGN 16
|
||||
#define HDMI_DEFAULT_REGM2 1
|
||||
|
||||
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
|
||||
{
|
||||
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
|
||||
hdmi_read_reg(pll->base, r))
|
||||
|
||||
DUMPPLL(PLLCTRL_PLL_CONTROL);
|
||||
DUMPPLL(PLLCTRL_PLL_STATUS);
|
||||
DUMPPLL(PLLCTRL_PLL_GO);
|
||||
DUMPPLL(PLLCTRL_CFG1);
|
||||
DUMPPLL(PLLCTRL_CFG2);
|
||||
DUMPPLL(PLLCTRL_CFG3);
|
||||
DUMPPLL(PLLCTRL_SSC_CFG1);
|
||||
DUMPPLL(PLLCTRL_SSC_CFG2);
|
||||
DUMPPLL(PLLCTRL_CFG4);
|
||||
}
|
||||
|
||||
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
|
||||
{
|
||||
struct hdmi_pll_info *pi = &pll->info;
|
||||
unsigned long refclk;
|
||||
u32 mf;
|
||||
|
||||
/* use our funky units */
|
||||
clkin /= 10000;
|
||||
|
||||
/*
|
||||
* Input clock is predivided by N + 1
|
||||
* out put of which is reference clk
|
||||
*/
|
||||
|
||||
pi->regn = HDMI_DEFAULT_REGN;
|
||||
|
||||
refclk = clkin / pi->regn;
|
||||
|
||||
pi->regm2 = HDMI_DEFAULT_REGM2;
|
||||
|
||||
/*
|
||||
* multiplier is pixel_clk/ref_clk
|
||||
* Multiplying by 100 to avoid fractional part removal
|
||||
*/
|
||||
pi->regm = phy * pi->regm2 / refclk;
|
||||
|
||||
/*
|
||||
* fractional multiplier is remainder of the difference between
|
||||
* multiplier and actual phy(required pixel clock thus should be
|
||||
* multiplied by 2^18(262144) divided by the reference clock
|
||||
*/
|
||||
mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
|
||||
pi->regmf = pi->regm2 * mf / refclk;
|
||||
|
||||
/*
|
||||
* Dcofreq should be set to 1 if required pixel clock
|
||||
* is greater than 1000MHz
|
||||
*/
|
||||
pi->dcofreq = phy > 1000 * 100;
|
||||
pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
|
||||
|
||||
/* Set the reference clock to sysclk reference */
|
||||
pi->refsel = HDMI_REFSEL_SYSCLK;
|
||||
|
||||
DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
|
||||
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
|
||||
}
|
||||
|
||||
|
||||
static int hdmi_pll_config(struct hdmi_pll_data *pll)
|
||||
{
|
||||
u32 r;
|
||||
struct hdmi_pll_info *fmt = &pll->info;
|
||||
|
||||
/* PLL start always use manual mode */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
|
||||
|
||||
r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
|
||||
r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
|
||||
r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
|
||||
hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
|
||||
|
||||
r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
|
||||
|
||||
r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
|
||||
r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
|
||||
r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
|
||||
r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
|
||||
|
||||
if (fmt->dcofreq) {
|
||||
/* divider programming for frequency beyond 1000Mhz */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
|
||||
r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
|
||||
} else {
|
||||
r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
|
||||
}
|
||||
|
||||
hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
|
||||
|
||||
r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
|
||||
r = FLD_MOD(r, fmt->regm2, 24, 18);
|
||||
r = FLD_MOD(r, fmt->regmf, 17, 0);
|
||||
hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
|
||||
|
||||
/* go now */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
|
||||
|
||||
/* wait for bit change */
|
||||
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
|
||||
0, 0, 1) != 1) {
|
||||
DSSERR("PLL GO bit not set\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait till the lock bit is set in PLL status */
|
||||
if (hdmi_wait_for_bit_change(pll->base,
|
||||
PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
|
||||
DSSERR("cannot lock PLL\n");
|
||||
DSSERR("CFG1 0x%x\n",
|
||||
hdmi_read_reg(pll->base, PLLCTRL_CFG1));
|
||||
DSSERR("CFG2 0x%x\n",
|
||||
hdmi_read_reg(pll->base, PLLCTRL_CFG2));
|
||||
DSSERR("CFG4 0x%x\n",
|
||||
hdmi_read_reg(pll->base, PLLCTRL_CFG4));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
DSSDBG("PLL locked!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_pll_reset(struct hdmi_pll_data *pll)
|
||||
{
|
||||
/* SYSRESET controlled by power FSM */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
|
||||
|
||||
/* READ 0x0 reset is in progress */
|
||||
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
|
||||
!= 1) {
|
||||
DSSERR("Failed to sysreset PLL\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
|
||||
{
|
||||
u16 r = 0;
|
||||
|
||||
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_reset(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_config(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
|
||||
{
|
||||
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
|
||||
}
|
||||
|
||||
#define PLL_OFFSET 0x200
|
||||
#define PLL_SIZE 0x100
|
||||
|
||||
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
|
||||
{
|
||||
struct resource *res;
|
||||
struct resource temp_res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
|
||||
if (!res) {
|
||||
DSSDBG("can't get PLL mem resource by name\n");
|
||||
/*
|
||||
* if hwmod/DT doesn't have the memory resource information
|
||||
* split into HDMI sub blocks by name, we try again by getting
|
||||
* the platform's first resource. this code will be removed when
|
||||
* the driver can get the mem resources by name
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
DSSERR("can't get PLL mem resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
temp_res.start = res->start + PLL_OFFSET;
|
||||
temp_res.end = temp_res.start + PLL_SIZE - 1;
|
||||
res = &temp_res;
|
||||
}
|
||||
|
||||
pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!pll->base) {
|
||||
DSSERR("can't ioremap PLLCTRL\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
275
drivers/video/fbdev/omap2/dss/hdmi_wp.c
Normal file
275
drivers/video/fbdev/omap2/dss/hdmi_wp.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* HDMI wrapper
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "HDMIWP"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
|
||||
|
||||
DUMPREG(HDMI_WP_REVISION);
|
||||
DUMPREG(HDMI_WP_SYSCONFIG);
|
||||
DUMPREG(HDMI_WP_IRQSTATUS_RAW);
|
||||
DUMPREG(HDMI_WP_IRQSTATUS);
|
||||
DUMPREG(HDMI_WP_IRQENABLE_SET);
|
||||
DUMPREG(HDMI_WP_IRQENABLE_CLR);
|
||||
DUMPREG(HDMI_WP_IRQWAKEEN);
|
||||
DUMPREG(HDMI_WP_PWR_CTRL);
|
||||
DUMPREG(HDMI_WP_DEBOUNCE);
|
||||
DUMPREG(HDMI_WP_VIDEO_CFG);
|
||||
DUMPREG(HDMI_WP_VIDEO_SIZE);
|
||||
DUMPREG(HDMI_WP_VIDEO_TIMING_H);
|
||||
DUMPREG(HDMI_WP_VIDEO_TIMING_V);
|
||||
DUMPREG(HDMI_WP_CLK);
|
||||
DUMPREG(HDMI_WP_AUDIO_CFG);
|
||||
DUMPREG(HDMI_WP_AUDIO_CFG2);
|
||||
DUMPREG(HDMI_WP_AUDIO_CTRL);
|
||||
DUMPREG(HDMI_WP_AUDIO_DATA);
|
||||
}
|
||||
|
||||
u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
|
||||
{
|
||||
return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
|
||||
}
|
||||
|
||||
void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
|
||||
{
|
||||
hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
|
||||
/* flush posted write */
|
||||
hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
|
||||
}
|
||||
|
||||
void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
|
||||
{
|
||||
hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
|
||||
}
|
||||
|
||||
void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
|
||||
{
|
||||
hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
|
||||
}
|
||||
|
||||
/* PHY_PWR_CMD */
|
||||
int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
|
||||
{
|
||||
/* Return if already the state */
|
||||
if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
|
||||
return 0;
|
||||
|
||||
/* Command for power control of HDMI PHY */
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
|
||||
|
||||
/* Status of the power control of HDMI PHY */
|
||||
if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
|
||||
!= val) {
|
||||
DSSERR("Failed to set PHY power mode to %d\n", val);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PLL_PWR_CMD */
|
||||
int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
|
||||
{
|
||||
/* Command for power control of HDMI PLL */
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
|
||||
|
||||
/* wait till PHY_PWR_STATUS is set */
|
||||
if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
|
||||
!= val) {
|
||||
DSSERR("Failed to set PLL_PWR_STATUS\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdmi_wp_video_start(struct hdmi_wp_data *wp)
|
||||
{
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
|
||||
{
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
|
||||
}
|
||||
|
||||
void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
|
||||
struct hdmi_video_format *video_fmt)
|
||||
{
|
||||
u32 l = 0;
|
||||
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
|
||||
10, 8);
|
||||
|
||||
l |= FLD_VAL(video_fmt->y_res, 31, 16);
|
||||
l |= FLD_VAL(video_fmt->x_res, 15, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
|
||||
}
|
||||
|
||||
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
u32 r;
|
||||
bool vsync_pol, hsync_pol;
|
||||
DSSDBG("Enter hdmi_wp_video_config_interface\n");
|
||||
|
||||
vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
|
||||
hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
|
||||
|
||||
r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
|
||||
r = FLD_MOD(r, vsync_pol, 7, 7);
|
||||
r = FLD_MOD(r, hsync_pol, 6, 6);
|
||||
r = FLD_MOD(r, timings->interlace, 3, 3);
|
||||
r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
|
||||
hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
|
||||
}
|
||||
|
||||
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
u32 timing_h = 0;
|
||||
u32 timing_v = 0;
|
||||
|
||||
DSSDBG("Enter hdmi_wp_video_config_timing\n");
|
||||
|
||||
timing_h |= FLD_VAL(timings->hbp, 31, 20);
|
||||
timing_h |= FLD_VAL(timings->hfp, 19, 8);
|
||||
timing_h |= FLD_VAL(timings->hsw, 7, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
|
||||
|
||||
timing_v |= FLD_VAL(timings->vbp, 31, 20);
|
||||
timing_v |= FLD_VAL(timings->vfp, 19, 8);
|
||||
timing_v |= FLD_VAL(timings->vsw, 7, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
|
||||
}
|
||||
|
||||
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
|
||||
struct omap_video_timings *timings, struct hdmi_config *param)
|
||||
{
|
||||
DSSDBG("Enter hdmi_wp_video_init_format\n");
|
||||
|
||||
video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
|
||||
video_fmt->y_res = param->timings.y_res;
|
||||
video_fmt->x_res = param->timings.x_res;
|
||||
if (param->timings.interlace)
|
||||
video_fmt->y_res /= 2;
|
||||
|
||||
timings->hbp = param->timings.hbp;
|
||||
timings->hfp = param->timings.hfp;
|
||||
timings->hsw = param->timings.hsw;
|
||||
timings->vbp = param->timings.vbp;
|
||||
timings->vfp = param->timings.vfp;
|
||||
timings->vsw = param->timings.vsw;
|
||||
timings->vsync_level = param->timings.vsync_level;
|
||||
timings->hsync_level = param->timings.hsync_level;
|
||||
timings->interlace = param->timings.interlace;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
|
||||
struct hdmi_audio_format *aud_fmt)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
DSSDBG("Enter hdmi_wp_audio_config_format\n");
|
||||
|
||||
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
|
||||
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
|
||||
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
|
||||
r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
|
||||
r = FLD_MOD(r, aud_fmt->type, 4, 4);
|
||||
r = FLD_MOD(r, aud_fmt->justification, 3, 3);
|
||||
r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
|
||||
r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
|
||||
r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
|
||||
}
|
||||
|
||||
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
|
||||
struct hdmi_audio_dma *aud_dma)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
DSSDBG("Enter hdmi_wp_audio_config_dma\n");
|
||||
|
||||
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
|
||||
r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
|
||||
r = FLD_MOD(r, aud_dma->block_size, 7, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
|
||||
|
||||
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
|
||||
r = FLD_MOD(r, aud_dma->mode, 9, 9);
|
||||
r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
|
||||
}
|
||||
|
||||
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
|
||||
{
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
|
||||
{
|
||||
REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define WP_SIZE 0x200
|
||||
|
||||
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
|
||||
{
|
||||
struct resource *res;
|
||||
struct resource temp_res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
|
||||
if (!res) {
|
||||
DSSDBG("can't get WP mem resource by name\n");
|
||||
/*
|
||||
* if hwmod/DT doesn't have the memory resource information
|
||||
* split into HDMI sub blocks by name, we try again by getting
|
||||
* the platform's first resource. this code will be removed when
|
||||
* the driver can get the mem resources by name
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
DSSERR("can't get WP mem resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
temp_res.start = res->start;
|
||||
temp_res.end = temp_res.start + WP_SIZE - 1;
|
||||
res = &temp_res;
|
||||
}
|
||||
|
||||
wp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!wp->base) {
|
||||
DSSERR("can't ioremap HDMI WP\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
529
drivers/video/fbdev/omap2/dss/manager-sysfs.c
Normal file
529
drivers/video/fbdev/omap2/dss/manager-sysfs.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* 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 "MANAGER"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
|
||||
}
|
||||
|
||||
static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = mgr->get_device(mgr);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
|
||||
dssdev->name : "<none>");
|
||||
}
|
||||
|
||||
static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const char *str = data;
|
||||
return sysfs_streq(dssdev->name, str);
|
||||
}
|
||||
|
||||
if (buf[size-1] == '\n')
|
||||
--len;
|
||||
|
||||
if (len > 0)
|
||||
dssdev = omap_dss_find_device((void *)buf, match);
|
||||
|
||||
if (len > 0 && dssdev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (dssdev) {
|
||||
DSSDBG("display %s found\n", dssdev->name);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
old_dssdev->driver->disconnect(old_dssdev);
|
||||
}
|
||||
|
||||
if (dssdev) {
|
||||
r = dssdev->driver->connect(dssdev);
|
||||
if (r) {
|
||||
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;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r) {
|
||||
DSSERR("failed to apply dispc config\n");
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
put_device:
|
||||
if (dssdev)
|
||||
omap_dss_put_device(dssdev);
|
||||
|
||||
return r ? r : size;
|
||||
}
|
||||
|
||||
static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
|
||||
}
|
||||
|
||||
static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
u32 color;
|
||||
int r;
|
||||
|
||||
r = kstrtouint(buf, 0, &color);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.default_color = color;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static const char *trans_key_type_str[] = {
|
||||
"gfx-destination",
|
||||
"video-source",
|
||||
};
|
||||
|
||||
static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
enum omap_dss_trans_key_type key_type;
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
key_type = info.trans_key_type;
|
||||
BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
enum omap_dss_trans_key_type key_type;
|
||||
struct omap_overlay_manager_info info;
|
||||
int r;
|
||||
|
||||
for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
|
||||
key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
|
||||
if (sysfs_streq(buf, trans_key_type_str[key_type]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_type == ARRAY_SIZE(trans_key_type_str))
|
||||
return -EINVAL;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_key_type = key_type;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
u32 key_value;
|
||||
int r;
|
||||
|
||||
r = kstrtouint(buf, 0, &key_value);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_key = key_value;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
bool enable;
|
||||
int r;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_enabled = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_alpha_blending_enabled_show(
|
||||
struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
|
||||
return -ENODEV;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.partial_alpha_enabled);
|
||||
}
|
||||
|
||||
static ssize_t manager_alpha_blending_enabled_store(
|
||||
struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
bool enable;
|
||||
int r;
|
||||
|
||||
if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
|
||||
return -ENODEV;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.partial_alpha_enabled = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
if (!dss_has_feature(FEAT_CPR))
|
||||
return -ENODEV;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
if (info.cpr_enable == enable)
|
||||
return size;
|
||||
|
||||
info.cpr_enable = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE,
|
||||
"%d %d %d %d %d %d %d %d %d\n",
|
||||
info.cpr_coefs.rr,
|
||||
info.cpr_coefs.rg,
|
||||
info.cpr_coefs.rb,
|
||||
info.cpr_coefs.gr,
|
||||
info.cpr_coefs.gg,
|
||||
info.cpr_coefs.gb,
|
||||
info.cpr_coefs.br,
|
||||
info.cpr_coefs.bg,
|
||||
info.cpr_coefs.bb);
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
struct omap_dss_cpr_coefs coefs;
|
||||
int r, i;
|
||||
s16 *arr;
|
||||
|
||||
if (!dss_has_feature(FEAT_CPR))
|
||||
return -ENODEV;
|
||||
|
||||
if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
|
||||
&coefs.rr, &coefs.rg, &coefs.rb,
|
||||
&coefs.gr, &coefs.gg, &coefs.gb,
|
||||
&coefs.br, &coefs.bg, &coefs.bb) != 9)
|
||||
return -EINVAL;
|
||||
|
||||
arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
|
||||
coefs.gr, coefs.gg, coefs.gb,
|
||||
coefs.br, coefs.bg, coefs.bb };
|
||||
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if (arr[i] < -512 || arr[i] > 511)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.cpr_coefs = coefs;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct manager_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_overlay_manager *, char *);
|
||||
ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define MANAGER_ATTR(_name, _mode, _show, _store) \
|
||||
struct manager_attribute manager_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
|
||||
static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
|
||||
manager_display_show, manager_display_store);
|
||||
static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
|
||||
manager_default_color_show, manager_default_color_store);
|
||||
static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_type_show, manager_trans_key_type_store);
|
||||
static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_value_show, manager_trans_key_value_store);
|
||||
static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_enabled_show,
|
||||
manager_trans_key_enabled_store);
|
||||
static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
|
||||
manager_alpha_blending_enabled_show,
|
||||
manager_alpha_blending_enabled_store);
|
||||
static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
|
||||
manager_cpr_enable_show,
|
||||
manager_cpr_enable_store);
|
||||
static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
|
||||
manager_cpr_coef_show,
|
||||
manager_cpr_coef_store);
|
||||
|
||||
|
||||
static struct attribute *manager_sysfs_attrs[] = {
|
||||
&manager_attr_name.attr,
|
||||
&manager_attr_display.attr,
|
||||
&manager_attr_default_color.attr,
|
||||
&manager_attr_trans_key_type.attr,
|
||||
&manager_attr_trans_key_value.attr,
|
||||
&manager_attr_trans_key_enabled.attr,
|
||||
&manager_attr_alpha_blending_enabled.attr,
|
||||
&manager_attr_cpr_enable.attr,
|
||||
&manager_attr_cpr_coef.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager *manager;
|
||||
struct manager_attribute *manager_attr;
|
||||
|
||||
manager = container_of(kobj, struct omap_overlay_manager, kobj);
|
||||
manager_attr = container_of(attr, struct manager_attribute, attr);
|
||||
|
||||
if (!manager_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return manager_attr->show(manager, buf);
|
||||
}
|
||||
|
||||
static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager *manager;
|
||||
struct manager_attribute *manager_attr;
|
||||
|
||||
manager = container_of(kobj, struct omap_overlay_manager, kobj);
|
||||
manager_attr = container_of(attr, struct manager_attribute, attr);
|
||||
|
||||
if (!manager_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return manager_attr->store(manager, buf, size);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops manager_sysfs_ops = {
|
||||
.show = manager_attr_show,
|
||||
.store = manager_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type manager_ktype = {
|
||||
.sysfs_ops = &manager_sysfs_ops,
|
||||
.default_attrs = manager_sysfs_attrs,
|
||||
};
|
||||
|
||||
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return kobject_init_and_add(&mgr->kobj, &manager_ktype,
|
||||
&pdev->dev.kobj, "manager%d", mgr->id);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
263
drivers/video/fbdev/omap2/dss/manager.c
Normal file
263
drivers/video/fbdev/omap2/dss/manager.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/manager.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 "MANAGER"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static int num_managers;
|
||||
static struct omap_overlay_manager *managers;
|
||||
|
||||
int dss_init_overlay_managers(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
num_managers = dss_feat_get_num_mgrs();
|
||||
|
||||
managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
|
||||
GFP_KERNEL);
|
||||
|
||||
BUG_ON(managers == NULL);
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
mgr->name = "lcd";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD;
|
||||
break;
|
||||
case 1:
|
||||
mgr->name = "tv";
|
||||
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
|
||||
break;
|
||||
case 2:
|
||||
mgr->name = "lcd2";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD2;
|
||||
break;
|
||||
case 3:
|
||||
mgr->name = "lcd3";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD3;
|
||||
break;
|
||||
}
|
||||
|
||||
mgr->caps = 0;
|
||||
mgr->supported_displays =
|
||||
dss_feat_get_supported_displays(mgr->id);
|
||||
mgr->supported_outputs =
|
||||
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)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int omap_dss_get_num_overlay_managers(void)
|
||||
{
|
||||
return num_managers;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
|
||||
|
||||
struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
|
||||
{
|
||||
if (num >= num_managers)
|
||||
return NULL;
|
||||
|
||||
return &managers[num];
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_overlay_manager);
|
||||
|
||||
int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
|
||||
const struct omap_overlay_manager_info *info)
|
||||
{
|
||||
if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
|
||||
/*
|
||||
* OMAP3 supports only graphics source transparency color key
|
||||
* and alpha blending simultaneously. See TRM 15.4.2.4.2.2
|
||||
* Alpha Mode.
|
||||
*/
|
||||
if (info->partial_alpha_enabled && info->trans_enabled
|
||||
&& info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
|
||||
DSSERR("check_manager: illegal transparency key\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_info **overlay_infos)
|
||||
{
|
||||
struct omap_overlay *ovl1, *ovl2;
|
||||
struct omap_overlay_info *info1, *info2;
|
||||
|
||||
list_for_each_entry(ovl1, &mgr->overlays, list) {
|
||||
info1 = overlay_infos[ovl1->id];
|
||||
|
||||
if (info1 == NULL)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(ovl2, &mgr->overlays, list) {
|
||||
if (ovl1 == ovl2)
|
||||
continue;
|
||||
|
||||
info2 = overlay_infos[ovl2->id];
|
||||
|
||||
if (info2 == NULL)
|
||||
continue;
|
||||
|
||||
if (info1->zorder == info2->zorder) {
|
||||
DSSERR("overlays %d and %d have the same "
|
||||
"zorder %d\n",
|
||||
ovl1->id, ovl2->id, info1->zorder);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
if (!dispc_mgr_timings_ok(mgr->id, timings)) {
|
||||
DSSERR("check_manager: invalid timings\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
struct dispc_clock_info cinfo = config->clock_info;
|
||||
int dl = config->video_port_width;
|
||||
bool stallmode = config->stallmode;
|
||||
bool fifohandcheck = config->fifohandcheck;
|
||||
|
||||
if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
|
||||
return -EINVAL;
|
||||
|
||||
/* fifohandcheck should be used only with stallmode */
|
||||
if (stallmode == false && fifohandcheck == true)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* io pad mode can be only checked by using dssdev connected to the
|
||||
* manager. Ignore checking these for now, add checks when manager
|
||||
* is capable of holding information related to the connected interface
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_mgr_check(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info,
|
||||
const struct omap_video_timings *mgr_timings,
|
||||
const struct dss_lcd_mgr_config *lcd_config,
|
||||
struct omap_overlay_info **overlay_infos)
|
||||
{
|
||||
struct omap_overlay *ovl;
|
||||
int r;
|
||||
|
||||
if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
|
||||
r = dss_mgr_check_zorder(mgr, overlay_infos);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dss_mgr_check_timings(mgr, mgr_timings);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dss_mgr_check_lcd_config(mgr, lcd_config);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
list_for_each_entry(ovl, &mgr->overlays, list) {
|
||||
struct omap_overlay_info *oi;
|
||||
int r;
|
||||
|
||||
oi = overlay_infos[ovl->id];
|
||||
|
||||
if (oi == NULL)
|
||||
continue;
|
||||
|
||||
r = dss_ovl_check(ovl, oi, mgr_timings);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
254
drivers/video/fbdev/omap2/dss/output.c
Normal file
254
drivers/video/fbdev/omap2/dss/output.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Texas Instruments Ltd
|
||||
* Author: Archit Taneja <archit@ti.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
static LIST_HEAD(output_list);
|
||||
static DEFINE_MUTEX(output_lock);
|
||||
|
||||
int omapdss_output_set_device(struct omap_dss_device *out,
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&output_lock);
|
||||
|
||||
if (out->dst) {
|
||||
DSSERR("output already has device %s connected to it\n",
|
||||
out->dst->name);
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (out->output_type != dssdev->type) {
|
||||
DSSERR("output type and display type don't match\n");
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
out->dst = dssdev;
|
||||
dssdev->src = out;
|
||||
|
||||
mutex_unlock(&output_lock);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
mutex_unlock(&output_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_output_set_device);
|
||||
|
||||
int omapdss_output_unset_device(struct omap_dss_device *out)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&output_lock);
|
||||
|
||||
if (!out->dst) {
|
||||
DSSERR("output doesn't have a device connected to it\n");
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
DSSERR("device %s is not disabled, cannot unset device\n",
|
||||
out->dst->name);
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
out->dst->src = NULL;
|
||||
out->dst = NULL;
|
||||
|
||||
mutex_unlock(&output_lock);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
mutex_unlock(&output_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_output_unset_device);
|
||||
|
||||
int omapdss_register_output(struct omap_dss_device *out)
|
||||
{
|
||||
list_add_tail(&out->list, &output_list);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_register_output);
|
||||
|
||||
void omapdss_unregister_output(struct omap_dss_device *out)
|
||||
{
|
||||
list_del(&out->list);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_unregister_output);
|
||||
|
||||
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
|
||||
list_for_each_entry(out, &output_list, list) {
|
||||
if (out->id == id)
|
||||
return out;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
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->src)
|
||||
dssdev = dssdev->src;
|
||||
|
||||
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)
|
||||
{
|
||||
if (dss_mgr_ops)
|
||||
return -EBUSY;
|
||||
|
||||
dss_mgr_ops = mgr_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dss_install_mgr_ops);
|
||||
|
||||
void dss_uninstall_mgr_ops(void)
|
||||
{
|
||||
dss_mgr_ops = NULL;
|
||||
}
|
||||
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)
|
||||
{
|
||||
dss_mgr_ops->set_timings(mgr, timings);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_set_timings);
|
||||
|
||||
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
dss_mgr_ops->set_lcd_config(mgr, config);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_set_lcd_config);
|
||||
|
||||
int dss_mgr_enable(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
return dss_mgr_ops->enable(mgr);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_enable);
|
||||
|
||||
void dss_mgr_disable(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
dss_mgr_ops->disable(mgr);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_disable);
|
||||
|
||||
void dss_mgr_start_update(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
dss_mgr_ops->start_update(mgr);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_start_update);
|
||||
|
||||
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
|
||||
|
||||
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);
|
456
drivers/video/fbdev/omap2/dss/overlay-sysfs.c
Normal file
456
drivers/video/fbdev/omap2/dss/overlay-sysfs.c
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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 "OVERLAY"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ovl->manager ? ovl->manager->name : "<none>");
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int i, r;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
struct omap_overlay_manager *old_mgr;
|
||||
int len = size;
|
||||
|
||||
if (buf[size-1] == '\n')
|
||||
--len;
|
||||
|
||||
if (len > 0) {
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
|
||||
if (sysfs_streq(buf, mgr->name))
|
||||
break;
|
||||
|
||||
mgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0 && mgr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mgr)
|
||||
DSSDBG("manager %s found\n", mgr->name);
|
||||
|
||||
if (mgr == ovl->manager)
|
||||
return size;
|
||||
|
||||
old_mgr = ovl->manager;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* detach old manager */
|
||||
if (old_mgr) {
|
||||
r = ovl->unset_manager(ovl);
|
||||
if (r) {
|
||||
DSSERR("detach failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = old_mgr->apply(old_mgr);
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mgr) {
|
||||
r = ovl->set_manager(ovl, mgr);
|
||||
if (r) {
|
||||
DSSERR("Failed to attach overlay\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return size;
|
||||
|
||||
err:
|
||||
dispc_runtime_put();
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.width, info.height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.pos_x, info.pos_y);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.pos_x = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.pos_y = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.out_width, info.out_height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.out_width = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.out_height = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (enable)
|
||||
r = ovl->enable(ovl);
|
||||
else
|
||||
r = ovl->disable(ovl);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.global_alpha);
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
u8 alpha;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtou8(buf, 0, &alpha);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.global_alpha = alpha;
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.pre_mult_alpha);
|
||||
}
|
||||
|
||||
static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
u8 alpha;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtou8(buf, 0, &alpha);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.pre_mult_alpha = alpha;
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
|
||||
}
|
||||
|
||||
static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
u8 zorder;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtou8(buf, 0, &zorder);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.zorder = zorder;
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct overlay_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_overlay *, char *);
|
||||
ssize_t (*store)(struct omap_overlay *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define OVERLAY_ATTR(_name, _mode, _show, _store) \
|
||||
struct overlay_attribute overlay_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
|
||||
static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
|
||||
overlay_manager_show, overlay_manager_store);
|
||||
static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
|
||||
static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
|
||||
static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
|
||||
overlay_position_show, overlay_position_store);
|
||||
static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
|
||||
overlay_output_size_show, overlay_output_size_store);
|
||||
static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
overlay_enabled_show, overlay_enabled_store);
|
||||
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
|
||||
overlay_global_alpha_show, overlay_global_alpha_store);
|
||||
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
|
||||
overlay_pre_mult_alpha_show,
|
||||
overlay_pre_mult_alpha_store);
|
||||
static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
|
||||
overlay_zorder_show, overlay_zorder_store);
|
||||
|
||||
static struct attribute *overlay_sysfs_attrs[] = {
|
||||
&overlay_attr_name.attr,
|
||||
&overlay_attr_manager.attr,
|
||||
&overlay_attr_input_size.attr,
|
||||
&overlay_attr_screen_width.attr,
|
||||
&overlay_attr_position.attr,
|
||||
&overlay_attr_output_size.attr,
|
||||
&overlay_attr_enabled.attr,
|
||||
&overlay_attr_global_alpha.attr,
|
||||
&overlay_attr_pre_mult_alpha.attr,
|
||||
&overlay_attr_zorder.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->show(overlay, buf);
|
||||
}
|
||||
|
||||
static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->store(overlay, buf, size);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops overlay_sysfs_ops = {
|
||||
.show = overlay_attr_show,
|
||||
.store = overlay_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type overlay_ktype = {
|
||||
.sysfs_ops = &overlay_sysfs_ops,
|
||||
.default_attrs = overlay_sysfs_attrs,
|
||||
};
|
||||
|
||||
int dss_overlay_kobj_init(struct omap_overlay *ovl,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
|
||||
&pdev->dev.kobj, "overlay%d", ovl->id);
|
||||
}
|
||||
|
||||
void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
|
||||
{
|
||||
kobject_del(&ovl->kobj);
|
||||
kobject_put(&ovl->kobj);
|
||||
}
|
202
drivers/video/fbdev/omap2/dss/overlay.c
Normal file
202
drivers/video/fbdev/omap2/dss/overlay.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/overlay.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 "OVERLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static int num_overlays;
|
||||
static struct omap_overlay *overlays;
|
||||
|
||||
int omap_dss_get_num_overlays(void)
|
||||
{
|
||||
return num_overlays;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_num_overlays);
|
||||
|
||||
struct omap_overlay *omap_dss_get_overlay(int num)
|
||||
{
|
||||
if (num >= num_overlays)
|
||||
return NULL;
|
||||
|
||||
return &overlays[num];
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_overlay);
|
||||
|
||||
void dss_init_overlays(struct platform_device *pdev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
num_overlays = dss_feat_get_num_ovls();
|
||||
|
||||
overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
|
||||
GFP_KERNEL);
|
||||
|
||||
BUG_ON(overlays == NULL);
|
||||
|
||||
for (i = 0; i < num_overlays; ++i) {
|
||||
struct omap_overlay *ovl = &overlays[i];
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
ovl->name = "gfx";
|
||||
ovl->id = OMAP_DSS_GFX;
|
||||
break;
|
||||
case 1:
|
||||
ovl->name = "vid1";
|
||||
ovl->id = OMAP_DSS_VIDEO1;
|
||||
break;
|
||||
case 2:
|
||||
ovl->name = "vid2";
|
||||
ovl->id = OMAP_DSS_VIDEO2;
|
||||
break;
|
||||
case 3:
|
||||
ovl->name = "vid3";
|
||||
ovl->id = OMAP_DSS_VIDEO3;
|
||||
break;
|
||||
}
|
||||
|
||||
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
|
||||
ovl->supported_modes =
|
||||
dss_feat_get_supported_color_modes(ovl->id);
|
||||
|
||||
r = dss_overlay_kobj_init(ovl, pdev);
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dss_uninit_overlays(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_overlays; ++i) {
|
||||
struct omap_overlay *ovl = &overlays[i];
|
||||
dss_overlay_kobj_uninit(ovl);
|
||||
}
|
||||
|
||||
kfree(overlays);
|
||||
overlays = NULL;
|
||||
num_overlays = 0;
|
||||
}
|
||||
|
||||
int dss_ovl_simple_check(struct omap_overlay *ovl,
|
||||
const struct omap_overlay_info *info)
|
||||
{
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
|
||||
if (info->out_width != 0 && info->width != info->out_width) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support "
|
||||
"scaling\n", ovl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->out_height != 0 && info->height != info->out_height) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support "
|
||||
"scaling\n", ovl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ovl->supported_modes & info->color_mode) == 0) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
|
||||
ovl->id, info->color_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->zorder >= omap_dss_get_num_overlays()) {
|
||||
DSSERR("check_overlay: zorder %d too high\n", info->zorder);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
|
||||
DSSERR("check_overlay: rotation type %d not supported\n",
|
||||
info->rotation_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
|
||||
const struct omap_video_timings *mgr_timings)
|
||||
{
|
||||
u16 outw, outh;
|
||||
u16 dw, dh;
|
||||
|
||||
dw = mgr_timings->x_res;
|
||||
dh = mgr_timings->y_res;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
|
||||
outw = info->width;
|
||||
outh = info->height;
|
||||
} else {
|
||||
if (info->out_width == 0)
|
||||
outw = info->width;
|
||||
else
|
||||
outw = info->out_width;
|
||||
|
||||
if (info->out_height == 0)
|
||||
outh = info->height;
|
||||
else
|
||||
outh = info->out_height;
|
||||
}
|
||||
|
||||
if (dw < info->pos_x + outw) {
|
||||
DSSERR("overlay %d horizontally not inside the display area "
|
||||
"(%d + %d >= %d)\n",
|
||||
ovl->id, info->pos_x, outw, dw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dh < info->pos_y + outh) {
|
||||
DSSERR("overlay %d vertically not inside the display area "
|
||||
"(%d + %d >= %d)\n",
|
||||
ovl->id, info->pos_y, outh, dh);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if replication logic should be used. Only use when overlay is in
|
||||
* RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
|
||||
*/
|
||||
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
|
||||
enum omap_color_mode mode)
|
||||
{
|
||||
if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
|
||||
return false;
|
||||
|
||||
return config.video_port_width > 16;
|
||||
}
|
1058
drivers/video/fbdev/omap2/dss/rfbi.c
Normal file
1058
drivers/video/fbdev/omap2/dss/rfbi.c
Normal file
File diff suppressed because it is too large
Load Diff
433
drivers/video/fbdev/omap2/dss/sdi.c
Normal file
433
drivers/video/fbdev/omap2/dss/sdi.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/sdi.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* 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 "SDI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
|
||||
bool update_enabled;
|
||||
struct regulator *vdds_sdi_reg;
|
||||
|
||||
struct dss_lcd_mgr_config mgr_config;
|
||||
struct omap_video_timings timings;
|
||||
int datapairs;
|
||||
|
||||
struct omap_dss_device output;
|
||||
|
||||
bool port_initialized;
|
||||
} sdi;
|
||||
|
||||
struct sdi_clk_calc_ctx {
|
||||
unsigned long pck_min, pck_max;
|
||||
|
||||
unsigned long fck;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
};
|
||||
|
||||
static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
||||
unsigned long pck, void *data)
|
||||
{
|
||||
struct sdi_clk_calc_ctx *ctx = data;
|
||||
|
||||
ctx->dispc_cinfo.lck_div = lckd;
|
||||
ctx->dispc_cinfo.pck_div = pckd;
|
||||
ctx->dispc_cinfo.lck = lck;
|
||||
ctx->dispc_cinfo.pck = pck;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dpi_calc_dss_cb(unsigned long fck, void *data)
|
||||
{
|
||||
struct sdi_clk_calc_ctx *ctx = data;
|
||||
|
||||
ctx->fck = fck;
|
||||
|
||||
return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
|
||||
dpi_calc_dispc_cb, ctx);
|
||||
}
|
||||
|
||||
static int sdi_calc_clock_div(unsigned long pclk,
|
||||
unsigned long *fck,
|
||||
struct dispc_clock_info *dispc_cinfo)
|
||||
{
|
||||
int i;
|
||||
struct sdi_clk_calc_ctx ctx;
|
||||
|
||||
/*
|
||||
* DSS fclk gives us very few possibilities, so finding a good pixel
|
||||
* clock may not be possible. We try multiple times to find the clock,
|
||||
* each time widening the pixel clock range we look for, up to
|
||||
* +/- 1MHz.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
bool ok;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
if (pclk > 1000 * i * i * i)
|
||||
ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
|
||||
else
|
||||
ctx.pck_min = 0;
|
||||
ctx.pck_max = pclk + 1000 * i * i * i;
|
||||
|
||||
ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx);
|
||||
if (ok) {
|
||||
*fck = ctx.fck;
|
||||
*dispc_cinfo = ctx.dispc_cinfo;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
|
||||
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
sdi.mgr_config.stallmode = false;
|
||||
sdi.mgr_config.fifohandcheck = false;
|
||||
|
||||
sdi.mgr_config.video_port_width = 24;
|
||||
sdi.mgr_config.lcden_sig_polarity = 1;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
|
||||
}
|
||||
|
||||
static int sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
struct omap_video_timings *t = &sdi.timings;
|
||||
unsigned long fck;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
unsigned long pck;
|
||||
int r;
|
||||
|
||||
if (out == NULL || out->manager == NULL) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = regulator_enable(sdi.vdds_sdi_reg);
|
||||
if (r)
|
||||
goto err_reg_enable;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
/* 15.5.9.1.2 */
|
||||
t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
|
||||
t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
|
||||
|
||||
r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo);
|
||||
if (r)
|
||||
goto err_calc_clock_div;
|
||||
|
||||
sdi.mgr_config.clock_info = dispc_cinfo;
|
||||
|
||||
pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
|
||||
|
||||
if (pck != t->pixelclock) {
|
||||
DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
|
||||
t->pixelclock, pck);
|
||||
|
||||
t->pixelclock = pck;
|
||||
}
|
||||
|
||||
|
||||
dss_mgr_set_timings(out->manager, t);
|
||||
|
||||
r = dss_set_fck_rate(fck);
|
||||
if (r)
|
||||
goto err_set_dss_clock_div;
|
||||
|
||||
sdi_config_lcd_manager(dssdev);
|
||||
|
||||
/*
|
||||
* LCLK and PCLK divisors are located in shadow registers, and we
|
||||
* normally write them to DISPC registers when enabling the output.
|
||||
* However, SDI uses pck-free as source clock for its PLL, and pck-free
|
||||
* is affected by the divisors. And as we need the PLL before enabling
|
||||
* the output, we need to write the divisors early.
|
||||
*
|
||||
* It seems just writing to the DISPC register is enough, and we don't
|
||||
* need to care about the shadow register mechanism for pck-free. The
|
||||
* exact reason for this is unknown.
|
||||
*/
|
||||
dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
|
||||
|
||||
dss_sdi_init(sdi.datapairs);
|
||||
r = dss_sdi_enable();
|
||||
if (r)
|
||||
goto err_sdi_enable;
|
||||
mdelay(2);
|
||||
|
||||
r = dss_mgr_enable(out->manager);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
dss_sdi_disable();
|
||||
err_sdi_enable:
|
||||
err_set_dss_clock_div:
|
||||
err_calc_clock_div:
|
||||
dispc_runtime_put();
|
||||
err_get_dispc:
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
err_reg_enable:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void sdi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
dss_sdi_disable();
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
}
|
||||
|
||||
static void sdi_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
sdi.timings = *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->pixelclock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
|
||||
{
|
||||
sdi.datapairs = datapairs;
|
||||
}
|
||||
|
||||
static int sdi_init_regulator(void)
|
||||
{
|
||||
struct regulator *vdds_sdi;
|
||||
|
||||
if (sdi.vdds_sdi_reg)
|
||||
return 0;
|
||||
|
||||
vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
|
||||
if (IS_ERR(vdds_sdi)) {
|
||||
if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
|
||||
DSSERR("can't get VDDS_SDI regulator\n");
|
||||
return PTR_ERR(vdds_sdi);
|
||||
}
|
||||
|
||||
sdi.vdds_sdi_reg = vdds_sdi;
|
||||
|
||||
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->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
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 = sdi_display_enable,
|
||||
.disable = sdi_display_disable,
|
||||
|
||||
.check_timings = sdi_check_timings,
|
||||
.set_timings = sdi_set_timings,
|
||||
.get_timings = sdi_get_timings,
|
||||
|
||||
.set_datapairs = sdi_set_datapairs,
|
||||
};
|
||||
|
||||
static void sdi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_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;
|
||||
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit sdi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
static int omap_sdi_probe(struct platform_device *pdev)
|
||||
{
|
||||
sdi.pdev = pdev;
|
||||
|
||||
sdi_init_output(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit omap_sdi_remove(struct platform_device *pdev)
|
||||
{
|
||||
sdi_uninit_output(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver omap_sdi_driver = {
|
||||
.probe = omap_sdi_probe,
|
||||
.remove = __exit_p(omap_sdi_remove),
|
||||
.driver = {
|
||||
.name = "omapdss_sdi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int __init sdi_init_platform_driver(void)
|
||||
{
|
||||
return platform_driver_register(&omap_sdi_driver);
|
||||
}
|
||||
|
||||
void __exit sdi_uninit_platform_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_sdi_driver);
|
||||
}
|
||||
|
||||
int __init sdi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
{
|
||||
struct device_node *ep;
|
||||
u32 datapairs;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
r = of_property_read_u32(ep, "datapairs", &datapairs);
|
||||
if (r) {
|
||||
DSSERR("failed to parse datapairs\n");
|
||||
goto err_datapairs;
|
||||
}
|
||||
|
||||
sdi.datapairs = datapairs;
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
sdi.pdev = pdev;
|
||||
|
||||
sdi_init_output(pdev);
|
||||
|
||||
sdi.port_initialized = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_datapairs:
|
||||
of_node_put(ep);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void __exit sdi_uninit_port(void)
|
||||
{
|
||||
if (!sdi.port_initialized)
|
||||
return;
|
||||
|
||||
sdi_uninit_output(sdi.pdev);
|
||||
}
|
980
drivers/video/fbdev/omap2/dss/venc.c
Normal file
980
drivers/video/fbdev/omap2/dss/venc.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/venc.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* VENC settings from TI's DSS driver
|
||||
*
|
||||
* 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 "VENC"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
/* Venc registers */
|
||||
#define VENC_REV_ID 0x00
|
||||
#define VENC_STATUS 0x04
|
||||
#define VENC_F_CONTROL 0x08
|
||||
#define VENC_VIDOUT_CTRL 0x10
|
||||
#define VENC_SYNC_CTRL 0x14
|
||||
#define VENC_LLEN 0x1C
|
||||
#define VENC_FLENS 0x20
|
||||
#define VENC_HFLTR_CTRL 0x24
|
||||
#define VENC_CC_CARR_WSS_CARR 0x28
|
||||
#define VENC_C_PHASE 0x2C
|
||||
#define VENC_GAIN_U 0x30
|
||||
#define VENC_GAIN_V 0x34
|
||||
#define VENC_GAIN_Y 0x38
|
||||
#define VENC_BLACK_LEVEL 0x3C
|
||||
#define VENC_BLANK_LEVEL 0x40
|
||||
#define VENC_X_COLOR 0x44
|
||||
#define VENC_M_CONTROL 0x48
|
||||
#define VENC_BSTAMP_WSS_DATA 0x4C
|
||||
#define VENC_S_CARR 0x50
|
||||
#define VENC_LINE21 0x54
|
||||
#define VENC_LN_SEL 0x58
|
||||
#define VENC_L21__WC_CTL 0x5C
|
||||
#define VENC_HTRIGGER_VTRIGGER 0x60
|
||||
#define VENC_SAVID__EAVID 0x64
|
||||
#define VENC_FLEN__FAL 0x68
|
||||
#define VENC_LAL__PHASE_RESET 0x6C
|
||||
#define VENC_HS_INT_START_STOP_X 0x70
|
||||
#define VENC_HS_EXT_START_STOP_X 0x74
|
||||
#define VENC_VS_INT_START_X 0x78
|
||||
#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
|
||||
#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
|
||||
#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
|
||||
#define VENC_VS_EXT_STOP_Y 0x88
|
||||
#define VENC_AVID_START_STOP_X 0x90
|
||||
#define VENC_AVID_START_STOP_Y 0x94
|
||||
#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
|
||||
#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
|
||||
#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
|
||||
#define VENC_TVDETGP_INT_START_STOP_X 0xB0
|
||||
#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
|
||||
#define VENC_GEN_CTRL 0xB8
|
||||
#define VENC_OUTPUT_CONTROL 0xC4
|
||||
#define VENC_OUTPUT_TEST 0xC8
|
||||
#define VENC_DAC_B__DAC_C 0xC8
|
||||
|
||||
struct venc_config {
|
||||
u32 f_control;
|
||||
u32 vidout_ctrl;
|
||||
u32 sync_ctrl;
|
||||
u32 llen;
|
||||
u32 flens;
|
||||
u32 hfltr_ctrl;
|
||||
u32 cc_carr_wss_carr;
|
||||
u32 c_phase;
|
||||
u32 gain_u;
|
||||
u32 gain_v;
|
||||
u32 gain_y;
|
||||
u32 black_level;
|
||||
u32 blank_level;
|
||||
u32 x_color;
|
||||
u32 m_control;
|
||||
u32 bstamp_wss_data;
|
||||
u32 s_carr;
|
||||
u32 line21;
|
||||
u32 ln_sel;
|
||||
u32 l21__wc_ctl;
|
||||
u32 htrigger_vtrigger;
|
||||
u32 savid__eavid;
|
||||
u32 flen__fal;
|
||||
u32 lal__phase_reset;
|
||||
u32 hs_int_start_stop_x;
|
||||
u32 hs_ext_start_stop_x;
|
||||
u32 vs_int_start_x;
|
||||
u32 vs_int_stop_x__vs_int_start_y;
|
||||
u32 vs_int_stop_y__vs_ext_start_x;
|
||||
u32 vs_ext_stop_x__vs_ext_start_y;
|
||||
u32 vs_ext_stop_y;
|
||||
u32 avid_start_stop_x;
|
||||
u32 avid_start_stop_y;
|
||||
u32 fid_int_start_x__fid_int_start_y;
|
||||
u32 fid_int_offset_y__fid_ext_start_x;
|
||||
u32 fid_ext_start_y__fid_ext_offset_y;
|
||||
u32 tvdetgp_int_start_stop_x;
|
||||
u32 tvdetgp_int_start_stop_y;
|
||||
u32 gen_ctrl;
|
||||
};
|
||||
|
||||
/* from TRM */
|
||||
static const struct venc_config venc_config_pal_trm = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 1,
|
||||
.sync_ctrl = 0x40,
|
||||
.llen = 0x35F, /* 863 */
|
||||
.flens = 0x270, /* 624 */
|
||||
.hfltr_ctrl = 0,
|
||||
.cc_carr_wss_carr = 0x2F7225ED,
|
||||
.c_phase = 0,
|
||||
.gain_u = 0x111,
|
||||
.gain_v = 0x181,
|
||||
.gain_y = 0x140,
|
||||
.black_level = 0x3B,
|
||||
.blank_level = 0x3B,
|
||||
.x_color = 0x7,
|
||||
.m_control = 0x2,
|
||||
.bstamp_wss_data = 0x3F,
|
||||
.s_carr = 0x2A098ACB,
|
||||
.line21 = 0,
|
||||
.ln_sel = 0x01290015,
|
||||
.l21__wc_ctl = 0x0000F603,
|
||||
.htrigger_vtrigger = 0,
|
||||
|
||||
.savid__eavid = 0x06A70108,
|
||||
.flen__fal = 0x00180270,
|
||||
.lal__phase_reset = 0x00040135,
|
||||
.hs_int_start_stop_x = 0x00880358,
|
||||
.hs_ext_start_stop_x = 0x000F035F,
|
||||
.vs_int_start_x = 0x01A70000,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x000001A7,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
|
||||
.vs_ext_stop_y = 0x00000025,
|
||||
.avid_start_stop_x = 0x03530083,
|
||||
.avid_start_stop_y = 0x026C002E,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0001008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x002E0138,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01380001,
|
||||
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00FF0000,
|
||||
};
|
||||
|
||||
/* from TRM */
|
||||
static const struct venc_config venc_config_ntsc_trm = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 1,
|
||||
.sync_ctrl = 0x8040,
|
||||
.llen = 0x359,
|
||||
.flens = 0x20C,
|
||||
.hfltr_ctrl = 0,
|
||||
.cc_carr_wss_carr = 0x043F2631,
|
||||
.c_phase = 0,
|
||||
.gain_u = 0x102,
|
||||
.gain_v = 0x16C,
|
||||
.gain_y = 0x12F,
|
||||
.black_level = 0x43,
|
||||
.blank_level = 0x38,
|
||||
.x_color = 0x7,
|
||||
.m_control = 0x1,
|
||||
.bstamp_wss_data = 0x38,
|
||||
.s_carr = 0x21F07C1F,
|
||||
.line21 = 0,
|
||||
.ln_sel = 0x01310011,
|
||||
.l21__wc_ctl = 0x0000F003,
|
||||
.htrigger_vtrigger = 0,
|
||||
|
||||
.savid__eavid = 0x069300F4,
|
||||
.flen__fal = 0x0016020C,
|
||||
.lal__phase_reset = 0x00060107,
|
||||
.hs_int_start_stop_x = 0x008E0350,
|
||||
.hs_ext_start_stop_x = 0x000F0359,
|
||||
.vs_int_start_x = 0x01A00000,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x020701A0,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
|
||||
.vs_ext_stop_y = 0x00000006,
|
||||
.avid_start_stop_x = 0x03480078,
|
||||
.avid_start_stop_y = 0x02060024,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0001008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01060006,
|
||||
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00F90000,
|
||||
};
|
||||
|
||||
static const struct venc_config venc_config_pal_bdghi = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 0,
|
||||
.sync_ctrl = 0,
|
||||
.hfltr_ctrl = 0,
|
||||
.x_color = 0,
|
||||
.line21 = 0,
|
||||
.ln_sel = 21,
|
||||
.htrigger_vtrigger = 0,
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00FB0000,
|
||||
|
||||
.llen = 864-1,
|
||||
.flens = 625-1,
|
||||
.cc_carr_wss_carr = 0x2F7625ED,
|
||||
.c_phase = 0xDF,
|
||||
.gain_u = 0x111,
|
||||
.gain_v = 0x181,
|
||||
.gain_y = 0x140,
|
||||
.black_level = 0x3e,
|
||||
.blank_level = 0x3e,
|
||||
.m_control = 0<<2 | 1<<1,
|
||||
.bstamp_wss_data = 0x42,
|
||||
.s_carr = 0x2a098acb,
|
||||
.l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
|
||||
.savid__eavid = 0x06A70108,
|
||||
.flen__fal = 23<<16 | 624<<0,
|
||||
.lal__phase_reset = 2<<17 | 310<<0,
|
||||
.hs_int_start_stop_x = 0x00920358,
|
||||
.hs_ext_start_stop_x = 0x000F035F,
|
||||
.vs_int_start_x = 0x1a7<<16,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x000601A7,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x27101af,
|
||||
.vs_ext_stop_y = 0x05,
|
||||
.avid_start_stop_x = 0x03530082,
|
||||
.avid_start_stop_y = 0x0270002E,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0005008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x002E0138,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01380005,
|
||||
};
|
||||
|
||||
const struct omap_video_timings omap_dss_pal_timings = {
|
||||
.x_res = 720,
|
||||
.y_res = 574,
|
||||
.pixelclock = 13500000,
|
||||
.hsw = 64,
|
||||
.hfp = 12,
|
||||
.hbp = 68,
|
||||
.vsw = 5,
|
||||
.vfp = 5,
|
||||
.vbp = 41,
|
||||
|
||||
.interlace = true,
|
||||
};
|
||||
EXPORT_SYMBOL(omap_dss_pal_timings);
|
||||
|
||||
const struct omap_video_timings omap_dss_ntsc_timings = {
|
||||
.x_res = 720,
|
||||
.y_res = 482,
|
||||
.pixelclock = 13500000,
|
||||
.hsw = 64,
|
||||
.hfp = 16,
|
||||
.hbp = 58,
|
||||
.vsw = 6,
|
||||
.vfp = 6,
|
||||
.vbp = 31,
|
||||
|
||||
.interlace = true,
|
||||
};
|
||||
EXPORT_SYMBOL(omap_dss_ntsc_timings);
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
struct mutex venc_lock;
|
||||
u32 wss_data;
|
||||
struct regulator *vdda_dac_reg;
|
||||
|
||||
struct clk *tv_dac_clk;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
enum omap_dss_venc_type type;
|
||||
bool invert_polarity;
|
||||
|
||||
struct omap_dss_device output;
|
||||
} venc;
|
||||
|
||||
static inline void venc_write_reg(int idx, u32 val)
|
||||
{
|
||||
__raw_writel(val, venc.base + idx);
|
||||
}
|
||||
|
||||
static inline u32 venc_read_reg(int idx)
|
||||
{
|
||||
u32 l = __raw_readl(venc.base + idx);
|
||||
return l;
|
||||
}
|
||||
|
||||
static void venc_write_config(const struct venc_config *config)
|
||||
{
|
||||
DSSDBG("write venc conf\n");
|
||||
|
||||
venc_write_reg(VENC_LLEN, config->llen);
|
||||
venc_write_reg(VENC_FLENS, config->flens);
|
||||
venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
|
||||
venc_write_reg(VENC_C_PHASE, config->c_phase);
|
||||
venc_write_reg(VENC_GAIN_U, config->gain_u);
|
||||
venc_write_reg(VENC_GAIN_V, config->gain_v);
|
||||
venc_write_reg(VENC_GAIN_Y, config->gain_y);
|
||||
venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
|
||||
venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
|
||||
venc_write_reg(VENC_M_CONTROL, config->m_control);
|
||||
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc.wss_data);
|
||||
venc_write_reg(VENC_S_CARR, config->s_carr);
|
||||
venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
|
||||
venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
|
||||
venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
|
||||
venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
|
||||
venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
|
||||
venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
|
||||
venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
|
||||
venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
|
||||
config->vs_int_stop_x__vs_int_start_y);
|
||||
venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
|
||||
config->vs_int_stop_y__vs_ext_start_x);
|
||||
venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
|
||||
config->vs_ext_stop_x__vs_ext_start_y);
|
||||
venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
|
||||
venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
|
||||
venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
|
||||
venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
|
||||
config->fid_int_start_x__fid_int_start_y);
|
||||
venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
|
||||
config->fid_int_offset_y__fid_ext_start_x);
|
||||
venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
|
||||
config->fid_ext_start_y__fid_ext_offset_y);
|
||||
|
||||
venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
|
||||
venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
|
||||
venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
|
||||
venc_write_reg(VENC_X_COLOR, config->x_color);
|
||||
venc_write_reg(VENC_LINE21, config->line21);
|
||||
venc_write_reg(VENC_LN_SEL, config->ln_sel);
|
||||
venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
|
||||
venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
|
||||
config->tvdetgp_int_start_stop_x);
|
||||
venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
|
||||
config->tvdetgp_int_start_stop_y);
|
||||
venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
|
||||
venc_write_reg(VENC_F_CONTROL, config->f_control);
|
||||
venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
|
||||
}
|
||||
|
||||
static void venc_reset(void)
|
||||
{
|
||||
int t = 1000;
|
||||
|
||||
venc_write_reg(VENC_F_CONTROL, 1<<8);
|
||||
while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
|
||||
if (--t == 0) {
|
||||
DSSERR("Failed to reset venc\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
|
||||
/* the magical sleep that makes things work */
|
||||
/* XXX more info? What bug this circumvents? */
|
||||
msleep(20);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int venc_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&venc.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void venc_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put_sync(&venc.pdev->dev);
|
||||
WARN_ON(r < 0 && r != -ENOSYS);
|
||||
}
|
||||
|
||||
static const struct venc_config *venc_timings_to_config(
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
|
||||
return &venc_config_pal_trm;
|
||||
|
||||
if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
|
||||
return &venc_config_ntsc_trm;
|
||||
|
||||
BUG();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int venc_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
u32 l;
|
||||
int r;
|
||||
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err0;
|
||||
|
||||
venc_reset();
|
||||
venc_write_config(venc_timings_to_config(&venc.timings));
|
||||
|
||||
dss_set_venc_output(venc.type);
|
||||
dss_set_dac_pwrdn_bgz(1);
|
||||
|
||||
l = 0;
|
||||
|
||||
if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
|
||||
l |= 1 << 1;
|
||||
else /* S-Video */
|
||||
l |= (1 << 0) | (1 << 2);
|
||||
|
||||
if (venc.invert_polarity == false)
|
||||
l |= 1 << 3;
|
||||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, l);
|
||||
|
||||
dss_mgr_set_timings(mgr, &venc.timings);
|
||||
|
||||
r = regulator_enable(venc.vdda_dac_reg);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
regulator_disable(venc.vdda_dac_reg);
|
||||
err1:
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
|
||||
dss_set_dac_pwrdn_bgz(0);
|
||||
|
||||
venc_runtime_put();
|
||||
err0:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
|
||||
dss_set_dac_pwrdn_bgz(0);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
regulator_disable(venc.vdda_dac_reg);
|
||||
|
||||
venc_runtime_put();
|
||||
}
|
||||
|
||||
static int venc_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_display_enable\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (out == NULL || out->manager == NULL) {
|
||||
DSSERR("Failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = venc_power_on(dssdev);
|
||||
if (r)
|
||||
goto err0;
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return 0;
|
||||
err0:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("venc_display_disable\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
venc_power_off(dssdev);
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static void venc_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("venc_set_timings\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
/* Reset WSS data when the TV standard changes. */
|
||||
if (memcmp(&venc.timings, timings, sizeof(*timings)))
|
||||
venc.wss_data = 0;
|
||||
|
||||
venc.timings = *timings;
|
||||
|
||||
dispc_set_tv_pclk(13500000);
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static int venc_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("venc_check_timings\n");
|
||||
|
||||
if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static u32 venc_get_wss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
return (venc.wss_data >> 8) ^ 0xfffff;
|
||||
}
|
||||
|
||||
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
||||
{
|
||||
const struct venc_config *config;
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_set_wss\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
config = venc_timings_to_config(&venc.timings);
|
||||
|
||||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
venc.wss_data = (wss ^ 0xfffff) << 8;
|
||||
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc.wss_data);
|
||||
|
||||
venc_runtime_put();
|
||||
|
||||
err:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_set_type(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_venc_type type)
|
||||
{
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
venc.type = type;
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
|
||||
bool invert_polarity)
|
||||
{
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
venc.invert_polarity = invert_polarity;
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static int venc_init_regulator(void)
|
||||
{
|
||||
struct regulator *vdda_dac;
|
||||
|
||||
if (venc.vdda_dac_reg != NULL)
|
||||
return 0;
|
||||
|
||||
if (venc.pdev->dev.of_node)
|
||||
vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
|
||||
else
|
||||
vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
|
||||
|
||||
if (IS_ERR(vdda_dac)) {
|
||||
if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
|
||||
DSSERR("can't get VDDA_DAC regulator\n");
|
||||
return PTR_ERR(vdda_dac);
|
||||
}
|
||||
|
||||
venc.vdda_dac_reg = vdda_dac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void venc_dump_regs(struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
|
||||
|
||||
if (venc_runtime_get())
|
||||
return;
|
||||
|
||||
DUMPREG(VENC_F_CONTROL);
|
||||
DUMPREG(VENC_VIDOUT_CTRL);
|
||||
DUMPREG(VENC_SYNC_CTRL);
|
||||
DUMPREG(VENC_LLEN);
|
||||
DUMPREG(VENC_FLENS);
|
||||
DUMPREG(VENC_HFLTR_CTRL);
|
||||
DUMPREG(VENC_CC_CARR_WSS_CARR);
|
||||
DUMPREG(VENC_C_PHASE);
|
||||
DUMPREG(VENC_GAIN_U);
|
||||
DUMPREG(VENC_GAIN_V);
|
||||
DUMPREG(VENC_GAIN_Y);
|
||||
DUMPREG(VENC_BLACK_LEVEL);
|
||||
DUMPREG(VENC_BLANK_LEVEL);
|
||||
DUMPREG(VENC_X_COLOR);
|
||||
DUMPREG(VENC_M_CONTROL);
|
||||
DUMPREG(VENC_BSTAMP_WSS_DATA);
|
||||
DUMPREG(VENC_S_CARR);
|
||||
DUMPREG(VENC_LINE21);
|
||||
DUMPREG(VENC_LN_SEL);
|
||||
DUMPREG(VENC_L21__WC_CTL);
|
||||
DUMPREG(VENC_HTRIGGER_VTRIGGER);
|
||||
DUMPREG(VENC_SAVID__EAVID);
|
||||
DUMPREG(VENC_FLEN__FAL);
|
||||
DUMPREG(VENC_LAL__PHASE_RESET);
|
||||
DUMPREG(VENC_HS_INT_START_STOP_X);
|
||||
DUMPREG(VENC_HS_EXT_START_STOP_X);
|
||||
DUMPREG(VENC_VS_INT_START_X);
|
||||
DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
|
||||
DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
|
||||
DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
|
||||
DUMPREG(VENC_VS_EXT_STOP_Y);
|
||||
DUMPREG(VENC_AVID_START_STOP_X);
|
||||
DUMPREG(VENC_AVID_START_STOP_Y);
|
||||
DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
|
||||
DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
|
||||
DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
|
||||
DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
|
||||
DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
|
||||
DUMPREG(VENC_GEN_CTRL);
|
||||
DUMPREG(VENC_OUTPUT_CONTROL);
|
||||
DUMPREG(VENC_OUTPUT_TEST);
|
||||
|
||||
venc_runtime_put();
|
||||
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
static int venc_get_clocks(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
|
||||
clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get tv_dac_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
} else {
|
||||
clk = NULL;
|
||||
}
|
||||
|
||||
venc.tv_dac_clk = clk;
|
||||
|
||||
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->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
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 = venc_display_enable,
|
||||
.disable = venc_display_disable,
|
||||
|
||||
.check_timings = venc_check_timings,
|
||||
.set_timings = venc_set_timings,
|
||||
.get_timings = venc_get_timings,
|
||||
|
||||
.set_type = venc_set_type,
|
||||
.invert_vid_out_polarity = venc_invert_vid_out_polarity,
|
||||
|
||||
.set_wss = venc_set_wss,
|
||||
.get_wss = venc_get_wss,
|
||||
};
|
||||
|
||||
static void venc_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_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;
|
||||
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit venc_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
static int venc_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *ep;
|
||||
u32 channels;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
|
||||
|
||||
r = of_property_read_u32(ep, "ti,channels", &channels);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to read property 'ti,channels': %d\n", r);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
|
||||
break;
|
||||
case 2:
|
||||
venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
of_node_put(ep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VENC HW IP initialisation */
|
||||
static int omap_venchw_probe(struct platform_device *pdev)
|
||||
{
|
||||
u8 rev_id;
|
||||
struct resource *venc_mem;
|
||||
int r;
|
||||
|
||||
venc.pdev = pdev;
|
||||
|
||||
mutex_init(&venc.venc_lock);
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
||||
venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
|
||||
if (!venc_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM VENC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
|
||||
resource_size(venc_mem));
|
||||
if (!venc.base) {
|
||||
DSSERR("can't ioremap VENC\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = venc_get_clocks(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err_runtime_get;
|
||||
|
||||
rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
|
||||
dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
|
||||
|
||||
venc_runtime_put();
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
r = venc_probe_of(pdev);
|
||||
if (r) {
|
||||
DSSERR("Invalid DT data\n");
|
||||
goto err_probe_of;
|
||||
}
|
||||
}
|
||||
|
||||
dss_debugfs_create_file("venc", venc_dump_regs);
|
||||
|
||||
venc_init_output(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe_of:
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit omap_venchw_remove(struct platform_device *pdev)
|
||||
{
|
||||
venc_uninit_output(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
if (venc.tv_dac_clk)
|
||||
clk_disable_unprepare(venc.tv_dac_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (venc.tv_dac_clk)
|
||||
clk_prepare_enable(venc.tv_dac_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops venc_pm_ops = {
|
||||
.runtime_suspend = venc_runtime_suspend,
|
||||
.runtime_resume = venc_runtime_resume,
|
||||
};
|
||||
|
||||
|
||||
static const struct of_device_id venc_of_match[] = {
|
||||
{ .compatible = "ti,omap2-venc", },
|
||||
{ .compatible = "ti,omap3-venc", },
|
||||
{ .compatible = "ti,omap4-venc", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver omap_venchw_driver = {
|
||||
.probe = omap_venchw_probe,
|
||||
.remove = __exit_p(omap_venchw_remove),
|
||||
.driver = {
|
||||
.name = "omapdss_venc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &venc_pm_ops,
|
||||
.of_match_table = venc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
int __init venc_init_platform_driver(void)
|
||||
{
|
||||
return platform_driver_register(&omap_venchw_driver);
|
||||
}
|
||||
|
||||
void __exit venc_uninit_platform_driver(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_venchw_driver);
|
||||
}
|
232
drivers/video/fbdev/omap2/dss/venc_panel.c
Normal file
232
drivers/video/fbdev/omap2/dss/venc_panel.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* VENC panel driver
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
struct mutex lock;
|
||||
} venc_panel;
|
||||
|
||||
static ssize_t display_output_type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
const char *ret;
|
||||
|
||||
switch (dssdev->phy.venc.type) {
|
||||
case OMAP_DSS_VENC_TYPE_COMPOSITE:
|
||||
ret = "composite";
|
||||
break;
|
||||
case OMAP_DSS_VENC_TYPE_SVIDEO:
|
||||
ret = "svideo";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t display_output_type_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
enum omap_dss_venc_type new_type;
|
||||
|
||||
if (sysfs_streq("composite", buf))
|
||||
new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
|
||||
else if (sysfs_streq("svideo", buf))
|
||||
new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
if (dssdev->phy.venc.type != new_type) {
|
||||
dssdev->phy.venc.type = new_type;
|
||||
omapdss_venc_set_type(dssdev, new_type);
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
omapdss_venc_display_disable(dssdev);
|
||||
omapdss_venc_display_enable(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&venc_panel.lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
|
||||
display_output_type_show, display_output_type_store);
|
||||
|
||||
static int venc_panel_probe(struct omap_dss_device *dssdev)
|
||||
{
|
||||
/* set default timings to PAL */
|
||||
const struct omap_video_timings default_timings = {
|
||||
.x_res = 720,
|
||||
.y_res = 574,
|
||||
.pixelclock = 13500000,
|
||||
.hsw = 64,
|
||||
.hfp = 12,
|
||||
.hbp = 68,
|
||||
.vsw = 5,
|
||||
.vfp = 5,
|
||||
.vbp = 41,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
|
||||
.interlace = true,
|
||||
};
|
||||
|
||||
mutex_init(&venc_panel.lock);
|
||||
|
||||
dssdev->panel.timings = default_timings;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int venc_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "venc_panel_enable\n");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
|
||||
omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
|
||||
omapdss_venc_invert_vid_out_polarity(dssdev,
|
||||
dssdev->phy.venc.invert_polarity);
|
||||
|
||||
r = omapdss_venc_display_enable(dssdev);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
mutex_unlock(&venc_panel.lock);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
mutex_unlock(&venc_panel.lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(dssdev->dev, "venc_panel_disable\n");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
|
||||
goto end;
|
||||
|
||||
omapdss_venc_display_disable(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
end:
|
||||
mutex_unlock(&venc_panel.lock);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
omapdss_venc_set_timings(dssdev, timings);
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
mutex_unlock(&venc_panel.lock);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
return omapdss_venc_set_wss(dssdev, wss);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver venc_driver = {
|
||||
.probe = venc_panel_probe,
|
||||
.remove = venc_panel_remove,
|
||||
|
||||
.enable = venc_panel_enable,
|
||||
.disable = venc_panel_disable,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
|
||||
|
||||
.set_timings = venc_panel_set_timings,
|
||||
.check_timings = venc_panel_check_timings,
|
||||
|
||||
.get_wss = venc_panel_get_wss,
|
||||
.set_wss = venc_panel_set_wss,
|
||||
|
||||
.driver = {
|
||||
.name = "venc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int venc_panel_init(void)
|
||||
{
|
||||
return omap_dss_register_driver(&venc_driver);
|
||||
}
|
||||
|
||||
void venc_panel_exit(void)
|
||||
{
|
||||
omap_dss_unregister_driver(&venc_driver);
|
||||
}
|
Reference in New Issue
Block a user