diff options
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 74 |
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 | ||
144 | static bool banked(int reg_nr) | 145 | static 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) | |||
913 | static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 938 | static 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; |