]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/video/omap2/dss/dss.c
OMAP: DSS2: Clean up probe for DSS & DSI
[mv-sheeva.git] / drivers / video / omap2 / dss / dss.c
index 3f1fee63c67830d2e9778238d2040b865df6cbef..57ce428deb04b1f880923f8e63fd4ec58a18086e 100644 (file)
@@ -28,8 +28,9 @@
 #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"
@@ -45,7 +46,6 @@ struct dss_reg {
 #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)
@@ -75,17 +75,17 @@ static struct {
        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);
@@ -230,7 +230,7 @@ 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)
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
 {
        return dss_generic_clk_source_names[clk_src];
 }
@@ -246,8 +246,8 @@ void dss_dump_clocks(struct seq_file *s)
 
        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) {
@@ -286,7 +286,6 @@ void dss_dump_regs(struct seq_file *s)
        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) &
@@ -300,18 +299,25 @@ void dss_dump_regs(struct seq_file *s)
 #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();
@@ -324,17 +330,27 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
        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();
@@ -342,25 +358,33 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
 
        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();
@@ -373,20 +397,26 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
        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 */
@@ -634,99 +664,6 @@ 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_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)
 {
@@ -809,6 +746,7 @@ static int dss_get_clock(struct clk **clock, const char *clk_name)
 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;
@@ -848,6 +786,27 @@ static int dss_get_clocks(void)
                        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:
@@ -861,12 +820,16 @@ 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)
@@ -1015,6 +978,14 @@ static void core_dump_clocks(struct seq_file *s)
                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);
@@ -1022,8 +993,11 @@ static void core_dump_clocks(struct seq_file *s)
        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);
        }
@@ -1047,10 +1021,25 @@ void dss_debug_dump_clocks(struct seq_file *s)
 /* 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;
@@ -1060,11 +1049,42 @@ static int omap_dsshw_probe(struct platform_device *pdev)
        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) {
@@ -1078,23 +1098,32 @@ static int omap_dsshw_probe(struct platform_device *pdev)
                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
@@ -1105,6 +1134,7 @@ static int omap_dsshw_remove(struct platform_device *pdev)
        WARN_ON(dss.num_clks_enabled > 0);
 
        dss_put_clocks();
+
        return 0;
 }