summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r--drivers/video/omap2/dss/Kconfig14
-rw-r--r--drivers/video/omap2/dss/Makefile2
-rw-r--r--drivers/video/omap2/dss/core.c480
-rw-r--r--drivers/video/omap2/dss/dispc.c335
-rw-r--r--drivers/video/omap2/dss/display.c35
-rw-r--r--drivers/video/omap2/dss/dpi.c45
-rw-r--r--drivers/video/omap2/dss/dsi.c967
-rw-r--r--drivers/video/omap2/dss/dss.c763
-rw-r--r--drivers/video/omap2/dss/dss.h153
-rw-r--r--drivers/video/omap2/dss/dss_features.c163
-rw-r--r--drivers/video/omap2/dss/dss_features.h27
-rw-r--r--drivers/video/omap2/dss/hdmi.c1332
-rw-r--r--drivers/video/omap2/dss/hdmi.h415
-rw-r--r--drivers/video/omap2/dss/hdmi_omap4_panel.c222
-rw-r--r--drivers/video/omap2/dss/manager.c13
-rw-r--r--drivers/video/omap2/dss/overlay.c10
-rw-r--r--drivers/video/omap2/dss/rfbi.c128
-rw-r--r--drivers/video/omap2/dss/sdi.c62
-rw-r--r--drivers/video/omap2/dss/venc.c128
19 files changed, 4113 insertions, 1181 deletions
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index 43b64403eaa..bfc5da0e970 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -1,8 +1,8 @@
menuconfig OMAP2_DSS
- tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
- depends on ARCH_OMAP2 || ARCH_OMAP3
+ tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)"
+ depends on ARCH_OMAP2PLUS
help
- OMAP2/3 Display Subsystem support.
+ OMAP2+ Display Subsystem support.
if OMAP2_DSS
@@ -60,6 +60,14 @@ config OMAP2_DSS_VENC
help
OMAP Video Encoder support for S-Video and composite TV-out.
+config OMAP4_DSS_HDMI
+ bool "HDMI support"
+ depends on ARCH_OMAP4
+ default y
+ help
+ HDMI Interface. This adds the High Definition Multimedia Interface.
+ See http://www.hdmi.org/ for HDMI specification.
+
config OMAP2_DSS_SDI
bool "SDI support"
depends on ARCH_OMAP3
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 7db17b5e570..10d9d3bb3e2 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -5,3 +5,5 @@ 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) += hdmi.o \
+ hdmi_omap4_panel.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 8e89f604928..1aa2ed1e786 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -34,332 +34,26 @@
#include <linux/regulator/consumer.h>
#include <plat/display.h>
-#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
static struct {
struct platform_device *pdev;
- int ctx_id;
-
- struct clk *dss_ick;
- struct clk *dss1_fck;
- struct clk *dss2_fck;
- struct clk *dss_54m_fck;
- struct clk *dss_96m_fck;
- unsigned num_clks_enabled;
struct regulator *vdds_dsi_reg;
struct regulator *vdds_sdi_reg;
- struct regulator *vdda_dac_reg;
} core;
-static void dss_clk_enable_all_no_ctx(void);
-static void dss_clk_disable_all_no_ctx(void);
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
-
static char *def_disp_name;
module_param_named(def_disp, def_disp_name, charp, 0);
-MODULE_PARM_DESC(def_disp_name, "default display name");
+MODULE_PARM_DESC(def_disp, "default display name");
#ifdef DEBUG
unsigned int dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
-/* CONTEXT */
-static int dss_get_ctx_id(void)
-{
- struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
- int r;
-
- if (!pdata->get_last_off_on_transaction_id)
- return 0;
- r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
- if (r < 0) {
- dev_err(&core.pdev->dev, "getting transaction ID failed, "
- "will force context restore\n");
- r = -1;
- }
- return r;
-}
-
-int dss_need_ctx_restore(void)
-{
- int id = dss_get_ctx_id();
-
- if (id < 0 || id != core.ctx_id) {
- DSSDBG("ctx id %d -> id %d\n",
- core.ctx_id, id);
- core.ctx_id = id;
- return 1;
- } else {
- return 0;
- }
-}
-
-static void save_all_ctx(void)
-{
- DSSDBG("save context\n");
-
- dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dss_save_context();
- dispc_save_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
- dsi_save_context();
-#endif
-
- dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-}
-
-static void restore_all_ctx(void)
-{
- DSSDBG("restore context\n");
-
- dss_clk_enable_all_no_ctx();
-
- dss_restore_context();
- dispc_restore_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
- dsi_restore_context();
-#endif
-
- dss_clk_disable_all_no_ctx();
-}
-
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-/* CLOCKS */
-static void core_dump_clocks(struct seq_file *s)
-{
- int i;
- struct clk *clocks[5] = {
- core.dss_ick,
- core.dss1_fck,
- core.dss2_fck,
- core.dss_54m_fck,
- core.dss_96m_fck
- };
-
- seq_printf(s, "- CORE -\n");
-
- seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
-
- for (i = 0; i < 5; i++) {
- if (!clocks[i])
- continue;
- seq_printf(s, "%-15s\t%lu\t%d\n",
- clocks[i]->name,
- clk_get_rate(clocks[i]),
- clocks[i]->usecount);
- }
-}
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
-
-static int dss_get_clock(struct clk **clock, const char *clk_name)
-{
- struct clk *clk;
-
- clk = clk_get(&core.pdev->dev, clk_name);
-
- if (IS_ERR(clk)) {
- DSSERR("can't get clock %s", clk_name);
- return PTR_ERR(clk);
- }
-
- *clock = clk;
-
- DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
-
- return 0;
-}
-
-static int dss_get_clocks(void)
-{
- int r;
-
- core.dss_ick = NULL;
- core.dss1_fck = NULL;
- core.dss2_fck = NULL;
- core.dss_54m_fck = NULL;
- core.dss_96m_fck = NULL;
-
- r = dss_get_clock(&core.dss_ick, "ick");
- if (r)
- goto err;
-
- r = dss_get_clock(&core.dss1_fck, "dss1_fck");
- if (r)
- goto err;
-
- r = dss_get_clock(&core.dss2_fck, "dss2_fck");
- if (r)
- goto err;
-
- r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
- if (r)
- goto err;
-
- r = dss_get_clock(&core.dss_96m_fck, "video_fck");
- if (r)
- goto err;
-
- return 0;
-
-err:
- if (core.dss_ick)
- clk_put(core.dss_ick);
- if (core.dss1_fck)
- clk_put(core.dss1_fck);
- if (core.dss2_fck)
- clk_put(core.dss2_fck);
- if (core.dss_54m_fck)
- clk_put(core.dss_54m_fck);
- if (core.dss_96m_fck)
- clk_put(core.dss_96m_fck);
-
- return r;
-}
-
-static void dss_put_clocks(void)
-{
- if (core.dss_96m_fck)
- clk_put(core.dss_96m_fck);
- clk_put(core.dss_54m_fck);
- clk_put(core.dss1_fck);
- clk_put(core.dss2_fck);
- clk_put(core.dss_ick);
-}
-
-unsigned long dss_clk_get_rate(enum dss_clock clk)
-{
- switch (clk) {
- case DSS_CLK_ICK:
- return clk_get_rate(core.dss_ick);
- case DSS_CLK_FCK1:
- return clk_get_rate(core.dss1_fck);
- case DSS_CLK_FCK2:
- return clk_get_rate(core.dss2_fck);
- case DSS_CLK_54M:
- return clk_get_rate(core.dss_54m_fck);
- case DSS_CLK_96M:
- return clk_get_rate(core.dss_96m_fck);
- }
-
- BUG();
- return 0;
-}
-
-static unsigned count_clk_bits(enum dss_clock clks)
-{
- unsigned num_clks = 0;
-
- if (clks & DSS_CLK_ICK)
- ++num_clks;
- if (clks & DSS_CLK_FCK1)
- ++num_clks;
- if (clks & DSS_CLK_FCK2)
- ++num_clks;
- if (clks & DSS_CLK_54M)
- ++num_clks;
- if (clks & DSS_CLK_96M)
- ++num_clks;
-
- return num_clks;
-}
-
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
-{
- unsigned num_clks = count_clk_bits(clks);
-
- if (clks & DSS_CLK_ICK)
- clk_enable(core.dss_ick);
- if (clks & DSS_CLK_FCK1)
- clk_enable(core.dss1_fck);
- if (clks & DSS_CLK_FCK2)
- clk_enable(core.dss2_fck);
- if (clks & DSS_CLK_54M)
- clk_enable(core.dss_54m_fck);
- if (clks & DSS_CLK_96M)
- clk_enable(core.dss_96m_fck);
-
- core.num_clks_enabled += num_clks;
-}
-
-void dss_clk_enable(enum dss_clock clks)
-{
- bool check_ctx = core.num_clks_enabled == 0;
-
- dss_clk_enable_no_ctx(clks);
-
- if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
- restore_all_ctx();
-}
-
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
-{
- unsigned num_clks = count_clk_bits(clks);
-
- if (clks & DSS_CLK_ICK)
- clk_disable(core.dss_ick);
- if (clks & DSS_CLK_FCK1)
- clk_disable(core.dss1_fck);
- if (clks & DSS_CLK_FCK2)
- clk_disable(core.dss2_fck);
- if (clks & DSS_CLK_54M)
- clk_disable(core.dss_54m_fck);
- if (clks & DSS_CLK_96M)
- clk_disable(core.dss_96m_fck);
-
- core.num_clks_enabled -= num_clks;
-}
-
-void dss_clk_disable(enum dss_clock clks)
-{
- if (cpu_is_omap34xx()) {
- unsigned num_clks = count_clk_bits(clks);
-
- BUG_ON(core.num_clks_enabled < num_clks);
-
- if (core.num_clks_enabled == num_clks)
- save_all_ctx();
- }
-
- dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_enable_all_no_ctx(void)
-{
- enum dss_clock clks;
-
- clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
- if (cpu_is_omap34xx())
- clks |= DSS_CLK_96M;
- dss_clk_enable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all_no_ctx(void)
-{
- enum dss_clock clks;
-
- clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
- if (cpu_is_omap34xx())
- clks |= DSS_CLK_96M;
- dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all(void)
-{
- enum dss_clock clks;
-
- clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
- if (cpu_is_omap34xx())
- clks |= DSS_CLK_96M;
- dss_clk_disable(clks);
-}
-
/* REGULATORS */
struct regulator *dss_get_vdds_dsi(void)
@@ -390,32 +84,7 @@ struct regulator *dss_get_vdds_sdi(void)
return reg;
}
-struct regulator *dss_get_vdda_dac(void)
-{
- struct regulator *reg;
-
- if (core.vdda_dac_reg != NULL)
- return core.vdda_dac_reg;
-
- reg = regulator_get(&core.pdev->dev, "vdda_dac");
- if (!IS_ERR(reg))
- core.vdda_dac_reg = reg;
-
- return reg;
-}
-
-/* DEBUGFS */
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-static void dss_debug_dump_clocks(struct seq_file *s)
-{
- core_dump_clocks(s);
- dss_dump_clocks(s);
- dispc_dump_clocks(s);
-#ifdef CONFIG_OMAP2_DSS_DSI
- dsi_dump_clocks(s);
-#endif
-}
-
static int dss_debug_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
@@ -497,7 +166,6 @@ static inline void dss_uninitialize_debugfs(void)
static int omap_dss_probe(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int skip_init = 0;
int r;
int i;
@@ -508,63 +176,43 @@ static int omap_dss_probe(struct platform_device *pdev)
dss_init_overlay_managers(pdev);
dss_init_overlays(pdev);
- r = dss_get_clocks();
- if (r)
- goto err_clocks;
-
- dss_clk_enable_all_no_ctx();
-
- core.ctx_id = dss_get_ctx_id();
- DSSDBG("initial ctx id %u\n", core.ctx_id);
-
-#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
- /* DISPC_CONTROL */
- if (omap_readl(0x48050440) & 1) /* LCD enabled? */
- skip_init = 1;
-#endif
-
- r = dss_init(skip_init);
+ r = dss_init_platform_driver();
if (r) {
- DSSERR("Failed to initialize DSS\n");
+ DSSERR("Failed to initialize DSS platform driver\n");
goto err_dss;
}
- r = rfbi_init();
- if (r) {
- DSSERR("Failed to initialize rfbi\n");
- goto err_rfbi;
- }
+ /* keep clocks enabled to prevent context saves/restores during init */
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
- r = dpi_init(pdev);
+ r = rfbi_init_platform_driver();
if (r) {
- DSSERR("Failed to initialize dpi\n");
- goto err_dpi;
+ DSSERR("Failed to initialize rfbi platform driver\n");
+ goto err_rfbi;
}
- r = dispc_init();
+ r = dispc_init_platform_driver();
if (r) {
- DSSERR("Failed to initialize dispc\n");
+ DSSERR("Failed to initialize dispc platform driver\n");
goto err_dispc;
}
- r = venc_init(pdev);
+ r = venc_init_platform_driver();
if (r) {
- DSSERR("Failed to initialize venc\n");
+ DSSERR("Failed to initialize venc platform driver\n");
goto err_venc;
}
- if (cpu_is_omap34xx()) {
- r = sdi_init(skip_init);
- if (r) {
- DSSERR("Failed to initialize SDI\n");
- goto err_sdi;
- }
+ r = dsi_init_platform_driver();
+ if (r) {
+ DSSERR("Failed to initialize DSI platform driver\n");
+ goto err_dsi;
+ }
- r = dsi_init(pdev);
- if (r) {
- DSSERR("Failed to initialize DSI\n");
- goto err_dsi;
- }
+ r = hdmi_init_platform_driver();
+ if (r) {
+ DSSERR("Failed to initialize hdmi\n");
+ goto err_hdmi;
}
r = dss_initialize_debugfs();
@@ -589,32 +237,25 @@ static int omap_dss_probe(struct platform_device *pdev)
pdata->default_device = dssdev;
}
- dss_clk_disable_all();
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return 0;
err_register:
dss_uninitialize_debugfs();
err_debugfs:
- if (cpu_is_omap34xx())
- dsi_exit();
+ hdmi_uninit_platform_driver();
+err_hdmi:
+ dsi_uninit_platform_driver();
err_dsi:
- if (cpu_is_omap34xx())
- sdi_exit();
-err_sdi:
- venc_exit();
+ venc_uninit_platform_driver();
err_venc:
- dispc_exit();
+ dispc_uninit_platform_driver();
err_dispc:
- dpi_exit();
-err_dpi:
- rfbi_exit();
+ rfbi_uninit_platform_driver();
err_rfbi:
- dss_exit();
+ dss_uninit_platform_driver();
err_dss:
- dss_clk_disable_all_no_ctx();
- dss_put_clocks();
-err_clocks:
return r;
}
@@ -623,61 +264,15 @@ static int omap_dss_remove(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
int i;
- int c;
dss_uninitialize_debugfs();
- venc_exit();
- dispc_exit();
- dpi_exit();
- rfbi_exit();
- if (cpu_is_omap34xx()) {
- dsi_exit();
- sdi_exit();
- }
-
- dss_exit();
-
- /* these should be removed at some point */
- c = core.dss_ick->usecount;
- if (c > 0) {
- DSSERR("warning: dss_ick usecount %d, disabling\n", c);
- while (c-- > 0)
- clk_disable(core.dss_ick);
- }
-
- c = core.dss1_fck->usecount;
- if (c > 0) {
- DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
- while (c-- > 0)
- clk_disable(core.dss1_fck);
- }
-
- c = core.dss2_fck->usecount;
- if (c > 0) {
- DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
- while (c-- > 0)
- clk_disable(core.dss2_fck);
- }
-
- c = core.dss_54m_fck->usecount;
- if (c > 0) {
- DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
- while (c-- > 0)
- clk_disable(core.dss_54m_fck);
- }
-
- if (core.dss_96m_fck) {
- c = core.dss_96m_fck->usecount;
- if (c > 0) {
- DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
- c);
- while (c-- > 0)
- clk_disable(core.dss_96m_fck);
- }
- }
-
- dss_put_clocks();
+ venc_uninit_platform_driver();
+ dispc_uninit_platform_driver();
+ rfbi_uninit_platform_driver();
+ dsi_uninit_platform_driver();
+ hdmi_uninit_platform_driver();
+ dss_uninit_platform_driver();
dss_uninit_overlays(pdev);
dss_uninit_overlay_managers(pdev);
@@ -965,11 +560,6 @@ static void __exit omap_dss_exit(void)
core.vdds_sdi_reg = NULL;
}
- if (core.vdda_dac_reg != NULL) {
- regulator_put(core.vdda_dac_reg);
- core.vdda_dac_reg = NULL;
- }
-
platform_driver_unregister(&omap_dss_driver);
omap_dss_bus_unregister();
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 9f8c69f16e6..7804779c9da 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/hardirq.h>
+#include <linux/interrupt.h>
#include <plat/sram.h>
#include <plat/clock.h>
@@ -42,8 +43,6 @@
#include "dss_features.h"
/* DISPC */
-#define DISPC_BASE 0x48050400
-
#define DISPC_SZ_REGS SZ_4K
struct dispc_reg { u16 idx; };
@@ -74,7 +73,7 @@ struct dispc_reg { u16 idx; };
#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408)
-#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
+#define DISPC_DIVISORo(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
#define DISPC_SIZE_DIG DISPC_REG(0x0078)
#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
@@ -129,6 +128,7 @@ struct dispc_reg { u16 idx; };
#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
+#define DISPC_DIVISOR DISPC_REG(0x0804)
#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
DISPC_IRQ_OCP_ERR | \
@@ -178,7 +178,9 @@ struct dispc_irq_stats {
};
static struct {
+ struct platform_device *pdev;
void __iomem *base;
+ int irq;
u32 fifo_size[3];
@@ -230,7 +232,7 @@ void dispc_save_context(void)
SR(TIMING_H(0));
SR(TIMING_V(0));
SR(POL_FREQ(0));
- SR(DIVISOR(0));
+ SR(DIVISORo(0));
SR(GLOBAL_ALPHA);
SR(SIZE_DIG);
SR(SIZE_LCD(0));
@@ -242,7 +244,7 @@ void dispc_save_context(void)
SR(TIMING_H(2));
SR(TIMING_V(2));
SR(POL_FREQ(2));
- SR(DIVISOR(2));
+ SR(DIVISORo(2));
SR(CONFIG2);
}
@@ -373,6 +375,9 @@ void dispc_save_context(void)
SR(VID_FIR_COEF_V(1, 7));
SR(VID_PRELOAD(1));
+
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ SR(DIVISOR);
}
void dispc_restore_context(void)
@@ -389,7 +394,7 @@ void dispc_restore_context(void)
RR(TIMING_H(0));
RR(TIMING_V(0));
RR(POL_FREQ(0));
- RR(DIVISOR(0));
+ RR(DIVISORo(0));
RR(GLOBAL_ALPHA);
RR(SIZE_DIG);
RR(SIZE_LCD(0));
@@ -400,7 +405,7 @@ void dispc_restore_context(void)
RR(TIMING_H(2));
RR(TIMING_V(2));
RR(POL_FREQ(2));
- RR(DIVISOR(2));
+ RR(DIVISORo(2));
RR(CONFIG2);
}
@@ -532,6 +537,9 @@ void dispc_restore_context(void)
RR(VID_PRELOAD(1));
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ RR(DIVISOR);
+
/* enable last, because LCD & DIGIT enable are here */
RR(CONTROL);
if (dss_has_feature(FEAT_MGR_LCD2))
@@ -552,9 +560,9 @@ void dispc_restore_context(void)
static inline void enable_clocks(bool enable)
{
if (enable)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
}
bool dispc_go_busy(enum omap_channel channel)
@@ -1000,6 +1008,20 @@ void dispc_set_burst_size(enum omap_plane plane,
enable_clocks(0);
}
+void dispc_enable_gamma_table(bool enable)
+{
+ /*
+ * This is partially implemented to support only disabling of
+ * the gamma table.
+ */
+ if (enable) {
+ DSSWARN("Gamma table enabling for TV not yet supported");
+ return;
+ }
+
+ REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
+}
+
static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
{
u32 val;
@@ -1129,10 +1151,16 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
u32 val;
const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
DISPC_VID_ACCU0(1) };
+ u8 hor_start, hor_end, vert_start, vert_end;
BUG_ON(plane == OMAP_DSS_GFX);
- val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+ dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+ dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+ val = FLD_VAL(vaccu, vert_start, vert_end) |
+ FLD_VAL(haccu, hor_start, hor_end);
+
dispc_write_reg(ac0_reg[plane-1], val);
}
@@ -1141,10 +1169,16 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
u32 val;
const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
DISPC_VID_ACCU1(1) };
+ u8 hor_start, hor_end, vert_start, vert_end;
BUG_ON(plane == OMAP_DSS_GFX);
- val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+ dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+ dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+ val = FLD_VAL(vaccu, vert_start, vert_end) |
+ FLD_VAL(haccu, hor_start, hor_end);
+
dispc_write_reg(ac1_reg[plane-1], val);
}
@@ -1182,16 +1216,25 @@ static void _dispc_set_scaling(enum omap_plane plane,
_dispc_set_fir(plane, fir_hinc, fir_vinc);
l = dispc_read_reg(dispc_reg_att[plane]);
- l &= ~((0x0f << 5) | (0x3 << 21));
+ /* RESIZEENABLE and VERTICALTAPS */
+ l &= ~((0x3 << 5) | (0x1 << 21));
l |= fir_hinc ? (1 << 5) : 0;
l |= fir_vinc ? (1 << 6) : 0;
+ l |= five_taps ? (1 << 21) : 0;
- l |= hscaleup ? 0 : (1 << 7);
- l |= vscaleup ? 0 : (1 << 8);
+ /* VRESIZECONF and HRESIZECONF */
+ if (dss_has_feature(FEAT_RESIZECONF)) {
+ l &= ~(0x3 << 7);
+ l |= hscaleup ? 0 : (1 << 7);
+ l |= vscaleup ? 0 : (1 << 8);
+ }
- l |= five_taps ? (1 << 21) : 0;
- l |= five_taps ? (1 << 22) : 0;
+ /* LINEBUFFERSPLIT */
+ if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
+ l &= ~(0x1 << 22);
+ l |= five_taps ? (1 << 22) : 0;
+ }
dispc_write_reg(dispc_reg_att[plane], l);
@@ -1215,9 +1258,11 @@ static void _dispc_set_scaling(enum omap_plane plane,
static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
bool mirroring, enum omap_color_mode color_mode)
{
+ bool row_repeat = false;
+ int vidrot = 0;
+
if (color_mode == OMAP_DSS_COLOR_YUV2 ||
color_mode == OMAP_DSS_COLOR_UYVY) {
- int vidrot = 0;
if (mirroring) {
switch (rotation) {
@@ -1251,16 +1296,15 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
}
}
- REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
-
if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
- REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
+ row_repeat = true;
else
- REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
- } else {
- REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
- REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
+ row_repeat = false;
}
+
+ REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+ if (dss_has_feature(FEAT_ROWREPEATENABLE))
+ REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
}
static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -2293,7 +2337,7 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
BUG_ON(pck_div < 2);
enable_clocks(1);
- dispc_write_reg(DISPC_DIVISOR(channel),
+ dispc_write_reg(DISPC_DIVISORo(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
enable_clocks(0);
}
@@ -2302,7 +2346,7 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
int *pck_div)
{
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR(channel));
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
*lck_div = FLD_GET(l, 23, 16);
*pck_div = FLD_GET(l, 7, 0);
}
@@ -2311,14 +2355,17 @@ unsigned long dispc_fclk_rate(void)
{
unsigned long r = 0;
- if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
- r = dss_clk_get_rate(DSS_CLK_FCK1);
- else
-#ifdef CONFIG_OMAP2_DSS_DSI
- r = dsi_get_dsi1_pll_rate();
-#else
- BUG();
-#endif
+ switch (dss_get_dispc_clk_source()) {
+ case DSS_CLK_SRC_FCK:
+ r = dss_clk_get_rate(DSS_CLK_FCK);
+ break;
+ case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ r = dsi_get_pll_hsdiv_dispc_rate();
+ break;
+ default:
+ BUG();
+ }
+
return r;
}
@@ -2328,47 +2375,72 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
unsigned long r;
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR(channel));
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
lcd = FLD_GET(l, 23, 16);
- r = dispc_fclk_rate();
+ switch (dss_get_lcd_clk_source(channel)) {
+ case DSS_CLK_SRC_FCK:
+ r = dss_clk_get_rate(DSS_CLK_FCK);
+ break;
+ case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ r = dsi_get_pll_hsdiv_dispc_rate();
+ break;
+ default:
+ BUG();
+ }
return r / lcd;
}
unsigned long dispc_pclk_rate(enum omap_channel channel)
{
- int lcd, pcd;
+ int pcd;
unsigned long r;
u32 l;
- l = dispc_read_reg(DISPC_DIVISOR(channel));
+ l = dispc_read_reg(DISPC_DIVISORo(channel));
- lcd = FLD_GET(l, 23, 16);
pcd = FLD_GET(l, 7, 0);
- r = dispc_fclk_rate();
+ r = dispc_lclk_rate(channel);
- return r / lcd / pcd;
+ return r / pcd;
}
void dispc_dump_clocks(struct seq_file *s)
{
int lcd, pcd;
+ u32 l;
+ enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+ enum dss_clk_source lcd_clk_src;
enable_clocks(1);
seq_printf(s, "- DISPC -\n");
- seq_printf(s, "dispc fclk source = %s\n",
- dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
- "dss1_alwon_fclk" : "dsi1_pll_fclk");
+ seq_printf(s, "dispc fclk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(dispc_clk_src),
+ dss_feat_get_clk_source_name(dispc_clk_src));
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
+ if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+ seq_printf(s, "- DISPC-CORE-CLK -\n");
+ l = dispc_read_reg(DISPC_DIVISOR);
+ lcd = FLD_GET(l, 23, 16);
+
+ seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+ (dispc_fclk_rate()/lcd), lcd);
+ }
seq_printf(s, "- LCD1 -\n");
+ lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD);
+
+ seq_printf(s, "lcd1_clk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(lcd_clk_src),
+ dss_feat_get_clk_source_name(lcd_clk_src));
+
dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2378,6 +2450,12 @@ void dispc_dump_clocks(struct seq_file *s)
if (dss_has_feature(FEAT_MGR_LCD2)) {
seq_printf(s, "- LCD2 -\n");
+ lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2);
+
+ seq_printf(s, "lcd2_clk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(lcd_clk_src),
+ dss_feat_get_clk_source_name(lcd_clk_src));
+
dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2440,7 +2518,7 @@ void dispc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
DUMPREG(DISPC_REVISION);
DUMPREG(DISPC_SYSCONFIG);
@@ -2459,7 +2537,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_TIMING_H(0));
DUMPREG(DISPC_TIMING_V(0));
DUMPREG(DISPC_POL_FREQ(0));
- DUMPREG(DISPC_DIVISOR(0));
+ DUMPREG(DISPC_DIVISORo(0));
DUMPREG(DISPC_GLOBAL_ALPHA);
DUMPREG(DISPC_SIZE_DIG);
DUMPREG(DISPC_SIZE_LCD(0));
@@ -2471,7 +2549,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_TIMING_H(2));
DUMPREG(DISPC_TIMING_V(2));
DUMPREG(DISPC_POL_FREQ(2));
- DUMPREG(DISPC_DIVISOR(2));
+ DUMPREG(DISPC_DIVISORo(2));
DUMPREG(DISPC_SIZE_LCD(2));
}
@@ -2597,7 +2675,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_VID_PRELOAD(0));
DUMPREG(DISPC_VID_PRELOAD(1));
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
#undef DUMPREG
}
@@ -2713,8 +2791,8 @@ int dispc_get_clock_div(enum omap_channel channel,
fck = dispc_fclk_rate();
- cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
- cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
+ cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
+ cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
cinfo->lck = fck / cinfo->lck_div;
cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2791,6 +2869,9 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
break;
}
+ if (ret)
+ goto err;
+
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -2866,10 +2947,10 @@ static void print_irq_status(u32 status)
* 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. */
-void dispc_irq_handler(void)
+static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
{
int i;
- u32 irqstatus;
+ u32 irqstatus, irqenable;
u32 handledirqs = 0;
u32 unhandled_errors;
struct omap_dispc_isr_data *isr_data;
@@ -2878,6 +2959,13 @@ void dispc_irq_handler(void)
spin_lock(&dispc.irq_lock);
irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
+ irqenable = dispc_read_reg(DISPC_IRQENABLE);
+
+ /* IRQ is not for us */
+ if (!(irqstatus & irqenable)) {
+ spin_unlock(&dispc.irq_lock);
+ return IRQ_NONE;
+ }
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock(&dispc.irq_stats_lock);
@@ -2929,6 +3017,8 @@ void dispc_irq_handler(void)
}
spin_unlock(&dispc.irq_lock);
+
+ return IRQ_HANDLED;
}
static void dispc_error_worker(struct work_struct *work)
@@ -3253,6 +3343,15 @@ static void _omap_dispc_initial_config(void)
l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
dispc_write_reg(DISPC_SYSCONFIG, l);
+ /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
+ if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+ l = dispc_read_reg(DISPC_DIVISOR);
+ /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
+ l = FLD_MOD(l, 1, 0, 0);
+ l = FLD_MOD(l, 1, 23, 16);
+ dispc_write_reg(DISPC_DIVISOR, l);
+ }
+
/* FUNCGATED */
if (dss_has_feature(FEAT_FUNCGATED))
REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
@@ -3269,47 +3368,6 @@ static void _omap_dispc_initial_config(void)
dispc_read_plane_fifo_sizes();
}
-int dispc_init(void)
-{
- u32 rev;
-
- spin_lock_init(&dispc.irq_lock);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- spin_lock_init(&dispc.irq_stats_lock);
- dispc.irq_stats.last_reset = jiffies;
-#endif
-
- INIT_WORK(&dispc.error_work, dispc_error_worker);
-
- dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
- if (!dispc.base) {
- DSSERR("can't ioremap DISPC\n");
- return -ENOMEM;
- }
-
- enable_clocks(1);
-
- _omap_dispc_initial_config();
-
- _omap_dispc_initialize_irq();
-
- dispc_save_context();
-
- rev = dispc_read_reg(DISPC_REVISION);
- printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
- FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
- enable_clocks(0);
-
- return 0;
-}
-
-void dispc_exit(void)
-{
- iounmap(dispc.base);
-}
-
int dispc_enable_plane(enum omap_plane plane, bool enable)
{
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
@@ -3359,3 +3417,94 @@ int dispc_setup_plane(enum omap_plane plane,
return r;
}
+
+/* DISPC HW IP initialisation */
+static int omap_dispchw_probe(struct platform_device *pdev)
+{
+ u32 rev;
+ int r = 0;
+ struct resource *dispc_mem;
+
+ dispc.pdev = pdev;
+
+ spin_lock_init(&dispc.irq_lock);
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock_init(&dispc.irq_stats_lock);
+ dispc.irq_stats.last_reset = jiffies;
+#endif
+
+ INIT_WORK(&dispc.error_work, dispc_error_worker);
+
+ dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
+ if (!dispc_mem) {
+ DSSERR("can't get IORESOURCE_MEM DISPC\n");
+ r = -EINVAL;
+ goto fail0;
+ }
+ dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
+ if (!dispc.base) {
+ DSSERR("can't ioremap DISPC\n");
+ r = -ENOMEM;
+ goto fail0;
+ }
+ dispc.irq = platform_get_irq(dispc.pdev, 0);
+ if (dispc.irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ r = -ENODEV;
+ goto fail1;
+ }
+
+ r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
+ "OMAP DISPC", dispc.pdev);
+ if (r < 0) {
+ DSSERR("request_irq failed\n");
+ goto fail1;
+ }
+
+ enable_clocks(1);
+
+ _omap_dispc_initial_config();
+
+ _omap_dispc_initialize_irq();
+
+ dispc_save_context();
+
+ rev = dispc_read_reg(DISPC_REVISION);
+ dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ enable_clocks(0);
+
+ return 0;
+fail1:
+ iounmap(dispc.base);
+fail0:
+ return r;
+}
+
+static int omap_dispchw_remove(struct platform_device *pdev)
+{
+ free_irq(dispc.irq, dispc.pdev);
+ iounmap(dispc.base);
+ return 0;
+}
+
+static struct platform_driver omap_dispchw_driver = {
+ .probe = omap_dispchw_probe,
+ .remove = omap_dispchw_remove,
+ .driver = {
+ .name = "omapdss_dispc",
+ .owner = THIS_MODULE,
+ },
+};
+
+int dispc_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dispchw_driver);
+}
+
+void dispc_uninit_platform_driver(void)
+{
+ return platform_driver_unregister(&omap_dispchw_driver);
+}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 22dd7a474f7..a85a6f38b40 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -25,14 +25,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
-#include <linux/list.h>
#include <linux/platform_device.h>
#include <plat/display.h>
#include "dss.h"
-static LIST_HEAD(display_list);
-
static ssize_t display_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -345,6 +342,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
return 16;
case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_SDI:
+ case OMAP_DISPLAY_TYPE_HDMI:
return 24;
default:
BUG();
@@ -371,6 +369,7 @@ bool dss_use_replication(struct omap_dss_device *dssdev,
case OMAP_DISPLAY_TYPE_DPI:
bpp = dssdev->phy.dpi.data_lines;
break;
+ case OMAP_DISPLAY_TYPE_HDMI:
case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_SDI:
bpp = 24;
@@ -396,29 +395,6 @@ void dss_init_device(struct platform_device *pdev,
switch (dssdev->type) {
#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_RFBI
- case OMAP_DISPLAY_TYPE_DBI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_SDI
- case OMAP_DISPLAY_TYPE_SDI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
- case OMAP_DISPLAY_TYPE_DSI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
- case OMAP_DISPLAY_TYPE_VENC:
-#endif
- break;
- default:
- DSSERR("Support for display '%s' not compiled in.\n",
- dssdev->name);
- return;
- }
-
- switch (dssdev->type) {
-#ifdef CONFIG_OMAP2_DSS_DPI
- case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
break;
#endif
@@ -442,8 +418,13 @@ void dss_init_device(struct platform_device *pdev,
r = dsi_init_display(dssdev);
break;
#endif
+ case OMAP_DISPLAY_TYPE_HDMI:
+ r = hdmi_init_display(dssdev);
+ break;
default:
- BUG();
+ DSSERR("Support for display '%s' not compiled in.\n",
+ dssdev->name);
+ return;
}
if (r) {
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 75fb0a51543..2d3ca4ca4a0 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -57,13 +57,13 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
if (r)
return r;
- dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+ dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
return r;
- *fck = dsi_cinfo.dsi1_pll_fclk;
+ *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
*lck_div = dispc_cinfo.lck_div;
*pck_div = dispc_cinfo.pck_div;
@@ -107,7 +107,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
bool is_tft;
int r = 0;
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb);
@@ -137,7 +137,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
dispc_set_lcd_timings(dssdev->manager->id, t);
err0:
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return r;
}
@@ -173,14 +173,14 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err1;
}
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
r = dpi_basic_init(dssdev);
if (r)
goto err2;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- dss_clk_enable(DSS_CLK_FCK2);
+ dss_clk_enable(DSS_CLK_SYSCK);
r = dsi_pll_init(dssdev, 0, 1);
if (r)
goto err3;
@@ -199,10 +199,10 @@ err4:
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
dsi_pll_uninit();
err3:
- dss_clk_disable(DSS_CLK_FCK2);
+ dss_clk_disable(DSS_CLK_SYSCK);
#endif
err2:
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg);
err1:
@@ -217,12 +217,12 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dssdev->manager->disable(dssdev->manager);
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
- dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
dsi_pll_uninit();
- dss_clk_disable(DSS_CLK_FCK2);
+ dss_clk_disable(DSS_CLK_SYSCK);
#endif
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg);
@@ -271,7 +271,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
if (r)
return r;
- fck = dsi_cinfo.dsi1_pll_fclk;
+ fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
lck_div = dispc_cinfo.lck_div;
pck_div = dispc_cinfo.pck_div;
}
@@ -303,22 +303,27 @@ int dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- return 0;
-}
+ if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
+ struct regulator *vdds_dsi;
-int dpi_init(struct platform_device *pdev)
-{
- if (cpu_is_omap34xx()) {
- dpi.vdds_dsi_reg = dss_get_vdds_dsi();
- if (IS_ERR(dpi.vdds_dsi_reg)) {
+ vdds_dsi = dss_get_vdds_dsi();
+
+ if (IS_ERR(vdds_dsi)) {
DSSERR("can't get VDDS_DSI regulator\n");
- return PTR_ERR(dpi.vdds_dsi_reg);
+ return PTR_ERR(vdds_dsi);
}
+
+ dpi.vdds_dsi_reg = vdds_dsi;
}
return 0;
}
+int dpi_init(void)
+{
+ return 0;
+}
+
void dpi_exit(void)
{
}
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index ddf3a056082..0a7f1a47f8e 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -38,12 +38,11 @@
#include <plat/clock.h>
#include "dss.h"
+#include "dss_features.h"
/*#define VERBOSE_IRQ*/
#define DSI_CATCH_MISSING_TE
-#define DSI_BASE 0x4804FC00
-
struct dsi_reg { u16 idx; };
#define DSI_REG(idx) ((const struct dsi_reg) { idx })
@@ -186,13 +185,15 @@ struct dsi_reg { u16 idx; };
#define DSI_DT_RX_SHORT_READ_1 0x21
#define DSI_DT_RX_SHORT_READ_2 0x22
-#define FINT_MAX 2100000
-#define FINT_MIN 750000
-#define REGN_MAX (1 << 7)
-#define REGM_MAX ((1 << 11) - 1)
-#define REGM3_MAX (1 << 4)
-#define REGM4_MAX (1 << 4)
-#define LP_DIV_MAX ((1 << 13) - 1)
+typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+
+#define DSI_MAX_NR_ISRS 2
+
+struct dsi_isr_data {
+ omap_dsi_isr_t isr;
+ void *arg;
+ u32 mask;
+};
enum fifo_size {
DSI_FIFO_SIZE_0 = 0,
@@ -220,9 +221,17 @@ struct dsi_irq_stats {
unsigned cio_irqs[32];
};
+struct dsi_isr_tables {
+ struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
+ struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
+ struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
+};
+
static struct
{
+ struct platform_device *pdev;
void __iomem *base;
+ int irq;
struct dsi_clock_info current_cinfo;
@@ -232,6 +241,7 @@ static struct
enum dsi_vc_mode mode;
struct omap_dss_device *dssdev;
enum fifo_size fifo_size;
+ int vc_id;
} vc[4];
struct mutex lock;
@@ -239,8 +249,10 @@ static struct
unsigned pll_locked;
- struct completion bta_completion;
- void (*bta_callback)(void);
+ spinlock_t irq_lock;
+ struct dsi_isr_tables isr_tables;
+ /* space for a copy used by the interrupt handler */
+ struct dsi_isr_tables isr_tables_copy;
int update_channel;
struct dsi_update_region update_region;
@@ -275,6 +287,11 @@ static struct
spinlock_t irq_stats_lock;
struct dsi_irq_stats irq_stats;
#endif
+ /* DSI PLL Parameter Ranges */
+ unsigned long regm_max, regn_max;
+ unsigned long regm_dispc_max, regm_dsi_max;
+ unsigned long fint_min, fint_max;
+ unsigned long lpdiv_max;
} dsi;
#ifdef DEBUG
@@ -318,6 +335,11 @@ static bool dsi_bus_is_locked(void)
return dsi.bus_lock.count == 0;
}
+static void dsi_completion_handler(void *data, u32 mask)
+{
+ complete((struct completion *)data);
+}
+
static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
int value)
{
@@ -387,6 +409,9 @@ static void dsi_perf_show(const char *name)
static void print_irq_status(u32 status)
{
+ if (status == 0)
+ return;
+
#ifndef VERBOSE_IRQ
if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
return;
@@ -422,6 +447,9 @@ static void print_irq_status(u32 status)
static void print_irq_status_vc(int channel, u32 status)
{
+ if (status == 0)
+ return;
+
#ifndef VERBOSE_IRQ
if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
return;
@@ -448,6 +476,9 @@ static void print_irq_status_vc(int channel, u32 status)
static void print_irq_status_cio(u32 status)
{
+ if (status == 0)
+ return;
+
printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
#define PIS(x) \
@@ -478,22 +509,33 @@ static void print_irq_status_cio(u32 status)
printk("\n");
}
-static int debug_irq;
-
-/* called from dss */
-void dsi_irq_handler(void)
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
{
- u32 irqstatus, vcstatus, ciostatus;
int i;
- irqstatus = dsi_read_reg(DSI_IRQSTATUS);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock(&dsi.irq_stats_lock);
+
dsi.irq_stats.irq_count++;
dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+
+ for (i = 0; i < 4; ++i)
+ dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+
+ dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+
+ spin_unlock(&dsi.irq_stats_lock);
+}
+#else
+#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
#endif
+static int debug_irq;
+
+static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+ int i;
+
if (irqstatus & DSI_IRQ_ERROR_MASK) {
DSSERR("DSI error, irqstatus %x\n", irqstatus);
print_irq_status(irqstatus);
@@ -504,37 +546,88 @@ void dsi_irq_handler(void)
print_irq_status(irqstatus);
}
-#ifdef DSI_CATCH_MISSING_TE
- if (irqstatus & DSI_IRQ_TE_TRIGGER)
- del_timer(&dsi.te_timer);
-#endif
+ for (i = 0; i < 4; ++i) {
+ if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
+ DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+ i, vcstatus[i]);
+ print_irq_status_vc(i, vcstatus[i]);
+ } else if (debug_irq) {
+ print_irq_status_vc(i, vcstatus[i]);
+ }
+ }
+
+ if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+ DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+ print_irq_status_cio(ciostatus);
+ } else if (debug_irq) {
+ print_irq_status_cio(ciostatus);
+ }
+}
+
+static void dsi_call_isrs(struct dsi_isr_data *isr_array,
+ unsigned isr_array_size, u32 irqstatus)
+{
+ struct dsi_isr_data *isr_data;
+ int i;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+ if (isr_data->isr && isr_data->mask & irqstatus)
+ isr_data->isr(isr_data->arg, irqstatus);
+ }
+}
+
+static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
+ u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+ int i;
+
+ dsi_call_isrs(isr_tables->isr_table,
+ ARRAY_SIZE(isr_tables->isr_table),
+ irqstatus);
for (i = 0; i < 4; ++i) {
- if ((irqstatus & (1<<i)) == 0)
+ if (vcstatus[i] == 0)
continue;
+ dsi_call_isrs(isr_tables->isr_table_vc[i],
+ ARRAY_SIZE(isr_tables->isr_table_vc[i]),
+ vcstatus[i]);
+ }
- vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+ if (ciostatus != 0)
+ dsi_call_isrs(isr_tables->isr_table_cio,
+ ARRAY_SIZE(isr_tables->isr_table_cio),
+ ciostatus);
+}
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
-#endif
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+{
+ u32 irqstatus, vcstatus[4], ciostatus;
+ int i;
- if (vcstatus & DSI_VC_IRQ_BTA) {
- complete(&dsi.bta_completion);
+ spin_lock(&dsi.irq_lock);
- if (dsi.bta_callback)
- dsi.bta_callback();
- }
+ irqstatus = dsi_read_reg(DSI_IRQSTATUS);
- if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
- DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
- i, vcstatus);
- print_irq_status_vc(i, vcstatus);
- } else if (debug_irq) {
- print_irq_status_vc(i, vcstatus);
+ /* IRQ is not for us */
+ if (!irqstatus) {
+ spin_unlock(&dsi.irq_lock);
+ return IRQ_NONE;
+ }
+
+ dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+ /* flush posted write */
+ dsi_read_reg(DSI_IRQSTATUS);
+
+ for (i = 0; i < 4; ++i) {
+ if ((irqstatus & (1 << i)) == 0) {
+ vcstatus[i] = 0;
+ continue;
}
- dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
+ vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+
+ dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
/* flush posted write */
dsi_read_reg(DSI_VC_IRQSTATUS(i));
}
@@ -542,117 +635,307 @@ void dsi_irq_handler(void)
if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
-#endif
-
dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
/* flush posted write */
dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+ } else {
+ ciostatus = 0;
+ }
- if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
- DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
- print_irq_status_cio(ciostatus);
- } else if (debug_irq) {
- print_irq_status_cio(ciostatus);
- }
+#ifdef DSI_CATCH_MISSING_TE
+ if (irqstatus & DSI_IRQ_TE_TRIGGER)
+ del_timer(&dsi.te_timer);
+#endif
+
+ /* make a copy and unlock, so that isrs can unregister
+ * themselves */
+ memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+
+ spin_unlock(&dsi.irq_lock);
+
+ dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+
+ dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+
+ dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
+
+ return IRQ_HANDLED;
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+ unsigned isr_array_size, u32 default_mask,
+ const struct dsi_reg enable_reg,
+ const struct dsi_reg status_reg)
+{
+ struct dsi_isr_data *isr_data;
+ u32 mask;
+ u32 old_mask;
+ int i;
+
+ mask = default_mask;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+
+ if (isr_data->isr == NULL)
+ continue;
+
+ mask |= isr_data->mask;
}
- dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
- /* flush posted write */
- dsi_read_reg(DSI_IRQSTATUS);
+ old_mask = dsi_read_reg(enable_reg);
+ /* clear the irqstatus for newly enabled irqs */
+ dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
+ dsi_write_reg(enable_reg, mask);
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
- spin_unlock(&dsi.irq_stats_lock);
+ /* flush posted writes */
+ dsi_read_reg(enable_reg);
+ dsi_read_reg(status_reg);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(void)
+{
+ u32 mask = DSI_IRQ_ERROR_MASK;
+#ifdef DSI_CATCH_MISSING_TE
+ mask |= DSI_IRQ_TE_TRIGGER;
#endif
+ _omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
+ ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+ DSI_IRQENABLE, DSI_IRQSTATUS);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(int vc)
+{
+ _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
+ ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+ DSI_VC_IRQ_ERROR_MASK,
+ DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
}
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(void)
+{
+ _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+ DSI_CIO_IRQ_ERROR_MASK,
+ DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+}
static void _dsi_initialize_irq(void)
{
- u32 l;
+ unsigned long flags;
+ int vc;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+
+ _omap_dsi_set_irqs();
+ for (vc = 0; vc < 4; ++vc)
+ _omap_dsi_set_irqs_vc(vc);
+ _omap_dsi_set_irqs_cio();
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
+}
+
+static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+ struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+ struct dsi_isr_data *isr_data;
+ int free_idx;
int i;
- /* disable all interrupts */
- dsi_write_reg(DSI_IRQENABLE, 0);
- for (i = 0; i < 4; ++i)
- dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
- dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
+ BUG_ON(isr == NULL);
- /* clear interrupt status */
- l = dsi_read_reg(DSI_IRQSTATUS);
- dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
+ /* check for duplicate entry and find a free slot */
+ free_idx = -1;
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
- for (i = 0; i < 4; ++i) {
- l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
- dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
+ if (isr_data->isr == isr && isr_data->arg == arg &&
+ isr_data->mask == mask) {
+ return -EINVAL;
+ }
+
+ if (isr_data->isr == NULL && free_idx == -1)
+ free_idx = i;
}
- l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
- dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
+ if (free_idx == -1)
+ return -EBUSY;
- /* enable error irqs */
- l = DSI_IRQ_ERROR_MASK;
-#ifdef DSI_CATCH_MISSING_TE
- l |= DSI_IRQ_TE_TRIGGER;
-#endif
- dsi_write_reg(DSI_IRQENABLE, l);
+ isr_data = &isr_array[free_idx];
+ isr_data->isr = isr;
+ isr_data->arg = arg;
+ isr_data->mask = mask;
- l = DSI_VC_IRQ_ERROR_MASK;
- for (i = 0; i < 4; ++i)
- dsi_write_reg(DSI_VC_IRQENABLE(i), l);
+ return 0;
+}
+
+static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+ struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+ struct dsi_isr_data *isr_data;
+ int i;
+
+ for (i = 0; i < isr_array_size; i++) {
+ isr_data = &isr_array[i];
+ if (isr_data->isr != isr || isr_data->arg != arg ||
+ isr_data->mask != mask)
+ continue;
+
+ isr_data->isr = NULL;
+ isr_data->arg = NULL;
+ isr_data->mask = 0;
+
+ return 0;
+ }
- l = DSI_CIO_IRQ_ERROR_MASK;
- dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
+ return -EINVAL;
}
-static u32 dsi_get_errors(void)
+static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
{
unsigned long flags;
- u32 e;
- spin_lock_irqsave(&dsi.errors_lock, flags);
- e = dsi.errors;
- dsi.errors = 0;
- spin_unlock_irqrestore(&dsi.errors_lock, flags);
- return e;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+ ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+ if (r == 0)
+ _omap_dsi_set_irqs();
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+ return r;
}
-static void dsi_vc_enable_bta_irq(int channel)
+static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
{
- u32 l;
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+ ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+ if (r == 0)
+ _omap_dsi_set_irqs();
- dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
- l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
- l |= DSI_VC_IRQ_BTA;
- dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+ return r;
}
-static void dsi_vc_disable_bta_irq(int channel)
+static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+ u32 mask)
{
- u32 l;
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask,
+ dsi.isr_tables.isr_table_vc[channel],
+ ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_vc(channel);
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+ u32 mask)
+{
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask,
+ dsi.isr_tables.isr_table_vc[channel],
+ ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_vc(channel);
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_cio();
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+ return r;
+}
+
+static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&dsi.irq_lock, flags);
+
+ r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+ ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+ if (r == 0)
+ _omap_dsi_set_irqs_cio();
+
+ spin_unlock_irqrestore(&dsi.irq_lock, flags);
- l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
- l &= ~DSI_VC_IRQ_BTA;
- dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+ return r;
}
-/* DSI func clock. this could also be DSI2_PLL_FCLK */
+static u32 dsi_get_errors(void)
+{
+ unsigned long flags;
+ u32 e;
+ spin_lock_irqsave(&dsi.errors_lock, flags);
+ e = dsi.errors;
+ dsi.errors = 0;
+ spin_unlock_irqrestore(&dsi.errors_lock, flags);
+ return e;
+}
+
+/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
static inline void enable_clocks(bool enable)
{
if (enable)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
}
/* source clock for DSI PLL. this could also be PCLKFREE */
static inline void dsi_enable_pll_clock(bool enable)
{
if (enable)
- dss_clk_enable(DSS_CLK_FCK2);
+ dss_clk_enable(DSS_CLK_SYSCK);
else
- dss_clk_disable(DSS_CLK_FCK2);
+ dss_clk_disable(DSS_CLK_SYSCK);
if (enable && dsi.pll_locked) {
if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
@@ -707,14 +990,14 @@ static inline int dsi_if_enable(bool enable)
return 0;
}
-unsigned long dsi_get_dsi1_pll_rate(void)
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
{
- return dsi.current_cinfo.dsi1_pll_fclk;
+ return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk;
}
-static unsigned long dsi_get_dsi2_pll_rate(void)
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(void)
{
- return dsi.current_cinfo.dsi2_pll_fclk;
+ return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk;
}
static unsigned long dsi_get_txbyteclkhs(void)
@@ -726,12 +1009,12 @@ static unsigned long dsi_fclk_rate(void)
{
unsigned long r;
- if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
- /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
- r = dss_clk_get_rate(DSS_CLK_FCK1);
+ if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) {
+ /* DSI FCLK source is DSS_CLK_FCK */
+ r = dss_clk_get_rate(DSS_CLK_FCK);
} else {
- /* DSI FCLK source is DSI2_PLL_FCLK */
- r = dsi_get_dsi2_pll_rate();
+ /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
+ r = dsi_get_pll_hsdiv_dsi_rate();
}
return r;
@@ -745,7 +1028,7 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
- if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
+ if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
return -EINVAL;
dsi_fclk = dsi_fclk_rate();
@@ -795,22 +1078,22 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
struct dsi_clock_info *cinfo)
{
- if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
+ if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
return -EINVAL;
- if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
+ if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
return -EINVAL;
- if (cinfo->regm3 > REGM3_MAX)
+ if (cinfo->regm_dispc > dsi.regm_dispc_max)
return -EINVAL;
- if (cinfo->regm4 > REGM4_MAX)
+ if (cinfo->regm_dsi > dsi.regm_dsi_max)
return -EINVAL;
- if (cinfo->use_dss2_fck) {
- cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
+ if (cinfo->use_sys_clk) {
+ cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
/* XXX it is unclear if highfreq should be used
- * with DSS2_FCK source also */
+ * with DSS_SYS_CLK source also */
cinfo->highfreq = 0;
} else {
cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
@@ -823,7 +1106,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
- if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
+ if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
return -EINVAL;
cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -831,15 +1114,17 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
return -EINVAL;
- if (cinfo->regm3 > 0)
- cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
+ if (cinfo->regm_dispc > 0)
+ cinfo->dsi_pll_hsdiv_dispc_clk =
+ cinfo->clkin4ddr / cinfo->regm_dispc;
else
- cinfo->dsi1_pll_fclk = 0;
+ cinfo->dsi_pll_hsdiv_dispc_clk = 0;
- if (cinfo->regm4 > 0)
- cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
+ if (cinfo->regm_dsi > 0)
+ cinfo->dsi_pll_hsdiv_dsi_clk =
+ cinfo->clkin4ddr / cinfo->regm_dsi;
else
- cinfo->dsi2_pll_fclk = 0;
+ cinfo->dsi_pll_hsdiv_dsi_clk = 0;
return 0;
}
@@ -852,23 +1137,25 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
struct dispc_clock_info best_dispc;
int min_fck_per_pck;
int match = 0;
- unsigned long dss_clk_fck2;
+ unsigned long dss_sys_clk, max_dss_fck;
+
+ dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
- dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
+ max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
if (req_pck == dsi.cache_req_pck &&
- dsi.cache_cinfo.clkin == dss_clk_fck2) {
+ dsi.cache_cinfo.clkin == dss_sys_clk) {
DSSDBG("DSI clock info found from cache\n");
*dsi_cinfo = dsi.cache_cinfo;
- dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
- dispc_cinfo);
+ dispc_find_clk_divs(is_tft, req_pck,
+ dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
return 0;
}
min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+ req_pck * min_fck_per_pck > max_dss_fck) {
DSSERR("Requested pixel clock not possible with the current "
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
"the constraint off.\n");
@@ -882,24 +1169,24 @@ retry:
memset(&best_dispc, 0, sizeof(best_dispc));
memset(&cur, 0, sizeof(cur));
- cur.clkin = dss_clk_fck2;
- cur.use_dss2_fck = 1;
+ cur.clkin = dss_sys_clk;
+ cur.use_sys_clk = 1;
cur.highfreq = 0;
/* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
/* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
/* To reduce PLL lock time, keep Fint high (around 2 MHz) */
- for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
+ for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
if (cur.highfreq == 0)
cur.fint = cur.clkin / cur.regn;
else
cur.fint = cur.clkin / (2 * cur.regn);
- if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
+ if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
continue;
/* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
- for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
+ for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
unsigned long a, b;
a = 2 * cur.regm * (cur.clkin/1000);
@@ -909,30 +1196,32 @@ retry:
if (cur.clkin4ddr > 1800 * 1000 * 1000)
break;
- /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
- for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
- ++cur.regm3) {
+ /* dsi_pll_hsdiv_dispc_clk(MHz) =
+ * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
+ for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
+ ++cur.regm_dispc) {
struct dispc_clock_info cur_dispc;
- cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
+ cur.dsi_pll_hsdiv_dispc_clk =
+ cur.clkin4ddr / cur.regm_dispc;
/* this will narrow down the search a bit,
* but still give pixclocks below what was
* requested */
- if (cur.dsi1_pll_fclk < req_pck)
+ if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
break;
- if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
+ if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
continue;
if (min_fck_per_pck &&
- cur.dsi1_pll_fclk <
+ cur.dsi_pll_hsdiv_dispc_clk <
req_pck * min_fck_per_pck)
continue;
match = 1;
dispc_find_clk_divs(is_tft, req_pck,
- cur.dsi1_pll_fclk,
+ cur.dsi_pll_hsdiv_dispc_clk,
&cur_dispc);
if (abs(cur_dispc.pck - req_pck) <
@@ -961,9 +1250,9 @@ found:
return -EINVAL;
}
- /* DSI2_PLL_FCLK (regm4) is not used */
- best.regm4 = 0;
- best.dsi2_pll_fclk = 0;
+ /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
+ best.regm_dsi = 0;
+ best.dsi_pll_hsdiv_dsi_clk = 0;
if (dsi_cinfo)
*dsi_cinfo = best;
@@ -982,23 +1271,27 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
int r = 0;
u32 l;
int f;
+ u8 regn_start, regn_end, regm_start, regm_end;
+ u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
DSSDBGF();
dsi.current_cinfo.fint = cinfo->fint;
dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
- dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
- dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
+ dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+ cinfo->dsi_pll_hsdiv_dispc_clk;
+ dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk =
+ cinfo->dsi_pll_hsdiv_dsi_clk;
dsi.current_cinfo.regn = cinfo->regn;
dsi.current_cinfo.regm = cinfo->regm;
- dsi.current_cinfo.regm3 = cinfo->regm3;
- dsi.current_cinfo.regm4 = cinfo->regm4;
+ dsi.current_cinfo.regm_dispc = cinfo->regm_dispc;
+ dsi.current_cinfo.regm_dsi = cinfo->regm_dsi;
DSSDBG("DSI Fint %ld\n", cinfo->fint);
DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
- cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
+ cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
cinfo->clkin,
cinfo->highfreq);
@@ -1015,24 +1308,39 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
- DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
- cinfo->regm3, cinfo->dsi1_pll_fclk);
- DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
- cinfo->regm4, cinfo->dsi2_pll_fclk);
+ DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+ cinfo->dsi_pll_hsdiv_dispc_clk);
+ DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+ cinfo->dsi_pll_hsdiv_dsi_clk);
+
+ dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
+ dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
+ dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
+ &regm_dispc_end);
+ dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
+ &regm_dsi_end);
REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
- l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
- l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
- l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
- 22, 19); /* DSI_CLOCK_DIV */
- l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
- 26, 23); /* DSIPROTO_CLOCK_DIV */
+ /* DSI_PLL_REGN */
+ l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
+ /* DSI_PLL_REGM */
+ l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
+ /* DSI_CLOCK_DIV */
+ l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
+ regm_dispc_start, regm_dispc_end);
+ /* DSIPROTO_CLOCK_DIV */
+ l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
+ regm_dsi_start, regm_dsi_end);
dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
- BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
+ BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
if (cinfo->fint < 1000000)
f = 0x3;
else if (cinfo->fint < 1250000)
@@ -1046,7 +1354,7 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
- l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
+ l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
11, 11); /* DSI_PLL_CLKSEL */
l = FLD_MOD(l, cinfo->highfreq,
12, 12); /* DSI_PLL_HIGHFREQ */
@@ -1101,6 +1409,26 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
DSSDBG("PLL init\n");
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+ /*
+ * HACK: this is just a quick hack to get the USE_DSI_PLL
+ * option working. USE_DSI_PLL is itself a big hack, and
+ * should be removed.
+ */
+ if (dsi.vdds_dsi_reg == NULL) {
+ struct regulator *vdds_dsi;
+
+ vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+ if (IS_ERR(vdds_dsi)) {
+ DSSERR("can't get VDDS_DSI regulator\n");
+ return PTR_ERR(vdds_dsi);
+ }
+
+ dsi.vdds_dsi_reg = vdds_dsi;
+ }
+#endif
+
enable_clocks(1);
dsi_enable_pll_clock(1);
@@ -1162,6 +1490,10 @@ void dsi_dump_clocks(struct seq_file *s)
{
int clksel;
struct dsi_clock_info *cinfo = &dsi.current_cinfo;
+ enum dss_clk_source dispc_clk_src, dsi_clk_src;
+
+ dispc_clk_src = dss_get_dispc_clk_source();
+ dsi_clk_src = dss_get_dsi_clk_source();
enable_clocks(1);
@@ -1171,30 +1503,34 @@ void dsi_dump_clocks(struct seq_file *s)
seq_printf(s, "dsi pll source = %s\n",
clksel == 0 ?
- "dss2_alwon_fclk" : "pclkfree");
+ "dss_sys_clk" : "pclkfree");
seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
cinfo->clkin4ddr, cinfo->regm);
- seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
- cinfo->dsi1_pll_fclk,
- cinfo->regm3,
- dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
+ dss_get_generic_clk_source_name(dispc_clk_src),
+ dss_feat_get_clk_source_name(dispc_clk_src),
+ cinfo->dsi_pll_hsdiv_dispc_clk,
+ cinfo->regm_dispc,
+ dispc_clk_src == DSS_CLK_SRC_FCK ?
"off" : "on");
- seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
- cinfo->dsi2_pll_fclk,
- cinfo->regm4,
- dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+ seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
+ dss_get_generic_clk_source_name(dsi_clk_src),
+ dss_feat_get_clk_source_name(dsi_clk_src),
+ cinfo->dsi_pll_hsdiv_dsi_clk,
+ cinfo->regm_dsi,
+ dsi_clk_src == DSS_CLK_SRC_FCK ?
"off" : "on");
seq_printf(s, "- DSI -\n");
- seq_printf(s, "dsi fclk source = %s\n",
- dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
- "dss1_alwon_fclk" : "dsi2_pll_fclk");
+ seq_printf(s, "dsi fclk source = %s (%s)\n",
+ dss_get_generic_clk_source_name(dsi_clk_src),
+ dss_feat_get_clk_source_name(dsi_clk_src));
seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
@@ -1306,7 +1642,7 @@ void dsi_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
DUMPREG(DSI_REVISION);
DUMPREG(DSI_SYSCONFIG);
@@ -1378,7 +1714,7 @@ void dsi_dump_regs(struct seq_file *s)
DUMPREG(DSI_PLL_CONFIGURATION1);
DUMPREG(DSI_PLL_CONFIGURATION2);
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
#undef DUMPREG
}
@@ -1622,20 +1958,6 @@ static int _dsi_reset(void)
return _dsi_wait_reset();
}
-static void dsi_reset_tx_fifo(int channel)
-{
- u32 mask;
- u32 l;
-
- /* set fifosize of the channel to 0, then return the old size */
- l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
-
- mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
- dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
-
- dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
-}
-
static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
enum fifo_size size3, enum fifo_size size4)
{
@@ -1753,8 +2075,6 @@ static void dsi_vc_initial_config(int channel)
r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
dsi_write_reg(DSI_VC_CTRL(channel), r);
-
- dsi.vc[channel].mode = DSI_VC_MODE_L4;
}
static int dsi_vc_config_l4(int channel)
@@ -1922,33 +2242,44 @@ static int dsi_vc_send_bta(int channel)
int dsi_vc_send_bta_sync(int channel)
{
+ DECLARE_COMPLETION_ONSTACK(completion);
int r = 0;
u32 err;
- INIT_COMPLETION(dsi.bta_completion);
+ r = dsi_register_isr_vc(channel, dsi_completion_handler,
+ &completion, DSI_VC_IRQ_BTA);
+ if (r)
+ goto err0;
- dsi_vc_enable_bta_irq(channel);
+ r = dsi_register_isr(dsi_completion_handler, &completion,
+ DSI_IRQ_ERROR_MASK);
+ if (r)
+ goto err1;
r = dsi_vc_send_bta(channel);
if (r)
- goto err;
+ goto err2;
- if (wait_for_completion_timeout(&dsi.bta_completion,
+ if (wait_for_completion_timeout(&completion,
msecs_to_jiffies(500)) == 0) {
DSSERR("Failed to receive BTA\n");
r = -EIO;
- goto err;
+ goto err2;
}
err = dsi_get_errors();
if (err) {
DSSERR("Error while sending BTA: %x\n", err);
r = -EIO;
- goto err;
+ goto err2;
}
-err:
- dsi_vc_disable_bta_irq(channel);
-
+err2:
+ dsi_unregister_isr(dsi_completion_handler, &completion,
+ DSI_IRQ_ERROR_MASK);
+err1:
+ dsi_unregister_isr_vc(channel, dsi_completion_handler,
+ &completion, DSI_VC_IRQ_BTA);
+err0:
return r;
}
EXPORT_SYMBOL(dsi_vc_send_bta_sync);
@@ -1961,7 +2292,7 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type,
WARN_ON(!dsi_bus_is_locked());
- data_id = data_type | channel << 6;
+ data_id = data_type | dsi.vc[channel].vc_id << 6;
val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
FLD_VAL(ecc, 31, 24);
@@ -2064,7 +2395,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
return -EINVAL;
}
- data_id = data_type | channel << 6;
+ data_id = data_type | dsi.vc[channel].vc_id << 6;
r = (data_id << 0) | (data << 8) | (ecc << 24);
@@ -2762,19 +3093,20 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif
+static void dsi_framedone_bta_callback(void *data, u32 mask);
+
static void dsi_handle_framedone(int error)
{
const int channel = dsi.update_channel;
- cancel_delayed_work(&dsi.framedone_timeout_work);
+ dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+ NULL, DSI_VC_IRQ_BTA);
- dsi_vc_disable_bta_irq(channel);
+ cancel_delayed_work(&dsi.framedone_timeout_work);
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
- dsi.bta_callback = NULL;
-
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
@@ -2808,7 +3140,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
dsi_handle_framedone(-ETIMEDOUT);
}
-static void dsi_framedone_bta_callback(void)
+static void dsi_framedone_bta_callback(void *data, u32 mask)
{
dsi_handle_framedone(0);
@@ -2848,15 +3180,19 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
* asynchronously.
* */
- dsi.bta_callback = dsi_framedone_bta_callback;
-
- barrier();
-
- dsi_vc_enable_bta_irq(channel);
+ r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
+ NULL, DSI_VC_IRQ_BTA);
+ if (r) {
+ DSSERR("Failed to register BTA ISR\n");
+ dsi_handle_framedone(-EIO);
+ return;
+ }
r = dsi_vc_send_bta(channel);
if (r) {
DSSERR("BTA after framedone failed\n");
+ dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+ NULL, DSI_VC_IRQ_BTA);
dsi_handle_framedone(-EIO);
}
}
@@ -2984,12 +3320,12 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
struct dsi_clock_info cinfo;
int r;
- /* we always use DSS2_FCK as input clock */
- cinfo.use_dss2_fck = true;
+ /* we always use DSS_CLK_SYSCK as input clock */
+ cinfo.use_sys_clk = true;
cinfo.regn = dssdev->phy.dsi.div.regn;
cinfo.regm = dssdev->phy.dsi.div.regm;
- cinfo.regm3 = dssdev->phy.dsi.div.regm3;
- cinfo.regm4 = dssdev->phy.dsi.div.regm4;
+ cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc;
+ cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi;
r = dsi_calc_clock_rates(dssdev, &cinfo);
if (r) {
DSSERR("Failed to calc dsi clocks\n");
@@ -3011,7 +3347,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
int r;
unsigned long long fck;
- fck = dsi_get_dsi1_pll_rate();
+ fck = dsi_get_pll_hsdiv_dispc_rate();
dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
@@ -3045,8 +3381,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err1;
- dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
+ dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+ dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
DSSDBG("PLL OK\n");
@@ -3082,8 +3418,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
err3:
dsi_complexio_uninit();
err2:
- dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+ dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
err1:
dsi_pll_uninit();
err0:
@@ -3099,8 +3435,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
dsi_vc_enable(2, 0);
dsi_vc_enable(3, 0);
- dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
- dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+ dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+ dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
dsi_complexio_uninit();
dsi_pll_uninit();
}
@@ -3220,29 +3556,107 @@ int dsi_init_display(struct omap_dss_device *dssdev)
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
- dsi.vc[0].dssdev = dssdev;
- dsi.vc[1].dssdev = dssdev;
+ if (dsi.vdds_dsi_reg == NULL) {
+ struct regulator *vdds_dsi;
+
+ vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+ if (IS_ERR(vdds_dsi)) {
+ DSSERR("can't get VDDS_DSI regulator\n");
+ return PTR_ERR(vdds_dsi);
+ }
+
+ dsi.vdds_dsi_reg = vdds_dsi;
+ }
return 0;
}
-void dsi_wait_dsi1_pll_active(void)
+int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+ if (!dsi.vc[i].dssdev) {
+ dsi.vc[i].dssdev = dssdev;
+ *channel = i;
+ return 0;
+ }
+ }
+
+ DSSERR("cannot get VC for display %s", dssdev->name);
+ return -ENOSPC;
+}
+EXPORT_SYMBOL(omap_dsi_request_vc);
+
+int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
+{
+ if (vc_id < 0 || vc_id > 3) {
+ DSSERR("VC ID out of range\n");
+ return -EINVAL;
+ }
+
+ if (channel < 0 || channel > 3) {
+ DSSERR("Virtual Channel out of range\n");
+ return -EINVAL;
+ }
+
+ if (dsi.vc[channel].dssdev != dssdev) {
+ DSSERR("Virtual Channel not allocated to display %s\n",
+ dssdev->name);
+ return -EINVAL;
+ }
+
+ dsi.vc[channel].vc_id = vc_id;
+
+ return 0;
+}
+EXPORT_SYMBOL(omap_dsi_set_vc_id);
+
+void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
+{
+ if ((channel >= 0 && channel <= 3) &&
+ dsi.vc[channel].dssdev == dssdev) {
+ dsi.vc[channel].dssdev = NULL;
+ dsi.vc[channel].vc_id = 0;
+ }
+}
+EXPORT_SYMBOL(omap_dsi_release_vc);
+
+void dsi_wait_pll_hsdiv_dispc_active(void)
{
if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
- DSSERR("DSI1 PLL clock not active\n");
+ DSSERR("%s (%s) not active\n",
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
}
-void dsi_wait_dsi2_pll_active(void)
+void dsi_wait_pll_hsdiv_dsi_active(void)
{
if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
- DSSERR("DSI2 PLL clock not active\n");
+ DSSERR("%s (%s) not active\n",
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
+}
+
+static void dsi_calc_clock_param_ranges(void)
+{
+ dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
+ dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
+ dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
+ dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
+ dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
+ dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
+ dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
}
-int dsi_init(struct platform_device *pdev)
+static int dsi_init(struct platform_device *pdev)
{
u32 rev;
- int r;
+ int r, i;
+ struct resource *dsi_mem;
+ spin_lock_init(&dsi.irq_lock);
spin_lock_init(&dsi.errors_lock);
dsi.errors = 0;
@@ -3251,8 +3665,6 @@ int dsi_init(struct platform_device *pdev)
dsi.irq_stats.last_reset = jiffies;
#endif
- init_completion(&dsi.bta_completion);
-
mutex_init(&dsi.lock);
sema_init(&dsi.bus_lock, 1);
@@ -3268,24 +3680,45 @@ int dsi_init(struct platform_device *pdev)
dsi.te_timer.function = dsi_te_timeout;
dsi.te_timer.data = 0;
#endif
- dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
+ dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0);
+ if (!dsi_mem) {
+ DSSERR("can't get IORESOURCE_MEM DSI\n");
+ r = -EINVAL;
+ goto err1;
+ }
+ dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem));
if (!dsi.base) {
DSSERR("can't ioremap DSI\n");
r = -ENOMEM;
goto err1;
}
+ dsi.irq = platform_get_irq(dsi.pdev, 0);
+ if (dsi.irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ r = -ENODEV;
+ goto err2;
+ }
- dsi.vdds_dsi_reg = dss_get_vdds_dsi();
- if (IS_ERR(dsi.vdds_dsi_reg)) {
- DSSERR("can't get VDDS_DSI regulator\n");
- r = PTR_ERR(dsi.vdds_dsi_reg);
+ r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED,
+ "OMAP DSI1", dsi.pdev);
+ if (r < 0) {
+ DSSERR("request_irq failed\n");
goto err2;
}
+ /* DSI VCs initialization */
+ for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+ dsi.vc[i].mode = DSI_VC_MODE_L4;
+ dsi.vc[i].dssdev = NULL;
+ dsi.vc[i].vc_id = 0;
+ }
+
+ dsi_calc_clock_param_ranges();
+
enable_clocks(1);
rev = dsi_read_reg(DSI_REVISION);
- printk(KERN_INFO "OMAP DSI rev %d.%d\n",
+ dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
enable_clocks(0);
@@ -3298,8 +3731,14 @@ err1:
return r;
}
-void dsi_exit(void)
+static void dsi_exit(void)
{
+ if (dsi.vdds_dsi_reg != NULL) {
+ regulator_put(dsi.vdds_dsi_reg);
+ dsi.vdds_dsi_reg = NULL;
+ }
+
+ free_irq(dsi.irq, dsi.pdev);
iounmap(dsi.base);
destroy_workqueue(dsi.workqueue);
@@ -3307,3 +3746,41 @@ void dsi_exit(void)
DSSDBG("omap_dsi_exit\n");
}
+/* DSI1 HW IP initialisation */
+static int omap_dsi1hw_probe(struct platform_device *pdev)
+{
+ int r;
+ dsi.pdev = pdev;
+ r = dsi_init(pdev);
+ if (r) {
+ DSSERR("Failed to initialize DSI\n");
+ goto err_dsi;
+ }
+err_dsi:
+ return r;
+}
+
+static int omap_dsi1hw_remove(struct platform_device *pdev)
+{
+ dsi_exit();
+ return 0;
+}
+
+static struct platform_driver omap_dsi1hw_driver = {
+ .probe = omap_dsi1hw_probe,
+ .remove = omap_dsi1hw_remove,
+ .driver = {
+ .name = "omapdss_dsi1",
+ .owner = THIS_MODULE,
+ },
+};
+
+int dsi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dsi1hw_driver);
+}
+
+void dsi_uninit_platform_driver(void)
+{
+ return platform_driver_unregister(&omap_dsi1hw_driver);
+}
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 77c3621c917..3f1fee63c67 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -26,14 +26,13 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/clk.h>
#include <plat/display.h>
+#include <plat/clock.h>
#include "dss.h"
-
-#define DSS_BASE 0x48050000
+#include "dss_features.h"
#define DSS_SZ_REGS SZ_512
@@ -59,9 +58,17 @@ struct dss_reg {
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
static struct {
+ struct platform_device *pdev;
void __iomem *base;
+ int ctx_id;
struct clk *dpll4_m4_ck;
+ struct clk *dss_ick;
+ struct clk *dss_fck;
+ struct clk *dss_sys_clk;
+ struct clk *dss_tv_fck;
+ struct clk *dss_video_fck;
+ unsigned num_clks_enabled;
unsigned long cache_req_pck;
unsigned long cache_prate;
@@ -70,10 +77,22 @@ static struct {
enum dss_clk_source dsi_clk_source;
enum dss_clk_source dispc_clk_source;
+ enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
} dss;
+static const char * const dss_generic_clk_source_names[] = {
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
+ [DSS_CLK_SRC_FCK] = "DSS_FCK",
+};
+
+static void dss_clk_enable_all_no_ctx(void);
+static void dss_clk_disable_all_no_ctx(void);
+static void dss_clk_enable_no_ctx(enum dss_clock clks);
+static void dss_clk_disable_no_ctx(enum dss_clock clks);
+
static int _omap_dss_wait_reset(void);
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
@@ -99,10 +118,11 @@ void dss_save_context(void)
SR(SYSCONFIG);
SR(CONTROL);
-#ifdef CONFIG_OMAP2_DSS_SDI
- SR(SDI_CONTROL);
- SR(PLL_CONTROL);
-#endif
+ if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+ OMAP_DISPLAY_TYPE_SDI) {
+ SR(SDI_CONTROL);
+ SR(PLL_CONTROL);
+ }
}
void dss_restore_context(void)
@@ -113,10 +133,11 @@ void dss_restore_context(void)
RR(SYSCONFIG);
RR(CONTROL);
-#ifdef CONFIG_OMAP2_DSS_SDI
- RR(SDI_CONTROL);
- RR(PLL_CONTROL);
-#endif
+ if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+ OMAP_DISPLAY_TYPE_SDI) {
+ RR(SDI_CONTROL);
+ RR(PLL_CONTROL);
+ }
}
#undef SR
@@ -209,66 +230,96 @@ void dss_sdi_disable(void)
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
}
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
+{
+ return dss_generic_clk_source_names[clk_src];
+}
+
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
unsigned long dpll4_m4_ck_rate;
+ const char *fclk_name, *fclk_real_name;
+ unsigned long fclk_rate;
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
- dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
seq_printf(s, "- DSS -\n");
- seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
+ fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
+ fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
+ fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
- if (cpu_is_omap3630())
- seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n",
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- dss_clk_get_rate(DSS_CLK_FCK1));
- else
- seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- dss_clk_get_rate(DSS_CLK_FCK1));
+ if (dss.dpll4_m4_ck) {
+ dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+ dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+
+ seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
+ seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
+ fclk_name, fclk_real_name,
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ fclk_rate);
+ else
+ seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
+ fclk_name, fclk_real_name,
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ fclk_rate);
+ } else {
+ seq_printf(s, "%s (%s) = %lu\n",
+ fclk_name, fclk_real_name,
+ fclk_rate);
+ }
+
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
}
void dss_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
DUMPREG(DSS_REVISION);
DUMPREG(DSS_SYSCONFIG);
DUMPREG(DSS_SYSSTATUS);
DUMPREG(DSS_IRQSTATUS);
DUMPREG(DSS_CONTROL);
- DUMPREG(DSS_SDI_CONTROL);
- DUMPREG(DSS_PLL_CONTROL);
- DUMPREG(DSS_SDI_STATUS);
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ 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_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
#undef DUMPREG
}
void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
{
int b;
+ u8 start, end;
+
+ switch (clk_src) {
+ case DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ b = 1;
+ dsi_wait_pll_hsdiv_dispc_active();
+ break;
+ default:
+ BUG();
+ }
- BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
- clk_src != DSS_SRC_DSS1_ALWON_FCLK);
-
- b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
-
- if (clk_src == DSS_SRC_DSI1_PLL_FCLK)
- dsi_wait_dsi1_pll_active();
+ dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
- REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
+ REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
dss.dispc_clk_source = clk_src;
}
@@ -277,19 +328,51 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
{
int b;
- BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
- clk_src != DSS_SRC_DSS1_ALWON_FCLK);
-
- b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
-
- if (clk_src == DSS_SRC_DSI2_PLL_FCLK)
- dsi_wait_dsi2_pll_active();
+ switch (clk_src) {
+ case DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+ b = 1;
+ dsi_wait_pll_hsdiv_dsi_active();
+ break;
+ default:
+ BUG();
+ }
REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
dss.dsi_clk_source = clk_src;
}
+void dss_select_lcd_clk_source(enum omap_channel channel,
+ enum dss_clk_source clk_src)
+{
+ int b, ix, pos;
+
+ if (!dss_has_feature(FEAT_LCD_CLK_SRC))
+ return;
+
+ switch (clk_src) {
+ case DSS_CLK_SRC_FCK:
+ b = 0;
+ break;
+ case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
+ b = 1;
+ dsi_wait_pll_hsdiv_dispc_active();
+ break;
+ default:
+ BUG();
+ }
+
+ pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
+ REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
+
+ ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+ dss.lcd_clk_source[ix] = clk_src;
+}
+
enum dss_clk_source dss_get_dispc_clk_source(void)
{
return dss.dispc_clk_source;
@@ -300,34 +383,52 @@ enum dss_clk_source dss_get_dsi_clk_source(void)
return dss.dsi_clk_source;
}
+enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+{
+ int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+ return dss.lcd_clk_source[ix];
+}
+
/* calculate clock rates using dividers in cinfo */
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
- unsigned long prate;
+ if (dss.dpll4_m4_ck) {
+ unsigned long prate;
+ u16 fck_div_max = 16;
- if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) ||
- cinfo->fck_div == 0)
- return -EINVAL;
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
+ fck_div_max = 32;
+
+ if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
+ return -EINVAL;
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+ prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- cinfo->fck = prate / cinfo->fck_div;
+ cinfo->fck = prate / cinfo->fck_div;
+ } else {
+ if (cinfo->fck_div != 0)
+ return -EINVAL;
+ cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+ }
return 0;
}
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
- unsigned long prate;
- int r;
+ if (dss.dpll4_m4_ck) {
+ unsigned long prate;
+ int r;
- if (cpu_is_omap34xx()) {
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
DSSDBG("dpll4_m4 = %ld\n", prate);
r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
if (r)
return r;
+ } else {
+ if (cinfo->fck_div != 0)
+ return -EINVAL;
}
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
@@ -337,12 +438,14 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
int dss_get_clock_div(struct dss_clock_info *cinfo)
{
- cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
+ cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
- if (cpu_is_omap34xx()) {
+ if (dss.dpll4_m4_ck) {
unsigned long prate;
+
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- if (cpu_is_omap3630())
+
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
cinfo->fck_div = prate / (cinfo->fck);
else
cinfo->fck_div = prate / (cinfo->fck / 2);
@@ -355,7 +458,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
unsigned long dss_get_dpll4_rate(void)
{
- if (cpu_is_omap34xx())
+ if (dss.dpll4_m4_ck)
return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
else
return 0;
@@ -369,16 +472,18 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
struct dss_clock_info best_dss;
struct dispc_clock_info best_dispc;
- unsigned long fck;
+ unsigned long fck, max_dss_fck;
- u16 fck_div;
+ u16 fck_div, fck_div_max = 16;
int match = 0;
int min_fck_per_pck;
prate = dss_get_dpll4_rate();
- fck = dss_clk_get_rate(DSS_CLK_FCK1);
+ max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ fck = dss_clk_get_rate(DSS_CLK_FCK);
if (req_pck == dss.cache_req_pck &&
((cpu_is_omap34xx() && prate == dss.cache_prate) ||
dss.cache_dss_cinfo.fck == fck)) {
@@ -391,7 +496,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+ req_pck * min_fck_per_pck > max_dss_fck) {
DSSERR("Requested pixel clock not possible with the current "
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
"the constraint off.\n");
@@ -402,10 +507,10 @@ retry:
memset(&best_dss, 0, sizeof(best_dss));
memset(&best_dispc, 0, sizeof(best_dispc));
- if (cpu_is_omap24xx()) {
+ if (dss.dpll4_m4_ck == NULL) {
struct dispc_clock_info cur_dispc;
/* XXX can we change the clock on omap2? */
- fck = dss_clk_get_rate(DSS_CLK_FCK1);
+ fck = dss_clk_get_rate(DSS_CLK_FCK);
fck_div = 1;
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
@@ -417,17 +522,19 @@ retry:
best_dispc = cur_dispc;
goto found;
- } else if (cpu_is_omap34xx()) {
- for (fck_div = (cpu_is_omap3630() ? 32 : 16);
- fck_div > 0; --fck_div) {
+ } else {
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
+ fck_div_max = 32;
+
+ for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- if (cpu_is_omap3630())
+ if (fck_div_max == 32)
fck = prate / fck_div;
else
fck = prate / fck_div * 2;
- if (fck > DISPC_MAX_FCK)
+ if (fck > max_dss_fck)
continue;
if (min_fck_per_pck &&
@@ -450,8 +557,6 @@ retry:
goto found;
}
}
- } else {
- BUG();
}
found:
@@ -482,31 +587,6 @@ found:
return 0;
}
-
-
-static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
-{
- dispc_irq_handler();
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
-{
- u32 irqstatus;
-
- irqstatus = dss_read_reg(DSS_IRQSTATUS);
-
- if (irqstatus & (1<<0)) /* DISPC_IRQ */
- dispc_irq_handler();
-#ifdef CONFIG_OMAP2_DSS_DSI
- if (irqstatus & (1<<1)) /* DSI_IRQ */
- dsi_irq_handler();
-#endif
-
- return IRQ_HANDLED;
-}
-
static int _omap_dss_wait_reset(void)
{
int t = 0;
@@ -549,34 +629,45 @@ void dss_set_dac_pwrdn_bgz(bool enable)
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
}
-int dss_init(bool skip_init)
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
+{
+ REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
+}
+
+static int dss_init(void)
{
int r;
u32 rev;
+ struct resource *dss_mem;
+ struct clk *dpll4_m4_ck;
- dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
+ dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+ if (!dss_mem) {
+ DSSERR("can't get IORESOURCE_MEM DSS\n");
+ r = -EINVAL;
+ goto fail0;
+ }
+ dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
if (!dss.base) {
DSSERR("can't ioremap DSS\n");
r = -ENOMEM;
goto fail0;
}
- if (!skip_init) {
- /* disable LCD and DIGIT output. This seems to fix the synclost
- * problem that we get, if the bootloader starts the DSS and
- * the kernel resets it */
- omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
+ /* disable LCD and DIGIT output. This seems to fix the synclost
+ * problem that we get, if the bootloader starts the DSS and
+ * the kernel resets it */
+ omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
- /* We need to wait here a bit, otherwise we sometimes start to
- * get synclost errors, and after that only power cycle will
- * restore DSS functionality. I have no idea why this happens.
- * And we have to wait _before_ resetting the DSS, but after
- * enabling clocks.
- */
- msleep(50);
+ /* We need to wait here a bit, otherwise we sometimes start to
+ * get synclost errors, and after that only power cycle will
+ * restore DSS functionality. I have no idea why this happens.
+ * And we have to wait _before_ resetting the DSS, but after
+ * enabling clocks.
+ */
+ msleep(50);
- _omap_dss_reset();
- }
+ _omap_dss_reset();
/* autoidle */
REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
@@ -589,29 +680,30 @@ int dss_init(bool skip_init)
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
-
- r = request_irq(INT_24XX_DSS_IRQ,
- cpu_is_omap24xx()
- ? dss_irq_handler_omap2
- : dss_irq_handler_omap3,
- 0, "OMAP DSS", NULL);
-
- if (r < 0) {
- DSSERR("omap2 dss: request_irq failed\n");
- goto fail1;
- }
-
if (cpu_is_omap34xx()) {
- dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(dss.dpll4_m4_ck)) {
+ dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
+ if (IS_ERR(dpll4_m4_ck)) {
DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(dss.dpll4_m4_ck);
- goto fail2;
+ r = PTR_ERR(dpll4_m4_ck);
+ goto fail1;
}
+ } else if (cpu_is_omap44xx()) {
+ dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
+ if (IS_ERR(dpll4_m4_ck)) {
+ DSSERR("Failed to get dpll4_m4_ck\n");
+ r = PTR_ERR(dpll4_m4_ck);
+ goto fail1;
+ }
+ } else { /* omap24xx */
+ dpll4_m4_ck = NULL;
}
- dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
- dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
+ dss.dpll4_m4_ck = dpll4_m4_ck;
+
+ dss.dsi_clk_source = DSS_CLK_SRC_FCK;
+ dss.dispc_clk_source = DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
dss_save_context();
@@ -621,21 +713,416 @@ int dss_init(bool skip_init)
return 0;
-fail2:
- free_irq(INT_24XX_DSS_IRQ, NULL);
fail1:
iounmap(dss.base);
fail0:
return r;
}
-void dss_exit(void)
+static void dss_exit(void)
{
- if (cpu_is_omap34xx())
+ if (dss.dpll4_m4_ck)
clk_put(dss.dpll4_m4_ck);
- free_irq(INT_24XX_DSS_IRQ, NULL);
-
iounmap(dss.base);
}
+/* CONTEXT */
+static int dss_get_ctx_id(void)
+{
+ struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+ int r;
+
+ if (!pdata->board_data->get_last_off_on_transaction_id)
+ return 0;
+ r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
+ if (r < 0) {
+ dev_err(&dss.pdev->dev, "getting transaction ID failed, "
+ "will force context restore\n");
+ r = -1;
+ }
+ return r;
+}
+
+int dss_need_ctx_restore(void)
+{
+ int id = dss_get_ctx_id();
+
+ if (id < 0 || id != dss.ctx_id) {
+ DSSDBG("ctx id %d -> id %d\n",
+ dss.ctx_id, id);
+ dss.ctx_id = id;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void save_all_ctx(void)
+{
+ DSSDBG("save context\n");
+
+ dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+
+ dss_save_context();
+ dispc_save_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+ dsi_save_context();
+#endif
+
+ dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+}
+
+static void restore_all_ctx(void)
+{
+ DSSDBG("restore context\n");
+
+ dss_clk_enable_all_no_ctx();
+
+ dss_restore_context();
+ dispc_restore_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+ dsi_restore_context();
+#endif
+
+ dss_clk_disable_all_no_ctx();
+}
+
+static int dss_get_clock(struct clk **clock, const char *clk_name)
+{
+ struct clk *clk;
+
+ clk = clk_get(&dss.pdev->dev, clk_name);
+
+ if (IS_ERR(clk)) {
+ DSSERR("can't get clock %s", clk_name);
+ return PTR_ERR(clk);
+ }
+
+ *clock = clk;
+
+ DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
+
+ return 0;
+}
+
+static int dss_get_clocks(void)
+{
+ int r;
+ struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+
+ dss.dss_ick = NULL;
+ dss.dss_fck = NULL;
+ dss.dss_sys_clk = NULL;
+ dss.dss_tv_fck = NULL;
+ dss.dss_video_fck = NULL;
+
+ r = dss_get_clock(&dss.dss_ick, "ick");
+ if (r)
+ goto err;
+
+ r = dss_get_clock(&dss.dss_fck, "fck");
+ if (r)
+ goto err;
+
+ if (!pdata->opt_clock_available) {
+ r = -ENODEV;
+ goto err;
+ }
+
+ if (pdata->opt_clock_available("sys_clk")) {
+ r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
+ if (r)
+ goto err;
+ }
+
+ if (pdata->opt_clock_available("tv_clk")) {
+ r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
+ if (r)
+ goto err;
+ }
+
+ if (pdata->opt_clock_available("video_clk")) {
+ r = dss_get_clock(&dss.dss_video_fck, "video_clk");
+ if (r)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ if (dss.dss_ick)
+ clk_put(dss.dss_ick);
+ if (dss.dss_fck)
+ clk_put(dss.dss_fck);
+ if (dss.dss_sys_clk)
+ clk_put(dss.dss_sys_clk);
+ if (dss.dss_tv_fck)
+ clk_put(dss.dss_tv_fck);
+ if (dss.dss_video_fck)
+ clk_put(dss.dss_video_fck);
+
+ return r;
+}
+
+static void dss_put_clocks(void)
+{
+ if (dss.dss_video_fck)
+ clk_put(dss.dss_video_fck);
+ if (dss.dss_tv_fck)
+ clk_put(dss.dss_tv_fck);
+ if (dss.dss_sys_clk)
+ clk_put(dss.dss_sys_clk);
+ clk_put(dss.dss_fck);
+ clk_put(dss.dss_ick);
+}
+
+unsigned long dss_clk_get_rate(enum dss_clock clk)
+{
+ switch (clk) {
+ case DSS_CLK_ICK:
+ return clk_get_rate(dss.dss_ick);
+ case DSS_CLK_FCK:
+ return clk_get_rate(dss.dss_fck);
+ case DSS_CLK_SYSCK:
+ return clk_get_rate(dss.dss_sys_clk);
+ case DSS_CLK_TVFCK:
+ return clk_get_rate(dss.dss_tv_fck);
+ case DSS_CLK_VIDFCK:
+ return clk_get_rate(dss.dss_video_fck);
+ }
+
+ BUG();
+ return 0;
+}
+
+static unsigned count_clk_bits(enum dss_clock clks)
+{
+ unsigned num_clks = 0;
+
+ if (clks & DSS_CLK_ICK)
+ ++num_clks;
+ if (clks & DSS_CLK_FCK)
+ ++num_clks;
+ if (clks & DSS_CLK_SYSCK)
+ ++num_clks;
+ if (clks & DSS_CLK_TVFCK)
+ ++num_clks;
+ if (clks & DSS_CLK_VIDFCK)
+ ++num_clks;
+
+ return num_clks;
+}
+
+static void dss_clk_enable_no_ctx(enum dss_clock clks)
+{
+ unsigned num_clks = count_clk_bits(clks);
+
+ if (clks & DSS_CLK_ICK)
+ clk_enable(dss.dss_ick);
+ if (clks & DSS_CLK_FCK)
+ clk_enable(dss.dss_fck);
+ if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+ clk_enable(dss.dss_sys_clk);
+ if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+ clk_enable(dss.dss_tv_fck);
+ if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+ clk_enable(dss.dss_video_fck);
+
+ dss.num_clks_enabled += num_clks;
+}
+
+void dss_clk_enable(enum dss_clock clks)
+{
+ bool check_ctx = dss.num_clks_enabled == 0;
+
+ dss_clk_enable_no_ctx(clks);
+
+ /*
+ * HACK: On omap4 the registers may not be accessible right after
+ * enabling the clocks. At some point this will be handled by
+ * pm_runtime, but for the time begin this should make things work.
+ */
+ if (cpu_is_omap44xx() && check_ctx)
+ udelay(10);
+
+ if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
+ restore_all_ctx();
+}
+
+static void dss_clk_disable_no_ctx(enum dss_clock clks)
+{
+ unsigned num_clks = count_clk_bits(clks);
+
+ if (clks & DSS_CLK_ICK)
+ clk_disable(dss.dss_ick);
+ if (clks & DSS_CLK_FCK)
+ clk_disable(dss.dss_fck);
+ if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+ clk_disable(dss.dss_sys_clk);
+ if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+ clk_disable(dss.dss_tv_fck);
+ if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+ clk_disable(dss.dss_video_fck);
+
+ dss.num_clks_enabled -= num_clks;
+}
+
+void dss_clk_disable(enum dss_clock clks)
+{
+ if (cpu_is_omap34xx()) {
+ unsigned num_clks = count_clk_bits(clks);
+
+ BUG_ON(dss.num_clks_enabled < num_clks);
+
+ if (dss.num_clks_enabled == num_clks)
+ save_all_ctx();
+ }
+
+ dss_clk_disable_no_ctx(clks);
+}
+
+static void dss_clk_enable_all_no_ctx(void)
+{
+ enum dss_clock clks;
+
+ clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+ if (cpu_is_omap34xx())
+ clks |= DSS_CLK_VIDFCK;
+ dss_clk_enable_no_ctx(clks);
+}
+
+static void dss_clk_disable_all_no_ctx(void)
+{
+ enum dss_clock clks;
+
+ clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+ if (cpu_is_omap34xx())
+ clks |= DSS_CLK_VIDFCK;
+ dss_clk_disable_no_ctx(clks);
+}
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+/* CLOCKS */
+static void core_dump_clocks(struct seq_file *s)
+{
+ int i;
+ struct clk *clocks[5] = {
+ dss.dss_ick,
+ dss.dss_fck,
+ dss.dss_sys_clk,
+ dss.dss_tv_fck,
+ dss.dss_video_fck
+ };
+
+ seq_printf(s, "- CORE -\n");
+
+ seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
+
+ for (i = 0; i < 5; i++) {
+ if (!clocks[i])
+ continue;
+ seq_printf(s, "%-15s\t%lu\t%d\n",
+ clocks[i]->name,
+ clk_get_rate(clocks[i]),
+ clocks[i]->usecount);
+ }
+}
+#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
+
+/* DEBUGFS */
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s)
+{
+ core_dump_clocks(s);
+ dss_dump_clocks(s);
+ dispc_dump_clocks(s);
+#ifdef CONFIG_OMAP2_DSS_DSI
+ dsi_dump_clocks(s);
+#endif
+}
+#endif
+
+
+/* DSS HW IP initialisation */
+static int omap_dsshw_probe(struct platform_device *pdev)
+{
+ int r;
+
+ dss.pdev = pdev;
+
+ r = dss_get_clocks();
+ if (r)
+ goto err_clocks;
+
+ dss_clk_enable_all_no_ctx();
+
+ dss.ctx_id = dss_get_ctx_id();
+ DSSDBG("initial ctx id %u\n", dss.ctx_id);
+
+ r = dss_init();
+ if (r) {
+ DSSERR("Failed to initialize DSS\n");
+ goto err_dss;
+ }
+
+ r = dpi_init();
+ if (r) {
+ DSSERR("Failed to initialize DPI\n");
+ goto err_dpi;
+ }
+
+ r = sdi_init();
+ if (r) {
+ DSSERR("Failed to initialize SDI\n");
+ goto err_sdi;
+ }
+
+ dss_clk_disable_all_no_ctx();
+ return 0;
+err_sdi:
+ dpi_exit();
+err_dpi:
+ dss_exit();
+err_dss:
+ dss_clk_disable_all_no_ctx();
+ dss_put_clocks();
+err_clocks:
+ return r;
+}
+
+static int omap_dsshw_remove(struct platform_device *pdev)
+{
+
+ dss_exit();
+
+ /*
+ * As part of hwmod changes, DSS is not the only controller of dss
+ * clocks; hwmod framework itself will also enable clocks during hwmod
+ * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
+ * need to disable clocks if their usecounts > 1.
+ */
+ WARN_ON(dss.num_clks_enabled > 0);
+
+ dss_put_clocks();
+ return 0;
+}
+
+static struct platform_driver omap_dsshw_driver = {
+ .probe = omap_dsshw_probe,
+ .remove = omap_dsshw_remove,
+ .driver = {
+ .name = "omapdss_dss",
+ .owner = THIS_MODULE,
+ },
+};
+
+int dss_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_dsshw_driver);
+}
+
+void dss_uninit_platform_driver(void)
+{
+ return platform_driver_unregister(&omap_dsshw_driver);
+}
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index b394951120a..c2f582bb19c 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -97,8 +97,6 @@ extern unsigned int dss_debug;
#define FLD_MOD(orig, val, start, end) \
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
-#define DISPC_MAX_FCK 173000000
-
enum omap_burst_size {
OMAP_DSS_BURST_4x32 = 0,
OMAP_DSS_BURST_8x32 = 1,
@@ -112,17 +110,25 @@ enum omap_parallel_interface_mode {
};
enum dss_clock {
- DSS_CLK_ICK = 1 << 0,
- DSS_CLK_FCK1 = 1 << 1,
- DSS_CLK_FCK2 = 1 << 2,
- DSS_CLK_54M = 1 << 3,
- DSS_CLK_96M = 1 << 4,
+ DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */
+ DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */
+ DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */
+ DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */
+ DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/
};
enum dss_clk_source {
- DSS_SRC_DSI1_PLL_FCLK,
- DSS_SRC_DSI2_PLL_FCLK,
- DSS_SRC_DSS1_ALWON_FCLK,
+ DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* OMAP3: DSI1_PLL_FCLK
+ * OMAP4: PLL1_CLK1 */
+ DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* OMAP3: DSI2_PLL_FCLK
+ * OMAP4: PLL1_CLK2 */
+ DSS_CLK_SRC_FCK, /* OMAP2/3: DSS1_ALWON_FCLK
+ * OMAP4: DSS_FCLK */
+};
+
+enum dss_hdmi_venc_clk_source_select {
+ DSS_VENC_TV_CLK = 0,
+ DSS_HDMI_M_PCLK = 1,
};
struct dss_clock_info {
@@ -148,36 +154,42 @@ struct dsi_clock_info {
unsigned long fint;
unsigned long clkin4ddr;
unsigned long clkin;
- unsigned long dsi1_pll_fclk;
- unsigned long dsi2_pll_fclk;
-
+ 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 regm3;
- u16 regm4;
-
+ u16 regm_dispc; /* OMAP3: REGM3
+ * OMAP4: REGM4 */
+ u16 regm_dsi; /* OMAP3: REGM4
+ * OMAP4: REGM5 */
u16 lp_clk_div;
u8 highfreq;
- bool use_dss2_fck;
+ bool use_sys_clk;
+};
+
+/* HDMI PLL structure */
+struct hdmi_pll_info {
+ u16 regn;
+ u16 regm;
+ u32 regmf;
+ u16 regm2;
+ u16 regsd;
+ u16 dcofreq;
};
struct seq_file;
struct platform_device;
/* core */
-void dss_clk_enable(enum dss_clock clks);
-void dss_clk_disable(enum dss_clock clks);
-unsigned long dss_clk_get_rate(enum dss_clock clk);
-int dss_need_ctx_restore(void);
-void dss_dump_clocks(struct seq_file *s);
struct bus_type *dss_get_bus(void);
struct regulator *dss_get_vdds_dsi(void);
struct regulator *dss_get_vdds_sdi(void);
-struct regulator *dss_get_vdda_dac(void);
/* display */
int dss_suspend_all_devices(void);
@@ -214,13 +226,23 @@ void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
/* DSS */
-int dss_init(bool skip_init);
-void dss_exit(void);
+int dss_init_platform_driver(void);
+void dss_uninit_platform_driver(void);
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
void dss_save_context(void);
void dss_restore_context(void);
+void dss_clk_enable(enum dss_clock clks);
+void dss_clk_disable(enum dss_clock clks);
+unsigned long dss_clk_get_rate(enum dss_clock clk);
+int dss_need_ctx_restore(void);
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src);
+void dss_dump_clocks(struct seq_file *s);
void dss_dump_regs(struct seq_file *s);
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s);
+#endif
void dss_sdi_init(u8 datapairs);
int dss_sdi_enable(void);
@@ -228,8 +250,11 @@ void dss_sdi_disable(void);
void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_lcd_clk_source(enum omap_channel channel,
+ enum dss_clk_source clk_src);
enum dss_clk_source dss_get_dispc_clk_source(void);
enum dss_clk_source dss_get_dsi_clk_source(void);
+enum 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);
@@ -244,11 +269,11 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
/* SDI */
#ifdef CONFIG_OMAP2_DSS_SDI
-int sdi_init(bool skip_init);
+int sdi_init(void);
void sdi_exit(void);
int sdi_init_display(struct omap_dss_device *display);
#else
-static inline int sdi_init(bool skip_init)
+static inline int sdi_init(void)
{
return 0;
}
@@ -259,8 +284,8 @@ static inline void sdi_exit(void)
/* DSI */
#ifdef CONFIG_OMAP2_DSS_DSI
-int dsi_init(struct platform_device *pdev);
-void dsi_exit(void);
+int dsi_init_platform_driver(void);
+void dsi_uninit_platform_driver(void);
void dsi_dump_clocks(struct seq_file *s);
void dsi_dump_irqs(struct seq_file *s);
@@ -271,7 +296,7 @@ void dsi_restore_context(void);
int dsi_init_display(struct omap_dss_device *display);
void dsi_irq_handler(void);
-unsigned long dsi_get_dsi1_pll_rate(void);
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void);
int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
struct dsi_clock_info *cinfo,
@@ -282,31 +307,36 @@ void dsi_pll_uninit(void);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high);
-void dsi_wait_dsi1_pll_active(void);
-void dsi_wait_dsi2_pll_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(void);
+void dsi_wait_pll_hsdiv_dsi_active(void);
#else
-static inline int dsi_init(struct platform_device *pdev)
+static inline int dsi_init_platform_driver(void)
{
return 0;
}
-static inline void dsi_exit(void)
+static inline void dsi_uninit_platform_driver(void)
{
}
-static inline void dsi_wait_dsi1_pll_active(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
{
+ WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
+ return 0;
}
-static inline void dsi_wait_dsi2_pll_active(void)
+static inline void dsi_wait_pll_hsdiv_dispc_active(void)
+{
+}
+static inline void dsi_wait_pll_hsdiv_dsi_active(void)
{
}
#endif
/* DPI */
#ifdef CONFIG_OMAP2_DSS_DPI
-int dpi_init(struct platform_device *pdev);
+int dpi_init(void);
void dpi_exit(void);
int dpi_init_display(struct omap_dss_device *dssdev);
#else
-static inline int dpi_init(struct platform_device *pdev)
+static inline int dpi_init(void)
{
return 0;
}
@@ -316,8 +346,8 @@ static inline void dpi_exit(void)
#endif
/* DISPC */
-int dispc_init(void);
-void dispc_exit(void);
+int dispc_init_platform_driver(void);
+void dispc_uninit_platform_driver(void);
void dispc_dump_clocks(struct seq_file *s);
void dispc_dump_irqs(struct seq_file *s);
void dispc_dump_regs(struct seq_file *s);
@@ -350,6 +380,7 @@ void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
void dispc_set_channel_out(enum omap_plane plane,
enum omap_channel channel_out);
+void dispc_enable_gamma_table(bool enable);
int dispc_setup_plane(enum omap_plane plane,
u32 paddr, u16 screen_width,
u16 pos_x, u16 pos_y,
@@ -409,24 +440,50 @@ int dispc_get_clock_div(enum omap_channel channel,
/* VENC */
#ifdef CONFIG_OMAP2_DSS_VENC
-int venc_init(struct platform_device *pdev);
-void venc_exit(void);
+int venc_init_platform_driver(void);
+void venc_uninit_platform_driver(void);
void venc_dump_regs(struct seq_file *s);
int venc_init_display(struct omap_dss_device *display);
#else
-static inline int venc_init(struct platform_device *pdev)
+static inline int venc_init_platform_driver(void)
+{
+ return 0;
+}
+static inline void venc_uninit_platform_driver(void)
+{
+}
+#endif
+
+/* HDMI */
+#ifdef CONFIG_OMAP4_DSS_HDMI
+int hdmi_init_platform_driver(void);
+void hdmi_uninit_platform_driver(void);
+int hdmi_init_display(struct omap_dss_device *dssdev);
+#else
+static inline int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+ return 0;
+}
+static inline int hdmi_init_platform_driver(void)
{
return 0;
}
-static inline void venc_exit(void)
+static inline void hdmi_uninit_platform_driver(void)
{
}
#endif
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+int hdmi_panel_init(void);
+void hdmi_panel_exit(void);
/* RFBI */
#ifdef CONFIG_OMAP2_DSS_RFBI
-int rfbi_init(void);
-void rfbi_exit(void);
+int rfbi_init_platform_driver(void);
+void rfbi_uninit_platform_driver(void);
void rfbi_dump_regs(struct seq_file *s);
int rfbi_configure(int rfbi_module, int bpp, int lines);
@@ -437,11 +494,11 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
unsigned long rfbi_get_max_tx_rate(void);
int rfbi_init_display(struct omap_dss_device *display);
#else
-static inline int rfbi_init(void)
+static inline int rfbi_init_platform_driver(void)
{
return 0;
}
-static inline void rfbi_exit(void)
+static inline void rfbi_uninit_platform_driver(void)
{
}
#endif
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index cf3ef696e14..aa1622241d0 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -25,14 +25,18 @@
#include <plat/display.h>
#include <plat/cpu.h>
+#include "dss.h"
#include "dss_features.h"
/* Defines a generic omap register field */
struct dss_reg_field {
- enum dss_feat_reg_field id;
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;
@@ -43,29 +47,68 @@ struct omap_dss_features {
const int num_ovls;
const enum omap_display_type *supported_displays;
const enum omap_color_mode *supported_color_modes;
+ const char * const *clksrc_names;
+ const struct dss_param_range *dss_params;
};
/* This struct is assigned to one of the below during initialization */
static 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_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_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 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,
@@ -73,10 +116,10 @@ static const enum omap_display_type omap2_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_VENC,
};
-static const enum omap_display_type omap3_dss_supported_displays[] = {
+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_SDI | OMAP_DISPLAY_TYPE_DSI,
+ OMAP_DISPLAY_TYPE_DSI,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DISPLAY_TYPE_VENC,
@@ -87,7 +130,7 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
/* OMAP_DSS_CHANNEL_DIGIT */
- OMAP_DISPLAY_TYPE_VENC,
+ OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
@@ -134,6 +177,54 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
};
+static const char * const omap2_dss_clk_source_names[] = {
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
+ [DSS_CLK_SRC_FCK] = "DSS_FCLK1",
+};
+
+static const char * const omap3_dss_clk_source_names[] = {
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
+ [DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
+};
+
+static const char * const omap4_dss_clk_source_names[] = {
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
+ [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
+ [DSS_CLK_SRC_FCK] = "DSS_FCLK",
+};
+
+static const struct dss_param_range omap2_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
+ [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 },
+};
+
+static const struct dss_param_range omap3_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
+ [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},
+};
+
+static const struct dss_param_range omap4_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
+ [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 },
+};
+
/* OMAP2 DSS Features */
static struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
@@ -141,12 +232,15 @@ static struct omap_dss_features omap2_dss_features = {
.has_feature =
FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
- FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
+ FEAT_PCKFREEENABLE | FEAT_FUNCGATED |
+ FEAT_ROWREPEATENABLE | FEAT_RESIZECONF,
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
.supported_color_modes = omap2_dss_supported_color_modes,
+ .clksrc_names = omap2_dss_clk_source_names,
+ .dss_params = omap2_dss_param_range,
};
/* OMAP3 DSS Features */
@@ -157,12 +251,15 @@ static struct omap_dss_features omap3430_dss_features = {
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
- FEAT_FUNCGATED,
+ FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
+ FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
.num_mgrs = 2,
.num_ovls = 3,
- .supported_displays = omap3_dss_supported_displays,
+ .supported_displays = omap3430_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
};
static struct omap_dss_features omap3630_dss_features = {
@@ -172,27 +269,34 @@ static struct omap_dss_features omap3630_dss_features = {
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
- FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
+ FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
+ FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
+ FEAT_RESIZECONF,
.num_mgrs = 2,
.num_ovls = 3,
- .supported_displays = omap3_dss_supported_displays,
+ .supported_displays = omap3630_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
};
/* OMAP4 DSS Features */
static struct omap_dss_features omap4_dss_features = {
- .reg_fields = omap3_dss_reg_fields,
- .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+ .reg_fields = omap4_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
- FEAT_MGR_LCD2,
+ FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+ FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
.num_mgrs = 3,
.num_ovls = 3,
.supported_displays = omap4_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
+ .clksrc_names = omap4_dss_clk_source_names,
+ .dss_params = omap4_dss_param_range,
};
/* Functions returning values related to a DSS feature */
@@ -206,6 +310,16 @@ int dss_feat_get_num_ovls(void)
return omap_current_dss_features->num_ovls;
}
+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];
@@ -223,6 +337,11 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
color_mode;
}
+const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+{
+ return omap_current_dss_features->clksrc_names[id];
+}
+
/* DSS has_feature check */
bool dss_has_feature(enum dss_feat_id id)
{
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index b9c70be9258..12e9c4ef0de 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -22,6 +22,7 @@
#define MAX_DSS_MANAGERS 3
#define MAX_DSS_OVERLAYS 3
+#define MAX_DSS_LCD_MANAGERS 2
/* DSS has feature id */
enum dss_feat_id {
@@ -33,6 +34,12 @@ enum dss_feat_id {
FEAT_PCKFREEENABLE = 1 << 5,
FEAT_FUNCGATED = 1 << 6,
FEAT_MGR_LCD2 = 1 << 7,
+ FEAT_LINEBUFFERSPLIT = 1 << 8,
+ FEAT_ROWREPEATENABLE = 1 << 9,
+ FEAT_RESIZECONF = 1 << 10,
+ /* Independent core clk divider */
+ FEAT_CORE_CLK_DIV = 1 << 11,
+ FEAT_LCD_CLK_SRC = 1 << 12,
};
/* DSS register field id */
@@ -42,15 +49,35 @@ enum dss_feat_reg_field {
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_DSIPLL_REGN,
+ FEAT_PARAM_DSIPLL_REGM,
+ FEAT_PARAM_DSIPLL_REGM_DISPC,
+ FEAT_PARAM_DSIPLL_REGM_DSI,
+ FEAT_PARAM_DSIPLL_FINT,
+ FEAT_PARAM_DSIPLL_LPDIV,
};
/* DSS Feature Functions */
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(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_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(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 dss_clk_source id);
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);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
new file mode 100644
index 00000000000..a981def8099
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -0,0 +1,1332 @@
+/*
+ * hdmi.c
+ *
+ * HDMI interface DSS driver setting for TI's OMAP4 family of processor.
+ * 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 <plat/display.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+static struct {
+ struct mutex lock;
+ struct omap_display_platform_data *pdata;
+ struct platform_device *pdev;
+ void __iomem *base_wp; /* HDMI wrapper */
+ int code;
+ int mode;
+ u8 edid[HDMI_EDID_MAX_LENGTH];
+ u8 edid_set;
+ bool custom_set;
+ struct hdmi_config cfg;
+} hdmi;
+
+/*
+ * 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.
+ */
+
+static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = {
+ { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0},
+ { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1},
+ { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1},
+ { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0},
+ { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0},
+ { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0},
+ { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0},
+ { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1},
+ { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1},
+ { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1},
+ { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0},
+ { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0},
+ { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1},
+ { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0},
+ { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1},
+ /* VESA From Here */
+ { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0},
+ { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1},
+ { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1},
+ { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0},
+ { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0},
+ { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1},
+ { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1},
+ { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1},
+ { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0},
+ { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0},
+ { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0},
+ { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0},
+ { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1},
+ { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1},
+ { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1},
+ { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1},
+ { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1},
+ { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1},
+ { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}
+};
+
+/*
+ * This is a static mapping array which maps the timing values
+ * with corresponding CEA / VESA code
+ */
+static const int code_index[OMAP_HDMI_TIMINGS_NB] = {
+ 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32,
+ /* <--15 CEA 17--> vesa*/
+ 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
+ 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B
+};
+
+/*
+ * This is reverse static mapping which maps the CEA / VESA code
+ * to the corresponding timing values
+ */
+static const int code_cea[39] = {
+ -1, 0, 3, 3, 2, 8, 5, 5, -1, -1,
+ -1, -1, -1, -1, -1, -1, 9, 10, 10, 1,
+ 7, 6, 6, -1, -1, -1, -1, -1, -1, 11,
+ 11, 12, 14, -1, -1, 13, 13, 4, 4
+};
+
+static const int code_vesa[85] = {
+ -1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
+ -1, -1, -1, -1, 17, -1, 23, -1, -1, -1,
+ -1, -1, 29, 18, -1, -1, -1, 32, 19, -1,
+ -1, -1, 21, -1, -1, 22, -1, -1, -1, 20,
+ -1, 30, 24, -1, -1, -1, -1, 25, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 31, 26, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 27, 28, -1, 33};
+
+static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
+
+static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val)
+{
+ __raw_writel(val, hdmi.base_wp + idx.idx);
+}
+
+static inline u32 hdmi_read_reg(const struct hdmi_reg idx)
+{
+ return __raw_readl(hdmi.base_wp + idx.idx);
+}
+
+static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
+ int b2, int b1, u32 val)
+{
+ u32 t = 0;
+ while (val != REG_GET(idx, b2, b1)) {
+ udelay(1);
+ if (t++ > 10000)
+ return !val;
+ }
+ return val;
+}
+
+int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+ DSSDBG("init_display\n");
+
+ return 0;
+}
+
+static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq,
+ struct hdmi_pll_info *fmt, u16 sd)
+{
+ u32 r;
+
+ /* PLL start always use manual mode */
+ REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
+
+ r = hdmi_read_reg(PLLCTRL_CFG1);
+ r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
+ r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1_PLL_REGN */
+
+ hdmi_write_reg(PLLCTRL_CFG1, r);
+
+ r = hdmi_read_reg(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 */
+
+ if (dcofreq) {
+ /* divider programming for frequency beyond 1000Mhz */
+ REG_FLD_MOD(PLLCTRL_CFG3, sd, 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(PLLCTRL_CFG2, r);
+
+ r = hdmi_read_reg(PLLCTRL_CFG4);
+ r = FLD_MOD(r, fmt->regm2, 24, 18);
+ r = FLD_MOD(r, fmt->regmf, 17, 0);
+
+ hdmi_write_reg(PLLCTRL_CFG4, r);
+
+ /* go now */
+ REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0);
+
+ /* wait for bit change */
+ if (hdmi_wait_for_bit_change(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(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
+ DSSWARN("cannot lock PLL\n");
+ DSSWARN("CFG1 0x%x\n",
+ hdmi_read_reg(PLLCTRL_CFG1));
+ DSSWARN("CFG2 0x%x\n",
+ hdmi_read_reg(PLLCTRL_CFG2));
+ DSSWARN("CFG4 0x%x\n",
+ hdmi_read_reg(PLLCTRL_CFG4));
+ return -ETIMEDOUT;
+ }
+
+ DSSDBG("PLL locked!\n");
+
+ return 0;
+}
+
+/* PHY_PWR_CMD */
+static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val)
+{
+ /* Command for power control of HDMI PHY */
+ REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6);
+
+ /* Status of the power control of HDMI PHY */
+ if (hdmi_wait_for_bit_change(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 */
+static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val)
+{
+ /* Command for power control of HDMI PLL */
+ REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2);
+
+ /* wait till PHY_PWR_STATUS is set */
+ if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) {
+ DSSERR("Failed to set PHY_PWR_STATUS\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_pll_reset(void)
+{
+ /* SYSRESET controlled by power FSM */
+ REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+
+ /* READ 0x0 reset is in progress */
+ if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
+ DSSERR("Failed to sysreset PLL\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_phy_init(void)
+{
+ u16 r = 0;
+
+ r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON);
+ if (r)
+ return r;
+
+ r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON);
+ 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(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(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+
+ /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+ hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
+
+ /* Setup max LDO voltage */
+ REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+
+ /* Write to phy address 3 to change the polarity control */
+ REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+
+ return 0;
+}
+
+static int hdmi_wait_softreset(void)
+{
+ /* reset W1 */
+ REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
+
+ /* wait till SOFTRESET == 0 */
+ if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
+ DSSERR("sysconfig reset failed\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int hdmi_pll_program(struct hdmi_pll_info *fmt)
+{
+ u16 r = 0;
+ enum hdmi_clk_refsel refsel;
+
+ /* wait for wrapper reset */
+ r = hdmi_wait_softreset();
+ if (r)
+ return r;
+
+ r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+ if (r)
+ return r;
+
+ r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
+ if (r)
+ return r;
+
+ r = hdmi_pll_reset();
+ if (r)
+ return r;
+
+ refsel = HDMI_REFSEL_SYSCLK;
+
+ r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void hdmi_phy_off(void)
+{
+ hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF);
+}
+
+static int hdmi_core_ddc_edid(u8 *pedid, int ext)
+{
+ u32 i, j;
+ char checksum = 0;
+ u32 offset = 0;
+
+ /* Turn on CLK for DDC */
+ REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0);
+
+ /*
+ * SW HACK : Without the Delay DDC(i2c bus) reads 0 values /
+ * right shifted values( The behavior is not consistent and seen only
+ * with some TV's)
+ */
+ usleep_range(800, 1000);
+
+ if (!ext) {
+ /* Clk SCL Devices */
+ REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_IN_PROG */
+ if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Failed to program DDC\n");
+ return -ETIMEDOUT;
+ }
+
+ /* Clear FIFO */
+ REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_IN_PROG */
+ if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+ 4, 4, 0) != 0) {
+ DSSERR("Failed to program DDC\n");
+ return -ETIMEDOUT;
+ }
+
+ } else {
+ if (ext % 2 != 0)
+ offset = 0x80;
+ }
+
+ /* Load Segment Address Register */
+ REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0);
+
+ /* Load Slave Address Register */
+ REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
+
+ /* Load Offset Address Register */
+ REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+
+ /* Load Byte Count */
+ REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
+
+ /* Set DDC_CMD */
+ if (ext)
+ REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0);
+ else
+ REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0);
+
+ /* HDMI_CORE_DDC_STATUS_BUS_LOW */
+ if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
+ DSSWARN("I2C Bus Low?\n");
+ return -EIO;
+ }
+ /* HDMI_CORE_DDC_STATUS_NO_ACK */
+ if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
+ DSSWARN("I2C No Ack\n");
+ return -EIO;
+ }
+
+ i = ext * 128;
+ j = 0;
+ while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) ||
+ (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) &&
+ j < 128) {
+
+ if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) {
+ /* FIFO not empty */
+ pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0);
+ j++;
+ }
+ }
+
+ for (j = 0; j < 128; j++)
+ checksum += pedid[j];
+
+ if (checksum != 0) {
+ DSSERR("E-EDID checksum failed!!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int read_edid(u8 *pedid, u16 max_length)
+{
+ int r = 0, n = 0, i = 0;
+ int max_ext_blocks = (max_length / 128) - 1;
+
+ r = hdmi_core_ddc_edid(pedid, 0);
+ if (r) {
+ return r;
+ } else {
+ n = pedid[0x7e];
+
+ /*
+ * README: need to comply with max_length set by the caller.
+ * Better implementation should be to allocate necessary
+ * memory to store EDID according to nb_block field found
+ * in first block
+ */
+ if (n > max_ext_blocks)
+ n = max_ext_blocks;
+
+ for (i = 1; i <= n; i++) {
+ r = hdmi_core_ddc_edid(pedid, i);
+ if (r)
+ return r;
+ }
+ }
+ return 0;
+}
+
+static int get_timings_index(void)
+{
+ int code;
+
+ if (hdmi.mode == 0)
+ code = code_vesa[hdmi.code];
+ else
+ code = code_cea[hdmi.code];
+
+ if (code == -1) {
+ /* HDMI code 4 corresponds to 640 * 480 VGA */
+ hdmi.code = 4;
+ /* DVI mode 1 corresponds to HDMI 0 to DVI */
+ hdmi.mode = HDMI_DVI;
+
+ code = code_vesa[hdmi.code];
+ }
+ return code;
+}
+
+static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
+{
+ int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
+ int timing_vsync = 0, timing_hsync = 0;
+ struct omap_video_timings temp;
+ struct hdmi_cm cm = {-1};
+ DSSDBG("hdmi_get_code\n");
+
+ for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) {
+ temp = cea_vesa_timings[i].timings;
+ if ((temp.pixel_clock == timing->pixel_clock) &&
+ (temp.x_res == timing->x_res) &&
+ (temp.y_res == timing->y_res)) {
+
+ temp_hsync = temp.hfp + temp.hsw + temp.hbp;
+ timing_hsync = timing->hfp + timing->hsw + timing->hbp;
+ temp_vsync = temp.vfp + temp.vsw + temp.vbp;
+ timing_vsync = timing->vfp + timing->vsw + timing->vbp;
+
+ DSSDBG("temp_hsync = %d , temp_vsync = %d"
+ "timing_hsync = %d, timing_vsync = %d\n",
+ temp_hsync, temp_hsync,
+ timing_hsync, timing_vsync);
+
+ if ((temp_hsync == timing_hsync) &&
+ (temp_vsync == timing_vsync)) {
+ code = i;
+ cm.code = code_index[i];
+ if (code < 14)
+ cm.mode = HDMI_HDMI;
+ else
+ cm.mode = HDMI_DVI;
+ DSSDBG("Hdmi_code = %d mode = %d\n",
+ cm.code, cm.mode);
+ break;
+ }
+ }
+ }
+
+ return cm;
+}
+
+static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
+ struct omap_video_timings *timings)
+{
+ /* X and Y resolution */
+ timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
+ edid[current_descriptor_addrs + 2]);
+ timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
+ edid[current_descriptor_addrs + 5]);
+
+ timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
+ edid[current_descriptor_addrs]);
+
+ timings->pixel_clock = 10 * timings->pixel_clock;
+
+ /* HORIZONTAL FRONT PORCH */
+ timings->hfp = edid[current_descriptor_addrs + 8] |
+ ((edid[current_descriptor_addrs + 11] & 0xc0) << 2);
+ /* HORIZONTAL SYNC WIDTH */
+ timings->hsw = edid[current_descriptor_addrs + 9] |
+ ((edid[current_descriptor_addrs + 11] & 0x30) << 4);
+ /* HORIZONTAL BACK PORCH */
+ timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) |
+ edid[current_descriptor_addrs + 3]) -
+ (timings->hfp + timings->hsw);
+ /* VERTICAL FRONT PORCH */
+ timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) |
+ ((edid[current_descriptor_addrs + 11] & 0x0f) << 2);
+ /* VERTICAL SYNC WIDTH */
+ timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) |
+ ((edid[current_descriptor_addrs + 11] & 0x03) << 4);
+ /* VERTICAL BACK PORCH */
+ timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) |
+ edid[current_descriptor_addrs + 6]) -
+ (timings->vfp + timings->vsw);
+
+}
+
+/* Description : This function gets the resolution information from EDID */
+static void get_edid_timing_data(u8 *edid)
+{
+ u8 count;
+ u16 current_descriptor_addrs;
+ struct hdmi_cm cm;
+ struct omap_video_timings edid_timings;
+
+ /* search block 0, there are 4 DTDs arranged in priority order */
+ for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+ current_descriptor_addrs =
+ EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ get_horz_vert_timing_info(current_descriptor_addrs,
+ edid, &edid_timings);
+ cm = hdmi_get_code(&edid_timings);
+ DSSDBG("Block0[%d] value matches code = %d , mode = %d\n",
+ count, cm.code, cm.mode);
+ if (cm.code == -1) {
+ continue;
+ } else {
+ hdmi.code = cm.code;
+ hdmi.mode = cm.mode;
+ DSSDBG("code = %d , mode = %d\n",
+ hdmi.code, hdmi.mode);
+ return;
+ }
+ }
+ if (edid[0x7e] != 0x00) {
+ for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+ count++) {
+ current_descriptor_addrs =
+ EDID_DESCRIPTOR_BLOCK1_ADDRESS +
+ count * EDID_TIMING_DESCRIPTOR_SIZE;
+ get_horz_vert_timing_info(current_descriptor_addrs,
+ edid, &edid_timings);
+ cm = hdmi_get_code(&edid_timings);
+ DSSDBG("Block1[%d] value matches code = %d, mode = %d",
+ count, cm.code, cm.mode);
+ if (cm.code == -1) {
+ continue;
+ } else {
+ hdmi.code = cm.code;
+ hdmi.mode = cm.mode;
+ DSSDBG("code = %d , mode = %d\n",
+ hdmi.code, hdmi.mode);
+ return;
+ }
+ }
+ }
+
+ DSSINFO("no valid timing found , falling back to VGA\n");
+ hdmi.code = 4; /* setting default value of 640 480 VGA */
+ hdmi.mode = HDMI_DVI;
+}
+
+static void hdmi_read_edid(struct omap_video_timings *dp)
+{
+ int ret = 0, code;
+
+ memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
+
+ if (!hdmi.edid_set)
+ ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH);
+
+ if (!ret) {
+ if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) {
+ /* search for timings of default resolution */
+ get_edid_timing_data(hdmi.edid);
+ hdmi.edid_set = true;
+ }
+ } else {
+ DSSWARN("failed to read E-EDID\n");
+ }
+
+ if (!hdmi.edid_set) {
+ DSSINFO("fallback to VGA\n");
+ hdmi.code = 4; /* setting default value of 640 480 VGA */
+ hdmi.mode = HDMI_DVI;
+ }
+
+ code = get_timings_index();
+
+ *dp = cea_vesa_timings[code].timings;
+}
+
+static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
+ struct hdmi_core_infoframe_avi *avi_cfg,
+ struct hdmi_core_packet_enable_repeat *repeat_cfg)
+{
+ DSSDBG("Enter hdmi_core_init\n");
+
+ /* video core */
+ video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
+ video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
+ video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
+ video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
+ video_cfg->hdmi_dvi = HDMI_DVI;
+ video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
+
+ /* info frame */
+ avi_cfg->db1_format = 0;
+ avi_cfg->db1_active_info = 0;
+ avi_cfg->db1_bar_info_dv = 0;
+ avi_cfg->db1_scan_info = 0;
+ avi_cfg->db2_colorimetry = 0;
+ avi_cfg->db2_aspect_ratio = 0;
+ avi_cfg->db2_active_fmt_ar = 0;
+ avi_cfg->db3_itc = 0;
+ avi_cfg->db3_ec = 0;
+ avi_cfg->db3_q_range = 0;
+ avi_cfg->db3_nup_scaling = 0;
+ avi_cfg->db4_videocode = 0;
+ avi_cfg->db5_pixel_repeat = 0;
+ avi_cfg->db6_7_line_eoftop = 0 ;
+ avi_cfg->db8_9_line_sofbottom = 0;
+ avi_cfg->db10_11_pixel_eofleft = 0;
+ avi_cfg->db12_13_pixel_sofright = 0;
+
+ /* packet enable and repeat */
+ repeat_cfg->audio_pkt = 0;
+ repeat_cfg->audio_pkt_repeat = 0;
+ repeat_cfg->avi_infoframe = 0;
+ repeat_cfg->avi_infoframe_repeat = 0;
+ repeat_cfg->gen_cntrl_pkt = 0;
+ repeat_cfg->gen_cntrl_pkt_repeat = 0;
+ repeat_cfg->generic_pkt = 0;
+ repeat_cfg->generic_pkt_repeat = 0;
+}
+
+static void hdmi_core_powerdown_disable(void)
+{
+ DSSDBG("Enter hdmi_core_powerdown_disable\n");
+ REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_release(void)
+{
+ DSSDBG("Enter hdmi_core_swreset_release\n");
+ REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_assert(void)
+{
+ DSSDBG("Enter hdmi_core_swreset_assert\n");
+ REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0);
+}
+
+/* DSS_HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_video_config *cfg)
+{
+ u32 r = 0;
+
+ /* sys_ctrl1 default configuration not tunable */
+ r = hdmi_read_reg(HDMI_CORE_CTRL1);
+ r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
+ r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
+ r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2);
+ r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1);
+ hdmi_write_reg(HDMI_CORE_CTRL1, r);
+
+ REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
+
+ /* Vid_Mode */
+ r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE);
+
+ /* dither truncation configuration */
+ if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
+ r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
+ r = FLD_MOD(r, 1, 5, 5);
+ } else {
+ r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
+ r = FLD_MOD(r, 0, 5, 5);
+ }
+ hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r);
+
+ /* HDMI_Ctrl */
+ r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL);
+ r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
+ r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
+ r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r);
+
+ /* TMDS_CTRL */
+ REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL,
+ cfg->tclk_sel_clkmult, 6, 5);
+}
+
+static void hdmi_core_aux_infoframe_avi_config(
+ struct hdmi_core_infoframe_avi info_avi)
+{
+ u32 val;
+ char sum = 0, checksum = 0;
+
+ sum += 0x82 + 0x002 + 0x00D;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D);
+
+ val = (info_avi.db1_format << 5) |
+ (info_avi.db1_active_info << 4) |
+ (info_avi.db1_bar_info_dv << 2) |
+ (info_avi.db1_scan_info);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val);
+ sum += val;
+
+ val = (info_avi.db2_colorimetry << 6) |
+ (info_avi.db2_aspect_ratio << 4) |
+ (info_avi.db2_active_fmt_ar);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val);
+ sum += val;
+
+ val = (info_avi.db3_itc << 7) |
+ (info_avi.db3_ec << 4) |
+ (info_avi.db3_q_range << 2) |
+ (info_avi.db3_nup_scaling);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val);
+ sum += val;
+
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode);
+ sum += info_avi.db4_videocode;
+
+ val = info_avi.db5_pixel_repeat;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val);
+ sum += val;
+
+ val = info_avi.db6_7_line_eoftop & 0x00FF;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val);
+ sum += val;
+
+ val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val);
+ sum += val;
+
+ val = info_avi.db8_9_line_sofbottom & 0x00FF;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val);
+ sum += val;
+
+ val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val);
+ sum += val;
+
+ val = info_avi.db10_11_pixel_eofleft & 0x00FF;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val);
+ sum += val;
+
+ val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val);
+ sum += val;
+
+ val = info_avi.db12_13_pixel_sofright & 0x00FF;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val);
+ sum += val;
+
+ val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
+ hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val);
+ sum += val;
+
+ checksum = 0x100 - sum;
+ hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum);
+}
+
+static void hdmi_core_av_packet_config(
+ struct hdmi_core_packet_enable_repeat repeat_cfg)
+{
+ /* enable/repeat the infoframe */
+ hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1,
+ (repeat_cfg.audio_pkt << 5) |
+ (repeat_cfg.audio_pkt_repeat << 4) |
+ (repeat_cfg.avi_infoframe << 1) |
+ (repeat_cfg.avi_infoframe_repeat));
+
+ /* enable/repeat the packet */
+ hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2,
+ (repeat_cfg.gen_cntrl_pkt << 3) |
+ (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
+ (repeat_cfg.generic_pkt << 1) |
+ (repeat_cfg.generic_pkt_repeat));
+}
+
+static void hdmi_wp_init(struct omap_video_timings *timings,
+ struct hdmi_video_format *video_fmt,
+ struct hdmi_video_interface *video_int)
+{
+ DSSDBG("Enter hdmi_wp_init\n");
+
+ timings->hbp = 0;
+ timings->hfp = 0;
+ timings->hsw = 0;
+ timings->vbp = 0;
+ timings->vfp = 0;
+ timings->vsw = 0;
+
+ video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
+ video_fmt->y_res = 0;
+ video_fmt->x_res = 0;
+
+ video_int->vsp = 0;
+ video_int->hsp = 0;
+
+ video_int->interlacing = 0;
+ video_int->tm = 0; /* HDMI_TIMING_SLAVE */
+
+}
+
+static void hdmi_wp_video_start(bool start)
+{
+ REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31);
+}
+
+static void hdmi_wp_video_init_format(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->y_res = param->timings.timings.y_res;
+ video_fmt->x_res = param->timings.timings.x_res;
+
+ timings->hbp = param->timings.timings.hbp;
+ timings->hfp = param->timings.timings.hfp;
+ timings->hsw = param->timings.timings.hsw;
+ timings->vbp = param->timings.timings.vbp;
+ timings->vfp = param->timings.timings.vfp;
+ timings->vsw = param->timings.timings.vsw;
+}
+
+static void hdmi_wp_video_config_format(
+ struct hdmi_video_format *video_fmt)
+{
+ u32 l = 0;
+
+ REG_FLD_MOD(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(HDMI_WP_VIDEO_SIZE, l);
+}
+
+static void hdmi_wp_video_config_interface(
+ struct hdmi_video_interface *video_int)
+{
+ u32 r;
+ DSSDBG("Enter hdmi_wp_video_config_interface\n");
+
+ r = hdmi_read_reg(HDMI_WP_VIDEO_CFG);
+ r = FLD_MOD(r, video_int->vsp, 7, 7);
+ r = FLD_MOD(r, video_int->hsp, 6, 6);
+ r = FLD_MOD(r, video_int->interlacing, 3, 3);
+ r = FLD_MOD(r, video_int->tm, 1, 0);
+ hdmi_write_reg(HDMI_WP_VIDEO_CFG, r);
+}
+
+static void hdmi_wp_video_config_timing(
+ 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(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(HDMI_WP_VIDEO_TIMING_V, timing_v);
+}
+
+static void hdmi_basic_configure(struct hdmi_config *cfg)
+{
+ /* HDMI */
+ struct omap_video_timings video_timing;
+ struct hdmi_video_format video_format;
+ struct hdmi_video_interface video_interface;
+ /* HDMI core */
+ struct hdmi_core_infoframe_avi avi_cfg;
+ struct hdmi_core_video_config v_core_cfg;
+ struct hdmi_core_packet_enable_repeat repeat_cfg;
+
+ hdmi_wp_init(&video_timing, &video_format,
+ &video_interface);
+
+ hdmi_core_init(&v_core_cfg,
+ &avi_cfg,
+ &repeat_cfg);
+
+ hdmi_wp_video_init_format(&video_format,
+ &video_timing, cfg);
+
+ hdmi_wp_video_config_timing(&video_timing);
+
+ /* video config */
+ video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+ hdmi_wp_video_config_format(&video_format);
+
+ video_interface.vsp = cfg->timings.vsync_pol;
+ video_interface.hsp = cfg->timings.hsync_pol;
+ video_interface.interlacing = cfg->interlace;
+ video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
+
+ hdmi_wp_video_config_interface(&video_interface);
+
+ /*
+ * configure core video part
+ * set software reset in the core
+ */
+ hdmi_core_swreset_assert();
+
+ /* power down off */
+ hdmi_core_powerdown_disable();
+
+ v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
+ v_core_cfg.hdmi_dvi = cfg->cm.mode;
+
+ hdmi_core_video_config(&v_core_cfg);
+
+ /* release software reset in the core */
+ hdmi_core_swreset_release();
+
+ /*
+ * configure packet
+ * info frame video see doc CEA861-D page 65
+ */
+ avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
+ avi_cfg.db1_active_info =
+ HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
+ avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
+ avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
+ avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
+ avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
+ avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
+ avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
+ avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
+ avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
+ avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
+ avi_cfg.db4_videocode = cfg->cm.code;
+ avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
+ avi_cfg.db6_7_line_eoftop = 0;
+ avi_cfg.db8_9_line_sofbottom = 0;
+ avi_cfg.db10_11_pixel_eofleft = 0;
+ avi_cfg.db12_13_pixel_sofright = 0;
+
+ hdmi_core_aux_infoframe_avi_config(avi_cfg);
+
+ /* enable/repeat the infoframe */
+ repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
+ repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
+ /* wakeup */
+ repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
+ repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
+ hdmi_core_av_packet_config(repeat_cfg);
+}
+
+static void update_hdmi_timings(struct hdmi_config *cfg,
+ struct omap_video_timings *timings, int code)
+{
+ cfg->timings.timings.x_res = timings->x_res;
+ cfg->timings.timings.y_res = timings->y_res;
+ cfg->timings.timings.hbp = timings->hbp;
+ cfg->timings.timings.hfp = timings->hfp;
+ cfg->timings.timings.hsw = timings->hsw;
+ cfg->timings.timings.vbp = timings->vbp;
+ cfg->timings.timings.vfp = timings->vfp;
+ cfg->timings.timings.vsw = timings->vsw;
+ cfg->timings.timings.pixel_clock = timings->pixel_clock;
+ cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol;
+ cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
+}
+
+static void hdmi_compute_pll(unsigned long clkin, int phy,
+ int n, struct hdmi_pll_info *pi)
+{
+ unsigned long refclk;
+ u32 mf;
+
+ /*
+ * Input clock is predivided by N + 1
+ * out put of which is reference clk
+ */
+ refclk = clkin / (n + 1);
+ pi->regn = n;
+
+ /*
+ * multiplier is pixel_clk/ref_clk
+ * Multiplying by 100 to avoid fractional part removal
+ */
+ pi->regm = (phy * 100/(refclk))/100;
+ pi->regm2 = 1;
+
+ /*
+ * 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 * refclk) * 262144;
+ pi->regmf = 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) / ((n + 1) * 250) + 5) / 10;
+
+ DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
+ DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+}
+
+static void hdmi_enable_clocks(int enable)
+{
+ if (enable)
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
+ DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+ else
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
+ DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+}
+
+static int hdmi_power_on(struct omap_dss_device *dssdev)
+{
+ int r, code = 0;
+ struct hdmi_pll_info pll_data;
+ struct omap_video_timings *p;
+ int clkin, n, phy;
+
+ hdmi_enable_clocks(1);
+
+ dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+ p = &dssdev->panel.timings;
+
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
+ dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+
+ if (!hdmi.custom_set) {
+ DSSDBG("Read EDID as no EDID is not set on poweron\n");
+ hdmi_read_edid(p);
+ }
+ code = get_timings_index();
+ dssdev->panel.timings = cea_vesa_timings[code].timings;
+ update_hdmi_timings(&hdmi.cfg, p, code);
+
+ clkin = 3840; /* 38.4 MHz */
+ n = 15; /* this is a constant for our math */
+ phy = p->pixel_clock;
+
+ hdmi_compute_pll(clkin, phy, n, &pll_data);
+
+ hdmi_wp_video_start(0);
+
+ /* config the PLL and PHY first */
+ r = hdmi_pll_program(&pll_data);
+ if (r) {
+ DSSDBG("Failed to lock PLL\n");
+ goto err;
+ }
+
+ r = hdmi_phy_init();
+ if (r) {
+ DSSDBG("Failed to start PHY\n");
+ goto err;
+ }
+
+ hdmi.cfg.cm.mode = hdmi.mode;
+ hdmi.cfg.cm.code = hdmi.code;
+ hdmi_basic_configure(&hdmi.cfg);
+
+ /* Make selection of HDMI in DSS */
+ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+ /* Select the dispc clock source as PRCM clock, to ensure that it is not
+ * DSI PLL source as the clock selected by DSI PLL might not be
+ * sufficient for the resolution selected / that can be changed
+ * dynamically by user. This can be moved to single location , say
+ * Boardfile.
+ */
+ dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+
+ /* bypass TV gamma table */
+ dispc_enable_gamma_table(0);
+
+ /* tv size */
+ dispc_set_digit_size(dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+
+ dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1);
+
+ hdmi_wp_video_start(1);
+
+ return 0;
+err:
+ hdmi_enable_clocks(0);
+ return -EIO;
+}
+
+static void hdmi_power_off(struct omap_dss_device *dssdev)
+{
+ dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+ hdmi_wp_video_start(0);
+ hdmi_phy_off();
+ hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+ hdmi_enable_clocks(0);
+
+ hdmi.edid_set = 0;
+}
+
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct hdmi_cm cm;
+
+ cm = hdmi_get_code(timings);
+ if (cm.code == -1) {
+ DSSERR("Invalid timing entered\n");
+ return -EINVAL;
+ }
+
+ return 0;
+
+}
+
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+{
+ struct hdmi_cm cm;
+
+ hdmi.custom_set = 1;
+ cm = hdmi_get_code(&dssdev->panel.timings);
+ hdmi.code = cm.code;
+ hdmi.mode = cm.mode;
+ omapdss_hdmi_display_enable(dssdev);
+ hdmi.custom_set = 0;
+}
+
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("ENTER hdmi_display_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ r = omap_dss_start_device(dssdev);
+ if (r) {
+ DSSERR("failed to start device\n");
+ goto err0;
+ }
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r) {
+ DSSERR("failed to enable GPIO's\n");
+ goto err1;
+ }
+ }
+
+ r = hdmi_power_on(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err2;
+ }
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err2:
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+err1:
+ omap_dss_stop_device(dssdev);
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter hdmi_display_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ hdmi_power_off(dssdev);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ omap_dss_stop_device(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+/* HDMI HW IP initialisation */
+static int omapdss_hdmihw_probe(struct platform_device *pdev)
+{
+ struct resource *hdmi_mem;
+
+ hdmi.pdata = pdev->dev.platform_data;
+ hdmi.pdev = pdev;
+
+ mutex_init(&hdmi.lock);
+
+ hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
+ if (!hdmi_mem) {
+ DSSERR("can't get IORESOURCE_MEM HDMI\n");
+ return -EINVAL;
+ }
+
+ /* Base address taken from platform */
+ hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem));
+ if (!hdmi.base_wp) {
+ DSSERR("can't ioremap WP\n");
+ return -ENOMEM;
+ }
+
+ hdmi_panel_init();
+
+ return 0;
+}
+
+static int omapdss_hdmihw_remove(struct platform_device *pdev)
+{
+ hdmi_panel_exit();
+
+ iounmap(hdmi.base_wp);
+
+ return 0;
+}
+
+static struct platform_driver omapdss_hdmihw_driver = {
+ .probe = omapdss_hdmihw_probe,
+ .remove = omapdss_hdmihw_remove,
+ .driver = {
+ .name = "omapdss_hdmi",
+ .owner = THIS_MODULE,
+ },
+};
+
+int hdmi_init_platform_driver(void)
+{
+ return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void hdmi_uninit_platform_driver(void)
+{
+ return platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
new file mode 100644
index 00000000000..9887ab96da3
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi.h
@@ -0,0 +1,415 @@
+/*
+ * hdmi.h
+ *
+ * HDMI driver definition for TI OMAP4 processors.
+ *
+ * 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 _OMAP4_DSS_HDMI_H_
+#define _OMAP4_DSS_HDMI_H_
+
+#include <linux/string.h>
+#include <plat/display.h>
+
+#define HDMI_WP 0x0
+#define HDMI_CORE_SYS 0x400
+#define HDMI_CORE_AV 0x900
+#define HDMI_PLLCTRL 0x200
+#define HDMI_PHY 0x300
+
+struct hdmi_reg { u16 idx; };
+
+#define HDMI_REG(idx) ((const struct hdmi_reg) { idx })
+
+/* HDMI Wrapper */
+#define HDMI_WP_REG(idx) HDMI_REG(HDMI_WP + idx)
+
+#define HDMI_WP_REVISION HDMI_WP_REG(0x0)
+#define HDMI_WP_SYSCONFIG HDMI_WP_REG(0x10)
+#define HDMI_WP_IRQSTATUS_RAW HDMI_WP_REG(0x24)
+#define HDMI_WP_IRQSTATUS HDMI_WP_REG(0x28)
+#define HDMI_WP_PWR_CTRL HDMI_WP_REG(0x40)
+#define HDMI_WP_IRQENABLE_SET HDMI_WP_REG(0x2C)
+#define HDMI_WP_VIDEO_CFG HDMI_WP_REG(0x50)
+#define HDMI_WP_VIDEO_SIZE HDMI_WP_REG(0x60)
+#define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68)
+#define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C)
+#define HDMI_WP_WP_CLK HDMI_WP_REG(0x70)
+
+/* HDMI IP Core System */
+#define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx)
+
+#define HDMI_CORE_SYS_VND_IDL HDMI_CORE_SYS_REG(0x0)
+#define HDMI_CORE_SYS_DEV_IDL HDMI_CORE_SYS_REG(0x8)
+#define HDMI_CORE_SYS_DEV_IDH HDMI_CORE_SYS_REG(0xC)
+#define HDMI_CORE_SYS_DEV_REV HDMI_CORE_SYS_REG(0x10)
+#define HDMI_CORE_SYS_SRST HDMI_CORE_SYS_REG(0x14)
+#define HDMI_CORE_CTRL1 HDMI_CORE_SYS_REG(0x20)
+#define HDMI_CORE_SYS_SYS_STAT HDMI_CORE_SYS_REG(0x24)
+#define HDMI_CORE_SYS_VID_ACEN HDMI_CORE_SYS_REG(0x124)
+#define HDMI_CORE_SYS_VID_MODE HDMI_CORE_SYS_REG(0x128)
+#define HDMI_CORE_SYS_INTR_STATE HDMI_CORE_SYS_REG(0x1C0)
+#define HDMI_CORE_SYS_INTR1 HDMI_CORE_SYS_REG(0x1C4)
+#define HDMI_CORE_SYS_INTR2 HDMI_CORE_SYS_REG(0x1C8)
+#define HDMI_CORE_SYS_INTR3 HDMI_CORE_SYS_REG(0x1CC)
+#define HDMI_CORE_SYS_INTR4 HDMI_CORE_SYS_REG(0x1D0)
+#define HDMI_CORE_SYS_UMASK1 HDMI_CORE_SYS_REG(0x1D4)
+#define HDMI_CORE_SYS_TMDS_CTRL HDMI_CORE_SYS_REG(0x208)
+#define HDMI_CORE_SYS_DE_DLY HDMI_CORE_SYS_REG(0xC8)
+#define HDMI_CORE_SYS_DE_CTRL HDMI_CORE_SYS_REG(0xCC)
+#define HDMI_CORE_SYS_DE_TOP HDMI_CORE_SYS_REG(0xD0)
+#define HDMI_CORE_SYS_DE_CNTL HDMI_CORE_SYS_REG(0xD8)
+#define HDMI_CORE_SYS_DE_CNTH HDMI_CORE_SYS_REG(0xDC)
+#define HDMI_CORE_SYS_DE_LINL HDMI_CORE_SYS_REG(0xE0)
+#define HDMI_CORE_SYS_DE_LINH_1 HDMI_CORE_SYS_REG(0xE4)
+#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1
+#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1
+#define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1
+#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1
+
+/* HDMI DDC E-DID */
+#define HDMI_CORE_DDC_CMD HDMI_CORE_SYS_REG(0x3CC)
+#define HDMI_CORE_DDC_STATUS HDMI_CORE_SYS_REG(0x3C8)
+#define HDMI_CORE_DDC_ADDR HDMI_CORE_SYS_REG(0x3B4)
+#define HDMI_CORE_DDC_OFFSET HDMI_CORE_SYS_REG(0x3BC)
+#define HDMI_CORE_DDC_COUNT1 HDMI_CORE_SYS_REG(0x3C0)
+#define HDMI_CORE_DDC_COUNT2 HDMI_CORE_SYS_REG(0x3C4)
+#define HDMI_CORE_DDC_DATA HDMI_CORE_SYS_REG(0x3D0)
+#define HDMI_CORE_DDC_SEGM HDMI_CORE_SYS_REG(0x3B8)
+
+/* HDMI IP Core Audio Video */
+#define HDMI_CORE_AV_REG(idx) HDMI_REG(HDMI_CORE_AV + idx)
+
+#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_AVI_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x110)
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15)
+#define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190)
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_MPEG_DBYTE HDMI_CORE_AV_REG(0x290)
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300)
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_GEN2_DBYTE HDMI_CORE_AV_REG(0x380)
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_ACR_CTRL HDMI_CORE_AV_REG(0x4)
+#define HDMI_CORE_AV_FREQ_SVAL HDMI_CORE_AV_REG(0x8)
+#define HDMI_CORE_AV_N_SVAL1 HDMI_CORE_AV_REG(0xC)
+#define HDMI_CORE_AV_N_SVAL2 HDMI_CORE_AV_REG(0x10)
+#define HDMI_CORE_AV_N_SVAL3 HDMI_CORE_AV_REG(0x14)
+#define HDMI_CORE_AV_CTS_SVAL1 HDMI_CORE_AV_REG(0x18)
+#define HDMI_CORE_AV_CTS_SVAL2 HDMI_CORE_AV_REG(0x1C)
+#define HDMI_CORE_AV_CTS_SVAL3 HDMI_CORE_AV_REG(0x20)
+#define HDMI_CORE_AV_CTS_HVAL1 HDMI_CORE_AV_REG(0x24)
+#define HDMI_CORE_AV_CTS_HVAL2 HDMI_CORE_AV_REG(0x28)
+#define HDMI_CORE_AV_CTS_HVAL3 HDMI_CORE_AV_REG(0x2C)
+#define HDMI_CORE_AV_AUD_MODE HDMI_CORE_AV_REG(0x50)
+#define HDMI_CORE_AV_SPDIF_CTRL HDMI_CORE_AV_REG(0x54)
+#define HDMI_CORE_AV_HW_SPDIF_FS HDMI_CORE_AV_REG(0x60)
+#define HDMI_CORE_AV_SWAP_I2S HDMI_CORE_AV_REG(0x64)
+#define HDMI_CORE_AV_SPDIF_ERTH HDMI_CORE_AV_REG(0x6C)
+#define HDMI_CORE_AV_I2S_IN_MAP HDMI_CORE_AV_REG(0x70)
+#define HDMI_CORE_AV_I2S_IN_CTRL HDMI_CORE_AV_REG(0x74)
+#define HDMI_CORE_AV_I2S_CHST0 HDMI_CORE_AV_REG(0x78)
+#define HDMI_CORE_AV_I2S_CHST1 HDMI_CORE_AV_REG(0x7C)
+#define HDMI_CORE_AV_I2S_CHST2 HDMI_CORE_AV_REG(0x80)
+#define HDMI_CORE_AV_I2S_CHST4 HDMI_CORE_AV_REG(0x84)
+#define HDMI_CORE_AV_I2S_CHST5 HDMI_CORE_AV_REG(0x88)
+#define HDMI_CORE_AV_ASRC HDMI_CORE_AV_REG(0x8C)
+#define HDMI_CORE_AV_I2S_IN_LEN HDMI_CORE_AV_REG(0x90)
+#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_AUDO_TXSTAT HDMI_CORE_AV_REG(0xC0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 HDMI_CORE_AV_REG(0xCC)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 HDMI_CORE_AV_REG(0xD0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 HDMI_CORE_AV_REG(0xD4)
+#define HDMI_CORE_AV_TEST_TXCTRL HDMI_CORE_AV_REG(0xF0)
+#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_SPD_TYPE HDMI_CORE_AV_REG(0x180)
+#define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184)
+#define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188)
+#define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280)
+#define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284)
+#define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288)
+#define HDMI_CORE_AV_MPEG_CHSUM HDMI_CORE_AV_REG(0x28C)
+#define HDMI_CORE_AV_CP_BYTE1 HDMI_CORE_AV_REG(0x37C)
+#define HDMI_CORE_AV_CEC_ADDR_ID HDMI_CORE_AV_REG(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
+
+/* PLL */
+#define HDMI_PLL_REG(idx) HDMI_REG(HDMI_PLLCTRL + idx)
+
+#define PLLCTRL_PLL_CONTROL HDMI_PLL_REG(0x0)
+#define PLLCTRL_PLL_STATUS HDMI_PLL_REG(0x4)
+#define PLLCTRL_PLL_GO HDMI_PLL_REG(0x8)
+#define PLLCTRL_CFG1 HDMI_PLL_REG(0xC)
+#define PLLCTRL_CFG2 HDMI_PLL_REG(0x10)
+#define PLLCTRL_CFG3 HDMI_PLL_REG(0x14)
+#define PLLCTRL_CFG4 HDMI_PLL_REG(0x20)
+
+/* HDMI PHY */
+#define HDMI_PHY_REG(idx) HDMI_REG(HDMI_PHY + idx)
+
+#define HDMI_TXPHY_TX_CTRL HDMI_PHY_REG(0x0)
+#define HDMI_TXPHY_DIGITAL_CTRL HDMI_PHY_REG(0x4)
+#define HDMI_TXPHY_POWER_CTRL HDMI_PHY_REG(0x8)
+#define HDMI_TXPHY_PAD_CFG_CTRL HDMI_PHY_REG(0xC)
+
+/* HDMI EDID Length */
+#define HDMI_EDID_MAX_LENGTH 256
+#define EDID_TIMING_DESCRIPTOR_SIZE 0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
+
+#define OMAP_HDMI_TIMINGS_NB 34
+
+#define REG_FLD_MOD(idx, val, start, end) \
+ hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end))
+#define REG_GET(idx, start, end) \
+ FLD_GET(hdmi_read_reg(idx), start, end)
+
+/* HDMI timing structure */
+struct hdmi_timings {
+ struct omap_video_timings timings;
+ int vsync_pol;
+ int hsync_pol;
+};
+
+enum hdmi_phy_pwr {
+ HDMI_PHYPWRCMD_OFF = 0,
+ HDMI_PHYPWRCMD_LDOON = 1,
+ HDMI_PHYPWRCMD_TXON = 2
+};
+
+enum hdmi_pll_pwr {
+ HDMI_PLLPWRCMD_ALLOFF = 0,
+ HDMI_PLLPWRCMD_PLLONLY = 1,
+ HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
+ HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
+};
+
+enum hdmi_clk_refsel {
+ HDMI_REFSEL_PCLK = 0,
+ HDMI_REFSEL_REF1 = 1,
+ HDMI_REFSEL_REF2 = 2,
+ HDMI_REFSEL_SYSCLK = 3
+};
+
+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_hdmi_dvi {
+ HDMI_DVI = 0,
+ HDMI_HDMI = 1
+};
+
+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
+};
+
+/* INFOFRAME_AVI_ 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
+};
+
+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
+};
+
+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;
+};
+
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_avi {
+ u8 db1_format;
+ /* Y0, Y1 rgb,yCbCr */
+ u8 db1_active_info;
+ /* A0 Active information Present */
+ u8 db1_bar_info_dv;
+ /* B0, B1 Bar info data valid */
+ u8 db1_scan_info;
+ /* S0, S1 scan information */
+ u8 db2_colorimetry;
+ /* C0, C1 colorimetry */
+ u8 db2_aspect_ratio;
+ /* M0, M1 Aspect ratio (4:3, 16:9) */
+ u8 db2_active_fmt_ar;
+ /* R0...R3 Active format aspect ratio */
+ u8 db3_itc;
+ /* ITC IT content. */
+ u8 db3_ec;
+ /* EC0, EC1, EC2 Extended colorimetry */
+ u8 db3_q_range;
+ /* Q1, Q0 Quantization range */
+ u8 db3_nup_scaling;
+ /* SC1, SC0 Non-uniform picture scaling */
+ u8 db4_videocode;
+ /* VIC0..6 Video format identification */
+ u8 db5_pixel_repeat;
+ /* PR0..PR3 Pixel repetition factor */
+ u16 db6_7_line_eoftop;
+ /* Line number end of top bar */
+ u16 db8_9_line_sofbottom;
+ /* Line number start of bottom bar */
+ u16 db10_11_pixel_eofleft;
+ /* Pixel number end of left bar */
+ u16 db12_13_pixel_sofright;
+ /* Pixel number start of right bar */
+};
+
+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;
+};
+
+struct hdmi_video_format {
+ enum hdmi_packing_mode packing_mode;
+ u32 y_res; /* Line per panel */
+ u32 x_res; /* pixel per line */
+};
+
+struct hdmi_video_interface {
+ int vsp; /* Vsync polarity */
+ int hsp; /* Hsync polarity */
+ int interlacing;
+ int tm; /* Timing mode */
+};
+
+struct hdmi_cm {
+ int code;
+ int mode;
+};
+
+struct hdmi_config {
+ struct hdmi_timings timings;
+ u16 interlace;
+ struct hdmi_cm cm;
+};
+
+#endif
diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_omap4_panel.c
new file mode 100644
index 00000000000..ffb5de94131
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi_omap4_panel.c
@@ -0,0 +1,222 @@
+/*
+ * hdmi_omap4_panel.c
+ *
+ * HDMI library support functions for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Mythri P k <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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <plat/display.h>
+
+#include "dss.h"
+
+static struct {
+ struct mutex hdmi_lock;
+} hdmi;
+
+
+static int hdmi_panel_probe(struct omap_dss_device *dssdev)
+{
+ DSSDBG("ENTER hdmi_panel_probe\n");
+
+ dssdev->panel.config = OMAP_DSS_LCD_TFT |
+ OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
+
+ /*
+ * Initialize the timings to 640 * 480
+ * This is only for framebuffer update not for TV timing setting
+ * Setting TV timing will be done only on enable
+ */
+ dssdev->panel.timings.x_res = 640;
+ dssdev->panel.timings.y_res = 480;
+
+ DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
+ dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+ return 0;
+}
+
+static void hdmi_panel_remove(struct omap_dss_device *dssdev)
+{
+
+}
+
+static int hdmi_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+ DSSDBG("ENTER hdmi_panel_enable\n");
+
+ mutex_lock(&hdmi.hdmi_lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ r = omapdss_hdmi_display_enable(dssdev);
+ if (r) {
+ DSSERR("failed to power on\n");
+ goto err;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+ mutex_unlock(&hdmi.hdmi_lock);
+
+ return r;
+}
+
+static void hdmi_panel_disable(struct omap_dss_device *dssdev)
+{
+ mutex_lock(&hdmi.hdmi_lock);
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ omapdss_hdmi_display_disable(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+ mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ mutex_lock(&hdmi.hdmi_lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+ omapdss_hdmi_display_disable(dssdev);
+
+err:
+ mutex_unlock(&hdmi.hdmi_lock);
+
+ return r;
+}
+
+static int hdmi_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ mutex_lock(&hdmi.hdmi_lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ r = omapdss_hdmi_display_enable(dssdev);
+ if (r) {
+ DSSERR("failed to power on\n");
+ goto err;
+ }
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+ mutex_unlock(&hdmi.hdmi_lock);
+
+ return r;
+}
+
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ mutex_lock(&hdmi.hdmi_lock);
+
+ *timings = dssdev->panel.timings;
+
+ mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ DSSDBG("hdmi_set_timings\n");
+
+ mutex_lock(&hdmi.hdmi_lock);
+
+ dssdev->panel.timings = *timings;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ /* turn the hdmi off and on to get new timings to use */
+ omapdss_hdmi_display_disable(dssdev);
+ omapdss_hdmi_display_set_timing(dssdev);
+ }
+
+ mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ int r = 0;
+
+ DSSDBG("hdmi_check_timings\n");
+
+ mutex_lock(&hdmi.hdmi_lock);
+
+ r = omapdss_hdmi_display_check_timing(dssdev, timings);
+ if (r) {
+ DSSERR("Timing cannot be applied\n");
+ goto err;
+ }
+err:
+ mutex_unlock(&hdmi.hdmi_lock);
+ return r;
+}
+
+static struct omap_dss_driver hdmi_driver = {
+ .probe = hdmi_panel_probe,
+ .remove = hdmi_panel_remove,
+ .enable = hdmi_panel_enable,
+ .disable = hdmi_panel_disable,
+ .suspend = hdmi_panel_suspend,
+ .resume = hdmi_panel_resume,
+ .get_timings = hdmi_get_timings,
+ .set_timings = hdmi_set_timings,
+ .check_timings = hdmi_check_timings,
+ .driver = {
+ .name = "hdmi_panel",
+ .owner = THIS_MODULE,
+ },
+};
+
+int hdmi_panel_init(void)
+{
+ mutex_init(&hdmi.hdmi_lock);
+
+ omap_dss_register_driver(&hdmi_driver);
+
+ return 0;
+}
+
+void hdmi_panel_exit(void)
+{
+ omap_dss_unregister_driver(&hdmi_driver);
+
+}
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 172d4e69730..bcd37ec8695 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -515,6 +515,8 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD;
+ } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
+ irq = DISPC_IRQ_EVSYNC_EVEN;
} else {
if (mgr->id == OMAP_DSS_CHANNEL_LCD)
irq = DISPC_IRQ_VSYNC;
@@ -536,7 +538,8 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -613,7 +616,8 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -1377,6 +1381,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
case OMAP_DISPLAY_TYPE_DBI:
case OMAP_DISPLAY_TYPE_SDI:
case OMAP_DISPLAY_TYPE_VENC:
+ case OMAP_DISPLAY_TYPE_HDMI:
default_get_overlay_fifo_thresholds(ovl->id, size,
&oc->burst_size, &oc->fifo_low,
&oc->fifo_high);
@@ -1394,7 +1399,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
}
r = 0;
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
if (!dss_cache.irq_enabled) {
u32 mask;
@@ -1407,7 +1412,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
dss_cache.irq_enabled = true;
}
configure_dispc();
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
spin_unlock_irqrestore(&dss_cache.lock, flags);
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 456efef03c2..f1aca6d0401 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -490,7 +490,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
ovl->manager = mgr;
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
/* XXX: on manual update display, in auto update mode, a bug happens
* here. When an overlay is first enabled on LCD, then it's disabled,
* and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
@@ -499,7 +499,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
* but I don't understand how or why. */
msleep(40);
dispc_set_channel_out(ovl->id, mgr->id);
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return 0;
}
@@ -679,7 +679,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
lcd2_mgr->set_device(lcd2_mgr, dssdev);
mgr = lcd2_mgr;
}
- } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
+ } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
+ && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
if (!lcd_mgr->device || force) {
if (lcd_mgr->device)
lcd_mgr->unset_device(lcd_mgr);
@@ -688,7 +689,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
}
}
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+ || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
if (!tv_mgr->device || force) {
if (tv_mgr->device)
tv_mgr->unset_device(tv_mgr);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 10a2ffe0288..5ea17f49c61 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -36,8 +36,6 @@
#include <plat/display.h>
#include "dss.h"
-#define RFBI_BASE 0x48050800
-
struct rfbi_reg { u16 idx; };
#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
@@ -100,6 +98,7 @@ static int rfbi_convert_timings(struct rfbi_timings *t);
static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
static struct {
+ struct platform_device *pdev;
void __iomem *base;
unsigned long l4_khz;
@@ -142,9 +141,9 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
static void rfbi_enable_clocks(bool enable)
{
if (enable)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
}
void omap_rfbi_write_command(const void *buf, u32 len)
@@ -497,7 +496,7 @@ unsigned long rfbi_get_max_tx_rate(void)
};
l4_rate = rfbi.l4_khz / 1000;
- dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
+ dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000;
for (i = 0; i < ARRAY_SIZE(ftab); i++) {
/* Use a window instead of an exact match, to account
@@ -922,7 +921,7 @@ void rfbi_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
DUMPREG(RFBI_REVISION);
DUMPREG(RFBI_SYSCONFIG);
@@ -953,54 +952,10 @@ void rfbi_dump_regs(struct seq_file *s)
DUMPREG(RFBI_VSYNC_WIDTH);
DUMPREG(RFBI_HSYNC_WIDTH);
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
#undef DUMPREG
}
-int rfbi_init(void)
-{
- u32 rev;
- u32 l;
-
- spin_lock_init(&rfbi.cmd_lock);
-
- init_completion(&rfbi.cmd_done);
- atomic_set(&rfbi.cmd_fifo_full, 0);
- atomic_set(&rfbi.cmd_pending, 0);
-
- rfbi.base = ioremap(RFBI_BASE, SZ_256);
- if (!rfbi.base) {
- DSSERR("can't ioremap RFBI\n");
- return -ENOMEM;
- }
-
- rfbi_enable_clocks(1);
-
- msleep(10);
-
- rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
-
- /* Enable autoidle and smart-idle */
- l = rfbi_read_reg(RFBI_SYSCONFIG);
- l |= (1 << 0) | (2 << 3);
- rfbi_write_reg(RFBI_SYSCONFIG, l);
-
- rev = rfbi_read_reg(RFBI_REVISION);
- printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
- FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
- rfbi_enable_clocks(0);
-
- return 0;
-}
-
-void rfbi_exit(void)
-{
- DSSDBG("rfbi_exit\n");
-
- iounmap(rfbi.base);
-}
-
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
int r;
@@ -1056,3 +1011,74 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
return 0;
}
+
+/* RFBI HW IP initialisation */
+static int omap_rfbihw_probe(struct platform_device *pdev)
+{
+ u32 rev;
+ u32 l;
+ struct resource *rfbi_mem;
+
+ rfbi.pdev = pdev;
+
+ spin_lock_init(&rfbi.cmd_lock);
+
+ init_completion(&rfbi.cmd_done);
+ atomic_set(&rfbi.cmd_fifo_full, 0);
+ atomic_set(&rfbi.cmd_pending, 0);
+
+ rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
+ if (!rfbi_mem) {
+ DSSERR("can't get IORESOURCE_MEM RFBI\n");
+ return -EINVAL;
+ }
+ rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
+ if (!rfbi.base) {
+ DSSERR("can't ioremap RFBI\n");
+ return -ENOMEM;
+ }
+
+ rfbi_enable_clocks(1);
+
+ msleep(10);
+
+ rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+
+ /* Enable autoidle and smart-idle */
+ l = rfbi_read_reg(RFBI_SYSCONFIG);
+ l |= (1 << 0) | (2 << 3);
+ rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+ rev = rfbi_read_reg(RFBI_REVISION);
+ dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
+static int omap_rfbihw_remove(struct platform_device *pdev)
+{
+ iounmap(rfbi.base);
+ return 0;
+}
+
+static struct platform_driver omap_rfbihw_driver = {
+ .probe = omap_rfbihw_probe,
+ .remove = omap_rfbihw_remove,
+ .driver = {
+ .name = "omapdss_rfbi",
+ .owner = THIS_MODULE,
+ },
+};
+
+int rfbi_init_platform_driver(void)
+{
+ return platform_driver_register(&omap_rfbihw_driver);
+}
+
+void rfbi_uninit_platform_driver(void)
+{
+ return platform_driver_unregister(&omap_rfbihw_driver);
+}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index b64adf7dfc8..54a53e64818 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -30,7 +30,6 @@
#include "dss.h"
static struct {
- bool skip_init;
bool update_enabled;
struct regulator *vdds_sdi_reg;
} sdi;
@@ -68,9 +67,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err1;
- /* In case of skip_init sdi_init has already enabled the clocks */
- if (!sdi.skip_init)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
sdi_basic_init(dssdev);
@@ -80,14 +77,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb);
- if (!sdi.skip_init) {
- r = dss_calc_clock_div(1, t->pixel_clock * 1000,
- &dss_cinfo, &dispc_cinfo);
- } else {
- r = dss_get_clock_div(&dss_cinfo);
- r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
- }
-
+ r = dss_calc_clock_div(1, t->pixel_clock * 1000,
+ &dss_cinfo, &dispc_cinfo);
if (r)
goto err2;
@@ -116,21 +107,17 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err2;
- if (!sdi.skip_init) {
- dss_sdi_init(dssdev->phy.sdi.datapairs);
- r = dss_sdi_enable();
- if (r)
- goto err1;
- mdelay(2);
- }
+ dss_sdi_init(dssdev->phy.sdi.datapairs);
+ r = dss_sdi_enable();
+ if (r)
+ goto err1;
+ mdelay(2);
dssdev->manager->enable(dssdev->manager);
- sdi.skip_init = 0;
-
return 0;
err2:
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
regulator_disable(sdi.vdds_sdi_reg);
err1:
omap_dss_stop_device(dssdev);
@@ -145,7 +132,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
dss_sdi_disable();
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
regulator_disable(sdi.vdds_sdi_reg);
@@ -157,25 +144,24 @@ int sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
+ if (sdi.vdds_sdi_reg == NULL) {
+ struct regulator *vdds_sdi;
+
+ vdds_sdi = dss_get_vdds_sdi();
+
+ if (IS_ERR(vdds_sdi)) {
+ DSSERR("can't get VDDS_SDI regulator\n");
+ return PTR_ERR(vdds_sdi);
+ }
+
+ sdi.vdds_sdi_reg = vdds_sdi;
+ }
+
return 0;
}
-int sdi_init(bool skip_init)
+int sdi_init(void)
{
- /* we store this for first display enable, then clear it */
- sdi.skip_init = skip_init;
-
- sdi.vdds_sdi_reg = dss_get_vdds_sdi();
- if (IS_ERR(sdi.vdds_sdi_reg)) {
- DSSERR("can't get VDDS_SDI regulator\n");
- return PTR_ERR(sdi.vdds_sdi_reg);
- }
- /*
- * Enable clocks already here, otherwise there would be a toggle
- * of them until sdi_display_enable is called.
- */
- if (skip_init)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
return 0;
}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index eff35050e28..8e35a5bae42 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -39,8 +39,6 @@
#include "dss.h"
-#define VENC_BASE 0x48050C00
-
/* Venc registers */
#define VENC_REV_ID 0x00
#define VENC_STATUS 0x04
@@ -289,6 +287,7 @@ const struct omap_video_timings omap_dss_ntsc_timings = {
EXPORT_SYMBOL(omap_dss_ntsc_timings);
static struct {
+ struct platform_device *pdev;
void __iomem *base;
struct mutex venc_lock;
u32 wss_data;
@@ -381,11 +380,11 @@ static void venc_reset(void)
static void venc_enable_clocks(int enable)
{
if (enable)
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
- DSS_CLK_96M);
+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+ DSS_CLK_VIDFCK);
else
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
- DSS_CLK_96M);
+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+ DSS_CLK_VIDFCK);
}
static const struct venc_config *venc_timings_to_config(
@@ -641,50 +640,23 @@ static struct omap_dss_driver venc_driver = {
};
/* driver end */
-
-
-int venc_init(struct platform_device *pdev)
+int venc_init_display(struct omap_dss_device *dssdev)
{
- u8 rev_id;
+ DSSDBG("init_display\n");
- mutex_init(&venc.venc_lock);
+ if (venc.vdda_dac_reg == NULL) {
+ struct regulator *vdda_dac;
- venc.wss_data = 0;
+ vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac");
- venc.base = ioremap(VENC_BASE, SZ_1K);
- if (!venc.base) {
- DSSERR("can't ioremap VENC\n");
- return -ENOMEM;
- }
+ if (IS_ERR(vdda_dac)) {
+ DSSERR("can't get VDDA_DAC regulator\n");
+ return PTR_ERR(vdda_dac);
+ }
- venc.vdda_dac_reg = dss_get_vdda_dac();
- if (IS_ERR(venc.vdda_dac_reg)) {
- iounmap(venc.base);
- DSSERR("can't get VDDA_DAC regulator\n");
- return PTR_ERR(venc.vdda_dac_reg);
+ venc.vdda_dac_reg = vdda_dac;
}
- venc_enable_clocks(1);
-
- rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
- printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
-
- venc_enable_clocks(0);
-
- return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_exit(void)
-{
- omap_dss_unregister_driver(&venc_driver);
-
- iounmap(venc.base);
-}
-
-int venc_init_display(struct omap_dss_device *dssdev)
-{
- DSSDBG("init_display\n");
-
return 0;
}
@@ -740,3 +712,73 @@ void venc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
+
+/* VENC HW IP initialisation */
+static int omap_venchw_probe(struct platform_device *pdev)
+{
+ u8 rev_id;
+ struct resource *venc_mem;
+
+ 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 = ioremap(venc_mem->start, resource_size(venc_mem));
+ if (!venc.base) {
+ DSSERR("can't ioremap VENC\n");
+ return -ENOMEM;
+ }
+
+ venc_enable_clocks(1);
+
+ rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+ dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
+
+ venc_enable_clocks(0);
+
+ return omap_dss_register_driver(&venc_driver);
+}
+
+static int omap_venchw_remove(struct platform_device *pdev)
+{
+ if (venc.vdda_dac_reg != NULL) {
+ regulator_put(venc.vdda_dac_reg);
+ venc.vdda_dac_reg = NULL;
+ }
+ omap_dss_unregister_driver(&venc_driver);
+
+ iounmap(venc.base);
+ return 0;
+}
+
+static struct platform_driver omap_venchw_driver = {
+ .probe = omap_venchw_probe,
+ .remove = omap_venchw_remove,
+ .driver = {
+ .name = "omapdss_venc",
+ .owner = THIS_MODULE,
+ },
+};
+
+int venc_init_platform_driver(void)
+{
+ if (cpu_is_omap44xx())
+ return 0;
+
+ return platform_driver_register(&omap_venchw_driver);
+}
+
+void venc_uninit_platform_driver(void)
+{
+ if (cpu_is_omap44xx())
+ return;
+
+ return platform_driver_unregister(&omap_venchw_driver);
+}