]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/omap/omapfb_main.c
59b0f0f4517d282e9d062a98f67938d082fb5b81
[linux-2.6-omap-h63xx.git] / drivers / video / omap / omapfb_main.c
1 /*
2  * File: drivers/video/omap/omapfb_main.c
3  *
4  * Framebuffer driver for TI OMAP boards
5  *
6  * Copyright (C) 2004 Nokia Corporation
7  * Author: Imre Deak <imre.deak@nokia.com>
8  *
9  * Acknowledgements:
10  *   Alex McMains <aam@ridgerun.com>       - Original driver
11  *   Juha Yrjola <juha.yrjola@nokia.com>   - Original driver and improvements
12  *   Dirk Behme <dirk.behme@de.bosch.com>  - changes for 2.6 kernel API
13  *   Texas Instruments                     - H3 support
14  *
15  * This program is free software; you can redistribute it and/or modify it
16  * under the terms of the GNU General Public License as published by the
17  * Free Software Foundation; either version 2 of the License, or (at your
18  * option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, write to the Free Software Foundation, Inc.,
27  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/mm.h>
33 #include <linux/init.h>
34 #include <linux/delay.h>
35 #include <linux/device.h>
36 #include <linux/dma-mapping.h>
37
38 #include <asm/uaccess.h>
39 #include <asm/atomic.h>
40 #include <asm/mach-types.h>
41
42 #include <asm/arch/dma.h>
43 #include <asm/arch/irqs.h>
44 #include <asm/arch/mux.h>
45 #include <asm/arch/board.h>
46 #include <asm/arch/omapfb.h>
47
48 /* #define OMAPFB_DBG 1 */
49
50 #include "debug.h"
51
52 #define OMAPFB_DRIVER   "omapfb"
53 #define MODULE_NAME     "omapfb"
54
55 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
56
57 static unsigned int     def_accel;
58 static unsigned long    def_vram;
59 static unsigned long    def_vxres;
60 static unsigned long    def_vyres;
61 static unsigned int     def_rotate;
62 static unsigned int     def_mirror;
63
64 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
65 static int              manual_update = 1;
66 #else
67 static int              manual_update;
68 #endif
69
70 static struct caps_table_struct {
71         unsigned long flag;
72         const char *name;
73 } omapfb_caps_table[] = {
74         { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
75         { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
76 };
77
78 /*
79  * ---------------------------------------------------------------------------
80  * LCD panel
81  * ---------------------------------------------------------------------------
82  */
83 extern struct lcd_panel h4_panel;
84 extern struct lcd_panel h3_panel;
85 extern struct lcd_panel h2_panel;
86 extern struct lcd_panel p2_panel;
87 extern struct lcd_panel osk_panel;
88 extern struct lcd_panel palmte_panel;
89 extern struct lcd_panel innovator1610_panel;
90 extern struct lcd_panel innovator1510_panel;
91 extern struct lcd_panel lph8923_panel;
92
93 static struct lcd_panel *panels[] = {
94 #ifdef CONFIG_MACH_OMAP_H2
95         &h2_panel,
96 #endif
97 #ifdef CONFIG_MACH_OMAP_H3
98         &h3_panel,
99 #endif
100 #ifdef CONFIG_MACH_OMAP_H4
101         &h4_panel,
102 #endif
103 #ifdef CONFIG_MACH_OMAP_PERSEUS2
104         &p2_panel,
105 #endif
106 #ifdef CONFIG_MACH_OMAP_OSK
107         &osk_panel,
108 #endif
109 #ifdef CONFIG_MACH_OMAP_PALMTE
110         &palmte_panel,
111 #endif
112
113 #ifdef CONFIG_MACH_OMAP_INNOVATOR
114
115 #ifdef CONFIG_ARCH_OMAP15XX
116         &innovator1510_panel,
117 #endif
118 #ifdef CONFIG_ARCH_OMAP16XX
119         &innovator1610_panel,
120 #endif
121
122 #endif
123 };
124
125 extern struct lcd_ctrl omap1_int_ctrl;
126 extern struct lcd_ctrl omap2_int_ctrl;
127 extern struct lcd_ctrl hwa742_ctrl;
128 extern struct lcd_ctrl blizzard_ctrl;
129
130 static struct lcd_ctrl *ctrls[] = {
131 #ifdef CONFIG_FB_OMAP_LCDC_INTERNAL
132 #ifdef CONFIG_ARCH_OMAP1
133         &omap1_int_ctrl,
134 #else
135         &omap2_int_ctrl,
136 #endif
137 #endif
138 };
139
140 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
141 #ifdef CONFIG_ARCH_OMAP1
142 extern struct lcd_ctrl_extif sossi_extif;
143 #else
144 extern struct lcd_ctrl_extif rfbi_extif;
145 #endif
146 #endif
147
148 static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
149 {
150         down(&fbdev->rqueue_sema);
151 }
152
153 static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
154 {
155         up(&fbdev->rqueue_sema);
156 }
157
158 /*
159  * ---------------------------------------------------------------------------
160  * LCD controller and LCD DMA
161  * ---------------------------------------------------------------------------
162  */
163 /* Lookup table to map elem size to elem type. */
164 static const int dma_elem_type[] = {
165         0,
166         OMAP_DMA_DATA_TYPE_S8,
167         OMAP_DMA_DATA_TYPE_S16,
168         0,
169         OMAP_DMA_DATA_TYPE_S32,
170 };
171
172 /* Allocate resources needed for LCD controller and LCD DMA operations. Video
173  * memory is allocated from system memory according to the virtual display
174  * size, except if a bigger memory size is specified explicitly as a kernel
175  * parameter.
176  */
177 static int ctrl_init(struct omapfb_device *fbdev)
178 {
179         int r;
180
181         DBGENTER(1);
182
183         r = fbdev->ctrl->init(fbdev, 0, def_vram);
184         if (r < 0) {
185                 pr_err("controller initialization failed\n");
186                 goto exit;
187         }
188
189         fbdev->ctrl->get_vram_layout(&fbdev->vram_size, &fbdev->vram_virt_base,
190                                      &fbdev->vram_phys_base);
191         memset((void *)fbdev->vram_virt_base, 0, fbdev->vram_size);
192
193         DBGPRINT(1, "vram_phys %08x vram_virt %p vram_size=%lu\n",
194                  fbdev->vram_phys_base, fbdev->vram_virt_base,
195                  fbdev->vram_size);
196
197         DBGLEAVE(1);
198         return 0;
199 exit:
200         DBGLEAVE(1);
201         return r;
202 }
203
204 static void ctrl_cleanup(struct omapfb_device *fbdev)
205 {
206         fbdev->ctrl->cleanup();
207 }
208
209 static int ctrl_change_mode(struct omapfb_device *fbdev)
210 {
211         int r;
212         unsigned long offset;
213         struct fb_var_screeninfo *var = &fbdev->fb_info->var;
214
215         DBGPRINT(1, "xoffset %d yoffset %d line_length %d bits_per_pixel %d\n",
216                 var->xoffset, var->yoffset, fbdev->fb_info->fix.line_length,
217                 var->bits_per_pixel);
218         offset = var->yoffset * fbdev->fb_info->fix.line_length +
219                  var->xoffset * var->bits_per_pixel / 8;
220         r = fbdev->ctrl->setup_plane(OMAPFB_PLANE_GFX, OMAPFB_CHANNEL_OUT_LCD,
221                                  offset, var->xres_virtual, 0, 0, var->xres,
222                                  var->yres, fbdev->color_mode);
223         DBGLEAVE(1);
224
225         return r;
226 }
227
228 /*
229  * ---------------------------------------------------------------------------
230  * fbdev framework callbacks and the ioctl interface
231  * ---------------------------------------------------------------------------
232  */
233 /* Called each time the omapfb device is opened */
234 static int omapfb_open(struct fb_info *info, int user)
235 {
236         DBGENTER(1);
237         DBGLEAVE(1);
238         return 0;
239 }
240
241 static void omapfb_sync(struct fb_info *info);
242
243 /* Called when the omapfb device is closed. We make sure that any pending
244  * gfx DMA operations are ended, before we return. */
245 static int omapfb_release(struct fb_info *info, int user)
246 {
247         DBGENTER(1);
248
249         omapfb_sync(info);
250
251         DBGLEAVE(1);
252         return 0;
253 }
254
255 /* Store a single color palette entry into a pseudo palette or the hardware
256  * palette if one is available. For now we support only 16bpp and thus store
257  * the entry only to the pseudo palette.
258  */
259 static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
260                         u_int blue, u_int transp, int update_hw_pal)
261 {
262         struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
263         u16 pal;
264         int r = 0;
265
266         if (regno < 16) {
267                 pal = ((red >> 11) << 11) | ((green >> 10) << 5) | (blue >> 11);
268                 ((u32 *)(info->pseudo_palette))[regno] = pal;
269         }
270
271         if (fbdev->ctrl->setcolreg)
272                 r = fbdev->ctrl->setcolreg(regno, red, green, blue, transp,
273                                                 update_hw_pal);
274
275         return r;
276 }
277
278 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
279                             u_int transp, struct fb_info *info)
280 {
281         int r = 0;
282
283         DBGENTER(2);
284
285         _setcolreg(info, regno, red, green, blue, transp, 1);
286
287         DBGLEAVE(2);
288
289         return r;
290 }
291
292 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
293 {
294         int count, index, r;
295         u16 *red, *green, *blue, *transp;
296         u16 trans = 0xffff;
297
298         red     = cmap->red;
299         green   = cmap->green;
300         blue    = cmap->blue;
301         transp  = cmap->transp;
302         index   = cmap->start;
303
304         for (count = 0; count < cmap->len; count++) {
305                 if (transp)
306                         trans = *transp++;
307                 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
308                                 count == cmap->len - 1);
309                 if (r != 0)
310                         return r;
311         }
312
313         return 0;
314 }
315
316
317 static void omapfb_update_full_screen(struct omapfb_device *fbdev);
318
319 static int omapfb_blank(int blank, struct fb_info *fbi)
320 {
321         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
322         int r = 0;
323
324         DBGENTER(1);
325
326         omapfb_rqueue_lock(fbdev);
327         switch (blank) {
328         case VESA_NO_BLANKING:
329                 if (fbdev->state == OMAPFB_SUSPENDED) {
330                         fbdev->panel->enable();
331                         if (fbdev->ctrl->resume)
332                                 fbdev->ctrl->resume();
333                         fbdev->state = OMAPFB_ACTIVE;
334                         if (fbdev->ctrl->get_update_mode() ==
335                                         OMAPFB_MANUAL_UPDATE)
336                                 omapfb_update_full_screen(fbdev);
337                 }
338                 break;
339         case VESA_POWERDOWN:
340                 if (fbdev->state == OMAPFB_ACTIVE) {
341                         if (fbdev->ctrl->suspend)
342                                 fbdev->ctrl->suspend();
343                         fbdev->panel->disable();
344                         fbdev->state = OMAPFB_SUSPENDED;
345                 }
346                 break;
347         default:
348                 r = -EINVAL;
349         }
350         omapfb_rqueue_unlock(fbdev);
351
352         DBGLEAVE(1);
353         return r;
354 }
355
356 static void omapfb_sync(struct fb_info *fbi)
357 {
358         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
359
360         omapfb_rqueue_lock(fbdev);
361         if (fbdev->ctrl->sync)
362                 fbdev->ctrl->sync();
363         omapfb_rqueue_unlock(fbdev);
364 }
365
366 /* Set fb_info.fix fields and also updates fbdev.
367  * When calling this fb_info.var must be set up already.
368  */
369 static void set_fb_fix(struct omapfb_device *fbdev)
370 {
371         struct fb_info           *fbi = fbdev->fb_info;
372         struct fb_fix_screeninfo *fix = &fbi->fix;
373         struct fb_var_screeninfo *var = &fbi->var;
374
375         strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id));
376         fix->type = FB_TYPE_PACKED_PIXELS;
377         switch (var->bits_per_pixel) {
378         case 16:
379                 fix->visual = FB_VISUAL_TRUECOLOR;
380                 break;
381         case 1:
382         case 2:
383         case 4:
384         case 8:
385                 fix->visual = FB_VISUAL_PSEUDOCOLOR;
386                 break;
387         }
388         fix->accel              = FB_ACCEL_OMAP1610;
389         fix->line_length        = var->xres_virtual * var->bits_per_pixel / 8;
390         fix->smem_len           = fbdev->vram_size;
391         fix->smem_start         = fbdev->vram_phys_base;
392 }
393
394 /* Check the values in var against our capabilities and in case of out of
395  * bound values try to adjust them.
396  */
397 static int set_fb_var(struct omapfb_device *fbdev,
398                       struct fb_var_screeninfo *var)
399 {
400         int             bpp;
401         unsigned long   max_frame_size;
402         unsigned long   line_size;
403         struct lcd_panel *panel = fbdev->panel;
404
405         bpp = var->bits_per_pixel = panel->bpp;
406
407         switch (bpp) {
408         case 16:
409                 fbdev->color_mode = OMAPFB_COLOR_RGB565;
410                 break;
411         case 8:
412                 fbdev->color_mode = OMAPFB_COLOR_CLUT_8BPP;
413                 break;
414         default:
415                 /* FIXME: other BPPs not yet supported */
416                 return -EINVAL;
417         }
418
419         switch (var->rotate) {
420         case 0:
421         case 180:
422                 var->xres = fbdev->panel->x_res;
423                 var->yres = fbdev->panel->y_res;
424                 break;
425         case 90:
426         case 270:
427                 var->xres = fbdev->panel->y_res;
428                 var->yres = fbdev->panel->x_res;
429                 break;
430         default:
431                 return -EINVAL;
432         }
433         if (var->xres_virtual < var->xres)
434                 var->xres_virtual = var->xres;
435         if (var->yres_virtual < var->yres)
436                 var->yres_virtual = var->yres;
437         max_frame_size = fbdev->vram_size;
438         line_size = var->xres_virtual * bpp / 8;
439         if (line_size * var->yres_virtual > max_frame_size) {
440                 /* Try to keep yres_virtual first */
441                 line_size = max_frame_size / var->yres_virtual;
442                 var->xres_virtual = line_size * 8 / bpp;
443                 if (var->xres_virtual < var->xres) {
444                         /* Still doesn't fit. Shrink yres_virtual too */
445                         var->xres_virtual = var->xres;
446                         line_size = var->xres * bpp / 8;
447                         var->yres_virtual = max_frame_size / line_size;
448                 }
449         }
450         if (var->xres + var->xoffset > var->xres_virtual)
451                 var->xoffset = var->xres_virtual - var->xres;
452         if (var->yres + var->yoffset > var->yres_virtual)
453                 var->yoffset = var->yres_virtual - var->yres;
454         line_size = var->xres * bpp / 8;
455
456         var->red.offset  = 11; var->red.length   = 5; var->red.msb_right   = 0;
457         var->green.offset= 5;  var->green.length = 6; var->green.msb_right = 0;
458         var->blue.offset = 0;  var->blue.length  = 5; var->blue.msb_right  = 0;
459
460         var->height             = -1;
461         var->width              = -1;
462         var->grayscale          = 0;
463         var->nonstd             = 0;
464
465         /* pixclock in ps, the rest in pixclock */
466         var->pixclock           = 10000000 / (panel->pixel_clock / 100);
467         var->left_margin        = panel->hfp;
468         var->right_margin       = panel->hbp;
469         var->upper_margin       = panel->vfp;
470         var->lower_margin       = panel->vbp;
471         var->hsync_len          = panel->hsw;
472         var->vsync_len          = panel->vsw;
473
474         /* TODO: get these from panel->config */
475         var->vmode              = FB_VMODE_NONINTERLACED;
476         var->sync               = 0;
477
478         return 0;
479 }
480
481 static struct fb_var_screeninfo new_var;
482
483 /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
484 static void omapfb_rotate(struct fb_info *fbi, int rotate)
485 {
486         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
487
488         DBGENTER(1);
489
490         if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) {
491                 memcpy(&new_var, &fbi->var, sizeof(new_var));
492                 new_var.rotate = rotate;
493                 if (set_fb_var(fbdev, &new_var) == 0 &&
494                     memcmp(&new_var, &fbi->var, sizeof(new_var))) {
495                         memcpy(&fbi->var, &new_var, sizeof(new_var));
496                         ctrl_change_mode(fbdev);
497                 }
498         }
499
500         DBGLEAVE(1);
501 }
502
503 /* Set new x,y offsets in the virtual display for the visible area and switch
504  * to the new mode.
505  */
506 static int omapfb_pan_display(struct fb_var_screeninfo *var,
507                                struct fb_info *fbi)
508 {
509         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
510         int r = 0;
511
512         DBGENTER(1);
513
514         if (var->xoffset != fbi->var.xoffset ||
515             var->yoffset != fbi->var.yoffset) {
516                 memcpy(&new_var, &fbi->var, sizeof(new_var));
517                 new_var.xoffset = var->xoffset;
518                 new_var.yoffset = var->yoffset;
519                 if (set_fb_var(fbdev, &new_var))
520                         r = -EINVAL;
521                 else {
522                         memcpy(&fbi->var, &new_var, sizeof(new_var));
523                         ctrl_change_mode(fbdev);
524                 }
525         }
526
527         DBGLEAVE(1);
528         return r;
529 }
530
531 /* Set mirror to vertical axis and switch to the new mode. */
532 static int omapfb_mirror(struct omapfb_device *fbdev, int mirror)
533 {
534         int r = 0;
535
536         DBGENTER(1);
537
538         mirror = mirror ? 1 : 0;
539         if (cpu_is_omap1510())
540                 r = -EINVAL;
541         else if (mirror != fbdev->mirror) {
542                 fbdev->mirror = mirror;
543                 r = ctrl_change_mode(fbdev);
544         }
545
546         DBGLEAVE(1);
547         return r;
548 }
549
550 /* Check values in var, try to adjust them in case of out of bound values if
551  * possible, or return error.
552  */
553 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
554 {
555         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
556         int r;
557
558         DBGENTER(1);
559
560         r = set_fb_var(fbdev, var);
561
562         DBGLEAVE(1);
563         return r;
564 }
565
566 /* Switch to a new mode. The parameters for it has been check already by
567  * omapfb_check_var.
568  */
569 static int omapfb_set_par(struct fb_info *fbi)
570 {
571         int r;
572         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
573
574         DBGENTER(1);
575
576         set_fb_fix(fbdev);
577         r = ctrl_change_mode(fbdev);
578
579         DBGLEAVE(1);
580         return r;
581 }
582
583 static int omapfb_update_win(struct omapfb_device *fbdev,
584                                 struct omapfb_update_window *win)
585 {
586         struct fb_var_screeninfo *var = &fbdev->fb_info->var;
587         int ret;
588
589         if (win->x >= var->xres || win->y >= var->yres)
590                 return -EINVAL;
591
592         if (!fbdev->ctrl->update_window ||
593             fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
594                 return -ENODEV;
595
596         if (win->x + win->width >= var->xres)
597                 win->width = var->xres - win->x;
598         if (win->y + win->height >= var->yres)
599                 win->height = var->yres - win->y;
600         if (!win->width || !win->height)
601                 return 0;
602
603         omapfb_rqueue_lock(fbdev);
604         ret = fbdev->ctrl->update_window(win, NULL, 0);
605         omapfb_rqueue_unlock(fbdev);
606
607         return ret;
608 }
609
610 static void omapfb_update_full_screen(struct omapfb_device *fbdev)
611 {
612         struct omapfb_update_window win;
613
614         win.x = 0;
615         win.y = 0;
616         win.width = fbdev->panel->x_res;
617         win.height = fbdev->panel->y_res;
618         win.format = 0;
619
620         omapfb_rqueue_lock(fbdev);
621         fbdev->ctrl->update_window(&win, NULL, 0);
622         omapfb_rqueue_unlock(fbdev);
623 }
624
625 static int omapfb_setup_plane(struct omapfb_device *fbdev,
626                               struct omapfb_setup_plane *sp)
627 {
628         int r;
629
630         omapfb_rqueue_lock(fbdev);
631         r = fbdev->ctrl->setup_plane(sp->plane, sp->channel_out, sp->offset,
632                                  sp->width, sp->pos_x, sp->pos_y, sp->width,
633                                  sp->height, sp->color_mode);
634         omapfb_rqueue_unlock(fbdev);
635
636         return r;
637 }
638
639 static int omapfb_enable_plane(struct omapfb_device *fbdev, int plane,
640                                 int enable)
641 {
642         int r;
643
644         omapfb_rqueue_lock(fbdev);
645         r = fbdev->ctrl->enable_plane(plane, enable);
646         omapfb_rqueue_unlock(fbdev);
647
648         return r;
649 }
650
651 static int omapfb_set_color_key(struct omapfb_device *fbdev,
652                                 struct omapfb_color_key *ck)
653 {
654         int r;
655
656         if (!fbdev->ctrl->set_color_key)
657                 return -ENODEV;
658
659         omapfb_rqueue_lock(fbdev);
660         r = fbdev->ctrl->set_color_key(ck);
661         omapfb_rqueue_unlock(fbdev);
662
663         return r;
664 }
665
666 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
667                                    enum omapfb_update_mode mode)
668 {
669         int r;
670
671         omapfb_rqueue_lock(fbdev);
672         r = fbdev->ctrl->set_update_mode(mode);
673         omapfb_rqueue_unlock(fbdev);
674
675         return r;
676 }
677
678 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
679 {
680         int r;
681
682         omapfb_rqueue_lock(fbdev);
683         r = fbdev->ctrl->get_update_mode();
684         omapfb_rqueue_unlock(fbdev);
685
686         return r;
687 }
688
689 static unsigned long omapfb_get_caps(struct fb_info *fbi)
690 {
691         struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
692         unsigned long caps;
693
694         caps = 0;
695         caps |= fbdev->panel->get_caps();
696         caps |= fbdev->ctrl->get_caps();
697         return caps;
698 }
699
700 /* For lcd testing */
701 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
702 {
703         omapfb_rqueue_lock(fbdev);
704         *(u16 *)fbdev->vram_virt_base = pixval;
705         if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
706                 struct omapfb_update_window win;
707
708                 win.x = 0;
709                 win.y = 0;
710                 win.width = 1;
711                 win.height = 1;
712                 win.format = 0;
713                 fbdev->ctrl->update_window(&win, NULL, 0);
714         }
715         omapfb_rqueue_unlock(fbdev);
716 }
717 EXPORT_SYMBOL(omapfb_write_first_pixel);
718
719 /* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
720  * here to be accessible by user mode code. In addition transparent copy
721  * graphics transformations, frame flipping support is provided through this
722  * interface.
723  */
724 static int omapfb_ioctl(struct inode *inode, struct file *file,
725                         unsigned int cmd, unsigned long arg,
726                         struct fb_info *fbi)
727 {
728         struct omapfb_device    *fbdev = (struct omapfb_device *)fbi->par;
729         struct fb_ops           *ops = fbi->fbops;
730         union {
731                 struct omapfb_update_window     update_window;
732                 struct omapfb_setup_plane       setup_plane;
733                 struct omapfb_enable_plane      enable_plane;
734                 struct omapfb_color_key         color_key;
735                 enum omapfb_update_mode         update_mode;
736                 unsigned long           caps;
737                 unsigned int            mirror;
738         } p;
739         int r = 0;
740
741         DBGENTER(2);
742
743         BUG_ON(!ops);
744         DBGPRINT(2, "cmd=%010x\n", cmd);
745         switch (cmd)
746         {
747         case OMAPFB_MIRROR:
748                 if (get_user(p.mirror, (int __user *)arg))
749                         r = -EFAULT;
750                 else
751                         omapfb_mirror(fbdev, p.mirror);
752                 break;
753         case OMAPFB_SYNC_GFX:
754                 omapfb_sync(fbi);
755                 break;
756         case OMAPFB_VSYNC:
757                 break;
758         case OMAPFB_SET_UPDATE_MODE:
759                 if (get_user(p.update_mode, (int __user *)arg))
760                         r = -EFAULT;
761                 else
762                         r = omapfb_set_update_mode(fbdev, p.update_mode);
763                 break;
764         case OMAPFB_GET_UPDATE_MODE:
765                 p.update_mode = omapfb_get_update_mode(fbdev);
766                 if (put_user(p.update_mode,
767                                         (enum omapfb_update_mode __user *)arg))
768                         r = -EFAULT;
769                 break;
770         case OMAPFB_UPDATE_WINDOW:
771                 if (copy_from_user(&p.update_window, (void __user *)arg,
772                                    sizeof(p.update_window)))
773                         r = -EFAULT;
774                 else
775                         r = omapfb_update_win(fbdev, &p.update_window);
776                 break;
777         case OMAPFB_SETUP_PLANE:
778                 if (copy_from_user(&p.setup_plane, (void __user *)arg,
779                                    sizeof(p.setup_plane)))
780                         r = -EFAULT;
781                 else
782                         r = omapfb_setup_plane(fbdev, &p.setup_plane);
783                 break;
784         case OMAPFB_ENABLE_PLANE:
785                 if (copy_from_user(&p.enable_plane, (void __user *)arg,
786                                    sizeof(p.enable_plane)))
787                         r = -EFAULT;
788                 else
789                         r = omapfb_enable_plane(fbdev,
790                                 p.enable_plane.plane, p.enable_plane.enable);
791                 break;
792         case OMAPFB_SET_COLOR_KEY:
793                 if (copy_from_user(&p.color_key, (void __user *)arg,
794                                    sizeof(p.color_key)))
795                         r = -EFAULT;
796                 else
797                         r = omapfb_set_color_key(fbdev, &p.color_key);
798                 break;
799         case OMAPFB_GET_CAPS:
800                 p.caps = omapfb_get_caps(fbi);
801                 if (put_user(p.caps, (unsigned long __user *)arg))
802                         r = -EFAULT;
803                 break;
804         case OMAPFB_LCD_TEST:
805                 {
806                         int test_num;
807
808                         if (get_user(test_num, (int __user *)arg)) {
809                                 r = -EFAULT;
810                                 break;
811                         }
812                         if (!fbdev->panel->run_test) {
813                                 r = -EINVAL;
814                                 break;
815                         }
816                         r = fbdev->panel->run_test(test_num);
817                         break;
818                 }
819         case OMAPFB_CTRL_TEST:
820                 {
821                         int test_num;
822
823                         if (get_user(test_num, (int __user *)arg)) {
824                                 r = -EFAULT;
825                                 break;
826                         }
827                         if (!fbdev->ctrl->run_test) {
828                                 r = -EINVAL;
829                                 break;
830                         }
831                         r = fbdev->ctrl->run_test(test_num);
832                         break;
833                 }
834         default:
835                 r = -EINVAL;
836         }
837
838         DBGLEAVE(2);
839         return r;
840 }
841
842 /* Callback table for the frame buffer framework. Some of these pointers
843  * will be changed according to the current setting of fb_info->accel_flags.
844  */
845 static struct fb_ops omapfb_ops = {
846         .owner          = THIS_MODULE,
847         .fb_open        = omapfb_open,
848         .fb_release     = omapfb_release,
849         .fb_setcolreg   = omapfb_setcolreg,
850         .fb_setcmap     = omapfb_setcmap,
851         .fb_fillrect    = cfb_fillrect,
852         .fb_copyarea    = cfb_copyarea,
853         .fb_imageblit   = cfb_imageblit,
854         .fb_cursor      = soft_cursor,
855         .fb_blank       = omapfb_blank,
856         .fb_ioctl       = omapfb_ioctl,
857         .fb_check_var   = omapfb_check_var,
858         .fb_set_par     = omapfb_set_par,
859         .fb_rotate      = omapfb_rotate,
860         .fb_pan_display = omapfb_pan_display,
861 };
862
863 /*
864  * ---------------------------------------------------------------------------
865  * Sysfs interface
866  * ---------------------------------------------------------------------------
867  */
868 /* omapfbX sysfs entries */
869 static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf)
870 {
871         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
872
873         return snprintf(buf, PAGE_SIZE, "%#010lx\n",
874                 omapfb_get_caps(fbdev->fb_info));
875 }
876
877 static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
878 {
879         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
880         int pos = 0;
881         int i;
882         unsigned long caps;
883
884         caps = omapfb_get_caps(fbdev->fb_info);
885         for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
886                 if (omapfb_caps_table[i].flag & caps) {
887                         pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
888                                         omapfb_caps_table[i].name);
889                 }
890         }
891         return min((int)PAGE_SIZE, pos);
892 }
893
894 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
895 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
896
897 /* panel sysfs entries */
898 static ssize_t omapfb_show_panel_name(struct device *dev,
899                                       struct device_attribute *attr, char *buf)
900 {
901         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
902
903         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
904 }
905
906 static ssize_t omapfb_show_bklight_level(struct device *dev,
907                                          struct device_attribute *attr,
908                                          char *buf)
909 {
910         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
911         int r;
912
913         if (fbdev->panel->get_bklight_level) {
914                 r = snprintf(buf, PAGE_SIZE, "%d\n",
915                              fbdev->panel->get_bklight_level());
916         } else
917                 r = -ENODEV;
918         return r;
919 }
920
921 static ssize_t omapfb_store_bklight_level(struct device *dev,
922                                           struct device_attribute *attr,
923                                           const char *buf, size_t size)
924 {
925         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
926         int r;
927
928         if (fbdev->panel->set_bklight_level) {
929                 unsigned int level;
930
931                 if (sscanf(buf, "%10d", &level) == 1) {
932                         r = fbdev->panel->set_bklight_level(level);
933                 } else
934                         r = -EINVAL;
935         } else
936                 r = -ENODEV;
937         return r ? r : size;
938 }
939
940 static ssize_t omapfb_show_bklight_max(struct device *dev,
941                                        struct device_attribute *attr, char *buf)
942 {
943         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
944         int r;
945
946         if (fbdev->panel->get_bklight_level) {
947                 r = snprintf(buf, PAGE_SIZE, "%d\n",
948                              fbdev->panel->get_bklight_max());
949         } else
950                 r = -ENODEV;
951         return r;
952 }
953
954 static struct device_attribute dev_attr_panel_name =
955         __ATTR(name, 0444, omapfb_show_panel_name, NULL);
956 static DEVICE_ATTR(backlight_level, 0664,
957                    omapfb_show_bklight_level, omapfb_store_bklight_level);
958 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
959
960 static struct attribute *panel_attrs[] = {
961         &dev_attr_panel_name.attr,
962         &dev_attr_backlight_level.attr,
963         &dev_attr_backlight_max.attr,
964         NULL,
965 };
966
967 static struct attribute_group panel_attr_grp = {
968         .name  = "panel",
969         .attrs = panel_attrs,
970 };
971
972 /* ctrl sysfs entries */
973 static ssize_t omapfb_show_ctrl_name(struct device *dev,
974                                      struct device_attribute *attr, char *buf)
975 {
976         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
977
978         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
979 }
980
981 static struct device_attribute dev_attr_ctrl_name =
982         __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
983
984 static struct attribute *ctrl_attrs[] = {
985         &dev_attr_ctrl_name.attr,
986         NULL,
987 };
988
989 static struct attribute_group ctrl_attr_grp = {
990         .name  = "ctrl",
991         .attrs = ctrl_attrs,
992 };
993
994 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
995 {
996         int r;
997
998         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
999                 goto fail0;
1000
1001         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1002                 goto fail1;
1003
1004         if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1005                 goto fail2;
1006
1007         if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1008                 goto fail3;
1009
1010         return 0;
1011 fail3:
1012         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1013 fail2:
1014         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1015 fail1:
1016         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1017 fail0:
1018         pr_err("unable to register sysfs interface\n");
1019         return r;
1020 }
1021
1022 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1023 {
1024         sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1025         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1026         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1027         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1028 }
1029
1030 /*
1031  * ---------------------------------------------------------------------------
1032  * LDM callbacks
1033  * ---------------------------------------------------------------------------
1034  */
1035 /* Initialize system fb_info object and set the default video mode.
1036  * The frame buffer memory already allocated by lcddma_init
1037  */
1038 static int fbinfo_init(struct omapfb_device *fbdev)
1039 {
1040         struct fb_info                  *info = fbdev->fb_info;
1041         struct fb_var_screeninfo        *var = &info->var;
1042         int                             r = 0;
1043
1044         DBGENTER(1);
1045
1046         BUG_ON(!fbdev->vram_virt_base);
1047
1048         info->fbops = &omapfb_ops;
1049         info->flags = FBINFO_FLAG_DEFAULT;
1050         info->screen_base = (char __iomem *)fbdev->vram_virt_base;
1051
1052         info->pseudo_palette = fbdev->pseudo_palette;
1053
1054         var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
1055         var->xres_virtual = def_vxres;
1056         var->yres_virtual = def_vyres;
1057         var->rotate       = def_rotate;
1058
1059         fbdev->mirror = def_mirror;
1060
1061         set_fb_var(fbdev, var);
1062         set_fb_fix(fbdev);
1063
1064         r = fb_alloc_cmap(&info->cmap, 16, 0);
1065         if (r != 0)
1066                 pr_err("unable to allocate color map memory\n");
1067
1068         DBGLEAVE(1);
1069         return r;
1070 }
1071
1072 /* Release the fb_info object */
1073 static void fbinfo_cleanup(struct omapfb_device *fbdev)
1074 {
1075         DBGENTER(1);
1076
1077         fb_dealloc_cmap(&fbdev->fb_info->cmap);
1078
1079         DBGLEAVE(1);
1080 }
1081
1082 /* Free driver resources. Can be called to rollback an aborted initialization
1083  * sequence.
1084  */
1085 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1086 {
1087         switch (state) {
1088         case OMAPFB_ACTIVE:
1089                 unregister_framebuffer(fbdev->fb_info);
1090         case 6:
1091                 omapfb_unregister_sysfs(fbdev);
1092                 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1093         case 5:
1094                 fbdev->panel->disable();
1095         case 4:
1096                 fbinfo_cleanup(fbdev);
1097         case 3:
1098                 ctrl_cleanup(fbdev);
1099         case 2:
1100                 fbdev->panel->cleanup();
1101         case 1:
1102                 dev_set_drvdata(fbdev->dev, NULL);
1103                 framebuffer_release(fbdev->fb_info);
1104         case 0:
1105                 /* nothing to free */
1106                 break;
1107         default:
1108                 BUG();
1109         }
1110 }
1111
1112 static int omapfb_find_panel(struct omapfb_device *fbdev)
1113 {
1114         const struct omap_lcd_config *conf;
1115         char name[17];
1116         int i;
1117
1118         conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
1119         fbdev->panel = NULL;
1120         if (conf == NULL)
1121                 return -1;
1122
1123         strncpy(name, conf->panel_name, sizeof(name) - 1);
1124         name[sizeof(name) - 1] = 0;
1125         for (i = 0; i < ARRAY_SIZE(panels); i++) {
1126                 if (strcmp(panels[i]->name, name) == 0) {
1127                         fbdev->panel = panels[i];
1128                         break;
1129                 }
1130         }
1131
1132         if (fbdev->panel == NULL)
1133                 return -1;
1134
1135         return 0;
1136 }
1137
1138 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1139 {
1140         struct omap_lcd_config *conf;
1141         char name[17];
1142         int i;
1143
1144         conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
1145
1146         fbdev->ctrl = NULL;
1147         if (conf == NULL)
1148                 return -1;
1149
1150         strncpy(name, conf->ctrl_name, sizeof(name) - 1);
1151         name[sizeof(name) - 1] = '\0';
1152
1153         if (strcmp(name, "internal") == 0) {
1154                 fbdev->ctrl = fbdev->int_ctrl;
1155                 return 0;
1156         }
1157
1158         for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1159                 if (strcmp(ctrls[i]->name, name) == 0) {
1160                         fbdev->ctrl = ctrls[i];
1161                         break;
1162                 }
1163         }
1164
1165         if (fbdev->ctrl == NULL)
1166                 return -1;
1167
1168         return 0;
1169 }
1170
1171 static void check_required_callbacks(struct omapfb_device *fbdev)
1172 {
1173 #define _C(x) (fbdev->ctrl->x != NULL)
1174 #define _P(x) (fbdev->panel->x != NULL)
1175         BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1176         BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1177                  _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1178                  _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1179                  _P(get_caps)));
1180 #undef _P
1181 #undef _C
1182 }
1183
1184 /* Called by LDM binding to probe and attach a new device.
1185  * Initialization sequence:
1186  *   1. allocate system fb_info structure
1187  *      select panel type according to machine type
1188  *   2. init LCD panel
1189  *   3. init LCD controller and LCD DMA
1190  *   4. init system fb_info structure
1191  *   5. init gfx DMA
1192  *   6. enable LCD panel
1193  *      start LCD frame transfer
1194  *   7. register system fb_info structure
1195  */
1196 static int omapfb_probe(struct device *dev)
1197 {
1198         struct platform_device  *pdev;
1199         struct omapfb_device    *fbdev = NULL;
1200         struct fb_info          *fbi;
1201         int                     init_state;
1202         unsigned long           phz, hhz, vhz;
1203         struct lcd_panel        *panel;
1204         int                     r = 0;
1205
1206         DBGENTER(1);
1207
1208         init_state = 0;
1209
1210         pdev = to_platform_device(dev);
1211         if (pdev->num_resources != 0) {
1212                 pr_err("probed for an unknown device\n");
1213                 r = -ENODEV;
1214                 goto cleanup;
1215         }
1216
1217         fbi = framebuffer_alloc(sizeof(struct omapfb_device), dev);
1218         if (fbi == NULL) {
1219                 pr_err("unable to allocate memory for device info\n");
1220                 r = -ENOMEM;
1221                 goto cleanup;
1222         }
1223         init_state++;
1224
1225         fbdev = (struct omapfb_device *)fbi->par;
1226         fbdev->fb_info = fbi;
1227         fbdev->dev = dev;
1228         dev_set_drvdata(dev, fbdev);
1229
1230         init_MUTEX(&fbdev->rqueue_sema);
1231
1232 #ifdef CONFIG_ARCH_OMAP1
1233         fbdev->int_ctrl = &omap1_int_ctrl;
1234 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1235         fbdev->ext_if = &sossi_extif;
1236 #endif
1237 #else   /* OMAP2 */
1238         fbdev->int_ctrl = &omap2_int_ctrl;
1239 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1240         fbdev->ext_if = &rfbi_extif;
1241 #endif
1242 #endif
1243         if (omapfb_find_ctrl(fbdev) < 0) {
1244                 pr_err("LCD controller not found, board not supported\n");
1245                 r = -ENODEV;
1246                 goto cleanup;
1247         }
1248
1249         if (omapfb_find_panel(fbdev) < 0) {
1250                 pr_err("LCD panel not found, board not supported\n");
1251                 r = -ENODEV;
1252                 goto cleanup;
1253         }
1254
1255         check_required_callbacks(fbdev);
1256
1257
1258         pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
1259
1260         r = fbdev->panel->init(fbdev);
1261         if (r)
1262                 goto cleanup;
1263         init_state++;
1264
1265         r = ctrl_init(fbdev);
1266         if (r)
1267                 goto cleanup;
1268         init_state++;
1269
1270         r = fbinfo_init(fbdev);
1271         if (r)
1272                 goto cleanup;
1273         init_state++;
1274
1275 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1276         /* Set DMA priority for EMIFF access to highest */
1277         omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
1278 #endif
1279
1280         r = fbdev->panel->enable();
1281         if (r)
1282                 goto cleanup;
1283         init_state++;
1284
1285         r = ctrl_change_mode(fbdev);
1286         if (r) {
1287                 pr_err("mode setting failed\n");
1288                 goto cleanup;
1289         }
1290
1291         omapfb_enable_plane(fbdev, 0, 1);
1292
1293         omapfb_set_update_mode(fbdev, manual_update ?
1294                                    OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1295
1296         r = omapfb_register_sysfs(fbdev);
1297         if (r)
1298                 goto cleanup;
1299         init_state++;
1300
1301         r = register_framebuffer(fbdev->fb_info);
1302         if (r != 0) {
1303                 pr_err("register_framebuffer failed\n");
1304                 goto cleanup;
1305         }
1306
1307         fbdev->state = OMAPFB_ACTIVE;
1308
1309         panel = fbdev->panel;
1310         phz = panel->pixel_clock * 1000;
1311         hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1312         vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1313
1314         pr_info(MODULE_NAME ": initialized vram=%lu "
1315                         "pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
1316                         fbdev->vram_size,
1317                         phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1318
1319         DBGLEAVE(1);
1320         return 0;
1321
1322 cleanup:
1323         omapfb_free_resources(fbdev, init_state);
1324
1325         DBGLEAVE(1);
1326         return r;
1327 }
1328
1329 /* Called when the device is being detached from the driver */
1330 static int omapfb_remove(struct device *dev)
1331 {
1332         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1333         enum omapfb_state saved_state = fbdev->state;
1334
1335         DBGENTER(1);
1336         /* FIXME: wait till completion of pending events */
1337
1338         fbdev->state = OMAPFB_DISABLED;
1339         omapfb_free_resources(fbdev, saved_state);
1340
1341         DBGLEAVE(1);
1342         return 0;
1343 }
1344
1345 /* PM suspend */
1346 static int omapfb_suspend(struct device *dev, pm_message_t mesg, u32 level)
1347 {
1348         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1349
1350         DBGENTER(1);
1351
1352         omapfb_blank(VESA_POWERDOWN, fbdev->fb_info);
1353
1354         DBGLEAVE(1);
1355
1356         return 0;
1357 }
1358
1359 /* PM resume */
1360 static int omapfb_resume(struct device *dev, u32 level)
1361 {
1362         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1363
1364         DBGENTER(1);
1365
1366         omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info);
1367
1368         DBGLEAVE(1);
1369         return 0;
1370 }
1371
1372 static struct device_driver omapfb_driver = {
1373         .name           = OMAPFB_DRIVER,
1374         .bus            = &platform_bus_type,
1375         .probe          = omapfb_probe,
1376         .remove         = omapfb_remove,
1377         .suspend        = omapfb_suspend,
1378         .resume         = omapfb_resume
1379 };
1380
1381 #ifndef MODULE
1382
1383 /* Process kernel command line parameters */
1384 static int __init omapfb_setup(char *options)
1385 {
1386         char *this_opt = NULL;
1387         int r = 0;
1388
1389         DBGENTER(1);
1390
1391         if (!options || !*options)
1392                 goto exit;
1393
1394         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1395                 if (!strncmp(this_opt, "accel", 5))
1396                         def_accel = 1;
1397                 else if (!strncmp(this_opt, "vram:", 5)) {
1398                         char *suffix;
1399                         def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1400                         switch (suffix[0]) {
1401                         case '\0':
1402                                 break;
1403                         case 'm':
1404                         case 'M':
1405                                 def_vram *= 1024;
1406                                 /* Fall through */
1407                         case 'k':
1408                         case 'K':
1409                                 def_vram *= 1024;
1410                                 break;
1411                         default:
1412                                 pr_err("invalid vram suffix\n");
1413                                 r = -1;
1414                         }
1415                 }
1416                 else if (!strncmp(this_opt, "vxres:", 6))
1417                         def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1418                 else if (!strncmp(this_opt, "vyres:", 6))
1419                         def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1420                 else if (!strncmp(this_opt, "rotate:", 7))
1421                         def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1422                 else if (!strncmp(this_opt, "mirror:", 7))
1423                         def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1424                 else if (!strncmp(this_opt, "manual_update", 13))
1425                         manual_update = 1;
1426                 else {
1427                         pr_err("invalid option\n");
1428                         r = -1;
1429                 }
1430         }
1431 exit:
1432         DBGLEAVE(1);
1433         return r;
1434 }
1435
1436 #endif
1437
1438 /* Register both the driver and the device */
1439 static int __init omapfb_init(void)
1440 {
1441         int r = 0;
1442
1443         DBGENTER(1);
1444
1445 #ifndef MODULE
1446         {
1447                 char *option;
1448
1449                 if (fb_get_options("omapfb", &option)) {
1450                         r = -ENODEV;
1451                         goto exit;
1452                 }
1453                 omapfb_setup(option);
1454         }
1455 #endif
1456         /* Register the driver with LDM */
1457         if (driver_register(&omapfb_driver)) {
1458                 pr_err("failed to register omapfb driver\n");
1459                 r = -ENODEV;
1460                 goto exit;
1461         }
1462
1463 exit:
1464         DBGLEAVE(1);
1465         return r;
1466 }
1467
1468 static void __exit omapfb_cleanup(void)
1469 {
1470         DBGENTER(1);
1471
1472         driver_unregister(&omapfb_driver);
1473
1474         DBGLEAVE(1);
1475 }
1476
1477 module_param_named(accel, def_accel, uint, 0664);
1478 module_param_named(vram, def_vram, ulong, 0664);
1479 module_param_named(vxres, def_vxres, long, 0664);
1480 module_param_named(vyres, def_vyres, long, 0664);
1481 module_param_named(rotate, def_rotate, uint, 0664);
1482 module_param_named(mirror, def_mirror, uint, 0664);
1483 module_param_named(manual_update, manual_update, bool, 0664);
1484
1485 module_init(omapfb_init);
1486 module_exit(omapfb_cleanup);
1487
1488 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1489 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1490 MODULE_LICENSE("GPL");