#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/clk.h>
+#include <linux/platform_device.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
#define DSS_REVISION DSS_REG(0x0000)
#define DSS_SYSCONFIG DSS_REG(0x0010)
#define DSS_SYSSTATUS DSS_REG(0x0014)
-#define DSS_IRQSTATUS DSS_REG(0x0018)
#define DSS_CONTROL DSS_REG(0x0040)
#define DSS_SDI_CONTROL DSS_REG(0x0044)
#define DSS_PLL_CONTROL DSS_REG(0x0048)
struct dss_clock_info cache_dss_cinfo;
struct dispc_clock_info cache_dispc_cinfo;
- 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];
+ enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
+ enum omap_dss_clk_source dispc_clk_source;
+ enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
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",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
};
static void dss_clk_enable_all_no_ctx(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)
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
{
return dss_generic_clk_source_names[clk_src];
}
seq_printf(s, "- DSS -\n");
- 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_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+ fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
if (dss.dpll4_m4_ck) {
DUMPREG(DSS_REVISION);
DUMPREG(DSS_SYSCONFIG);
DUMPREG(DSS_SYSSTATUS);
- DUMPREG(DSS_IRQSTATUS);
DUMPREG(DSS_CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
#undef DUMPREG
}
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{
+ struct platform_device *dsidev;
int b;
u8 start, end;
switch (clk_src) {
- case DSS_CLK_SRC_FCK:
+ case OMAP_DSS_CLK_SRC_FCK:
b = 0;
break;
- case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
b = 1;
- dsi_wait_pll_hsdiv_dispc_active();
+ dsidev = dsi_get_dsidev_from_id(0);
+ dsi_wait_pll_hsdiv_dispc_active(dsidev);
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ b = 2;
+ dsidev = dsi_get_dsidev_from_id(1);
+ dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
dss.dispc_clk_source = clk_src;
}
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
+void dss_select_dsi_clk_source(int dsi_module,
+ enum omap_dss_clk_source clk_src)
{
+ struct platform_device *dsidev;
int b;
switch (clk_src) {
- case DSS_CLK_SRC_FCK:
+ case OMAP_DSS_CLK_SRC_FCK:
b = 0;
break;
- case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+ BUG_ON(dsi_module != 0);
+ b = 1;
+ dsidev = dsi_get_dsidev_from_id(0);
+ dsi_wait_pll_hsdiv_dsi_active(dsidev);
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
+ BUG_ON(dsi_module != 1);
b = 1;
- dsi_wait_pll_hsdiv_dsi_active();
+ dsidev = dsi_get_dsidev_from_id(1);
+ dsi_wait_pll_hsdiv_dsi_active(dsidev);
break;
default:
BUG();
REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
- dss.dsi_clk_source = clk_src;
+ dss.dsi_clk_source[dsi_module] = clk_src;
}
void dss_select_lcd_clk_source(enum omap_channel channel,
- enum dss_clk_source clk_src)
+ enum omap_dss_clk_source clk_src)
{
+ struct platform_device *dsidev;
int b, ix, pos;
if (!dss_has_feature(FEAT_LCD_CLK_SRC))
return;
switch (clk_src) {
- case DSS_CLK_SRC_FCK:
+ case OMAP_DSS_CLK_SRC_FCK:
b = 0;
break;
- case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+ case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
b = 1;
- dsi_wait_pll_hsdiv_dispc_active();
+ dsidev = dsi_get_dsidev_from_id(0);
+ dsi_wait_pll_hsdiv_dispc_active(dsidev);
+ break;
+ case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+ BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
+ b = 1;
+ dsidev = dsi_get_dsidev_from_id(1);
+ dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
dss.lcd_clk_source[ix] = clk_src;
}
-enum dss_clk_source dss_get_dispc_clk_source(void)
+enum omap_dss_clk_source dss_get_dispc_clk_source(void)
{
return dss.dispc_clk_source;
}
-enum dss_clk_source dss_get_dsi_clk_source(void)
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
{
- return dss.dsi_clk_source;
+ return dss.dsi_clk_source[dsi_module];
}
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+enum omap_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];
+ if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+ int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+ return dss.lcd_clk_source[ix];
+ } else {
+ /* LCD_CLK source is the same as DISPC_FCLK source for
+ * OMAP2 and OMAP3 */
+ return dss.dispc_clk_source;
+ }
}
/* calculate clock rates using dividers in cinfo */
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_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;
- }
-
- /* 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);
-
- _omap_dss_reset();
-
- /* autoidle */
- REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
-
- /* Select DPLL */
- REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
-
-#ifdef CONFIG_OMAP2_DSS_VENC
- REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
- REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
- REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
-#endif
- if (cpu_is_omap34xx()) {
- 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(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.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();
-
- rev = dss_read_reg(DSS_REVISION);
- printk(KERN_INFO "OMAP DSS rev %d.%d\n",
- FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
- return 0;
-
-fail1:
- iounmap(dss.base);
-fail0:
- return r;
-}
-
-static void dss_exit(void)
-{
- if (dss.dpll4_m4_ck)
- clk_put(dss.dpll4_m4_ck);
-
- iounmap(dss.base);
-}
-
/* CONTEXT */
static int dss_get_ctx_id(void)
{
static int dss_get_clocks(void)
{
int r;
+ struct clk *dpll4_m4_ck;
struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
dss.dss_ick = NULL;
goto err;
}
+ if (cpu_is_omap34xx()) {
+ 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(dpll4_m4_ck);
+ goto err;
+ }
+ } 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 dpll_per_m5x2_ck\n");
+ r = PTR_ERR(dpll4_m4_ck);
+ goto err;
+ }
+ } else { /* omap24xx */
+ dpll4_m4_ck = NULL;
+ }
+
+ dss.dpll4_m4_ck = dpll4_m4_ck;
+
+
return 0;
err:
clk_put(dss.dss_tv_fck);
if (dss.dss_video_fck)
clk_put(dss.dss_video_fck);
+ if (dss.dpll4_m4_ck)
+ clk_put(dss.dpll4_m4_ck);
return r;
}
static void dss_put_clocks(void)
{
+ if (dss.dpll4_m4_ck)
+ clk_put(dss.dpll4_m4_ck);
if (dss.dss_video_fck)
clk_put(dss.dss_video_fck);
if (dss.dss_tv_fck)
dss.dss_video_fck
};
+ const char *names[5] = {
+ "ick",
+ "fck",
+ "sys_clk",
+ "tv_fck",
+ "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",
+ seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
+ names[i],
clocks[i]->name,
+ 24 - strlen(names[i]) - strlen(clocks[i]->name),
+ "",
clk_get_rate(clocks[i]),
clocks[i]->usecount);
}
/* DSS HW IP initialisation */
static int omap_dsshw_probe(struct platform_device *pdev)
{
+ struct resource *dss_mem;
+ u32 rev;
int r;
dss.pdev = pdev;
+ dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+ if (!dss_mem) {
+ DSSERR("can't get IORESOURCE_MEM DSS\n");
+ r = -EINVAL;
+ goto err_ioremap;
+ }
+ dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
+ if (!dss.base) {
+ DSSERR("can't ioremap DSS\n");
+ r = -ENOMEM;
+ goto err_ioremap;
+ }
+
r = dss_get_clocks();
if (r)
goto err_clocks;
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;
- }
+ /* 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);
+
+#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
+ /* 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.
+ *
+ * This bug was at least present on OMAP3430. It's unknown
+ * if it happens on OMAP2 or OMAP3630.
+ */
+ msleep(50);
+#endif
+
+ _omap_dss_reset();
+
+ /* autoidle */
+ REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
+
+ /* Select DPLL */
+ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
+
+#ifdef CONFIG_OMAP2_DSS_VENC
+ REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
+ REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
+ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
+#endif
+ dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+ dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+ dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+ dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
r = dpi_init();
if (r) {
goto err_sdi;
}
+ dss_save_context();
+
+ rev = dss_read_reg(DSS_REVISION);
+ printk(KERN_INFO "OMAP DSS rev %d.%d\n",
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
dss_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:
+ iounmap(dss.base);
+err_ioremap:
return r;
}
static int omap_dsshw_remove(struct platform_device *pdev)
{
+ dpi_exit();
+ sdi_exit();
- dss_exit();
+ iounmap(dss.base);
/*
* As part of hwmod changes, DSS is not the only controller of dss
WARN_ON(dss.num_clks_enabled > 0);
dss_put_clocks();
+
return 0;
}