aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c74
1 files changed, 63 insertions, 11 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 778bffbbdbb7..cffec90afa93 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -139,6 +139,7 @@ struct sh_mobile_lcdc_priv {
139 struct notifier_block notifier; 139 struct notifier_block notifier;
140 unsigned long saved_shared_regs[NR_SHARED_REGS]; 140 unsigned long saved_shared_regs[NR_SHARED_REGS];
141 int started; 141 int started;
142 int forced_bpp; /* 2 channel LCDC must share bpp setting */
142}; 143};
143 144
144static bool banked(int reg_nr) 145static bool banked(int reg_nr)
@@ -461,13 +462,18 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
461 struct sh_mobile_lcdc_chan *ch; 462 struct sh_mobile_lcdc_chan *ch;
462 struct sh_mobile_lcdc_board_cfg *board_cfg; 463 struct sh_mobile_lcdc_board_cfg *board_cfg;
463 unsigned long tmp; 464 unsigned long tmp;
465 int bpp = 0;
464 int k, m; 466 int k, m;
465 int ret = 0; 467 int ret = 0;
466 468
467 /* enable clocks before accessing the hardware */ 469 /* enable clocks before accessing the hardware */
468 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 470 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
469 if (priv->ch[k].enabled) 471 if (priv->ch[k].enabled) {
470 sh_mobile_lcdc_clk_on(priv); 472 sh_mobile_lcdc_clk_on(priv);
473 if (!bpp)
474 bpp = priv->ch[k].info->var.bits_per_pixel;
475 }
476 }
471 477
472 /* reset */ 478 /* reset */
473 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); 479 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)
535 } 541 }
536 542
537 /* word and long word swap */ 543 /* word and long word swap */
538 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); 544 switch (bpp) {
545 case 16:
546 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
547 break;
548 case 24:
549 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7);
550 break;
551 case 32:
552 lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4);
553 break;
554 }
539 555
540 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 556 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
541 ch = &priv->ch[k]; 557 ch = &priv->ch[k];
@@ -546,7 +562,16 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
546 /* set bpp format in PKF[4:0] */ 562 /* set bpp format in PKF[4:0] */
547 tmp = lcdc_read_chan(ch, LDDFR); 563 tmp = lcdc_read_chan(ch, LDDFR);
548 tmp &= ~0x0001001f; 564 tmp &= ~0x0001001f;
549 tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; 565 switch (ch->info->var.bits_per_pixel) {
566 case 16:
567 tmp |= 0x03;
568 break;
569 case 24:
570 tmp |= 0x0b;
571 break;
572 case 32:
573 break;
574 }
550 lcdc_write_chan(ch, LDDFR, tmp); 575 lcdc_write_chan(ch, LDDFR, tmp);
551 576
552 /* point out our frame buffer */ 577 /* point out our frame buffer */
@@ -913,6 +938,7 @@ static int sh_mobile_open(struct fb_info *info, int user)
913static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 938static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
914{ 939{
915 struct sh_mobile_lcdc_chan *ch = info->par; 940 struct sh_mobile_lcdc_chan *ch = info->par;
941 struct sh_mobile_lcdc_priv *p = ch->lcdc;
916 942
917 if (var->xres > MAX_XRES || var->yres > MAX_YRES || 943 if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
918 var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { 944 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
922 PICOS2KHZ(var->pixclock)); 948 PICOS2KHZ(var->pixclock));
923 return -EINVAL; 949 return -EINVAL;
924 } 950 }
951
952 /* only accept the forced_bpp for dual channel configurations */
953 if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
954 return -EINVAL;
955
956 switch (var->bits_per_pixel) {
957 case 16: /* PKF[4:0] = 00011 - RGB 565 */
958 case 24: /* PKF[4:0] = 01011 - RGB 888 */
959 case 32: /* PKF[4:0] = 00000 - RGBA 888 */
960 break;
961 default:
962 return -EINVAL;
963 }
964
925 return 0; 965 return 0;
926} 966}
927 967
@@ -954,19 +994,27 @@ static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
954 var->transp.length = 0; 994 var->transp.length = 0;
955 break; 995 break;
956 996
957 case 32: /* PKF[4:0] = 00000 - RGB 888 997 case 24: /* PKF[4:0] = 01011 - RGB 888 */
958 * sh7722 pdf says 00RRGGBB but reality is GGBB00RR 998 var->red.offset = 16;
959 * this may be because LDDDSR has word swap enabled..
960 */
961 var->red.offset = 0;
962 var->red.length = 8; 999 var->red.length = 8;
963 var->green.offset = 24; 1000 var->green.offset = 8;
964 var->green.length = 8; 1001 var->green.length = 8;
965 var->blue.offset = 16; 1002 var->blue.offset = 0;
966 var->blue.length = 8; 1003 var->blue.length = 8;
967 var->transp.offset = 0; 1004 var->transp.offset = 0;
968 var->transp.length = 0; 1005 var->transp.length = 0;
969 break; 1006 break;
1007
1008 case 32: /* PKF[4:0] = 00000 - RGBA 888 */
1009 var->red.offset = 16;
1010 var->red.length = 8;
1011 var->green.offset = 8;
1012 var->green.length = 8;
1013 var->blue.offset = 0;
1014 var->blue.length = 8;
1015 var->transp.offset = 24;
1016 var->transp.length = 8;
1017 break;
970 default: 1018 default:
971 return -EINVAL; 1019 return -EINVAL;
972 } 1020 }
@@ -1170,6 +1218,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1170 goto err1; 1218 goto err1;
1171 } 1219 }
1172 1220
1221 /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
1222 if (j == 2)
1223 priv->forced_bpp = pdata->ch[0].bpp;
1224
1173 priv->base = ioremap_nocache(res->start, resource_size(res)); 1225 priv->base = ioremap_nocache(res->start, resource_size(res));
1174 if (!priv->base) 1226 if (!priv->base)
1175 goto err1; 1227 goto err1;