GNU Linux-libre 4.9.301-gnu1
[releases.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 /*
598  * Set new x,y offsets in the virtual display for the visible area and switch
599  * to the new mode.
600  */
601 static int omapfb_pan_display(struct fb_var_screeninfo *var,
602                                struct fb_info *fbi)
603 {
604         struct omapfb_plane_struct *plane = fbi->par;
605         struct omapfb_device *fbdev = plane->fbdev;
606         int r = 0;
607
608         omapfb_rqueue_lock(fbdev);
609         if (var->xoffset != fbi->var.xoffset ||
610             var->yoffset != fbi->var.yoffset) {
611                 struct fb_var_screeninfo *new_var = &fbdev->new_var;
612
613                 memcpy(new_var, &fbi->var, sizeof(*new_var));
614                 new_var->xoffset = var->xoffset;
615                 new_var->yoffset = var->yoffset;
616                 if (set_fb_var(fbi, new_var))
617                         r = -EINVAL;
618                 else {
619                         memcpy(&fbi->var, new_var, sizeof(*new_var));
620                         ctrl_change_mode(fbi);
621                 }
622         }
623         omapfb_rqueue_unlock(fbdev);
624
625         return r;
626 }
627
628 /* Set mirror to vertical axis and switch to the new mode. */
629 static int omapfb_mirror(struct fb_info *fbi, int mirror)
630 {
631         struct omapfb_plane_struct *plane = fbi->par;
632         struct omapfb_device *fbdev = plane->fbdev;
633         int r = 0;
634
635         omapfb_rqueue_lock(fbdev);
636         mirror = mirror ? 1 : 0;
637         if (cpu_is_omap15xx())
638                 r = -EINVAL;
639         else if (mirror != plane->info.mirror) {
640                 plane->info.mirror = mirror;
641                 r = ctrl_change_mode(fbi);
642         }
643         omapfb_rqueue_unlock(fbdev);
644
645         return r;
646 }
647
648 /*
649  * Check values in var, try to adjust them in case of out of bound values if
650  * possible, or return error.
651  */
652 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
653 {
654         struct omapfb_plane_struct *plane = fbi->par;
655         struct omapfb_device *fbdev = plane->fbdev;
656         int r;
657
658         omapfb_rqueue_lock(fbdev);
659         if (fbdev->ctrl->sync != NULL)
660                 fbdev->ctrl->sync();
661         r = set_fb_var(fbi, var);
662         omapfb_rqueue_unlock(fbdev);
663
664         return r;
665 }
666
667 /*
668  * Switch to a new mode. The parameters for it has been check already by
669  * omapfb_check_var.
670  */
671 static int omapfb_set_par(struct fb_info *fbi)
672 {
673         struct omapfb_plane_struct *plane = fbi->par;
674         struct omapfb_device *fbdev = plane->fbdev;
675         int r = 0;
676
677         omapfb_rqueue_lock(fbdev);
678         set_fb_fix(fbi, 0);
679         r = ctrl_change_mode(fbi);
680         omapfb_rqueue_unlock(fbdev);
681
682         return r;
683 }
684
685 int omapfb_update_window_async(struct fb_info *fbi,
686                                 struct omapfb_update_window *win,
687                                 void (*callback)(void *),
688                                 void *callback_data)
689 {
690         int xres, yres;
691         struct omapfb_plane_struct *plane = fbi->par;
692         struct omapfb_device *fbdev = plane->fbdev;
693         struct fb_var_screeninfo *var = &fbi->var;
694
695         switch (var->rotate) {
696         case 0:
697         case 180:
698                 xres = fbdev->panel->x_res;
699                 yres = fbdev->panel->y_res;
700                 break;
701         case 90:
702         case 270:
703                 xres = fbdev->panel->y_res;
704                 yres = fbdev->panel->x_res;
705                 break;
706         default:
707                 return -EINVAL;
708         }
709
710         if (win->x >= xres || win->y >= yres ||
711             win->out_x > xres || win->out_y > yres)
712                 return -EINVAL;
713
714         if (!fbdev->ctrl->update_window ||
715             fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
716                 return -ENODEV;
717
718         if (win->x + win->width > xres)
719                 win->width = xres - win->x;
720         if (win->y + win->height > yres)
721                 win->height = yres - win->y;
722         if (win->out_x + win->out_width > xres)
723                 win->out_width = xres - win->out_x;
724         if (win->out_y + win->out_height > yres)
725                 win->out_height = yres - win->out_y;
726         if (!win->width || !win->height || !win->out_width || !win->out_height)
727                 return 0;
728
729         return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
730 }
731 EXPORT_SYMBOL(omapfb_update_window_async);
732
733 static int omapfb_update_win(struct fb_info *fbi,
734                                 struct omapfb_update_window *win)
735 {
736         struct omapfb_plane_struct *plane = fbi->par;
737         int ret;
738
739         omapfb_rqueue_lock(plane->fbdev);
740         ret = omapfb_update_window_async(fbi, win, NULL, NULL);
741         omapfb_rqueue_unlock(plane->fbdev);
742
743         return ret;
744 }
745
746 static int omapfb_update_full_screen(struct fb_info *fbi)
747 {
748         struct omapfb_plane_struct *plane = fbi->par;
749         struct omapfb_device *fbdev = plane->fbdev;
750         struct omapfb_update_window win;
751         int r;
752
753         if (!fbdev->ctrl->update_window ||
754             fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
755                 return -ENODEV;
756
757         win.x = 0;
758         win.y = 0;
759         win.width = fbi->var.xres;
760         win.height = fbi->var.yres;
761         win.out_x = 0;
762         win.out_y = 0;
763         win.out_width = fbi->var.xres;
764         win.out_height = fbi->var.yres;
765         win.format = 0;
766
767         omapfb_rqueue_lock(fbdev);
768         r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL);
769         omapfb_rqueue_unlock(fbdev);
770
771         return r;
772 }
773
774 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
775 {
776         struct omapfb_plane_struct *plane = fbi->par;
777         struct omapfb_device *fbdev = plane->fbdev;
778         struct lcd_panel *panel = fbdev->panel;
779         struct omapfb_plane_info old_info;
780         int r = 0;
781
782         if (pi->pos_x + pi->out_width > panel->x_res ||
783             pi->pos_y + pi->out_height > panel->y_res)
784                 return -EINVAL;
785
786         omapfb_rqueue_lock(fbdev);
787         if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) {
788                 /*
789                  * This plane's memory was freed, can't enable it
790                  * until it's reallocated.
791                  */
792                 r = -EINVAL;
793                 goto out;
794         }
795         old_info = plane->info;
796         plane->info = *pi;
797         if (pi->enabled) {
798                 r = ctrl_change_mode(fbi);
799                 if (r < 0) {
800                         plane->info = old_info;
801                         goto out;
802                 }
803         }
804         r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
805         if (r < 0) {
806                 plane->info = old_info;
807                 goto out;
808         }
809 out:
810         omapfb_rqueue_unlock(fbdev);
811         return r;
812 }
813
814 static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
815 {
816         struct omapfb_plane_struct *plane = fbi->par;
817
818         *pi = plane->info;
819         return 0;
820 }
821
822 static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
823 {
824         struct omapfb_plane_struct *plane = fbi->par;
825         struct omapfb_device *fbdev = plane->fbdev;
826         struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx];
827         size_t size;
828         int r = 0;
829
830         if (fbdev->ctrl->setup_mem == NULL)
831                 return -ENODEV;
832         if (mi->type != OMAPFB_MEMTYPE_SDRAM)
833                 return -EINVAL;
834
835         size = PAGE_ALIGN(mi->size);
836         omapfb_rqueue_lock(fbdev);
837         if (plane->info.enabled) {
838                 r = -EBUSY;
839                 goto out;
840         }
841         if (rg->size != size || rg->type != mi->type) {
842                 struct fb_var_screeninfo *new_var = &fbdev->new_var;
843                 unsigned long old_size = rg->size;
844                 u8            old_type = rg->type;
845                 unsigned long paddr;
846
847                 rg->size = size;
848                 rg->type = mi->type;
849                 /*
850                  * size == 0 is a special case, for which we
851                  * don't check / adjust the screen parameters.
852                  * This isn't a problem since the plane can't
853                  * be reenabled unless its size is > 0.
854                  */
855                 if (old_size != size && size) {
856                         if (size) {
857                                 memcpy(new_var, &fbi->var, sizeof(*new_var));
858                                 r = set_fb_var(fbi, new_var);
859                                 if (r < 0)
860                                         goto out;
861                         }
862                 }
863
864                 if (fbdev->ctrl->sync)
865                         fbdev->ctrl->sync();
866                 r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr);
867                 if (r < 0) {
868                         /* Revert changes. */
869                         rg->size = old_size;
870                         rg->type = old_type;
871                         goto out;
872                 }
873                 rg->paddr = paddr;
874
875                 if (old_size != size) {
876                         if (size) {
877                                 memcpy(&fbi->var, new_var, sizeof(fbi->var));
878                                 set_fb_fix(fbi, 0);
879                         } else {
880                                 /*
881                                  * Set these explicitly to indicate that the
882                                  * plane memory is dealloce'd, the other
883                                  * screen parameters in var / fix are invalid.
884                                  */
885                                 mutex_lock(&fbi->mm_lock);
886                                 fbi->fix.smem_start = 0;
887                                 fbi->fix.smem_len = 0;
888                                 mutex_unlock(&fbi->mm_lock);
889                         }
890                 }
891         }
892 out:
893         omapfb_rqueue_unlock(fbdev);
894
895         return r;
896 }
897
898 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
899 {
900         struct omapfb_plane_struct *plane = fbi->par;
901         struct omapfb_device *fbdev = plane->fbdev;
902         struct omapfb_mem_region *rg;
903
904         rg = &fbdev->mem_desc.region[plane->idx];
905         memset(mi, 0, sizeof(*mi));
906         mi->size = rg->size;
907         mi->type = rg->type;
908
909         return 0;
910 }
911
912 static int omapfb_set_color_key(struct omapfb_device *fbdev,
913                                 struct omapfb_color_key *ck)
914 {
915         int r;
916
917         if (!fbdev->ctrl->set_color_key)
918                 return -ENODEV;
919
920         omapfb_rqueue_lock(fbdev);
921         r = fbdev->ctrl->set_color_key(ck);
922         omapfb_rqueue_unlock(fbdev);
923
924         return r;
925 }
926
927 static int omapfb_get_color_key(struct omapfb_device *fbdev,
928                                 struct omapfb_color_key *ck)
929 {
930         int r;
931
932         if (!fbdev->ctrl->get_color_key)
933                 return -ENODEV;
934
935         omapfb_rqueue_lock(fbdev);
936         r = fbdev->ctrl->get_color_key(ck);
937         omapfb_rqueue_unlock(fbdev);
938
939         return r;
940 }
941
942 static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
943 static int notifier_inited;
944
945 static void omapfb_init_notifier(void)
946 {
947         int i;
948
949         for (i = 0; i < OMAPFB_PLANE_NUM; i++)
950                 BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
951 }
952
953 int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
954                                 omapfb_notifier_callback_t callback,
955                                 void *callback_data)
956 {
957         int r;
958
959         if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM)
960                 return -EINVAL;
961
962         if (!notifier_inited) {
963                 omapfb_init_notifier();
964                 notifier_inited = 1;
965         }
966
967         omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
968                                         unsigned long, void *))callback;
969         omapfb_nb->data = callback_data;
970         r = blocking_notifier_chain_register(
971                                 &omapfb_client_list[omapfb_nb->plane_idx],
972                                 &omapfb_nb->nb);
973         if (r)
974                 return r;
975         if (omapfb_dev != NULL &&
976             omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
977                 omapfb_dev->ctrl->bind_client(omapfb_nb);
978         }
979
980         return 0;
981 }
982 EXPORT_SYMBOL(omapfb_register_client);
983
984 int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
985 {
986         return blocking_notifier_chain_unregister(
987                 &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
988 }
989 EXPORT_SYMBOL(omapfb_unregister_client);
990
991 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
992 {
993         int i;
994
995         if (!notifier_inited)
996                 /* no client registered yet */
997                 return;
998
999         for (i = 0; i < OMAPFB_PLANE_NUM; i++)
1000                 blocking_notifier_call_chain(&omapfb_client_list[i], event,
1001                                     fbdev->fb_info[i]);
1002 }
1003 EXPORT_SYMBOL(omapfb_notify_clients);
1004
1005 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
1006                                    enum omapfb_update_mode mode)
1007 {
1008         int r;
1009
1010         omapfb_rqueue_lock(fbdev);
1011         r = fbdev->ctrl->set_update_mode(mode);
1012         omapfb_rqueue_unlock(fbdev);
1013
1014         return r;
1015 }
1016
1017 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
1018 {
1019         int r;
1020
1021         omapfb_rqueue_lock(fbdev);
1022         r = fbdev->ctrl->get_update_mode();
1023         omapfb_rqueue_unlock(fbdev);
1024
1025         return r;
1026 }
1027
1028 static void omapfb_get_caps(struct omapfb_device *fbdev, int plane,
1029                                      struct omapfb_caps *caps)
1030 {
1031         memset(caps, 0, sizeof(*caps));
1032         fbdev->ctrl->get_caps(plane, caps);
1033         caps->ctrl |= fbdev->panel->get_caps(fbdev->panel);
1034 }
1035
1036 /* For lcd testing */
1037 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
1038 {
1039         omapfb_rqueue_lock(fbdev);
1040         *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
1041         if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
1042                 struct omapfb_update_window win;
1043
1044                 memset(&win, 0, sizeof(win));
1045                 win.width = 2;
1046                 win.height = 2;
1047                 win.out_width = 2;
1048                 win.out_height = 2;
1049                 fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL);
1050         }
1051         omapfb_rqueue_unlock(fbdev);
1052 }
1053 EXPORT_SYMBOL(omapfb_write_first_pixel);
1054
1055 /*
1056  * Ioctl interface. Part of the kernel mode frame buffer API is duplicated
1057  * here to be accessible by user mode code.
1058  */
1059 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
1060                         unsigned long arg)
1061 {
1062         struct omapfb_plane_struct *plane = fbi->par;
1063         struct omapfb_device    *fbdev = plane->fbdev;
1064         struct fb_ops           *ops = fbi->fbops;
1065         union {
1066                 struct omapfb_update_window     update_window;
1067                 struct omapfb_plane_info        plane_info;
1068                 struct omapfb_mem_info          mem_info;
1069                 struct omapfb_color_key         color_key;
1070                 enum omapfb_update_mode         update_mode;
1071                 struct omapfb_caps              caps;
1072                 unsigned int            mirror;
1073                 int                     plane_out;
1074                 int                     enable_plane;
1075         } p;
1076         int r = 0;
1077
1078         BUG_ON(!ops);
1079         switch (cmd) {
1080         case OMAPFB_MIRROR:
1081                 if (get_user(p.mirror, (int __user *)arg))
1082                         r = -EFAULT;
1083                 else
1084                         omapfb_mirror(fbi, p.mirror);
1085                 break;
1086         case OMAPFB_SYNC_GFX:
1087                 omapfb_sync(fbi);
1088                 break;
1089         case OMAPFB_VSYNC:
1090                 break;
1091         case OMAPFB_SET_UPDATE_MODE:
1092                 if (get_user(p.update_mode, (int __user *)arg))
1093                         r = -EFAULT;
1094                 else
1095                         r = omapfb_set_update_mode(fbdev, p.update_mode);
1096                 break;
1097         case OMAPFB_GET_UPDATE_MODE:
1098                 p.update_mode = omapfb_get_update_mode(fbdev);
1099                 if (put_user(p.update_mode,
1100                                         (enum omapfb_update_mode __user *)arg))
1101                         r = -EFAULT;
1102                 break;
1103         case OMAPFB_UPDATE_WINDOW_OLD:
1104                 if (copy_from_user(&p.update_window, (void __user *)arg,
1105                                    sizeof(struct omapfb_update_window_old)))
1106                         r = -EFAULT;
1107                 else {
1108                         struct omapfb_update_window *u = &p.update_window;
1109                         u->out_x = u->x;
1110                         u->out_y = u->y;
1111                         u->out_width = u->width;
1112                         u->out_height = u->height;
1113                         memset(u->reserved, 0, sizeof(u->reserved));
1114                         r = omapfb_update_win(fbi, u);
1115                 }
1116                 break;
1117         case OMAPFB_UPDATE_WINDOW:
1118                 if (copy_from_user(&p.update_window, (void __user *)arg,
1119                                    sizeof(p.update_window)))
1120                         r = -EFAULT;
1121                 else
1122                         r = omapfb_update_win(fbi, &p.update_window);
1123                 break;
1124         case OMAPFB_SETUP_PLANE:
1125                 if (copy_from_user(&p.plane_info, (void __user *)arg,
1126                                    sizeof(p.plane_info)))
1127                         r = -EFAULT;
1128                 else
1129                         r = omapfb_setup_plane(fbi, &p.plane_info);
1130                 break;
1131         case OMAPFB_QUERY_PLANE:
1132                 if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
1133                         break;
1134                 if (copy_to_user((void __user *)arg, &p.plane_info,
1135                                    sizeof(p.plane_info)))
1136                         r = -EFAULT;
1137                 break;
1138         case OMAPFB_SETUP_MEM:
1139                 if (copy_from_user(&p.mem_info, (void __user *)arg,
1140                                    sizeof(p.mem_info)))
1141                         r = -EFAULT;
1142                 else
1143                         r = omapfb_setup_mem(fbi, &p.mem_info);
1144                 break;
1145         case OMAPFB_QUERY_MEM:
1146                 if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0)
1147                         break;
1148                 if (copy_to_user((void __user *)arg, &p.mem_info,
1149                                    sizeof(p.mem_info)))
1150                         r = -EFAULT;
1151                 break;
1152         case OMAPFB_SET_COLOR_KEY:
1153                 if (copy_from_user(&p.color_key, (void __user *)arg,
1154                                    sizeof(p.color_key)))
1155                         r = -EFAULT;
1156                 else
1157                         r = omapfb_set_color_key(fbdev, &p.color_key);
1158                 break;
1159         case OMAPFB_GET_COLOR_KEY:
1160                 if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
1161                         break;
1162                 if (copy_to_user((void __user *)arg, &p.color_key,
1163                                  sizeof(p.color_key)))
1164                         r = -EFAULT;
1165                 break;
1166         case OMAPFB_GET_CAPS:
1167                 omapfb_get_caps(fbdev, plane->idx, &p.caps);
1168                 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
1169                         r = -EFAULT;
1170                 break;
1171         case OMAPFB_LCD_TEST:
1172                 {
1173                         int test_num;
1174
1175                         if (get_user(test_num, (int __user *)arg)) {
1176                                 r = -EFAULT;
1177                                 break;
1178                         }
1179                         if (!fbdev->panel->run_test) {
1180                                 r = -EINVAL;
1181                                 break;
1182                         }
1183                         r = fbdev->panel->run_test(fbdev->panel, test_num);
1184                         break;
1185                 }
1186         case OMAPFB_CTRL_TEST:
1187                 {
1188                         int test_num;
1189
1190                         if (get_user(test_num, (int __user *)arg)) {
1191                                 r = -EFAULT;
1192                                 break;
1193                         }
1194                         if (!fbdev->ctrl->run_test) {
1195                                 r = -EINVAL;
1196                                 break;
1197                         }
1198                         r = fbdev->ctrl->run_test(test_num);
1199                         break;
1200                 }
1201         default:
1202                 r = -EINVAL;
1203         }
1204
1205         return r;
1206 }
1207
1208 static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1209 {
1210         struct omapfb_plane_struct *plane = info->par;
1211         struct omapfb_device *fbdev = plane->fbdev;
1212         int r;
1213
1214         omapfb_rqueue_lock(fbdev);
1215         r = fbdev->ctrl->mmap(info, vma);
1216         omapfb_rqueue_unlock(fbdev);
1217
1218         return r;
1219 }
1220
1221 /*
1222  * Callback table for the frame buffer framework. Some of these pointers
1223  * will be changed according to the current setting of fb_info->accel_flags.
1224  */
1225 static struct fb_ops omapfb_ops = {
1226         .owner          = THIS_MODULE,
1227         .fb_open        = omapfb_open,
1228         .fb_release     = omapfb_release,
1229         .fb_setcolreg   = omapfb_setcolreg,
1230         .fb_setcmap     = omapfb_setcmap,
1231         .fb_fillrect    = cfb_fillrect,
1232         .fb_copyarea    = cfb_copyarea,
1233         .fb_imageblit   = cfb_imageblit,
1234         .fb_blank       = omapfb_blank,
1235         .fb_ioctl       = omapfb_ioctl,
1236         .fb_check_var   = omapfb_check_var,
1237         .fb_set_par     = omapfb_set_par,
1238         .fb_pan_display = omapfb_pan_display,
1239 };
1240
1241 /*
1242  * ---------------------------------------------------------------------------
1243  * Sysfs interface
1244  * ---------------------------------------------------------------------------
1245  */
1246 /* omapfbX sysfs entries */
1247 static ssize_t omapfb_show_caps_num(struct device *dev,
1248                                     struct device_attribute *attr, char *buf)
1249 {
1250         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1251         int plane;
1252         size_t size;
1253         struct omapfb_caps caps;
1254
1255         plane = 0;
1256         size = 0;
1257         while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1258                 omapfb_get_caps(fbdev, plane, &caps);
1259                 size += snprintf(&buf[size], PAGE_SIZE - size,
1260                         "plane#%d %#010x %#010x %#010x\n",
1261                         plane, caps.ctrl, caps.plane_color, caps.wnd_color);
1262                 plane++;
1263         }
1264         return size;
1265 }
1266
1267 static ssize_t omapfb_show_caps_text(struct device *dev,
1268                                      struct device_attribute *attr, char *buf)
1269 {
1270         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1271         int i;
1272         struct omapfb_caps caps;
1273         int plane;
1274         size_t size;
1275
1276         plane = 0;
1277         size = 0;
1278         while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1279                 omapfb_get_caps(fbdev, plane, &caps);
1280                 size += snprintf(&buf[size], PAGE_SIZE - size,
1281                                  "plane#%d:\n", plane);
1282                 for (i = 0; i < ARRAY_SIZE(ctrl_caps) &&
1283                      size < PAGE_SIZE; i++) {
1284                         if (ctrl_caps[i].flag & caps.ctrl)
1285                                 size += snprintf(&buf[size], PAGE_SIZE - size,
1286                                         " %s\n", ctrl_caps[i].name);
1287                 }
1288                 size += snprintf(&buf[size], PAGE_SIZE - size,
1289                                  " plane colors:\n");
1290                 for (i = 0; i < ARRAY_SIZE(color_caps) &&
1291                      size < PAGE_SIZE; i++) {
1292                         if (color_caps[i].flag & caps.plane_color)
1293                                 size += snprintf(&buf[size], PAGE_SIZE - size,
1294                                         "  %s\n", color_caps[i].name);
1295                 }
1296                 size += snprintf(&buf[size], PAGE_SIZE - size,
1297                                  " window colors:\n");
1298                 for (i = 0; i < ARRAY_SIZE(color_caps) &&
1299                      size < PAGE_SIZE; i++) {
1300                         if (color_caps[i].flag & caps.wnd_color)
1301                                 size += snprintf(&buf[size], PAGE_SIZE - size,
1302                                         "  %s\n", color_caps[i].name);
1303                 }
1304
1305                 plane++;
1306         }
1307         return size;
1308 }
1309
1310 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1311 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1312
1313 /* panel sysfs entries */
1314 static ssize_t omapfb_show_panel_name(struct device *dev,
1315                                       struct device_attribute *attr, char *buf)
1316 {
1317         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1318
1319         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
1320 }
1321
1322 static ssize_t omapfb_show_bklight_level(struct device *dev,
1323                                          struct device_attribute *attr,
1324                                          char *buf)
1325 {
1326         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1327         int r;
1328
1329         if (fbdev->panel->get_bklight_level) {
1330                 r = snprintf(buf, PAGE_SIZE, "%d\n",
1331                              fbdev->panel->get_bklight_level(fbdev->panel));
1332         } else
1333                 r = -ENODEV;
1334         return r;
1335 }
1336
1337 static ssize_t omapfb_store_bklight_level(struct device *dev,
1338                                           struct device_attribute *attr,
1339                                           const char *buf, size_t size)
1340 {
1341         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1342         int r;
1343
1344         if (fbdev->panel->set_bklight_level) {
1345                 unsigned int level;
1346
1347                 if (sscanf(buf, "%10d", &level) == 1) {
1348                         r = fbdev->panel->set_bklight_level(fbdev->panel,
1349                                                             level);
1350                 } else
1351                         r = -EINVAL;
1352         } else
1353                 r = -ENODEV;
1354         return r ? r : size;
1355 }
1356
1357 static ssize_t omapfb_show_bklight_max(struct device *dev,
1358                                        struct device_attribute *attr, char *buf)
1359 {
1360         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1361         int r;
1362
1363         if (fbdev->panel->get_bklight_level) {
1364                 r = snprintf(buf, PAGE_SIZE, "%d\n",
1365                              fbdev->panel->get_bklight_max(fbdev->panel));
1366         } else
1367                 r = -ENODEV;
1368         return r;
1369 }
1370
1371 static struct device_attribute dev_attr_panel_name =
1372         __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1373 static DEVICE_ATTR(backlight_level, 0664,
1374                    omapfb_show_bklight_level, omapfb_store_bklight_level);
1375 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1376
1377 static struct attribute *panel_attrs[] = {
1378         &dev_attr_panel_name.attr,
1379         &dev_attr_backlight_level.attr,
1380         &dev_attr_backlight_max.attr,
1381         NULL,
1382 };
1383
1384 static struct attribute_group panel_attr_grp = {
1385         .name  = "panel",
1386         .attrs = panel_attrs,
1387 };
1388
1389 /* ctrl sysfs entries */
1390 static ssize_t omapfb_show_ctrl_name(struct device *dev,
1391                                      struct device_attribute *attr, char *buf)
1392 {
1393         struct omapfb_device *fbdev = dev_get_drvdata(dev);
1394
1395         return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
1396 }
1397
1398 static struct device_attribute dev_attr_ctrl_name =
1399         __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1400
1401 static struct attribute *ctrl_attrs[] = {
1402         &dev_attr_ctrl_name.attr,
1403         NULL,
1404 };
1405
1406 static struct attribute_group ctrl_attr_grp = {
1407         .name  = "ctrl",
1408         .attrs = ctrl_attrs,
1409 };
1410
1411 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
1412 {
1413         int r;
1414
1415         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
1416                 goto fail0;
1417
1418         if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1419                 goto fail1;
1420
1421         if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1422                 goto fail2;
1423
1424         if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1425                 goto fail3;
1426
1427         return 0;
1428 fail3:
1429         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1430 fail2:
1431         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1432 fail1:
1433         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1434 fail0:
1435         dev_err(fbdev->dev, "unable to register sysfs interface\n");
1436         return r;
1437 }
1438
1439 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1440 {
1441         sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1442         sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1443         device_remove_file(fbdev->dev, &dev_attr_caps_num);
1444         device_remove_file(fbdev->dev, &dev_attr_caps_text);
1445 }
1446
1447 /*
1448  * ---------------------------------------------------------------------------
1449  * LDM callbacks
1450  * ---------------------------------------------------------------------------
1451  */
1452 /* Initialize system fb_info object and set the default video mode.
1453  * The frame buffer memory already allocated by lcddma_init
1454  */
1455 static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info)
1456 {
1457         struct fb_var_screeninfo        *var = &info->var;
1458         struct fb_fix_screeninfo        *fix = &info->fix;
1459         int                             r = 0;
1460
1461         info->fbops = &omapfb_ops;
1462         info->flags = FBINFO_FLAG_DEFAULT;
1463
1464         strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
1465
1466         info->pseudo_palette = fbdev->pseudo_palette;
1467
1468         var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
1469         var->xres = def_vxres;
1470         var->yres = def_vyres;
1471         var->xres_virtual = def_vxres;
1472         var->yres_virtual = def_vyres;
1473         var->rotate       = def_rotate;
1474         var->bits_per_pixel = fbdev->panel->bpp;
1475
1476         set_fb_var(info, var);
1477         set_fb_fix(info, 1);
1478
1479         r = fb_alloc_cmap(&info->cmap, 16, 0);
1480         if (r != 0)
1481                 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1482
1483         return r;
1484 }
1485
1486 /* Release the fb_info object */
1487 static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1488 {
1489         fb_dealloc_cmap(&fbi->cmap);
1490 }
1491
1492 static void planes_cleanup(struct omapfb_device *fbdev)
1493 {
1494         int i;
1495
1496         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1497                 if (fbdev->fb_info[i] == NULL)
1498                         break;
1499                 fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
1500                 framebuffer_release(fbdev->fb_info[i]);
1501         }
1502 }
1503
1504 static int planes_init(struct omapfb_device *fbdev)
1505 {
1506         struct fb_info *fbi;
1507         int i;
1508         int r;
1509
1510         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1511                 struct omapfb_plane_struct *plane;
1512                 fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
1513                                         fbdev->dev);
1514                 if (fbi == NULL) {
1515                         dev_err(fbdev->dev,
1516                                 "unable to allocate memory for plane info\n");
1517                         planes_cleanup(fbdev);
1518                         return -ENOMEM;
1519                 }
1520                 plane = fbi->par;
1521                 plane->idx = i;
1522                 plane->fbdev = fbdev;
1523                 plane->info.mirror = def_mirror;
1524                 fbdev->fb_info[i] = fbi;
1525
1526                 if ((r = fbinfo_init(fbdev, fbi)) < 0) {
1527                         framebuffer_release(fbi);
1528                         planes_cleanup(fbdev);
1529                         return r;
1530                 }
1531                 plane->info.out_width = fbi->var.xres;
1532                 plane->info.out_height = fbi->var.yres;
1533         }
1534         return 0;
1535 }
1536
1537 /*
1538  * Free driver resources. Can be called to rollback an aborted initialization
1539  * sequence.
1540  */
1541 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1542 {
1543         int i;
1544
1545         switch (state) {
1546         case OMAPFB_ACTIVE:
1547                 for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
1548                         unregister_framebuffer(fbdev->fb_info[i]);
1549         case 7:
1550                 omapfb_unregister_sysfs(fbdev);
1551         case 6:
1552                 fbdev->panel->disable(fbdev->panel);
1553         case 5:
1554                 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1555         case 4:
1556                 planes_cleanup(fbdev);
1557         case 3:
1558                 ctrl_cleanup(fbdev);
1559         case 2:
1560                 fbdev->panel->cleanup(fbdev->panel);
1561         case 1:
1562                 dev_set_drvdata(fbdev->dev, NULL);
1563                 kfree(fbdev);
1564         case 0:
1565                 /* nothing to free */
1566                 break;
1567         default:
1568                 BUG();
1569         }
1570 }
1571
1572 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1573 {
1574         struct omapfb_platform_data *conf;
1575         char name[17];
1576         int i;
1577
1578         conf = dev_get_platdata(fbdev->dev);
1579
1580         fbdev->ctrl = NULL;
1581
1582         strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
1583         name[sizeof(name) - 1] = '\0';
1584
1585         if (strcmp(name, "internal") == 0) {
1586                 fbdev->ctrl = fbdev->int_ctrl;
1587                 return 0;
1588         }
1589
1590         for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1591                 dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
1592                 if (strcmp(ctrls[i]->name, name) == 0) {
1593                         fbdev->ctrl = ctrls[i];
1594                         break;
1595                 }
1596         }
1597
1598         if (fbdev->ctrl == NULL) {
1599                 dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
1600                 return -1;
1601         }
1602
1603         return 0;
1604 }
1605
1606 static void check_required_callbacks(struct omapfb_device *fbdev)
1607 {
1608 #define _C(x) (fbdev->ctrl->x != NULL)
1609 #define _P(x) (fbdev->panel->x != NULL)
1610         BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1611         BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1612                  _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1613                  _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1614                  _P(get_caps)));
1615 #undef _P
1616 #undef _C
1617 }
1618
1619 /*
1620  * Called by LDM binding to probe and attach a new device.
1621  * Initialization sequence:
1622  *   1. allocate system omapfb_device structure
1623  *   2. select controller type according to platform configuration
1624  *      init LCD panel
1625  *   3. init LCD controller and LCD DMA
1626  *   4. init system fb_info structure for all planes
1627  *   5. setup video mode for first plane and enable it
1628  *   6. enable LCD panel
1629  *   7. register sysfs attributes
1630  *   OMAPFB_ACTIVE: register system fb_info structure for all planes
1631  */
1632 static int omapfb_do_probe(struct platform_device *pdev,
1633                                 struct lcd_panel *panel)
1634 {
1635         struct omapfb_device    *fbdev = NULL;
1636         int                     init_state;
1637         unsigned long           phz, hhz, vhz;
1638         unsigned long           vram;
1639         int                     i;
1640         int                     r = 0;
1641
1642         init_state = 0;
1643
1644         if (pdev->num_resources != 0) {
1645                 dev_err(&pdev->dev, "probed for an unknown device\n");
1646                 r = -ENODEV;
1647                 goto cleanup;
1648         }
1649
1650         if (dev_get_platdata(&pdev->dev) == NULL) {
1651                 dev_err(&pdev->dev, "missing platform data\n");
1652                 r = -ENOENT;
1653                 goto cleanup;
1654         }
1655
1656         fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
1657         if (fbdev == NULL) {
1658                 dev_err(&pdev->dev,
1659                         "unable to allocate memory for device info\n");
1660                 r = -ENOMEM;
1661                 goto cleanup;
1662         }
1663         init_state++;
1664
1665         fbdev->dev = &pdev->dev;
1666         fbdev->panel = panel;
1667         fbdev->dssdev = &omapdss_device;
1668         platform_set_drvdata(pdev, fbdev);
1669
1670         mutex_init(&fbdev->rqueue_mutex);
1671
1672         fbdev->int_ctrl = &omap1_int_ctrl;
1673 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1674         fbdev->ext_if = &omap1_ext_if;
1675 #endif
1676         if (omapfb_find_ctrl(fbdev) < 0) {
1677                 dev_err(fbdev->dev,
1678                         "LCD controller not found, board not supported\n");
1679                 r = -ENODEV;
1680                 goto cleanup;
1681         }
1682
1683         r = fbdev->panel->init(fbdev->panel, fbdev);
1684         if (r)
1685                 goto cleanup;
1686
1687         pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
1688
1689         def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res;
1690         def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res;
1691
1692         init_state++;
1693
1694         r = ctrl_init(fbdev);
1695         if (r)
1696                 goto cleanup;
1697         if (fbdev->ctrl->mmap != NULL)
1698                 omapfb_ops.fb_mmap = omapfb_mmap;
1699         init_state++;
1700
1701         check_required_callbacks(fbdev);
1702
1703         r = planes_init(fbdev);
1704         if (r)
1705                 goto cleanup;
1706         init_state++;
1707
1708 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1709         /* Set DMA priority for EMIFF access to highest */
1710         omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
1711 #endif
1712
1713         r = ctrl_change_mode(fbdev->fb_info[0]);
1714         if (r) {
1715                 dev_err(fbdev->dev, "mode setting failed\n");
1716                 goto cleanup;
1717         }
1718
1719         /* GFX plane is enabled by default */
1720         r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
1721         if (r)
1722                 goto cleanup;
1723
1724         omapfb_set_update_mode(fbdev, manual_update ?
1725                                    OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1726         init_state++;
1727
1728         r = fbdev->panel->enable(fbdev->panel);
1729         if (r)
1730                 goto cleanup;
1731         init_state++;
1732
1733         r = omapfb_register_sysfs(fbdev);
1734         if (r)
1735                 goto cleanup;
1736         init_state++;
1737
1738         vram = 0;
1739         for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1740                 r = register_framebuffer(fbdev->fb_info[i]);
1741                 if (r != 0) {
1742                         dev_err(fbdev->dev,
1743                                 "registering framebuffer %d failed\n", i);
1744                         goto cleanup;
1745                 }
1746                 vram += fbdev->mem_desc.region[i].size;
1747         }
1748
1749         fbdev->state = OMAPFB_ACTIVE;
1750
1751         panel = fbdev->panel;
1752         phz = panel->pixel_clock * 1000;
1753         hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1754         vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1755
1756         omapfb_dev = fbdev;
1757
1758         pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
1759                         vram, fbdev->mem_desc.region_cnt);
1760         pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
1761                         "vfreq %lu.%lu Hz\n",
1762                         phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1763
1764         return 0;
1765
1766 cleanup:
1767         omapfb_free_resources(fbdev, init_state);
1768
1769         return r;
1770 }
1771
1772 static int omapfb_probe(struct platform_device *pdev)
1773 {
1774         int r;
1775
1776         BUG_ON(fbdev_pdev != NULL);
1777
1778         r = platform_device_register(&omapdss_device);
1779         if (r) {
1780                 dev_err(&pdev->dev, "can't register omapdss device\n");
1781                 return r;
1782         }
1783
1784         /* Delay actual initialization until the LCD is registered */
1785         fbdev_pdev = pdev;
1786         if (fbdev_panel != NULL)
1787                 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1788         return 0;
1789 }
1790
1791 void omapfb_register_panel(struct lcd_panel *panel)
1792 {
1793         BUG_ON(fbdev_panel != NULL);
1794
1795         fbdev_panel = panel;
1796         if (fbdev_pdev != NULL)
1797                 omapfb_do_probe(fbdev_pdev, fbdev_panel);
1798 }
1799 EXPORT_SYMBOL_GPL(omapfb_register_panel);
1800
1801 /* Called when the device is being detached from the driver */
1802 static int omapfb_remove(struct platform_device *pdev)
1803 {
1804         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1805         enum omapfb_state saved_state = fbdev->state;
1806
1807         /* FIXME: wait till completion of pending events */
1808
1809         fbdev->state = OMAPFB_DISABLED;
1810         omapfb_free_resources(fbdev, saved_state);
1811
1812         platform_device_unregister(&omapdss_device);
1813         fbdev->dssdev = NULL;
1814
1815         return 0;
1816 }
1817
1818 /* PM suspend */
1819 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1820 {
1821         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1822
1823         if (fbdev != NULL)
1824                 omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]);
1825         return 0;
1826 }
1827
1828 /* PM resume */
1829 static int omapfb_resume(struct platform_device *pdev)
1830 {
1831         struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1832
1833         if (fbdev != NULL)
1834                 omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]);
1835         return 0;
1836 }
1837
1838 static struct platform_driver omapfb_driver = {
1839         .probe          = omapfb_probe,
1840         .remove         = omapfb_remove,
1841         .suspend        = omapfb_suspend,
1842         .resume         = omapfb_resume,
1843         .driver         = {
1844                 .name   = MODULE_NAME,
1845         },
1846 };
1847
1848 #ifndef MODULE
1849
1850 /* Process kernel command line parameters */
1851 static int __init omapfb_setup(char *options)
1852 {
1853         char *this_opt = NULL;
1854         int r = 0;
1855
1856         pr_debug("omapfb: options %s\n", options);
1857
1858         if (!options || !*options)
1859                 return 0;
1860
1861         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1862                 if (!strncmp(this_opt, "accel", 5))
1863                         def_accel = 1;
1864                 else if (!strncmp(this_opt, "vram:", 5)) {
1865                         char *suffix;
1866                         unsigned long vram;
1867                         vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1868                         switch (suffix[0]) {
1869                         case '\0':
1870                                 break;
1871                         case 'm':
1872                         case 'M':
1873                                 vram *= 1024;
1874                                 /* Fall through */
1875                         case 'k':
1876                         case 'K':
1877                                 vram *= 1024;
1878                                 break;
1879                         default:
1880                                 pr_debug("omapfb: invalid vram suffix %c\n",
1881                                          suffix[0]);
1882                                 r = -1;
1883                         }
1884                         def_vram[def_vram_cnt++] = vram;
1885                 }
1886                 else if (!strncmp(this_opt, "vxres:", 6))
1887                         def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1888                 else if (!strncmp(this_opt, "vyres:", 6))
1889                         def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1890                 else if (!strncmp(this_opt, "rotate:", 7))
1891                         def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1892                 else if (!strncmp(this_opt, "mirror:", 7))
1893                         def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1894                 else if (!strncmp(this_opt, "manual_update", 13))
1895                         manual_update = 1;
1896                 else {
1897                         pr_debug("omapfb: invalid option\n");
1898                         r = -1;
1899                 }
1900         }
1901
1902         return r;
1903 }
1904
1905 #endif
1906
1907 /* Register both the driver and the device */
1908 static int __init omapfb_init(void)
1909 {
1910 #ifndef MODULE
1911         char *option;
1912
1913         if (fb_get_options("omapfb", &option))
1914                 return -ENODEV;
1915         omapfb_setup(option);
1916 #endif
1917         /* Register the driver with LDM */
1918         if (platform_driver_register(&omapfb_driver)) {
1919                 pr_debug("failed to register omapfb driver\n");
1920                 return -ENODEV;
1921         }
1922
1923         return 0;
1924 }
1925
1926 static void __exit omapfb_cleanup(void)
1927 {
1928         platform_driver_unregister(&omapfb_driver);
1929 }
1930
1931 module_param_named(accel, def_accel, uint, 0664);
1932 module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1933 module_param_named(vxres, def_vxres, long, 0664);
1934 module_param_named(vyres, def_vyres, long, 0664);
1935 module_param_named(rotate, def_rotate, uint, 0664);
1936 module_param_named(mirror, def_mirror, uint, 0664);
1937 module_param_named(manual_update, manual_update, bool, 0664);
1938
1939 module_init(omapfb_init);
1940 module_exit(omapfb_cleanup);
1941
1942 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1943 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1944 MODULE_LICENSE("GPL");