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