aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_lcdcfb.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-08-31 07:00:53 -0400
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2011-09-05 12:37:13 -0400
commit0386219441d48e0f0902e9f145f0d75ad952d753 (patch)
treec63b4cce6f9e1012837befb4b3422a35822157bc /drivers/video/sh_mobile_lcdcfb.c
parentda6cf5125f66ed1810616937777884cea021e66a (diff)
fbdev: sh_mobile_lcdc: Adjust requested parameters in .fb_check_var
Instead of failing when the requested fb_var_screeninfo parameters are not supported, adjust the parameters according to the hardware capabilities. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c103
1 files changed, 88 insertions, 15 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 088cb17857e3..33b0ff83c154 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1055,28 +1055,101 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
1055{ 1055{
1056 struct sh_mobile_lcdc_chan *ch = info->par; 1056 struct sh_mobile_lcdc_chan *ch = info->par;
1057 struct sh_mobile_lcdc_priv *p = ch->lcdc; 1057 struct sh_mobile_lcdc_priv *p = ch->lcdc;
1058 unsigned int best_dist = (unsigned int)-1;
1059 unsigned int best_xres = 0;
1060 unsigned int best_yres = 0;
1061 unsigned int i;
1058 1062
1059 if (var->xres > MAX_XRES || var->yres > MAX_YRES || 1063 if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1060 var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
1061 dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
1062 var->left_margin, var->xres, var->right_margin, var->hsync_len,
1063 var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
1064 PICOS2KHZ(var->pixclock));
1065 return -EINVAL; 1064 return -EINVAL;
1065
1066 /* If board code provides us with a list of available modes, make sure
1067 * we use one of them. Find the mode closest to the requested one. The
1068 * distance between two modes is defined as the size of the
1069 * non-overlapping parts of the two rectangles.
1070 */
1071 for (i = 0; i < ch->cfg.num_cfg; ++i) {
1072 const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
1073 unsigned int dist;
1074
1075 /* We can only round up. */
1076 if (var->xres > mode->xres || var->yres > mode->yres)
1077 continue;
1078
1079 dist = var->xres * var->yres + mode->xres * mode->yres
1080 - 2 * min(var->xres, mode->xres)
1081 * min(var->yres, mode->yres);
1082
1083 if (dist < best_dist) {
1084 best_xres = mode->xres;
1085 best_yres = mode->yres;
1086 best_dist = dist;
1087 }
1066 } 1088 }
1067 1089
1068 /* only accept the forced_bpp for dual channel configurations */ 1090 /* If no available mode can be used, return an error. */
1069 if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) 1091 if (ch->cfg.num_cfg != 0) {
1092 if (best_dist == (unsigned int)-1)
1093 return -EINVAL;
1094
1095 var->xres = best_xres;
1096 var->yres = best_yres;
1097 }
1098
1099 /* Make sure the virtual resolution is at least as big as the visible
1100 * resolution.
1101 */
1102 if (var->xres_virtual < var->xres)
1103 var->xres_virtual = var->xres;
1104 if (var->yres_virtual < var->yres)
1105 var->yres_virtual = var->yres;
1106
1107 if (var->bits_per_pixel <= 16) { /* RGB 565 */
1108 var->bits_per_pixel = 16;
1109 var->red.offset = 11;
1110 var->red.length = 5;
1111 var->green.offset = 5;
1112 var->green.length = 6;
1113 var->blue.offset = 0;
1114 var->blue.length = 5;
1115 var->transp.offset = 0;
1116 var->transp.length = 0;
1117 } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
1118 var->bits_per_pixel = 24;
1119 var->red.offset = 16;
1120 var->red.length = 8;
1121 var->green.offset = 8;
1122 var->green.length = 8;
1123 var->blue.offset = 0;
1124 var->blue.length = 8;
1125 var->transp.offset = 0;
1126 var->transp.length = 0;
1127 } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
1128 var->bits_per_pixel = 32;
1129 var->red.offset = 16;
1130 var->red.length = 8;
1131 var->green.offset = 8;
1132 var->green.length = 8;
1133 var->blue.offset = 0;
1134 var->blue.length = 8;
1135 var->transp.offset = 24;
1136 var->transp.length = 8;
1137 } else
1070 return -EINVAL; 1138 return -EINVAL;
1071 1139
1072 switch (var->bits_per_pixel) { 1140 var->red.msb_right = 0;
1073 case 16: /* PKF[4:0] = 00011 - RGB 565 */ 1141 var->green.msb_right = 0;
1074 case 24: /* PKF[4:0] = 01011 - RGB 888 */ 1142 var->blue.msb_right = 0;
1075 case 32: /* PKF[4:0] = 00000 - RGBA 888 */ 1143 var->transp.msb_right = 0;
1076 break; 1144
1077 default: 1145 /* Make sure we don't exceed our allocated memory. */
1146 if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1147 info->fix.smem_len)
1148 return -EINVAL;
1149
1150 /* only accept the forced_bpp for dual channel configurations */
1151 if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
1078 return -EINVAL; 1152 return -EINVAL;
1079 }
1080 1153
1081 return 0; 1154 return 0;
1082} 1155}