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