diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 12:14:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 12:14:00 -0400 |
commit | 63c422afe3739b68bec0b5c42807d1450c951caf (patch) | |
tree | 2cdbcbd4c6fcea69fbe0b164242336c38168f631 /drivers/video | |
parent | 6f3a28f7d1f0a65a78443c273b6e8ec01becf301 (diff) | |
parent | d14b272bc63f35a8f20b4b1df16c080b8d24f8f1 (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm:
[ARM] 3848/1: pxafb: Add option of fixing video modes and spitz QVGA mode support
[ARM] 3880/1: remove the last trace of iop31x support
[ARM] 3879/1: ep93xx: instantiate platform devices for ep93xx ethernet
[ARM] 3809/3: get rid of 4 megabyte kernel image size limit
[ARM] Fix XIP_KERNEL build error in arch/arm/mm/mmu.c
[ARM] 3874/1: Remove leftover usage of asm/timeofday.h
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/pxafb.c | 106 | ||||
-rw-r--r-- | drivers/video/pxafb.h | 4 |
2 files changed, 78 insertions, 32 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 | ||
61 | static void (*pxafb_backlight_power)(int); | 61 | static void (*pxafb_backlight_power)(int); |
62 | static void (*pxafb_lcd_power)(int); | 62 | static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); |
63 | 63 | ||
64 | static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); | 64 | static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); |
65 | static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); | 65 | static 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 | */ | ||
220 | static 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 | |||
240 | static 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); | |||
225 | static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 267 | static 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 | ||
699 | static void pxafb_setup_gpio(struct pxafb_info *fbi) | 755 | static 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; |
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index 47f41f70db7a..7499a1c4bf79 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h | |||
@@ -41,10 +41,6 @@ struct pxafb_info { | |||
41 | struct fb_info fb; | 41 | struct fb_info fb; |
42 | struct device *dev; | 42 | struct device *dev; |
43 | 43 | ||
44 | u_int max_bpp; | ||
45 | u_int max_xres; | ||
46 | u_int max_yres; | ||
47 | |||
48 | /* | 44 | /* |
49 | * These are the addresses we mapped | 45 | * These are the addresses we mapped |
50 | * the framebuffer memory region to. | 46 | * the framebuffer memory region to. |