]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/video/s3c-fb.c
Merge tag 'sound-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[karo-tx-linux.git] / drivers / video / s3c-fb.c
index f3105160bf9829104d22ec4c9e2b24c063debeaa..ea7b661e7229039c29770c50414f4846e6865192 100644 (file)
@@ -47,7 +47,7 @@
 #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
 #undef writel
 #define writel(v, r) do { \
-       printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
+       pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \
        __raw_writel(v, r); \
 } while (0)
 #endif /* FB_S3C_DEBUG_REGWRITE */
@@ -361,7 +361,7 @@ static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
        result = (unsigned int)tmp / 1000;
 
        dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
-               pixclk, clk, result, clk / result);
+               pixclk, clk, result, result ? clk / result : clk);
 
        return result;
 }
@@ -495,7 +495,6 @@ static int s3c_fb_set_par(struct fb_info *info)
        u32 alpha = 0;
        u32 data;
        u32 pagewidth;
-       int clkdiv;
 
        dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
@@ -532,48 +531,9 @@ static int s3c_fb_set_par(struct fb_info *info)
        /* disable the window whilst we update it */
        writel(0, regs + WINCON(win_no));
 
-       /* use platform specified window as the basis for the lcd timings */
-
-       if (win_no == sfb->pdata->default_win) {
-               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
-
-               data = sfb->pdata->vidcon0;
-               data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
-               if (clkdiv > 1)
-                       data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
-               else
-                       data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
-
-               /* write the timing data to the panel */
-
-               if (sfb->variant.is_2443)
-                       data |= (1 << 5);
-
-               writel(data, regs + VIDCON0);
-
+       if (!sfb->output_on)
                s3c_fb_enable(sfb, 1);
 
-               data = VIDTCON0_VBPD(var->upper_margin - 1) |
-                      VIDTCON0_VFPD(var->lower_margin - 1) |
-                      VIDTCON0_VSPW(var->vsync_len - 1);
-
-               writel(data, regs + sfb->variant.vidtcon);
-
-               data = VIDTCON1_HBPD(var->left_margin - 1) |
-                      VIDTCON1_HFPD(var->right_margin - 1) |
-                      VIDTCON1_HSPW(var->hsync_len - 1);
-
-               /* VIDTCON1 */
-               writel(data, regs + sfb->variant.vidtcon + 4);
-
-               data = VIDTCON2_LINEVAL(var->yres - 1) |
-                      VIDTCON2_HOZVAL(var->xres - 1) |
-                      VIDTCON2_LINEVAL_E(var->yres - 1) |
-                      VIDTCON2_HOZVAL_E(var->xres - 1);
-               writel(data, regs + sfb->variant.vidtcon + 8);
-       }
-
        /* write the buffer address */
 
        /* start and end registers stride is 8 */
@@ -839,6 +799,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        struct s3c_fb *sfb = win->parent;
        unsigned int index = win->index;
        u32 wincon;
+       u32 output_on = sfb->output_on;
 
        dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
 
@@ -877,34 +838,18 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
        shadow_protect_win(win, 1);
        writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
-       shadow_protect_win(win, 0);
 
        /* Check the enabled state to see if we need to be running the
         * main LCD interface, as if there are no active windows then
         * it is highly likely that we also do not need to output
         * anything.
         */
-
-       /* We could do something like the following code, but the current
-        * system of using framebuffer events means that we cannot make
-        * the distinction between just window 0 being inactive and all
-        * the windows being down.
-        *
-        * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
-       */
-
-       /* we're stuck with this until we can do something about overriding
-        * the power control using the blanking event for a single fb.
-        */
-       if (index == sfb->pdata->default_win) {
-               shadow_protect_win(win, 1);
-               s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
-               shadow_protect_win(win, 0);
-       }
+       s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
+       shadow_protect_win(win, 0);
 
        pm_runtime_put_sync(sfb->dev);
 
-       return 0;
+       return output_on == sfb->output_on;
 }
 
 /**
@@ -1111,7 +1056,7 @@ static struct fb_ops s3c_fb_ops = {
  *
  * Calculate the pixel clock when none has been given through platform data.
  */
-static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
+static void s3c_fb_missing_pixclock(struct fb_videomode *mode)
 {
        u64 pixclk = 1000000000000ULL;
        u32 div;
@@ -1144,11 +1089,11 @@ static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
 
        dev_dbg(sfb->dev, "allocating memory for display\n");
 
-       real_size = windata->win_mode.xres * windata->win_mode.yres;
+       real_size = windata->xres * windata->yres;
        virt_size = windata->virtual_x * windata->virtual_y;
 
        dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
-               real_size, windata->win_mode.xres, windata->win_mode.yres,
+               real_size, windata->xres, windata->yres,
                virt_size, windata->virtual_x, windata->virtual_y);
 
        size = (real_size > virt_size) ? real_size : virt_size;
@@ -1230,7 +1175,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
                                      struct s3c_fb_win **res)
 {
        struct fb_var_screeninfo *var;
-       struct fb_videomode *initmode;
+       struct fb_videomode initmode;
        struct s3c_fb_pd_win *windata;
        struct s3c_fb_win *win;
        struct fb_info *fbinfo;
@@ -1251,11 +1196,11 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        }
 
        windata = sfb->pdata->win[win_no];
