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