Merge branch 'fix/misc' into for-linus
[pandora-kernel.git] / drivers / video / s3c-fb.c
index d3a568e..bb63c07 100644 (file)
@@ -211,23 +211,21 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 
 /**
  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
+ * @id: window id.
  * @sfb: The hardware state.
  * @pixclock: The pixel clock wanted, in picoseconds.
  *
  * Given the specified pixel clock, work out the necessary divider to get
  * close to the output frequency.
  */
-static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
+static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk)
 {
+       struct s3c_fb_pd_win *win = sfb->pdata->win[id];
        unsigned long clk = clk_get_rate(sfb->bus_clk);
-       unsigned long long tmp;
        unsigned int result;
 
-       tmp = (unsigned long long)clk;
-       tmp *= pixclk;
-
-       do_div(tmp, 1000000000UL);
-       result = (unsigned int)tmp / 1000;
+       pixclk *= win->win_mode.refresh;
+       result = clk / pixclk;
 
        dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
                pixclk, clk, result, clk / result);
@@ -267,6 +265,7 @@ static int s3c_fb_set_par(struct fb_info *info)
        struct s3c_fb *sfb = win->parent;
        void __iomem *regs = sfb->regs;
        int win_no = win->index;
+       u32 osdc_data = 0;
        u32 data;
        u32 pagewidth;
        int clkdiv;
@@ -302,7 +301,7 @@ static int s3c_fb_set_par(struct fb_info *info)
        /* use window 0 as the basis for the lcd output timings */
 
        if (win_no == 0) {
-               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
+               clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock);
 
                data = sfb->pdata->vidcon0;
                data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
@@ -358,9 +357,14 @@ static int s3c_fb_set_par(struct fb_info *info)
        writel(data, regs + VIDOSD_B(win_no));
 
        data = var->xres * var->yres;
+
+       osdc_data = VIDISD14C_ALPHA1_R(0xf) |
+               VIDISD14C_ALPHA1_G(0xf) |
+               VIDISD14C_ALPHA1_B(0xf);
+
        if (s3c_fb_has_osd_d(win_no)) {
                writel(data, regs + VIDOSD_D(win_no));
-               writel(0, regs + VIDOSD_C(win_no));
+               writel(osdc_data, regs + VIDOSD_C(win_no));
        } else
                writel(data, regs + VIDOSD_C(win_no));
 
@@ -409,8 +413,12 @@ static int s3c_fb_set_par(struct fb_info *info)
                                data |= WINCON1_BPPMODE_19BPP_A1666;
                        else
                                data |= WINCON1_BPPMODE_18BPP_666;
-               } else if (var->transp.length != 0)
-                       data |= WINCON1_BPPMODE_25BPP_A1888;
+               } else if (var->transp.length == 1)
+                       data |= WINCON1_BPPMODE_25BPP_A1888
+                               | WINCON1_BLD_PIX;
+               else if (var->transp.length == 4)
+                       data |= WINCON1_BPPMODE_28BPP_A4888
+                               | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
                else
                        data |= WINCON0_BPPMODE_24BPP_888;
 
@@ -418,6 +426,20 @@ static int s3c_fb_set_par(struct fb_info *info)
                break;
        }
 
+       /* It has no color key control register for window0 */
+       if (win_no > 0) {
+               u32 keycon0_data = 0, keycon1_data = 0;
+
+               keycon0_data = ~(WxKEYCON0_KEYBL_EN |
+                               WxKEYCON0_KEYEN_F |
+                               WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
+
+               keycon1_data = WxKEYCON1_COLVAL(0xffffff);
+
+               writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
+               writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
+       }
+
        writel(data, regs + WINCON(win_no));
        writel(0x0, regs + WINxMAP(win_no));
 
@@ -700,9 +722,12 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
  */
 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
 {
-       fb_dealloc_cmap(&win->fbinfo->cmap);
-       unregister_framebuffer(win->fbinfo);
-       s3c_fb_free_memory(sfb, win);
+       if (win->fbinfo) {
+               unregister_framebuffer(win->fbinfo);
+               fb_dealloc_cmap(&win->fbinfo->cmap);
+               s3c_fb_free_memory(sfb, win);
+               framebuffer_release(win->fbinfo);
+       }
 }
 
 /**
@@ -753,7 +778,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = s3c_fb_alloc_memory(sfb, win);
        if (ret) {
                dev_err(sfb->dev, "failed to allocate display memory\n");
-               goto err_framebuffer;
+               return ret;
        }
 
        /* setup the r/b/g positions for the window's palette */
@@ -776,7 +801,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
        if (ret < 0) {
                dev_err(sfb->dev, "check_var failed on initial video params\n");
-               goto err_alloc_mem;
+               return ret;
        }
 
        /* create initial colour map */
@@ -796,20 +821,13 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = register_framebuffer(fbinfo);
        if (ret < 0) {
                dev_err(sfb->dev, "failed to register framebuffer\n");
-               goto err_alloc_mem;
+               return ret;
        }
 
        *res = win;
        dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
 
        return 0;
-
-err_alloc_mem:
-       s3c_fb_free_memory(sfb, win);
-
-err_framebuffer:
-       unregister_framebuffer(fbinfo);
-       return ret;
 }
 
 /**