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; |
