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