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