aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2011-01-05 05:21:00 -0500
committerPaul Mundt <lethal@linux-sh.org>2011-01-06 01:43:18 -0500
commit417d48274e755e537bae60461558c1f63a4e14de (patch)
tree49a70964e2ccf625a4b028cb8eb0403735c93de8
parent97cbc8fb1e35e328073e84c4031bd338306397d6 (diff)
fbdev: sh_mobile_lcdcfb: Enable 32 bpp and 24 bpp support
This patch extends the LCDC driver with 24 bpp and 32 bpp support. These modes have been kept disabled earlier due to dependencies between the potential two LCDC channels that are exported as two separate framebuffer devices. The dependency boils down to a byte swap register that is shared between multiple channels. With this patch applied all single channel LCDC hardware can chose freely from 16, 24 and 32 bpp. Dual channel LCDC must stick to the same setup for both channels. Without this patch only 16 bpp is fully supported. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-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;