diff options
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 104 |
1 files changed, 74 insertions, 30 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index b02d97a879d6..bd4840a8a6b7 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) -#define DEFAULT_XRES 1280 -#define DEFAULT_YRES 1024 +#define MAX_XRES 1920 +#define MAX_YRES 1080 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, @@ -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,25 +938,30 @@ 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 < 160 || var->xres > 1920 || - var->yres < 120 || var->yres > 1080 || - var->left_margin < 32 || var->left_margin > 320 || - var->right_margin < 12 || var->right_margin > 240 || - var->upper_margin < 12 || var->upper_margin > 120 || - var->lower_margin < 1 || var->lower_margin > 64 || - var->hsync_len < 32 || var->hsync_len > 240 || - var->vsync_len < 2 || var->vsync_len > 64 || - var->pixclock < 6000 || var->pixclock > 40000 || + if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { - dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", - var->xres, var->yres, - var->left_margin, var->right_margin, - var->upper_margin, var->lower_margin, - var->hsync_len, var->vsync_len, - var->pixclock); + dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n", + var->left_margin, var->xres, var->right_margin, var->hsync_len, + var->upper_margin, var->yres, var->lower_margin, var->vsync_len, + 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; } @@ -964,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; } @@ -1180,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; @@ -1226,7 +1268,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } if (!mode) - max_size = DEFAULT_XRES * DEFAULT_YRES; + max_size = MAX_XRES * MAX_YRES; else if (max_cfg) dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", max_cfg->xres, max_cfg->yres); @@ -1238,12 +1280,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) mode = &default_720p; num_cfg = 1; } else { - num_cfg = ch->cfg.num_cfg; + num_cfg = cfg->num_cfg; } fb_videomode_to_modelist(mode, num_cfg, &info->modelist); fb_videomode_to_var(var, mode); + var->width = cfg->lcd_size_cfg.width; + var->height = cfg->lcd_size_cfg.height; /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; var->activate = FB_ACTIVATE_NOW; |