]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/omap/omapfb_main.c
f6586985006edd08086ed52e86158b028d7545f6
[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_omap1510()) {
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_omap1510()) {
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_omap1510() && 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_omap1510())
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 = fbi->par;
630         struct omapfb_device *fbdev = plane->fbdev;
631         struct fb_var_screeninfo *var;
632
633         var = &fbi->var;
634
635         if (win->x >= var->xres || win->y >= var->yres)
636                 return -EINVAL;
637
638         if (!fbdev->ctrl->update_window ||
639             fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
640                 return -ENODEV;
641
642         if (win->x + win->width >= var->xres)
643                 win->width = var->xres - win->x;
644         if (win->y + win->height >= var->yres)
645                 win->height = var->yres - win->y;
646         if (!win->width || !win->height)
647                 return 0;
648
649         return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
650 }
651 EXPORT_SYMBOL(omapfb_update_window_async);
652
653 static int omapfb_update_win(struct fb_info *fbi,
654                                 struct omapfb_update_window *win)
655 {
656         struct omapfb_plane_struct *plane = fbi->par;
657         int ret;
658
659         omapfb_rqueue_lock(plane->fbdev);
660         ret = omapfb_update_window_async(fbi, win, NULL, 0);
661         omapfb_rqueue_unlock(plane->fbdev);
662
663         return ret;
664 }
665
666 static int omapfb_update_full_screen(struct fb_info *fbi)
667 {
668         struct omapfb_plane_struct *plane = fbi->par;
669         struct omapfb_device *fbdev = plane->fbdev;
670         struct omapfb_update_window win;
671         int r;
672
673         if (!fbdev->ctrl->update_window ||
674             fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
675                 return -ENODEV;
676
677         win.x = 0;
678         win.y = 0;
679         win.width = fbi->var.xres;
680         win.height = fbi->var.yres;
681         win.format = 0;
682
683         omapfb_rqueue_lock(fbdev);
684         r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
685         omapfb_rqueue_unlock(fbdev);
686
687         return r;
688 }
689
690 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
691 {
692         struct omapfb_plane_struct *plane = fbi->par;
693         struct omapfb_device *fbdev = plane->fbdev;
694         struct lcd_panel *panel = fbdev->panel;
695         int r;
696
697         if (pi->pos_x + pi->out_width > panel->x_res ||
698             pi->pos_y + pi->out_height > panel->y_res)
699                 return -EINVAL;
700
701         plane->info = *pi;
702         r = ctrl_change_mode(fbi);
703         if (r < 0)
704                 return r;
705         return fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
706 }
707
708 static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
709 {
710         struct omapfb_plane_struct *plane = fbi->par;
711
712         *pi = plane->info;
713         return 0;
714 }
715
716 static int omapfb_set_color_key(struct omapfb_device *fbdev,
717                                 struct omapfb_color_key *ck)
718 {
719         int r;
720
721         if (!fbdev->ctrl->set_color_key)
722                 return -ENODEV;
723
724         omapfb_rqueue_lock(fbdev);
725         r = fbdev->ctrl->set_color_key(ck);
726         omapfb_rqueue_unlock(fbdev);
727
728         return r;
729 }
730
731 static int omapfb_get_color_key(struct omapfb_device *fbdev,
732                                 struct omapfb_color_key *ck)
733 {
734         int r;
735
736         if (!fbdev->ctrl->get_color_key)
737                 return -ENODEV;
738
739         omapfb_rqueue_lock(fbdev);
740         r = fbdev->ctrl->get_color_key(ck);
741         omapfb_rqueue_unlock(fbdev);
742
743         return r;
744 }
745
746 static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
747 static int notifier_inited;
748
749 static void omapfb_init_notifier(void)
750 {
751         int i;
752
753         for (i = 0; i < OMAPFB_PLANE_NUM; i++)
754                 BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
755 }
756
757 int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
758                            omapfb_notifier_callback_t callback,
759                            void *callback_data)
760 {
761         int r;
762
763         if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
764                 return -EINVAL;
765
766         if (!notifier_inited) {
767                 omapfb_init_notifier();
768                 notifier_inited = 1;
769         }
770
771         omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
772                                         unsigned long, void *))callback;
773         omapfb_nb->data = callback_data;
774         r = blocking_notifier_chain_register(
775                                 &omapfb_client_list[omapfb_nb->plane_idx],
776                                 &omapfb_nb->nb);
777         if (r)
778                 return r;
779         if (omapfb_dev != NULL &&
780             omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
781                 omapfb_dev->ctrl->bind_client(omapfb_nb);
782         }
783
784         return 0;
785 }
786 EXPORT_SYMBOL(omapfb_register_client);
787
788 int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
789 {
790         return blocking_notifier_chain_unregister(
791                 &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
792 }
793 EXPORT_SYMBOL(omapfb_unregister_client);
794
795 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
796 {
797         int i;
798
799         if (!notifier_inited)
800                 /* no client registered yet */
801                 return;
802
803         for (i = 0; i < OMAPFB_PLANE_NUM; i++)
804                 blocking_notifier_call_chain(&omapfb_client_list[i], event,
805                                     fbdev->fb_info[i]);
806 }
807 EXPORT_SYMBOL(omapfb_notify_clients);
808
809 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
810                                    enum omapfb_update_mode mode)
811 {
812         int r;
813
814         omapfb_rqueue_lock(fbdev);
815         r = fbdev->ctrl->set_update_mode(mode);
816         omapfb_rqueue_unlock(fbdev);
817
818         return r;
819 }
820
821 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
822 {
823         int r;
824
825         omapfb_rqueue_lock(fbdev);
826         r = fbdev->ctrl->get_update_mode();
827         omapfb_rqueue_unlock(fbdev);
828
829         return r;
830 }
831
832 static unsigned long omapfb_get_caps(struct omapfb_device *fbdev)
833 {
834         unsigned long caps;
835
836         caps = 0;
837         caps |= fbdev->panel->get_caps(fbdev->panel);
838         caps |= fbdev->ctrl->get_caps();
839         return caps;
840 }
841
842 /* For lcd testing */
843 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
844 {
845         omapfb_rqueue_lock(fbdev);
846         *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
847         if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
848                 struct omapfb_update_window win;
849
850                 win.x = 0;
851                 win.y = 0;
852                 win.width = 1;
853                 win.height = 1;
854                 win.format = 0;
855                 fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
856         }
857         omapfb_rqueue_unlock(fbdev);
858 }
859 EXPORT_SYMBOL(omapfb_write_first_pixel);
860
861 /* Ioctl interface. Part of the kernel mode frame buffer API is duplicated
862  * here to be accessible by user mode code.
863  */
864 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
865                         unsigned long arg)
866 {
867         struct omapfb_plane_struct *plane = fbi->par;
868         struct omapfb_device    *fbdev = plane->fbdev;
869         struct fb_ops           *ops = fbi->fbops;
870         union {
871                 struct omapfb_update_window     update_window;
872                 struct omapfb_plane_info        plane_info;
873                 struct omapfb_color_key         color_key;
874                 enum omapfb_update_mode         update_mode;
875                 unsigned long           caps;
876                 unsigned int            mirror;
877                 int                     plane_out;
878                 int                     enable_plane;
879         } p;
880         int r = 0;
881
882         BUG_ON(!ops);
883         switch (cmd)
884         {
885         case OMAPFB_MIRROR:
886                 if (get_user(p.mirror, (int __user *)arg))
887                         r = -EFAULT;
888                 else
889                         omapfb_mirror(fbi, p.mirror);
890                 break;
891         case OMAPFB_SYNC_GFX:
892                 omapfb_sync(fbi);
893                 break;
894         case OMAPFB_VSYNC:
895                 break;
896         case OMAPFB_SET_UPDATE_MODE:
897                 if (get_user(p.update_mode, (int __user *)arg))
898                         r = -EFAULT;
899                 else
900                         r = omapfb_set_update_mode(fbdev, p.update_mode);
901                 break;
902         case OMAPFB_GET_UPDATE_MODE:
903                 p.update_mode = omapfb_get_update_mode(fbdev);
904                 if (put_user(p.update_mode,
905                                         (enum omapfb_update_mode __user *)arg))
906                         r = -EFAULT;
907                 break;
908         case OMAPFB_UPDATE_WINDOW_OLD:
909                 if (copy_from_user(&p.update_window, (void __user *)arg,
910                                    sizeof(struct omapfb_update_window_old)))
911                         r = -EFAULT;
912                 else {
913                         p.update_window.format = 0;
914                         r = omapfb_update_win(fbi, &p.update_window);
915                 }
916                 break;
917         case OMAPFB_UPDATE_WINDOW:
918                 if (copy_from_user(&p.update_window, (void __user *)arg,
919                                    sizeof(p.update_window)))
920                         r = -EFAULT;
921                 else
922                         r = omapfb_update_win(fbi, &p.update_window);
923                 break;
924         case OMAPFB_SETUP_PLANE:
925                 if (copy_from_user(&p.plane_info, (void __user *)arg,
926                                    sizeof(p.plane_info)))
927                         r = -EFAULT;
928                 else
929                         r = omapfb_setup_plane(fbi, &p.plane_info);
930                 break;
931         case OMAPFB_QUERY_PLANE:
932                 if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
933                         break;
934                 if (copy_to_user((void __user *)arg, &p.plane_info,
935                                    sizeof(p.plane_info)))
936                         r = -EFAULT;
937                 break;
938         case OMAPFB_SET_COLOR_KEY:
939                 if (copy_from_user(&p.color_key, (void __user *)arg,
940                                    sizeof(p.color_key)))
941                         r = -EFAULT;
942                 else
943                         r = omapfb_set_color_key(fbdev, &p.color_key);
944                 break;
945         case OMAPFB_GET_COLOR_KEY:
946                 if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
947                         break;
948                 if (copy_to_user((void __user *)arg, &p.color_key,
949                                  sizeof(p.color_key)))
950                         r = -EFAULT;
951                 break;
952         case OMAPFB_LCD_TEST:
953                 {
954                         int test_num;
955
956                         if (get_user(test_num, (int __user *)arg)) {
957                                 r = -EFAULT;
958                                 break;
959                         }
960                         if (!fbdev->panel->run_test) {
961                                 r = -EINVAL;
962                                 break;
963                         }
964                         r = fbdev->panel->run_test(fbdev->panel, test_num);
965                         break;
966                 }
967         case OMAPFB_CTRL_TEST:
968                 {
969                         int test_num;
970
971                         if (get_user(test_num, (int __user *)arg)) {
972                                 r = -EFAULT;
973                                 break;
974                         }
975                         if (!fbdev->ctrl->run_test) {
976                                 r = -EINVAL;
977                                 break;
978                         }
979                         r = fbdev->ctrl->run_test(test_num);
980                         break;
981                 }
982         default:
983                 r = -EINVAL;
984         }
985
986         return r;
987 }
988
989 /* Callback table for the frame buffer framework. Some of these pointers
990  * will be changed according to the current setting of fb_info->accel_flags.
991  */
992 static struct fb_ops omapfb_ops = {
993         .owner          = THIS_MODULE,
994         .fb_open        = omapfb_open,
995         .fb_release     = omapfb_release,
996         .fb_setcolreg   = omapfb_setcolreg,
997         .fb_setcmap     = omapfb_setcmap,
998         .fb_fillrect    = cfb_fillrect,
999         .fb_copyarea    = cfb_copyarea,
1000         .fb_imageblit   = cfb_imageblit,
1001         .fb_blank       = omapfb_blank,
1002         .fb_ioctl       = omapfb_ioctl,
1003         .fb_check_var   = omapfb_check_var,
1004         .fb_set_par     = omapfb_set_par,
1005         .fb_rotate      = omapfb_rotate,
1006         .fb_pan_display = omapfb_pan_display,
1007 };
1008
1009 /*
1010  * ---------------------------------------------------------------------------
1011  * Sysfs interface
1012  * ---------------------------------------------------------------------------
1013  */
1014 /* omapfbX sysfs entries */
1015 static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf)
1016 {
1017         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1018
1019         return snprintf(buf, PAGE_SIZE, "%#010lx\n", omapfb_get_caps(fbdev));
1020 }
1021
1022 static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf)
1023 {
1024         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1025         int pos = 0;
1026         int i;
1027         unsigned long caps;
1028
1029         caps = omapfb_get_caps(fbdev);
1030         for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) {
1031                 if (omapfb_caps_table[i].flag & caps) {
1032                         pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n",
1033                                         omapfb_caps_table[i].name);
1034                 }
1035         }
1036         return min((int)PAGE_SIZE, pos);
1037 }
1038
1039 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1040 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1041
1042 /* panel sysfs entries */
1043 static ssize_t omapfb_show_panel_name(struct device *dev,
1044                                       struct device_attribute *attr, char *buf)
1045 {
1046         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1047
1048         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
1049 }
1050
1051 static ssize_t omapfb_show_bklight_level(struct device *dev,
1052                                          struct device_attribute *attr,
1053                                          char *buf)
1054 {
1055         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1056         int r;
1057
1058         if (fbdev->panel->get_bklight_level) {
1059                 r = snprintf(buf, PAGE_SIZE, "%d\n",
1060                              fbdev->panel->get_bklight_level(fbdev->panel));
1061         } else
1062                 r = -ENODEV;
1063         return r;
1064 }
1065
1066 static ssize_t omapfb_store_bklight_level(struct device *dev,
1067                                           struct device_attribute *attr,
1068                                           const char *buf, size_t size)
1069 {
1070         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1071         int r;
1072
1073         if (fbdev->panel->set_bklight_level) {
1074                 unsigned int level;
1075
1076                 if (sscanf(buf, "%10d", &level) == 1) {
1077                         r = fbdev->panel->set_bklight_level(fbdev->panel, level);
1078                 } else
1079                         r = -EINVAL;
1080         } else
1081                 r = -ENODEV;
1082         return r ? r : size;
1083 }
1084
1085 static ssize_t omapfb_show_bklight_max(struct device *dev,
1086                                        struct device_attribute *attr, char *buf)
1087 {
1088         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1089         int r;
1090
1091         if (fbdev->panel->get_bklight_level) {
1092                 r = snprintf(buf, PAGE_SIZE, "%d\n",
1093                              fbdev->panel->get_bklight_max(fbdev->panel));
1094         } else
1095                 r = -ENODEV;
1096         return r;
1097 }
1098
1099 static struct device_attribute dev_attr_panel_name =
1100         __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1101 static DEVICE_ATTR(backlight_level, 0664,
1102                    omapfb_show_bklight_level, omapfb_store_bklight_level);
1103 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1104
1105 static struct attribute *panel_attrs[] = {
1106         &dev_attr_panel_name.attr,
1107         &dev_attr_backlight_level.attr,
1108         &dev_attr_backlight_max.attr,
1109         NULL,
1110 };
1111
1112 static struct attribute_group panel_attr_grp = {
1113         .name  = "panel",
1114         .attrs = panel_attrs,
1115 };
1116
1117 /* ctrl sysfs entries */
1118 static ssize_t omapfb_show_ctrl_name(struct device *dev,
1119                                      struct device_attribute *attr, char *buf)
1120 {
1121         struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
1122
1123         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
1124 }
1125
1126 static struct device_attribute dev_attr_ctrl_name =
1127         __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1128
1129 static struct attribute *ctrl_attrs[] = {
1130         &dev_attr_ctrl_name.attr,
1131         NULL,
1132 };
1133
1134 static struct attribute_group ctrl_attr_grp = {
1135         .name  = "ctrl",
1136         .attrs = ctrl_attrs,
1137 };
1138
1139 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
1140 {
1141         int r;
1142
1143         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
1144                 goto fail0;
1145
1146         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1147                 goto fail1;
1148
1149         if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1150                 goto fail2;
1151
1152         if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1153                 goto fail3;
1154
1155         return 0;
1156 fail3:
1157         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1158 fail2:
1159         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1160 fail1:
1161         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1162 fail0:
1163         dev_err(fbdev->dev, "unable to register sysfs interface\n");
1164         return r;
1165 }
1166
1167 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1168 {
1169         sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1170         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1171         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1172         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1173 }
1174
1175 /*
1176  * ---------------------------------------------------------------------------
1177  * LDM callbacks
1178  * ---------------------------------------------------------------------------
1179  */
1180 /* Initialize system fb_info object and set the default video mode.
1181  * The frame buffer memory already allocated by lcddma_init
1182  */
1183 static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info,
1184                         struct omapfb_mem_region *region)
1185 {
1186         struct fb_var_screeninfo        *var = &info->var;
1187         struct fb_fix_screeninfo        *fix = &info->fix;
1188         int                             r = 0;
1189
1190         info->fbops = &omapfb_ops;
1191         info->flags = FBINFO_FLAG_DEFAULT;
1192
1193         strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
1194
1195         info->screen_base       = (char __iomem *)region->vaddr;
1196         fix->smem_start         = region->paddr;
1197         fix->smem_len           = region->size;
1198
1199         info->pseudo_palette = fbdev->pseudo_palette;
1200
1201         var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
1202         var->xres = def_vxres;
1203         var->yres = def_vyres;
1204         var->xres_virtual = def_vxres;
1205         var->yres_virtual = def_vyres;
1206         var->rotate       = def_rotate;
1207         var->bits_per_pixel = fbdev->panel->bpp;
1208
1209         set_fb_var(info, var);
1210         set_fb_fix(info);
1211
1212         r = fb_alloc_cmap(&info->cmap, 16, 0);
1213         if (r != 0)
1214                 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1215
1216         return r;
1217 }
1218
1219 /* Release the fb_info object */
1220 static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1221 {
1222         fb_dealloc_cmap(&fbi->cmap);
1223 }
1224
1225 static void planes_cleanup(struct omapfb_device *fbdev)
1226 {
1227         int i;
1228
1229         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1230                 if (fbdev->fb_info[i] == NULL)
1231                         break;
1232                 fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
1233                 framebuffer_release(fbdev->fb_info[i]);
1234         }
1235 }
1236
1237 static int planes_init(struct omapfb_device *fbdev)
1238 {
1239         struct fb_info *fbi;
1240         int i;
1241         int r;
1242
1243         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1244                 struct omapfb_plane_struct *plane;
1245                 fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
1246                                         fbdev->dev);
1247                 if (fbi == NULL) {
1248                         dev_err(fbdev->dev,
1249                                 "unable to allocate memory for plane info\n");
1250                         planes_cleanup(fbdev);
1251                         return -ENOMEM;
1252                 }
1253                 plane = fbi->par;
1254                 plane->idx = i;
1255                 plane->fbdev = fbdev;
1256                 plane->info.mirror = def_mirror;
1257                 fbdev->fb_info[i] = fbi;
1258
1259                 if ((r = fbinfo_init(fbdev, fbi,
1260                                         &fbdev->mem_desc.region[i])) < 0) {
1261                         framebuffer_release(fbi);
1262                         planes_cleanup(fbdev);
1263                         return r;
1264                 }
1265                 plane->info.out_width = fbi->var.xres;
1266                 plane->info.out_height = fbi->var.yres;
1267         }
1268         return 0;
1269 }
1270
1271 /* Free driver resources. Can be called to rollback an aborted initialization
1272  * sequence.
1273  */
1274 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1275 {
1276         int i;
1277
1278         switch (state) {
1279         case OMAPFB_ACTIVE:
1280                 for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
1281                         unregister_framebuffer(fbdev->fb_info[i]);
1282         case 7:
1283                 omapfb_unregister_sysfs(fbdev);
1284         case 6:
1285                 fbdev->panel->disable(fbdev->panel);
1286         case 5:
1287                 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1288         case 4:
1289                 planes_cleanup(fbdev);
1290         case 3:
1291                 ctrl_cleanup(fbdev);
1292         case 2:
1293                 fbdev->panel->cleanup(fbdev->panel);
1294         case 1:
1295                 dev_set_drvdata(fbdev->dev, NULL);
1296                 kfree(fbdev);
1297         case 0:
1298                 /* nothing to free */
1299                 break;
1300         default:
1301                 BUG();
1302         }
1303 }
1304
1305 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1306 {
1307         struct omapfb_platform_data *conf;
1308         char name[17];
1309         int i;
1310
1311         conf = fbdev->dev->platform_data;
1312
1313         fbdev->ctrl = NULL;
1314
1315         strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
1316         name[sizeof(name) - 1] = '\0';
1317
1318         if (strcmp(name, "internal") == 0) {
1319                 fbdev->ctrl = fbdev->int_ctrl;
1320                 return 0;
1321         }
1322
1323         for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1324                 dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
1325                 if (strcmp(ctrls[i]->name, name) == 0) {
1326                         fbdev->ctrl = ctrls[i];
1327                         break;
1328                 }
1329         }
1330
1331         if (fbdev->ctrl == NULL) {
1332                 dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
1333                 return -1;
1334         }
1335
1336         return 0;
1337 }
1338
1339 static void check_required_callbacks(struct omapfb_device *fbdev)
1340 {
1341 #define _C(x) (fbdev->ctrl->x != NULL)
1342 #define _P(x) (fbdev->panel->x != NULL)
1343         BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1344         BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1345                  _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1346                  _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1347                  _P(get_caps)));
1348 #undef _P
1349 #undef _C
1350 }
1351
1352 /* Called by LDM binding to probe and attach a new device.
1353  * Initialization sequence:
1354  *   1. allocate system omapfb_device structure
1355  *   2. select controller type according to platform configuration
1356  *      init LCD panel
1357  *   3. init LCD controller and LCD DMA
1358  *   4. init system fb_info structure for all planes
1359  *   5. setup video mode for first plane and enable it
1360  *   6. enable LCD panel
1361  *   7. register sysfs attributes
1362  *   OMAPFB_ACTIVE: register system fb_info structure for all planes
1363  */
1364 static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
1365 {
1366         struct omapfb_device    *fbdev = NULL;
1367         int                     init_state;
1368         unsigned long           phz, hhz, vhz;
1369         unsigned long           vram;
1370         int                     i;
1371         int                     r = 0;
1372
1373         init_state = 0;
1374
1375         if (pdev->num_resources != 0) {
1376                 dev_err(&pdev->dev, "probed for an unknown device\n");
1377                 r = -ENODEV;
1378                 goto cleanup;
1379         }
1380
1381         if (pdev->dev.platform_data == NULL) {
1382                 dev_err(&pdev->dev, "missing platform data\n");
1383                 r = -ENOENT;
1384                 goto cleanup;
1385         }
1386
1387         fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
1388         if (fbdev == NULL) {
1389                 dev_err(&pdev->dev,
1390                         "unable to allocate memory for device info\n");
1391                 r = -ENOMEM;
1392                 goto cleanup;
1393         }
1394         init_state++;
1395
1396         fbdev->dev = &pdev->dev;
1397         fbdev->panel = panel;
1398         platform_set_drvdata(pdev, fbdev);
1399
1400         mutex_init(&fbdev->rqueue_mutex);
1401
1402 #ifdef CONFIG_ARCH_OMAP1
1403         fbdev->int_ctrl = &omap1_int_ctrl;
1404 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1405         fbdev->ext_if = &omap1_ext_if;
1406 #endif
1407 #else   /* OMAP2 */
1408         fbdev->int_ctrl = &omap2_int_ctrl;
1409 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1410         fbdev->ext_if = &omap2_ext_if;
1411 #endif
1412 #endif
1413         if (omapfb_find_ctrl(fbdev) < 0) {
1414                 dev_err(fbdev->dev,
1415                         "LCD controller not found, board not supported\n");
1416                 r = -ENODEV;
1417                 goto cleanup;
1418         }
1419
1420         r = fbdev->panel->init(fbdev->panel, fbdev);
1421         if (r)
1422                 goto cleanup;
1423
1424         pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
1425
1426         def_vxres = def_vxres ? : fbdev->panel->x_res;
1427         def_vyres = def_vyres ? : fbdev->panel->y_res;
1428
1429         init_state++;
1430
1431         r = ctrl_init(fbdev);
1432         if (r)
1433                 goto cleanup;
1434         init_state++;
1435
1436         check_required_callbacks(fbdev);
1437
1438         r = planes_init(fbdev);
1439         if (r)
1440                 goto cleanup;
1441         init_state++;
1442
1443 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1444         /* Set DMA priority for EMIFF access to highest */
1445         if (cpu_class_is_omap1())
1446                 omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
1447 #endif
1448
1449         r = ctrl_change_mode(fbdev->fb_info[0]);
1450         if (r) {
1451                 dev_err(fbdev->dev, "mode setting failed\n");
1452                 goto cleanup;
1453         }
1454
1455         /* GFX plane is enabled by default */
1456         r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
1457         if (r)
1458                 goto cleanup;
1459
1460         omapfb_set_update_mode(fbdev, manual_update ?
1461                                    OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1462         init_state++;
1463
1464         r = fbdev->panel->enable(fbdev->panel);
1465         if (r)
1466                 goto cleanup;
1467         init_state++;
1468
1469         r = omapfb_register_sysfs(fbdev);
1470         if (r)
1471                 goto cleanup;
1472         init_state++;
1473
1474         vram = 0;
1475         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1476                 r = register_framebuffer(fbdev->fb_info[i]);
1477                 if (r != 0) {
1478                         dev_err(fbdev->dev,
1479                                 "registering framebuffer %d failed\n", i);
1480                         goto cleanup;
1481                 }
1482                 vram += fbdev->mem_desc.region[i].size;
1483         }
1484
1485         fbdev->state = OMAPFB_ACTIVE;
1486
1487         panel = fbdev->panel;
1488         phz = panel->pixel_clock * 1000;
1489         hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1490         vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1491
1492         omapfb_dev = fbdev;
1493
1494         pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
1495                         vram, fbdev->mem_desc.region_cnt);
1496         pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
1497                         "vfreq %lu.%lu Hz\n",
1498                         phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1499
1500         return 0;
1501
1502 cleanup:
1503         omapfb_free_resources(fbdev, init_state);
1504
1505         return r;
1506 }
1507
1508 static int omapfb_probe(struct platform_device *pdev)
1509 {
1510         BUG_ON(fbdev_pdev != NULL);
1511
1512         /* Delay actual initialization until the LCD is registered */
1513         fbdev_pdev = pdev;
1514         if (fbdev_panel != NULL)
1515                 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1516         return 0;
1517 }
1518
1519 void omapfb_register_panel(struct lcd_panel *panel)
1520 {
1521         BUG_ON(fbdev_panel != NULL);
1522
1523         fbdev_panel = panel;
1524         if (fbdev_pdev != NULL)
1525                 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1526 }
1527
1528 /* Called when the device is being detached from the driver */
1529 static int omapfb_remove(struct platform_device *pdev)
1530 {
1531         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1532         enum omapfb_state saved_state = fbdev->state;
1533
1534         /* FIXME: wait till completion of pending events */
1535
1536         fbdev->state = OMAPFB_DISABLED;
1537         omapfb_free_resources(fbdev, saved_state);
1538
1539         return 0;
1540 }
1541
1542 /* PM suspend */
1543 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1544 {
1545         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1546
1547         omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
1548
1549         return 0;
1550 }
1551
1552 /* PM resume */
1553 static int omapfb_resume(struct platform_device *pdev)
1554 {
1555         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1556
1557         omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
1558         return 0;
1559 }
1560
1561 static struct platform_driver omapfb_driver = {
1562         .probe          = omapfb_probe,
1563         .remove         = omapfb_remove,
1564         .suspend        = omapfb_suspend,
1565         .resume         = omapfb_resume,
1566         .driver         = {
1567                 .name   = MODULE_NAME,
1568                 .owner  = THIS_MODULE,
1569         },
1570 };
1571
1572 #ifndef MODULE
1573
1574 /* Process kernel command line parameters */
1575 static int __init omapfb_setup(char *options)
1576 {
1577         char *this_opt = NULL;
1578         int r = 0;
1579
1580         pr_debug("omapfb: options %s\n", options);
1581
1582         if (!options || !*options)
1583                 return 0;
1584
1585         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1586                 if (!strncmp(this_opt, "accel", 5))
1587                         def_accel = 1;
1588                 else if (!strncmp(this_opt, "vram:", 5)) {
1589                         char *suffix;
1590                         unsigned long vram;
1591                         vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1592                         switch (suffix[0]) {
1593                         case '\0':
1594                                 break;
1595                         case 'm':
1596                         case 'M':
1597                                 vram *= 1024;
1598                                 /* Fall through */
1599                         case 'k':
1600                         case 'K':
1601                                 vram *= 1024;
1602                                 break;
1603                         default:
1604                                 pr_debug("omapfb: invalid vram suffix %c\n",
1605                                          suffix[0]);
1606                                 r = -1;
1607                         }
1608                         def_vram[def_vram_cnt++] = vram;
1609                 }
1610                 else if (!strncmp(this_opt, "vxres:", 6))
1611                         def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1612                 else if (!strncmp(this_opt, "vyres:", 6))
1613                         def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1614                 else if (!strncmp(this_opt, "rotate:", 7))
1615                         def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1616                 else if (!strncmp(this_opt, "mirror:", 7))
1617                         def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1618                 else if (!strncmp(this_opt, "manual_update", 13))
1619                         manual_update = 1;
1620                 else {
1621                         pr_debug("omapfb: invalid option\n");
1622                         r = -1;
1623                 }
1624         }
1625
1626         return r;
1627 }
1628
1629 #endif
1630
1631 /* Register both the driver and the device */
1632 static int __init omapfb_init(void)
1633 {
1634 #ifndef MODULE
1635         char *option;
1636
1637         if (fb_get_options("omapfb", &option))
1638                 return -ENODEV;
1639         omapfb_setup(option);
1640 #endif
1641         /* Register the driver with LDM */
1642         if (platform_driver_register(&omapfb_driver)) {
1643                 pr_debug("failed to register omapfb driver\n");
1644                 return -ENODEV;
1645         }
1646
1647         return 0;
1648 }
1649
1650 static void __exit omapfb_cleanup(void)
1651 {
1652         platform_driver_unregister(&omapfb_driver);
1653 }
1654
1655 module_param_named(accel, def_accel, uint, 0664);
1656 module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1657 module_param_named(vxres, def_vxres, long, 0664);
1658 module_param_named(vyres, def_vyres, long, 0664);
1659 module_param_named(rotate, def_rotate, uint, 0664);
1660 module_param_named(mirror, def_mirror, uint, 0664);
1661 module_param_named(manual_update, manual_update, bool, 0664);
1662
1663 module_init(omapfb_init);
1664 module_exit(omapfb_cleanup);
1665
1666 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1667 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1668 MODULE_LICENSE("GPL");