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