aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/pxafb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r--drivers/video/pxafb.c106
1 files changed, 78 insertions, 28 deletions
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index bbb07106cd54..3bc5da4a57ca 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -59,7 +59,7 @@
59#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP) 59#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
60 60
61static void (*pxafb_backlight_power)(int); 61static void (*pxafb_backlight_power)(int);
62static void (*pxafb_lcd_power)(int); 62static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
63 63
64static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); 64static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
65static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); 65static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
@@ -214,6 +214,48 @@ extern unsigned int get_clk_frequency_khz(int info);
214#endif 214#endif
215 215
216/* 216/*
217 * Select the smallest mode that allows the desired resolution to be
218 * displayed. If desired parameters can be rounded up.
219 */
220static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
221{
222 struct pxafb_mode_info *mode = NULL;
223 struct pxafb_mode_info *modelist = mach->modes;
224 unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
225 unsigned int i;
226
227 for (i = 0 ; i < mach->num_modes ; i++) {
228 if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
229 modelist[i].xres < best_x && modelist[i].yres < best_y &&
230 modelist[i].bpp >= var->bits_per_pixel ) {
231 best_x = modelist[i].xres;
232 best_y = modelist[i].yres;
233 mode = &modelist[i];
234 }
235 }
236
237 return mode;
238}
239
240static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
241{
242 var->xres = mode->xres;
243 var->yres = mode->yres;
244 var->bits_per_pixel = mode->bpp;
245 var->pixclock = mode->pixclock;
246 var->hsync_len = mode->hsync_len;
247 var->left_margin = mode->left_margin;
248 var->right_margin = mode->right_margin;
249 var->vsync_len = mode->vsync_len;
250 var->upper_margin = mode->upper_margin;
251 var->lower_margin = mode->lower_margin;
252 var->sync = mode->sync;
253 var->grayscale = mode->cmap_greyscale;
254 var->xres_virtual = var->xres;
255 var->yres_virtual = var->yres;
256}
257
258/*
217 * pxafb_check_var(): 259 * pxafb_check_var():
218 * Get the video params out of 'var'. If a value doesn't fit, round it up, 260 * Get the video params out of 'var'. If a value doesn't fit, round it up,
219 * if it's too big, return -EINVAL. 261 * if it's too big, return -EINVAL.
@@ -225,15 +267,29 @@ extern unsigned int get_clk_frequency_khz(int info);
225static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 267static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
226{ 268{
227 struct pxafb_info *fbi = (struct pxafb_info *)info; 269 struct pxafb_info *fbi = (struct pxafb_info *)info;
270 struct pxafb_mach_info *inf = fbi->dev->platform_data;
228 271
229 if (var->xres < MIN_XRES) 272 if (var->xres < MIN_XRES)
230 var->xres = MIN_XRES; 273 var->xres = MIN_XRES;
231 if (var->yres < MIN_YRES) 274 if (var->yres < MIN_YRES)
232 var->yres = MIN_YRES; 275 var->yres = MIN_YRES;
233 if (var->xres > fbi->max_xres) 276
234 return -EINVAL; 277 if (inf->fixed_modes) {
235 if (var->yres > fbi->max_yres) 278 struct pxafb_mode_info *mode;
236 return -EINVAL; 279
280 mode = pxafb_getmode(inf, var);
281 if (!mode)
282 return -EINVAL;
283 pxafb_setmode(var, mode);
284 } else {
285 if (var->xres > inf->modes->xres)
286 return -EINVAL;
287 if (var->yres > inf->modes->yres)
288 return -EINVAL;
289 if (var->bits_per_pixel > inf->modes->bpp)
290 return -EINVAL;
291 }
292
237 var->xres_virtual = 293 var->xres_virtual =
238 max(var->xres_virtual, var->xres); 294 max(var->xres_virtual, var->xres);
239 var->yres_virtual = 295 var->yres_virtual =
@@ -693,7 +749,7 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
693 pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff"); 749 pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff");
694 750
695 if (pxafb_lcd_power) 751 if (pxafb_lcd_power)
696 pxafb_lcd_power(on); 752 pxafb_lcd_power(on, &fbi->fb.var);
697} 753}
698 754
699static void pxafb_setup_gpio(struct pxafb_info *fbi) 755static void pxafb_setup_gpio(struct pxafb_info *fbi)
@@ -869,9 +925,11 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
869 * registers. 925 * registers.
870 */ 926 */
871 if (old_state == C_ENABLE) { 927 if (old_state == C_ENABLE) {
928 __pxafb_lcd_power(fbi, 0);
872 pxafb_disable_controller(fbi); 929 pxafb_disable_controller(fbi);
873 pxafb_setup_gpio(fbi); 930 pxafb_setup_gpio(fbi);
874 pxafb_enable_controller(fbi); 931 pxafb_enable_controller(fbi);
932 __pxafb_lcd_power(fbi, 1);
875 } 933 }
876 break; 934 break;
877 935
@@ -1049,6 +1107,8 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
1049 struct pxafb_info *fbi; 1107 struct pxafb_info *fbi;
1050 void *addr; 1108 void *addr;
1051 struct pxafb_mach_info *inf = dev->platform_data; 1109 struct pxafb_mach_info *inf = dev->platform_data;
1110 struct pxafb_mode_info *mode = inf->modes;
1111 int i, smemlen;
1052 1112
1053 /* Alloc the pxafb_info and pseudo_palette in one step */ 1113 /* Alloc the pxafb_info and pseudo_palette in one step */
1054 fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); 1114 fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1082,31 +1142,21 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
1082 addr = addr + sizeof(struct pxafb_info); 1142 addr = addr + sizeof(struct pxafb_info);
1083 fbi->fb.pseudo_palette = addr; 1143 fbi->fb.pseudo_palette = addr;
1084 1144
1085 fbi->max_xres = inf->xres; 1145 pxafb_setmode(&fbi->fb.var, mode);
1086 fbi->fb.var.xres = inf->xres; 1146
1087 fbi->fb.var.xres_virtual = inf->xres;
1088 fbi->max_yres = inf->yres;
1089 fbi->fb.var.yres = inf->yres;
1090 fbi->fb.var.yres_virtual = inf->yres;
1091 fbi->max_bpp = inf->bpp;
1092 fbi->fb.var.bits_per_pixel = inf->bpp;
1093 fbi->fb.var.pixclock = inf->pixclock;
1094 fbi->fb.var.hsync_len = inf->hsync_len;
1095 fbi->fb.var.left_margin = inf->left_margin;
1096 fbi->fb.var.right_margin = inf->right_margin;
1097 fbi->fb.var.vsync_len = inf->vsync_len;
1098 fbi->fb.var.upper_margin = inf->upper_margin;
1099 fbi->fb.var.lower_margin = inf->lower_margin;
1100 fbi->fb.var.sync = inf->sync;
1101 fbi->fb.var.grayscale = inf->cmap_greyscale;
1102 fbi->cmap_inverse = inf->cmap_inverse; 1147 fbi->cmap_inverse = inf->cmap_inverse;
1103 fbi->cmap_static = inf->cmap_static; 1148 fbi->cmap_static = inf->cmap_static;
1149
1104 fbi->lccr0 = inf->lccr0; 1150 fbi->lccr0 = inf->lccr0;
1105 fbi->lccr3 = inf->lccr3; 1151 fbi->lccr3 = inf->lccr3;
1106 fbi->state = C_STARTUP; 1152 fbi->state = C_STARTUP;
1107 fbi->task_state = (u_char)-1; 1153 fbi->task_state = (u_char)-1;
1108 fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * 1154
1109 fbi->max_bpp / 8; 1155 for (i = 0; i < inf->num_modes; i++) {
1156 smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
1157 if (smemlen > fbi->fb.fix.smem_len)
1158 fbi->fb.fix.smem_len = smemlen;
1159 }
1110 1160
1111 init_waitqueue_head(&fbi->ctrlr_wait); 1161 init_waitqueue_head(&fbi->ctrlr_wait);
1112 INIT_WORK(&fbi->task, pxafb_task, fbi); 1162 INIT_WORK(&fbi->task, pxafb_task, fbi);
@@ -1307,12 +1357,12 @@ int __init pxafb_probe(struct platform_device *dev)
1307 (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) 1357 (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
1308 dev_warn(&dev->dev, "Dual panel only valid in passive mode\n"); 1358 dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
1309 if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && 1359 if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
1310 (inf->upper_margin || inf->lower_margin)) 1360 (inf->modes->upper_margin || inf->modes->lower_margin))
1311 dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n"); 1361 dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
1312#endif 1362#endif
1313 1363
1314 dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp); 1364 dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
1315 if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) { 1365 if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
1316 dev_err(&dev->dev, "Invalid resolution or bit depth\n"); 1366 dev_err(&dev->dev, "Invalid resolution or bit depth\n");
1317 ret = -EINVAL; 1367 ret = -EINVAL;
1318 goto failed; 1368 goto failed;