]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/omap/omapfb_main.c
[PATCH] ARM: OMAP: Fix fb driver miscompile
[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                         if (fbdev->ctrl->resume)
353                                 fbdev->ctrl->resume();
354                         fbdev->panel->enable();
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                         fbdev->panel->disable();
364                         if (fbdev->ctrl->suspend)
365                                 fbdev->ctrl->suspend();
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 7:
1112                 omapfb_unregister_sysfs(fbdev);
1113         case 6:
1114                 fbdev->panel->disable();
1115         case 5:
1116                 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1117         case 4:
1118                 fbinfo_cleanup(fbdev);
1119         case 3:
1120                 ctrl_cleanup(fbdev);
1121         case 2:
1122                 fbdev->panel->cleanup();
1123         case 1:
1124                 dev_set_drvdata(fbdev->dev, NULL);
1125                 framebuffer_release(fbdev->fb_info);
1126         case 0:
1127                 /* nothing to free */
1128                 break;
1129         default:
1130                 BUG();
1131         }
1132 }
1133
1134 static int omapfb_find_panel(struct omapfb_device *fbdev)
1135 {
1136         const struct omap_lcd_config *conf;
1137         char name[17];
1138         int i;
1139
1140         conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
1141         fbdev->panel = NULL;
1142         if (conf == NULL)
1143                 return -1;
1144
1145         strncpy(name, conf->panel_name, sizeof(name) - 1);
1146         name[sizeof(name) - 1] = 0;
1147         for (i = 0; i < ARRAY_SIZE(panels); i++) {
1148                 if (strcmp(panels[i]->name, name) == 0) {
1149                         fbdev->panel = panels[i];
1150                         break;
1151                 }
1152         }
1153
1154         if (fbdev->panel == NULL)
1155                 return -1;
1156
1157         return 0;
1158 }
1159
1160 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1161 {
1162         struct omap_lcd_config *conf;
1163         char name[17];
1164         int i;
1165
1166         conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
1167
1168         fbdev->ctrl = NULL;
1169         if (conf == NULL)
1170                 return -1;
1171
1172         strncpy(name, conf->ctrl_name, sizeof(name) - 1);
1173         name[sizeof(name) - 1] = '\0';
1174
1175         if (strcmp(name, "internal") == 0) {
1176                 fbdev->ctrl = fbdev->int_ctrl;
1177                 return 0;
1178         }
1179
1180         for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1181                 if (strcmp(ctrls[i]->name, name) == 0) {
1182                         fbdev->ctrl = ctrls[i];
1183                         break;
1184                 }
1185         }
1186
1187         if (fbdev->ctrl == NULL)
1188                 return -1;
1189
1190         return 0;
1191 }
1192
1193 static void check_required_callbacks(struct omapfb_device *fbdev)
1194 {
1195 #define _C(x) (fbdev->ctrl->x != NULL)
1196 #define _P(x) (fbdev->panel->x != NULL)
1197         BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1198         BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1199                  _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1200                  _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1201                  _P(get_caps)));
1202 #undef _P
1203 #undef _C
1204 }
1205
1206 /* Called by LDM binding to probe and attach a new device.
1207  * Initialization sequence:
1208  *   1. allocate system fb_info structure
1209  *      select panel type according to machine type
1210  *   2. init LCD panel
1211  *   3. init LCD controller and LCD DMA
1212  *   4. init system fb_info structure
1213  *   5. init gfx DMA
1214  *   6. enable LCD panel
1215  *      start LCD frame transfer
1216  *   7. register system fb_info structure
1217  */
1218 static int omapfb_probe(struct platform_device *pdev)
1219 {
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         if (pdev->num_resources != 0) {
1232                 pr_err("probed for an unknown device\n");
1233                 r = -ENODEV;
1234                 goto cleanup;
1235         }
1236
1237         fbi = framebuffer_alloc(sizeof(struct omapfb_device), &pdev->dev);
1238         if (fbi == NULL) {
1239                 pr_err("unable to allocate memory for device info\n");
1240                 r = -ENOMEM;
1241                 goto cleanup;
1242         }
1243         init_state++;
1244
1245         fbdev = (struct omapfb_device *)fbi->par;
1246         fbdev->fb_info = fbi;
1247         fbdev->dev = &pdev->dev;
1248         platform_set_drvdata(pdev, fbdev);
1249
1250         init_MUTEX(&fbdev->rqueue_sema);
1251
1252 #ifdef CONFIG_ARCH_OMAP1
1253 #ifdef CONFIG_FB_OMAP_LCDC_INTERNAL
1254         fbdev->int_ctrl = &omap1_int_ctrl;
1255 #endif
1256 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1257         fbdev->ext_if = &sossi_extif;
1258 #endif
1259 #else   /* OMAP2 */
1260         fbdev->int_ctrl = &omap2_int_ctrl;
1261 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1262         fbdev->ext_if = &rfbi_extif;
1263 #endif
1264 #endif
1265         if (omapfb_find_ctrl(fbdev) < 0) {
1266                 pr_err("LCD controller not found, board not supported\n");
1267                 r = -ENODEV;
1268                 goto cleanup;
1269         }
1270
1271         if (omapfb_find_panel(fbdev) < 0) {
1272                 pr_err("LCD panel not found, board not supported\n");
1273                 r = -ENODEV;
1274                 goto cleanup;
1275         }
1276
1277         check_required_callbacks(fbdev);
1278
1279
1280         pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
1281
1282         r = fbdev->panel->init(fbdev);
1283         if (r)
1284                 goto cleanup;
1285         init_state++;
1286
1287         r = ctrl_init(fbdev);
1288         if (r)
1289                 goto cleanup;
1290         init_state++;
1291
1292         r = fbinfo_init(fbdev);
1293         if (r)
1294                 goto cleanup;
1295         init_state++;
1296
1297 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1298         /* Set DMA priority for EMIFF access to highest */
1299         omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15);
1300 #endif
1301
1302         r = ctrl_change_mode(fbdev);
1303         if (r) {
1304                 pr_err("mode setting failed\n");
1305                 goto cleanup;
1306         }
1307
1308         omapfb_enable_plane(fbdev, 0, 1);
1309
1310         omapfb_set_update_mode(fbdev, manual_update ?
1311                                    OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1312         init_state++;
1313
1314         r = fbdev->panel->enable();
1315         if (r)
1316                 goto cleanup;
1317         init_state++;
1318
1319         r = omapfb_register_sysfs(fbdev);
1320         if (r)
1321                 goto cleanup;
1322         init_state++;
1323
1324         r = register_framebuffer(fbdev->fb_info);
1325         if (r != 0) {
1326                 pr_err("register_framebuffer failed\n");
1327                 goto cleanup;
1328         }
1329
1330         fbdev->state = OMAPFB_ACTIVE;
1331
1332         panel = fbdev->panel;
1333         phz = panel->pixel_clock * 1000;
1334         hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1335         vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1336
1337         pr_info(MODULE_NAME ": initialized vram=%lu "
1338                         "pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
1339                         fbdev->vram_size,
1340                         phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1341
1342         DBGLEAVE(1);
1343         return 0;
1344
1345 cleanup:
1346         omapfb_free_resources(fbdev, init_state);
1347
1348         DBGLEAVE(1);
1349         return r;
1350 }
1351
1352 /* Called when the device is being detached from the driver */
1353 static int omapfb_remove(struct platform_device *pdev)
1354 {
1355         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1356         enum omapfb_state saved_state = fbdev->state;
1357
1358         DBGENTER(1);
1359         /* FIXME: wait till completion of pending events */
1360
1361         fbdev->state = OMAPFB_DISABLED;
1362         omapfb_free_resources(fbdev, saved_state);
1363
1364         DBGLEAVE(1);
1365         return 0;
1366 }
1367
1368 /* PM suspend */
1369 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1370 {
1371         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1372
1373         DBGENTER(1);
1374
1375         omapfb_blank(VESA_POWERDOWN, fbdev->fb_info);
1376
1377         DBGLEAVE(1);
1378
1379         return 0;
1380 }
1381
1382 /* PM resume */
1383 static int omapfb_resume(struct platform_device *pdev)
1384 {
1385         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1386
1387         DBGENTER(1);
1388
1389         omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info);
1390
1391         DBGLEAVE(1);
1392         return 0;
1393 }
1394
1395 static struct platform_driver omapfb_driver = {
1396         .probe          = omapfb_probe,
1397         .remove         = omapfb_remove,
1398         .suspend        = omapfb_suspend,
1399         .resume         = omapfb_resume,
1400         .driver         = {
1401                 .name   = OMAPFB_DRIVER,
1402                 .owner  = THIS_MODULE,
1403         },
1404 };
1405
1406 #ifndef MODULE
1407
1408 /* Process kernel command line parameters */
1409 static int __init omapfb_setup(char *options)
1410 {
1411         char *this_opt = NULL;
1412         int r = 0;
1413
1414         DBGENTER(1);
1415
1416         if (!options || !*options)
1417                 goto exit;
1418
1419         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1420                 if (!strncmp(this_opt, "accel", 5))
1421                         def_accel = 1;
1422                 else if (!strncmp(this_opt, "vram:", 5)) {
1423                         char *suffix;
1424                         def_vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1425                         switch (suffix[0]) {
1426                         case '\0':
1427                                 break;
1428                         case 'm':
1429                         case 'M':
1430                                 def_vram *= 1024;
1431                                 /* Fall through */
1432                         case 'k':
1433                         case 'K':
1434                                 def_vram *= 1024;
1435                                 break;
1436                         default:
1437                                 pr_err("invalid vram suffix\n");
1438                                 r = -1;
1439                         }
1440                 }
1441                 else if (!strncmp(this_opt, "vxres:", 6))
1442                         def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1443                 else if (!strncmp(this_opt, "vyres:", 6))
1444                         def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1445                 else if (!strncmp(this_opt, "rotate:", 7))
1446                         def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1447                 else if (!strncmp(this_opt, "mirror:", 7))
1448                         def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1449                 else if (!strncmp(this_opt, "manual_update", 13))
1450                         manual_update = 1;
1451                 else {
1452                         pr_err("invalid option\n");
1453                         r = -1;
1454                 }
1455         }
1456 exit:
1457         DBGLEAVE(1);
1458         return r;
1459 }
1460
1461 #endif
1462
1463 /* Register both the driver and the device */
1464 static int __init omapfb_init(void)
1465 {
1466         int r = 0;
1467
1468         DBGENTER(1);
1469
1470 #ifndef MODULE
1471         {
1472                 char *option;
1473
1474                 if (fb_get_options("omapfb", &option)) {
1475                         r = -ENODEV;
1476                         goto exit;
1477                 }
1478                 omapfb_setup(option);
1479         }
1480 #endif
1481         /* Register the driver with LDM */
1482         if (platform_driver_register(&omapfb_driver)) {
1483                 pr_err("failed to register omapfb driver\n");
1484                 r = -ENODEV;
1485                 goto exit;
1486         }
1487
1488 exit:
1489         DBGLEAVE(1);
1490         return r;
1491 }
1492
1493 static void __exit omapfb_cleanup(void)
1494 {
1495         DBGENTER(1);
1496
1497         platform_driver_unregister(&omapfb_driver);
1498
1499         DBGLEAVE(1);
1500 }
1501
1502 module_param_named(accel, def_accel, uint, 0664);
1503 module_param_named(vram, def_vram, ulong, 0664);
1504 module_param_named(vxres, def_vxres, long, 0664);
1505 module_param_named(vyres, def_vyres, long, 0664);
1506 module_param_named(rotate, def_rotate, uint, 0664);
1507 module_param_named(mirror, def_mirror, uint, 0664);
1508 module_param_named(manual_update, manual_update, bool, 0664);
1509
1510 module_init(omapfb_init);
1511 module_exit(omapfb_cleanup);
1512
1513 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1514 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1515 MODULE_LICENSE("GPL");