-       initmode = &windata->win_mode;
+       initmode = *sfb->pdata->vtiming;
 
        WARN_ON(windata->max_bpp == 0);
-       WARN_ON(windata->win_mode.xres == 0);
-       WARN_ON(windata->win_mode.yres == 0);
+       WARN_ON(windata->xres == 0);
+       WARN_ON(windata->yres == 0);
 
        win = fbinfo->par;
        *res = win;
@@ -1294,7 +1239,9 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        }
 
        /* setup the initial video mode from the window */
-       fb_videomode_to_var(&fbinfo->var, initmode);
+       initmode.xres = windata->xres;
+       initmode.yres = windata->yres;
+       fb_videomode_to_var(&fbinfo->var, &initmode);
 
        fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
        fbinfo->fix.accel       = FB_ACCEL_NONE;
@@ -1338,6 +1285,53 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        return 0;
 }
 
+/**
+ * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
+ * @sfb: The base resources for the hardware.
+ *
+ * Set horizontal and vertical lcd rgb interface timing.
+ */
+static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
+{
+       struct fb_videomode *vmode = sfb->pdata->vtiming;
+       void __iomem *regs = sfb->regs;
+       int clkdiv;
+       u32 data;
+
+       if (!vmode->pixclock)
+               s3c_fb_missing_pixclock(vmode);
+
+       clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock);
+
+       data = sfb->pdata->vidcon0;
+       data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+       if (clkdiv > 1)
+               data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
+       else
+               data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
+
+       if (sfb->variant.is_2443)
+               data |= (1 << 5);
+       writel(data, regs + VIDCON0);
+
+       data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
+              VIDTCON0_VFPD(vmode->lower_margin - 1) |
+              VIDTCON0_VSPW(vmode->vsync_len - 1);
+       writel(data, regs + sfb->variant.vidtcon);
+
+       data = VIDTCON1_HBPD(vmode->left_margin - 1) |
+              VIDTCON1_HFPD(vmode->right_margin - 1) |
+              VIDTCON1_HSPW(vmode->hsync_len - 1);
+       writel(data, regs + sfb->variant.vidtcon + 4);
+
+       data = VIDTCON2_LINEVAL(vmode->yres - 1) |
+              VIDTCON2_HOZVAL(vmode->xres - 1) |
+              VIDTCON2_LINEVAL_E(vmode->yres - 1) |
+              VIDTCON2_HOZVAL_E(vmode->xres - 1);
+       writel(data, regs + sfb->variant.vidtcon + 8);
+}
+
 /**
  * s3c_fb_clear_win() - clear hardware window registers.
  * @sfb: The base resources for the hardware.
@@ -1354,8 +1348,14 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
        writel(0, regs + VIDOSD_A(win, sfb->variant));
        writel(0, regs + VIDOSD_B(win, sfb->variant));
        writel(0, regs + VIDOSD_C(win, sfb->variant));
-       reg = readl(regs + SHADOWCON);
-       writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
+
+       if (sfb->variant.has_shadowcon) {
+               reg = readl(sfb->regs + SHADOWCON);
+               reg &= ~(SHADOWCON_WINx_PROTECT(win) |
+                       SHADOWCON_CHx_ENABLE(win) |
+                       SHADOWCON_CHx_LOCAL_ENABLE(win));
+               writel(reg, sfb->regs + SHADOWCON);
+       }
 }
 
 static int __devinit s3c_fb_probe(struct platform_device *pdev)
@@ -1481,15 +1481,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
                writel(0xffffff, regs + WKEYCON1);
        }
 
+       s3c_fb_set_rgb_timing(sfb);
+
        /* we have the register setup, start allocating framebuffers */
 
        for (win = 0; win < fbdrv->variant.nr_windows; win++) {
                if (!pd->win[win])
                        continue;
 
-               if (!pd->win[win]->win_mode.pixclock)
-                       s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
-
                ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
                                       &sfb->windows[win]);
                if (ret < 0) {
@@ -1564,6 +1563,8 @@ static int s3c_fb_suspend(struct device *dev)
        struct s3c_fb_win *win;
        int win_no;
 
+       pm_runtime_get_sync(sfb->dev);
+
        for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
                win = sfb->windows[win_no];
                if (!win)
@@ -1577,6 +1578,9 @@ static int s3c_fb_suspend(struct device *dev)
                clk_disable(sfb->lcd_clk);
 
        clk_disable(sfb->bus_clk);
+
+       pm_runtime_put_sync(sfb->dev);
+
        return 0;
 }
 
@@ -1589,6 +1593,8 @@ static int s3c_fb_resume(struct device *dev)
        int win_no;
        u32 reg;
 
+       pm_runtime_get_sync(sfb->dev);
+
        clk_enable(sfb->bus_clk);
 
        if (!sfb->variant.has_clksel)
@@ -1623,6 +1629,8 @@ static int s3c_fb_resume(struct device *dev)
                shadow_protect_win(win, 0);
        }
 
+       s3c_fb_set_rgb_timing(sfb);
+
        /* restore framebuffers */
        for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
                win = sfb->windows[win_no];
@@ -1633,6 +1641,8 @@ static int s3c_fb_resume(struct device *dev)
                s3c_fb_set_par(win->fbinfo);
        }
 
+       pm_runtime_put_sync(sfb->dev);
+
        return 0;
 }
 #endif