fbdev: sh_mobile_lcdcfb: Enable 32 bpp and 24 bpp support
[~shefty/rdma-dev.git] / drivers / video / sh_mobile_lcdcfb.c
index 778bffbbdbb7abf194757860bb93d600bb56212d..cffec90afa931eb24dda73488256588ac2af3f9b 100644 (file)
@@ -139,6 +139,7 @@ struct sh_mobile_lcdc_priv {
        struct notifier_block notifier;
        unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
+       int forced_bpp; /* 2 channel LCDC must share bpp setting */
 };
 
 static bool banked(int reg_nr)
@@ -461,13 +462,18 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        struct sh_mobile_lcdc_chan *ch;
        struct sh_mobile_lcdc_board_cfg *board_cfg;
        unsigned long tmp;
+       int bpp = 0;
        int k, m;
        int ret = 0;
 
        /* enable clocks before accessing the hardware */
-       for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
-               if (priv->ch[k].enabled)
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               if (priv->ch[k].enabled) {
                        sh_mobile_lcdc_clk_on(priv);
+                       if (!bpp)
+                               bpp = priv->ch[k].info->var.bits_per_pixel;
+               }
+       }
 
        /* reset */
        lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
@@ -535,7 +541,17 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        }
 
        /* word and long word swap */
-       lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+       switch (bpp) {
+       case 16:
+               lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+               break;
+       case 24:
+               lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7);
+               break;
+       case 32:
+               lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4);
+               break;
+       }
 
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
@@ -546,7 +562,16 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                /* set bpp format in PKF[4:0] */
                tmp = lcdc_read_chan(ch, LDDFR);
                tmp &= ~0x0001001f;
-               tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0;
+               switch (ch->info->var.bits_per_pixel) {
+               case 16:
+                       tmp |= 0x03;
+                       break;
+               case 24:
+                       tmp |= 0x0b;
+                       break;
+               case 32:
+                       break;
+               }
                lcdc_write_chan(ch, LDDFR, tmp);
 
                /* point out our frame buffer */
@@ -913,6 +938,7 @@ static int sh_mobile_open(struct fb_info *info, int user)
 static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct sh_mobile_lcdc_chan *ch = info->par;
+       struct sh_mobile_lcdc_priv *p = ch->lcdc;
 
        if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
            var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
@@ -922,6 +948,20 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
                         PICOS2KHZ(var->pixclock));
                return -EINVAL;
        }
+
+       /* only accept the forced_bpp for dual channel configurations */
+       if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
+               return -EINVAL;
+
+       switch (var->bits_per_pixel) {
+       case 16: /* PKF[4:0] = 00011 - RGB 565 */
+       case 24: /* PKF[4:0] = 01011 - RGB 888 */
+       case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+               break;
+       default:
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -954,19 +994,27 @@ static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
                var->transp.length = 0;
                break;
 
-       case 32: /* PKF[4:0] = 00000 - RGB 888
-                 * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
-                 * this may be because LDDDSR has word swap enabled..
-                 */
-               var->red.offset = 0;
+       case 24: /* PKF[4:0] = 01011 - RGB 888 */
+               var->red.offset = 16;
                var->red.length = 8;
-               var->green.offset = 24;
+               var->green.offset = 8;
                var->green.length = 8;
-               var->blue.offset = 16;
+               var->blue.offset = 0;
                var->blue.length = 8;
                var->transp.offset = 0;
                var->transp.length = 0;
                break;
+
+       case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+               var->red.offset = 16;
+               var->red.length = 8;
+               var->green.offset = 8;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               var->transp.offset = 24;
+               var->transp.length = 8;
+               break;
        default:
                return -EINVAL;
        }
@@ -1170,6 +1218,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                goto err1;
        }
 
+       /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
+       if (j == 2)
+               priv->forced_bpp = pdata->ch[0].bpp;
+
        priv->base = ioremap_nocache(res->start, resource_size(res));
        if (!priv->base)
                goto err1;