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