Merge branches 'at91', 'cache', 'cup', 'ep93xx', 'ixp4xx', 'nuc', 'pending-dma-stream...
[sfrench/cifs-2.6.git] / drivers / video / omap2 / omapfb / omapfb-main.c
1 /*
2  * linux/drivers/video/omap2/omapfb-main.c
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <linux/module.h>
24 #include <linux/delay.h>
25 #include <linux/fb.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/vmalloc.h>
28 #include <linux/device.h>
29 #include <linux/platform_device.h>
30 #include <linux/omapfb.h>
31
32 #include <plat/display.h>
33 #include <plat/vram.h>
34 #include <plat/vrfb.h>
35
36 #include "omapfb.h"
37
38 #define MODULE_NAME     "omapfb"
39
40 #define OMAPFB_PLANE_XRES_MIN           8
41 #define OMAPFB_PLANE_YRES_MIN           8
42
43 static char *def_mode;
44 static char *def_vram;
45 static int def_vrfb;
46 static int def_rotate;
47 static int def_mirror;
48
49 #ifdef DEBUG
50 unsigned int omapfb_debug;
51 module_param_named(debug, omapfb_debug, bool, 0644);
52 static unsigned int omapfb_test_pattern;
53 module_param_named(test, omapfb_test_pattern, bool, 0644);
54 #endif
55
56 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
57
58 #ifdef DEBUG
59 static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
60 {
61         struct fb_var_screeninfo *var = &fbi->var;
62         struct fb_fix_screeninfo *fix = &fbi->fix;
63         void __iomem *addr = fbi->screen_base;
64         const unsigned bytespp = var->bits_per_pixel >> 3;
65         const unsigned line_len = fix->line_length / bytespp;
66
67         int r = (color >> 16) & 0xff;
68         int g = (color >> 8) & 0xff;
69         int b = (color >> 0) & 0xff;
70
71         if (var->bits_per_pixel == 16) {
72                 u16 __iomem *p = (u16 __iomem *)addr;
73                 p += y * line_len + x;
74
75                 r = r * 32 / 256;
76                 g = g * 64 / 256;
77                 b = b * 32 / 256;
78
79                 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
80         } else if (var->bits_per_pixel == 24) {
81                 u8 __iomem *p = (u8 __iomem *)addr;
82                 p += (y * line_len + x) * 3;
83
84                 __raw_writeb(b, p + 0);
85                 __raw_writeb(g, p + 1);
86                 __raw_writeb(r, p + 2);
87         } else if (var->bits_per_pixel == 32) {
88                 u32 __iomem *p = (u32 __iomem *)addr;
89                 p += y * line_len + x;
90                 __raw_writel(color, p);
91         }
92 }
93
94 static void fill_fb(struct fb_info *fbi)
95 {
96         struct fb_var_screeninfo *var = &fbi->var;
97         const short w = var->xres_virtual;
98         const short h = var->yres_virtual;
99         void __iomem *addr = fbi->screen_base;
100         int y, x;
101
102         if (!addr)
103                 return;
104
105         DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
106
107         for (y = 0; y < h; y++) {
108                 for (x = 0; x < w; x++) {
109                         if (x < 20 && y < 20)
110                                 draw_pixel(fbi, x, y, 0xffffff);
111                         else if (x < 20 && (y > 20 && y < h - 20))
112                                 draw_pixel(fbi, x, y, 0xff);
113                         else if (y < 20 && (x > 20 && x < w - 20))
114                                 draw_pixel(fbi, x, y, 0xff00);
115                         else if (x > w - 20 && (y > 20 && y < h - 20))
116                                 draw_pixel(fbi, x, y, 0xff0000);
117                         else if (y > h - 20 && (x > 20 && x < w - 20))
118                                 draw_pixel(fbi, x, y, 0xffff00);
119                         else if (x == 20 || x == w - 20 ||
120                                         y == 20 || y == h - 20)
121                                 draw_pixel(fbi, x, y, 0xffffff);
122                         else if (x == y || w - x == h - y)
123                                 draw_pixel(fbi, x, y, 0xff00ff);
124                         else if (w - x == y || x == h - y)
125                                 draw_pixel(fbi, x, y, 0x00ffff);
126                         else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
127                                 int t = x * 3 / w;
128                                 unsigned r = 0, g = 0, b = 0;
129                                 unsigned c;
130                                 if (var->bits_per_pixel == 16) {
131                                         if (t == 0)
132                                                 b = (y % 32) * 256 / 32;
133                                         else if (t == 1)
134                                                 g = (y % 64) * 256 / 64;
135                                         else if (t == 2)
136                                                 r = (y % 32) * 256 / 32;
137                                 } else {
138                                         if (t == 0)
139                                                 b = (y % 256);
140                                         else if (t == 1)
141                                                 g = (y % 256);
142                                         else if (t == 2)
143                                                 r = (y % 256);
144                                 }
145                                 c = (r << 16) | (g << 8) | (b << 0);
146                                 draw_pixel(fbi, x, y, c);
147                         } else {
148                                 draw_pixel(fbi, x, y, 0);
149                         }
150                 }
151         }
152 }
153 #endif
154
155 static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
156 {
157         struct vrfb *vrfb = &ofbi->region.vrfb;
158         unsigned offset;
159
160         switch (rot) {
161         case FB_ROTATE_UR:
162                 offset = 0;
163                 break;
164         case FB_ROTATE_CW:
165                 offset = vrfb->yoffset;
166                 break;
167         case FB_ROTATE_UD:
168                 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
169                 break;
170         case FB_ROTATE_CCW:
171                 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
172                 break;
173         default:
174                 BUG();
175         }
176
177         offset *= vrfb->bytespp;
178
179         return offset;
180 }
181
182 static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
183 {
184         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
185                 return ofbi->region.vrfb.paddr[rot]
186                         + omapfb_get_vrfb_offset(ofbi, rot);
187         } else {
188                 return ofbi->region.paddr;
189         }
190 }
191
192 static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
193 {
194         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
195                 return ofbi->region.vrfb.paddr[0];
196         else
197                 return ofbi->region.paddr;
198 }
199
200 static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
201 {
202         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
203                 return ofbi->region.vrfb.vaddr[0];
204         else
205                 return ofbi->region.vaddr;
206 }
207
208 static struct omapfb_colormode omapfb_colormodes[] = {
209         {
210                 .dssmode = OMAP_DSS_COLOR_UYVY,
211                 .bits_per_pixel = 16,
212                 .nonstd = OMAPFB_COLOR_YUV422,
213         }, {
214                 .dssmode = OMAP_DSS_COLOR_YUV2,
215                 .bits_per_pixel = 16,
216                 .nonstd = OMAPFB_COLOR_YUY422,
217         }, {
218                 .dssmode = OMAP_DSS_COLOR_ARGB16,
219                 .bits_per_pixel = 16,
220                 .red    = { .length = 4, .offset = 8, .msb_right = 0 },
221                 .green  = { .length = 4, .offset = 4, .msb_right = 0 },
222                 .blue   = { .length = 4, .offset = 0, .msb_right = 0 },
223                 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
224         }, {
225                 .dssmode = OMAP_DSS_COLOR_RGB16,
226                 .bits_per_pixel = 16,
227                 .red    = { .length = 5, .offset = 11, .msb_right = 0 },
228                 .green  = { .length = 6, .offset = 5, .msb_right = 0 },
229                 .blue   = { .length = 5, .offset = 0, .msb_right = 0 },
230                 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
231         }, {
232                 .dssmode = OMAP_DSS_COLOR_RGB24P,
233                 .bits_per_pixel = 24,
234                 .red    = { .length = 8, .offset = 16, .msb_right = 0 },
235                 .green  = { .length = 8, .offset = 8, .msb_right = 0 },
236                 .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
237                 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
238         }, {
239                 .dssmode = OMAP_DSS_COLOR_RGB24U,
240                 .bits_per_pixel = 32,
241                 .red    = { .length = 8, .offset = 16, .msb_right = 0 },
242                 .green  = { .length = 8, .offset = 8, .msb_right = 0 },
243                 .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
244                 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
245         }, {
246                 .dssmode = OMAP_DSS_COLOR_ARGB32,
247                 .bits_per_pixel = 32,
248                 .red    = { .length = 8, .offset = 16, .msb_right = 0 },
249                 .green  = { .length = 8, .offset = 8, .msb_right = 0 },
250                 .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
251                 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
252         }, {
253                 .dssmode = OMAP_DSS_COLOR_RGBA32,
254                 .bits_per_pixel = 32,
255                 .red    = { .length = 8, .offset = 24, .msb_right = 0 },
256                 .green  = { .length = 8, .offset = 16, .msb_right = 0 },
257                 .blue   = { .length = 8, .offset = 8, .msb_right = 0 },
258                 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
259         }, {
260                 .dssmode = OMAP_DSS_COLOR_RGBX32,
261                 .bits_per_pixel = 32,
262                 .red    = { .length = 8, .offset = 24, .msb_right = 0 },
263                 .green  = { .length = 8, .offset = 16, .msb_right = 0 },
264                 .blue   = { .length = 8, .offset = 8, .msb_right = 0 },
265                 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
266         },
267 };
268
269 static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
270                 struct omapfb_colormode *color)
271 {
272         bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
273         {
274                 return f1->length == f2->length &&
275                         f1->offset == f2->offset &&
276                         f1->msb_right == f2->msb_right;
277         }
278
279         if (var->bits_per_pixel == 0 ||
280                         var->red.length == 0 ||
281                         var->blue.length == 0 ||
282                         var->green.length == 0)
283                 return 0;
284
285         return var->bits_per_pixel == color->bits_per_pixel &&
286                 cmp_component(&var->red, &color->red) &&
287                 cmp_component(&var->green, &color->green) &&
288                 cmp_component(&var->blue, &color->blue) &&
289                 cmp_component(&var->transp, &color->transp);
290 }
291
292 static void assign_colormode_to_var(struct fb_var_screeninfo *var,
293                 struct omapfb_colormode *color)
294 {
295         var->bits_per_pixel = color->bits_per_pixel;
296         var->nonstd = color->nonstd;
297         var->red = color->red;
298         var->green = color->green;
299         var->blue = color->blue;
300         var->transp = color->transp;
301 }
302
303 static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
304                 enum omap_color_mode *mode)
305 {
306         enum omap_color_mode dssmode;
307         int i;
308
309         /* first match with nonstd field */
310         if (var->nonstd) {
311                 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
312                         struct omapfb_colormode *m = &omapfb_colormodes[i];
313                         if (var->nonstd == m->nonstd) {
314                                 assign_colormode_to_var(var, m);
315                                 *mode = m->dssmode;
316                                 return 0;
317                         }
318                 }
319
320                 return -EINVAL;
321         }
322
323         /* then try exact match of bpp and colors */
324         for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
325                 struct omapfb_colormode *m = &omapfb_colormodes[i];
326                 if (cmp_var_to_colormode(var, m)) {
327                         assign_colormode_to_var(var, m);
328                         *mode = m->dssmode;
329                         return 0;
330                 }
331         }
332
333         /* match with bpp if user has not filled color fields
334          * properly */
335         switch (var->bits_per_pixel) {
336         case 1:
337                 dssmode = OMAP_DSS_COLOR_CLUT1;
338                 break;
339         case 2:
340                 dssmode = OMAP_DSS_COLOR_CLUT2;
341                 break;
342         case 4:
343                 dssmode = OMAP_DSS_COLOR_CLUT4;
344                 break;
345         case 8:
346                 dssmode = OMAP_DSS_COLOR_CLUT8;
347                 break;
348         case 12:
349                 dssmode = OMAP_DSS_COLOR_RGB12U;
350                 break;
351         case 16:
352                 dssmode = OMAP_DSS_COLOR_RGB16;
353                 break;
354         case 24:
355                 dssmode = OMAP_DSS_COLOR_RGB24P;
356                 break;
357         case 32:
358                 dssmode = OMAP_DSS_COLOR_RGB24U;
359                 break;
360         default:
361                 return -EINVAL;
362         }
363
364         for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
365                 struct omapfb_colormode *m = &omapfb_colormodes[i];
366                 if (dssmode == m->dssmode) {
367                         assign_colormode_to_var(var, m);
368                         *mode = m->dssmode;
369                         return 0;
370                 }
371         }
372
373         return -EINVAL;
374 }
375
376 static int check_fb_res_bounds(struct fb_var_screeninfo *var)
377 {
378         int xres_min = OMAPFB_PLANE_XRES_MIN;
379         int xres_max = 2048;
380         int yres_min = OMAPFB_PLANE_YRES_MIN;
381         int yres_max = 2048;
382
383         /* XXX: some applications seem to set virtual res to 0. */
384         if (var->xres_virtual == 0)
385                 var->xres_virtual = var->xres;
386
387         if (var->yres_virtual == 0)
388                 var->yres_virtual = var->yres;
389
390         if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
391                 return -EINVAL;
392
393         if (var->xres < xres_min)
394                 var->xres = xres_min;
395         if (var->yres < yres_min)
396                 var->yres = yres_min;
397         if (var->xres > xres_max)
398                 var->xres = xres_max;
399         if (var->yres > yres_max)
400                 var->yres = yres_max;
401
402         if (var->xres > var->xres_virtual)
403                 var->xres = var->xres_virtual;
404         if (var->yres > var->yres_virtual)
405                 var->yres = var->yres_virtual;
406
407         return 0;
408 }
409
410 static void shrink_height(unsigned long max_frame_size,
411                 struct fb_var_screeninfo *var)
412 {
413         DBG("can't fit FB into memory, reducing y\n");
414         var->yres_virtual = max_frame_size /
415                 (var->xres_virtual * var->bits_per_pixel >> 3);
416
417         if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
418                 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
419
420         if (var->yres > var->yres_virtual)
421                 var->yres = var->yres_virtual;
422 }
423
424 static void shrink_width(unsigned long max_frame_size,
425                 struct fb_var_screeninfo *var)
426 {
427         DBG("can't fit FB into memory, reducing x\n");
428         var->xres_virtual = max_frame_size / var->yres_virtual /
429                 (var->bits_per_pixel >> 3);
430
431         if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
432                 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
433
434         if (var->xres > var->xres_virtual)
435                 var->xres = var->xres_virtual;
436 }
437
438 static int check_vrfb_fb_size(unsigned long region_size,
439                 const struct fb_var_screeninfo *var)
440 {
441         unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
442                 var->yres_virtual, var->bits_per_pixel >> 3);
443
444         return min_phys_size > region_size ? -EINVAL : 0;
445 }
446
447 static int check_fb_size(const struct omapfb_info *ofbi,
448                 struct fb_var_screeninfo *var)
449 {
450         unsigned long max_frame_size = ofbi->region.size;
451         int bytespp = var->bits_per_pixel >> 3;
452         unsigned long line_size = var->xres_virtual * bytespp;
453
454         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
455                 /* One needs to check for both VRFB and OMAPFB limitations. */
456                 if (check_vrfb_fb_size(max_frame_size, var))
457                         shrink_height(omap_vrfb_max_height(
458                                 max_frame_size, var->xres_virtual, bytespp) *
459                                 line_size, var);
460
461                 if (check_vrfb_fb_size(max_frame_size, var)) {
462                         DBG("cannot fit FB to memory\n");
463                         return -EINVAL;
464                 }
465
466                 return 0;
467         }
468
469         DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
470
471         if (line_size * var->yres_virtual > max_frame_size)
472                 shrink_height(max_frame_size, var);
473
474         if (line_size * var->yres_virtual > max_frame_size) {
475                 shrink_width(max_frame_size, var);
476                 line_size = var->xres_virtual * bytespp;
477         }
478
479         if (line_size * var->yres_virtual > max_frame_size) {
480                 DBG("cannot fit FB to memory\n");
481                 return -EINVAL;
482         }
483
484         return 0;
485 }
486
487 /*
488  * Consider if VRFB assisted rotation is in use and if the virtual space for
489  * the zero degree view needs to be mapped. The need for mapping also acts as
490  * the trigger for setting up the hardware on the context in question. This
491  * ensures that one does not attempt to access the virtual view before the
492  * hardware is serving the address translations.
493  */
494 static int setup_vrfb_rotation(struct fb_info *fbi)
495 {
496         struct omapfb_info *ofbi = FB2OFB(fbi);
497         struct omapfb2_mem_region *rg = &ofbi->region;
498         struct vrfb *vrfb = &rg->vrfb;
499         struct fb_var_screeninfo *var = &fbi->var;
500         struct fb_fix_screeninfo *fix = &fbi->fix;
501         unsigned bytespp;
502         bool yuv_mode;
503         enum omap_color_mode mode;
504         int r;
505         bool reconf;
506
507         if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
508                 return 0;
509
510         DBG("setup_vrfb_rotation\n");
511
512         r = fb_mode_to_dss_mode(var, &mode);
513         if (r)
514                 return r;
515
516         bytespp = var->bits_per_pixel >> 3;
517
518         yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
519
520         /* We need to reconfigure VRFB if the resolution changes, if yuv mode
521          * is enabled/disabled, or if bytes per pixel changes */
522
523         /* XXX we shouldn't allow this when framebuffer is mmapped */
524
525         reconf = false;
526
527         if (yuv_mode != vrfb->yuv_mode)
528                 reconf = true;
529         else if (bytespp != vrfb->bytespp)
530                 reconf = true;
531         else if (vrfb->xres != var->xres_virtual ||
532                         vrfb->yres != var->yres_virtual)
533                 reconf = true;
534
535         if (vrfb->vaddr[0] && reconf) {
536                 fbi->screen_base = NULL;
537                 fix->smem_start = 0;
538                 fix->smem_len = 0;
539                 iounmap(vrfb->vaddr[0]);
540                 vrfb->vaddr[0] = NULL;
541                 DBG("setup_vrfb_rotation: reset fb\n");
542         }
543
544         if (vrfb->vaddr[0])
545                 return 0;
546
547         omap_vrfb_setup(&rg->vrfb, rg->paddr,
548                         var->xres_virtual,
549                         var->yres_virtual,
550                         bytespp, yuv_mode);
551
552         /* Now one can ioremap the 0 angle view */
553         r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
554         if (r)
555                 return r;
556
557         /* used by open/write in fbmem.c */
558         fbi->screen_base = ofbi->region.vrfb.vaddr[0];
559
560         fix->smem_start = ofbi->region.vrfb.paddr[0];
561
562         switch (var->nonstd) {
563         case OMAPFB_COLOR_YUV422:
564         case OMAPFB_COLOR_YUY422:
565                 fix->line_length =
566                         (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
567                 break;
568         default:
569                 fix->line_length =
570                         (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
571                 break;
572         }
573
574         fix->smem_len = var->yres_virtual * fix->line_length;
575
576         return 0;
577 }
578
579 int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
580                         struct fb_var_screeninfo *var)
581 {
582         int i;
583
584         for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
585                 struct omapfb_colormode *mode = &omapfb_colormodes[i];
586                 if (dssmode == mode->dssmode) {
587                         assign_colormode_to_var(var, mode);
588                         return 0;
589                 }
590         }
591         return -ENOENT;
592 }
593
594 void set_fb_fix(struct fb_info *fbi)
595 {
596         struct fb_fix_screeninfo *fix = &fbi->fix;
597         struct fb_var_screeninfo *var = &fbi->var;
598         struct omapfb_info *ofbi = FB2OFB(fbi);
599         struct omapfb2_mem_region *rg = &ofbi->region;
600
601         DBG("set_fb_fix\n");
602
603         /* used by open/write in fbmem.c */
604         fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
605
606         /* used by mmap in fbmem.c */
607         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
608                 switch (var->nonstd) {
609                 case OMAPFB_COLOR_YUV422:
610                 case OMAPFB_COLOR_YUY422:
611                         fix->line_length =
612                                 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
613                         break;
614                 default:
615                         fix->line_length =
616                                 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
617                         break;
618                 }
619
620                 fix->smem_len = var->yres_virtual * fix->line_length;
621         } else {
622                 fix->line_length =
623                         (var->xres_virtual * var->bits_per_pixel) >> 3;
624                 fix->smem_len = rg->size;
625         }
626
627         fix->smem_start = omapfb_get_region_paddr(ofbi);
628
629         fix->type = FB_TYPE_PACKED_PIXELS;
630
631         if (var->nonstd)
632                 fix->visual = FB_VISUAL_PSEUDOCOLOR;
633         else {
634                 switch (var->bits_per_pixel) {
635                 case 32:
636                 case 24:
637                 case 16:
638                 case 12:
639                         fix->visual = FB_VISUAL_TRUECOLOR;
640                         /* 12bpp is stored in 16 bits */
641                         break;
642                 case 1:
643                 case 2:
644                 case 4:
645                 case 8:
646                         fix->visual = FB_VISUAL_PSEUDOCOLOR;
647                         break;
648                 }
649         }
650
651         fix->accel = FB_ACCEL_NONE;
652
653         fix->xpanstep = 1;
654         fix->ypanstep = 1;
655 }
656
657 /* check new var and possibly modify it to be ok */
658 int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
659 {
660         struct omapfb_info *ofbi = FB2OFB(fbi);
661         struct omap_dss_device *display = fb2display(fbi);
662         enum omap_color_mode mode = 0;
663         int i;
664         int r;
665
666         DBG("check_fb_var %d\n", ofbi->id);
667
668         if (ofbi->region.size == 0)
669                 return 0;
670
671         r = fb_mode_to_dss_mode(var, &mode);
672         if (r) {
673                 DBG("cannot convert var to omap dss mode\n");
674                 return r;
675         }
676
677         for (i = 0; i < ofbi->num_overlays; ++i) {
678                 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
679                         DBG("invalid mode\n");
680                         return -EINVAL;
681                 }
682         }
683
684         if (var->rotate < 0 || var->rotate > 3)
685                 return -EINVAL;
686
687         if (check_fb_res_bounds(var))
688                 return -EINVAL;
689
690         if (check_fb_size(ofbi, var))
691                 return -EINVAL;
692
693         if (var->xres + var->xoffset > var->xres_virtual)
694                 var->xoffset = var->xres_virtual - var->xres;
695         if (var->yres + var->yoffset > var->yres_virtual)
696                 var->yoffset = var->yres_virtual - var->yres;
697
698         DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
699                         var->xres, var->yres,
700                         var->xres_virtual, var->yres_virtual);
701
702         var->height             = -1;
703         var->width              = -1;
704         var->grayscale          = 0;
705
706         if (display && display->get_timings) {
707                 struct omap_video_timings timings;
708                 display->get_timings(display, &timings);
709
710                 /* pixclock in ps, the rest in pixclock */
711                 var->pixclock = timings.pixel_clock != 0 ?
712                         KHZ2PICOS(timings.pixel_clock) :
713                         0;
714                 var->left_margin = timings.hfp;
715                 var->right_margin = timings.hbp;
716                 var->upper_margin = timings.vfp;
717                 var->lower_margin = timings.vbp;
718                 var->hsync_len = timings.hsw;
719                 var->vsync_len = timings.vsw;
720         } else {
721                 var->pixclock = 0;
722                 var->left_margin = 0;
723                 var->right_margin = 0;
724                 var->upper_margin = 0;
725                 var->lower_margin = 0;
726                 var->hsync_len = 0;
727                 var->vsync_len = 0;
728         }
729
730         /* TODO: get these from panel->config */
731         var->vmode              = FB_VMODE_NONINTERLACED;
732         var->sync               = 0;
733
734         return 0;
735 }
736
737 /*
738  * ---------------------------------------------------------------------------
739  * fbdev framework callbacks
740  * ---------------------------------------------------------------------------
741  */
742 static int omapfb_open(struct fb_info *fbi, int user)
743 {
744         return 0;
745 }
746
747 static int omapfb_release(struct fb_info *fbi, int user)
748 {
749 #if 0
750         struct omapfb_info *ofbi = FB2OFB(fbi);
751         struct omapfb2_device *fbdev = ofbi->fbdev;
752         struct omap_dss_device *display = fb2display(fbi);
753
754         DBG("Closing fb with plane index %d\n", ofbi->id);
755
756         omapfb_lock(fbdev);
757
758         if (display && display->get_update_mode && display->update) {
759                 /* XXX this update should be removed, I think. But it's
760                  * good for debugging */
761                 if (display->get_update_mode(display) ==
762                                 OMAP_DSS_UPDATE_MANUAL) {
763                         u16 w, h;
764
765                         if (display->sync)
766                                 display->sync(display);
767
768                         display->get_resolution(display, &w, &h);
769                         display->update(display, 0, 0, w, h);
770                 }
771         }
772
773         if (display && display->sync)
774                 display->sync(display);
775
776         omapfb_unlock(fbdev);
777 #endif
778         return 0;
779 }
780
781 static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
782                 struct fb_fix_screeninfo *fix, int rotation)
783 {
784         unsigned offset;
785
786         offset = var->yoffset * fix->line_length +
787                 var->xoffset * (var->bits_per_pixel >> 3);
788
789         return offset;
790 }
791
792 static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
793                 struct fb_fix_screeninfo *fix, int rotation)
794 {
795         unsigned offset;
796
797         if (rotation == FB_ROTATE_UD)
798                 offset = (var->yres_virtual - var->yres) *
799                         fix->line_length;
800         else if (rotation == FB_ROTATE_CW)
801                 offset = (var->yres_virtual - var->yres) *
802                         (var->bits_per_pixel >> 3);
803         else
804                 offset = 0;
805
806         if (rotation == FB_ROTATE_UR)
807                 offset += var->yoffset * fix->line_length +
808                         var->xoffset * (var->bits_per_pixel >> 3);
809         else if (rotation == FB_ROTATE_UD)
810                 offset -= var->yoffset * fix->line_length +
811                         var->xoffset * (var->bits_per_pixel >> 3);
812         else if (rotation == FB_ROTATE_CW)
813                 offset -= var->xoffset * fix->line_length +
814                         var->yoffset * (var->bits_per_pixel >> 3);
815         else if (rotation == FB_ROTATE_CCW)
816                 offset += var->xoffset * fix->line_length +
817                         var->yoffset * (var->bits_per_pixel >> 3);
818
819         return offset;
820 }
821
822
823 /* setup overlay according to the fb */
824 static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
825                 u16 posx, u16 posy, u16 outw, u16 outh)
826 {
827         int r = 0;
828         struct omapfb_info *ofbi = FB2OFB(fbi);
829         struct fb_var_screeninfo *var = &fbi->var;
830         struct fb_fix_screeninfo *fix = &fbi->fix;
831         enum omap_color_mode mode = 0;
832         int offset;
833         u32 data_start_p;
834         void __iomem *data_start_v;
835         struct omap_overlay_info info;
836         int xres, yres;
837         int screen_width;
838         int mirror;
839         int rotation = var->rotate;
840         int i;
841
842         for (i = 0; i < ofbi->num_overlays; i++) {
843                 if (ovl != ofbi->overlays[i])
844                         continue;
845
846                 rotation = (rotation + ofbi->rotation[i]) % 4;
847                 break;
848         }
849
850         DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
851                         posx, posy, outw, outh);
852
853         if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
854                 xres = var->yres;
855                 yres = var->xres;
856         } else {
857                 xres = var->xres;
858                 yres = var->yres;
859         }
860
861
862         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
863                 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
864                 data_start_v = NULL;
865         } else {
866                 data_start_p = omapfb_get_region_paddr(ofbi);
867                 data_start_v = omapfb_get_region_vaddr(ofbi);
868         }
869
870         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
871                 offset = calc_rotation_offset_vrfb(var, fix, rotation);
872         else
873                 offset = calc_rotation_offset_dma(var, fix, rotation);
874
875         data_start_p += offset;
876         data_start_v += offset;
877
878         if (offset)
879                 DBG("offset %d, %d = %d\n",
880                                 var->xoffset, var->yoffset, offset);
881
882         DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
883
884         r = fb_mode_to_dss_mode(var, &mode);
885         if (r) {
886                 DBG("fb_mode_to_dss_mode failed");
887                 goto err;
888         }
889
890         switch (var->nonstd) {
891         case OMAPFB_COLOR_YUV422:
892         case OMAPFB_COLOR_YUY422:
893                 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
894                         screen_width = fix->line_length
895                                 / (var->bits_per_pixel >> 2);
896                         break;
897                 }
898         default:
899                 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
900                 break;
901         }
902
903         ovl->get_overlay_info(ovl, &info);
904
905         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
906                 mirror = 0;
907         else
908                 mirror = ofbi->mirror;
909
910         info.paddr = data_start_p;
911         info.vaddr = data_start_v;
912         info.screen_width = screen_width;
913         info.width = xres;
914         info.height = yres;
915         info.color_mode = mode;
916         info.rotation_type = ofbi->rotation_type;
917         info.rotation = rotation;
918         info.mirror = mirror;
919
920         info.pos_x = posx;
921         info.pos_y = posy;
922         info.out_width = outw;
923         info.out_height = outh;
924
925         r = ovl->set_overlay_info(ovl, &info);
926         if (r) {
927                 DBG("ovl->setup_overlay_info failed\n");
928                 goto err;
929         }
930
931         return 0;
932
933 err:
934         DBG("setup_overlay failed\n");
935         return r;
936 }
937
938 /* apply var to the overlay */
939 int omapfb_apply_changes(struct fb_info *fbi, int init)
940 {
941         int r = 0;
942         struct omapfb_info *ofbi = FB2OFB(fbi);
943         struct fb_var_screeninfo *var = &fbi->var;
944         struct omap_overlay *ovl;
945         u16 posx, posy;
946         u16 outw, outh;
947         int i;
948
949 #ifdef DEBUG
950         if (omapfb_test_pattern)
951                 fill_fb(fbi);
952 #endif
953
954         for (i = 0; i < ofbi->num_overlays; i++) {
955                 ovl = ofbi->overlays[i];
956
957                 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
958
959                 if (ofbi->region.size == 0) {
960                         /* the fb is not available. disable the overlay */
961                         omapfb_overlay_enable(ovl, 0);
962                         if (!init && ovl->manager)
963                                 ovl->manager->apply(ovl->manager);
964                         continue;
965                 }
966
967                 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
968                         int rotation = (var->rotate + ofbi->rotation[i]) % 4;
969                         if (rotation == FB_ROTATE_CW ||
970                                         rotation == FB_ROTATE_CCW) {
971                                 outw = var->yres;
972                                 outh = var->xres;
973                         } else {
974                                 outw = var->xres;
975                                 outh = var->yres;
976                         }
977                 } else {
978                         outw = ovl->info.out_width;
979                         outh = ovl->info.out_height;
980                 }
981
982                 if (init) {
983                         posx = 0;
984                         posy = 0;
985                 } else {
986                         posx = ovl->info.pos_x;
987                         posy = ovl->info.pos_y;
988                 }
989
990                 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
991                 if (r)
992                         goto err;
993
994                 if (!init && ovl->manager)
995                         ovl->manager->apply(ovl->manager);
996         }
997         return 0;
998 err:
999         DBG("apply_changes failed\n");
1000         return r;
1001 }
1002
1003 /* checks var and eventually tweaks it to something supported,
1004  * DO NOT MODIFY PAR */
1005 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1006 {
1007         int r;
1008
1009         DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1010
1011         r = check_fb_var(fbi, var);
1012
1013         return r;
1014 }
1015
1016 /* set the video mode according to info->var */
1017 static int omapfb_set_par(struct fb_info *fbi)
1018 {
1019         int r;
1020
1021         DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1022
1023         set_fb_fix(fbi);
1024
1025         r = setup_vrfb_rotation(fbi);
1026         if (r)
1027                 return r;
1028
1029         r = omapfb_apply_changes(fbi, 0);
1030
1031         return r;
1032 }
1033
1034 static int omapfb_pan_display(struct fb_var_screeninfo *var,
1035                 struct fb_info *fbi)
1036 {
1037         struct fb_var_screeninfo new_var;
1038         int r;
1039
1040         DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1041
1042         if (var->xoffset == fbi->var.xoffset &&
1043             var->yoffset == fbi->var.yoffset)
1044                 return 0;
1045
1046         new_var = fbi->var;
1047         new_var.xoffset = var->xoffset;
1048         new_var.yoffset = var->yoffset;
1049
1050         fbi->var = new_var;
1051
1052         r = omapfb_apply_changes(fbi, 0);
1053
1054         return r;
1055 }
1056
1057 static void mmap_user_open(struct vm_area_struct *vma)
1058 {
1059         struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1060
1061         atomic_inc(&ofbi->map_count);
1062 }
1063
1064 static void mmap_user_close(struct vm_area_struct *vma)
1065 {
1066         struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1067
1068         atomic_dec(&ofbi->map_count);
1069 }
1070
1071 static struct vm_operations_struct mmap_user_ops = {
1072         .open = mmap_user_open,
1073         .close = mmap_user_close,
1074 };
1075
1076 static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1077 {
1078         struct omapfb_info *ofbi = FB2OFB(fbi);
1079         struct fb_fix_screeninfo *fix = &fbi->fix;
1080         unsigned long off;
1081         unsigned long start;
1082         u32 len;
1083
1084         if (vma->vm_end - vma->vm_start == 0)
1085                 return 0;
1086         if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1087                 return -EINVAL;
1088         off = vma->vm_pgoff << PAGE_SHIFT;
1089
1090         start = omapfb_get_region_paddr(ofbi);
1091         len = fix->smem_len;
1092         if (off >= len)
1093                 return -EINVAL;
1094         if ((vma->vm_end - vma->vm_start + off) > len)
1095                 return -EINVAL;
1096
1097         off += start;
1098
1099         DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1100
1101         vma->vm_pgoff = off >> PAGE_SHIFT;
1102         vma->vm_flags |= VM_IO | VM_RESERVED;
1103         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1104         vma->vm_ops = &mmap_user_ops;
1105         vma->vm_private_data = ofbi;
1106         if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1107                              vma->vm_end - vma->vm_start, vma->vm_page_prot))
1108                 return -EAGAIN;
1109         /* vm_ops.open won't be called for mmap itself. */
1110         atomic_inc(&ofbi->map_count);
1111         return 0;
1112 }
1113
1114 /* Store a single color palette entry into a pseudo palette or the hardware
1115  * palette if one is available. For now we support only 16bpp and thus store
1116  * the entry only to the pseudo palette.
1117  */
1118 static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1119                 u_int blue, u_int transp, int update_hw_pal)
1120 {
1121         /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1122         /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1123         struct fb_var_screeninfo *var = &fbi->var;
1124         int r = 0;
1125
1126         enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1127
1128         /*switch (plane->color_mode) {*/
1129         switch (mode) {
1130         case OMAPFB_COLOR_YUV422:
1131         case OMAPFB_COLOR_YUV420:
1132         case OMAPFB_COLOR_YUY422:
1133                 r = -EINVAL;
1134                 break;
1135         case OMAPFB_COLOR_CLUT_8BPP:
1136         case OMAPFB_COLOR_CLUT_4BPP:
1137         case OMAPFB_COLOR_CLUT_2BPP:
1138         case OMAPFB_COLOR_CLUT_1BPP:
1139                 /*
1140                    if (fbdev->ctrl->setcolreg)
1141                    r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1142                    transp, update_hw_pal);
1143                    */
1144                 /* Fallthrough */
1145                 r = -EINVAL;
1146                 break;
1147         case OMAPFB_COLOR_RGB565:
1148         case OMAPFB_COLOR_RGB444:
1149         case OMAPFB_COLOR_RGB24P:
1150         case OMAPFB_COLOR_RGB24U:
1151                 if (r != 0)
1152                         break;
1153
1154                 if (regno < 0) {
1155                         r = -EINVAL;
1156                         break;
1157                 }
1158
1159                 if (regno < 16) {
1160                         u16 pal;
1161                         pal = ((red >> (16 - var->red.length)) <<
1162                                         var->red.offset) |
1163                                 ((green >> (16 - var->green.length)) <<
1164                                  var->green.offset) |
1165                                 (blue >> (16 - var->blue.length));
1166                         ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1167                 }
1168                 break;
1169         default:
1170                 BUG();
1171         }
1172         return r;
1173 }
1174
1175 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1176                 u_int transp, struct fb_info *info)
1177 {
1178         DBG("setcolreg\n");
1179
1180         return _setcolreg(info, regno, red, green, blue, transp, 1);
1181 }
1182
1183 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1184 {
1185         int count, index, r;
1186         u16 *red, *green, *blue, *transp;
1187         u16 trans = 0xffff;
1188
1189         DBG("setcmap\n");
1190
1191         red     = cmap->red;
1192         green   = cmap->green;
1193         blue    = cmap->blue;
1194         transp  = cmap->transp;
1195         index   = cmap->start;
1196
1197         for (count = 0; count < cmap->len; count++) {
1198                 if (transp)
1199                         trans = *transp++;
1200                 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1201                                 count == cmap->len - 1);
1202                 if (r != 0)
1203                         return r;
1204         }
1205
1206         return 0;
1207 }
1208
1209 static int omapfb_blank(int blank, struct fb_info *fbi)
1210 {
1211         struct omapfb_info *ofbi = FB2OFB(fbi);
1212         struct omapfb2_device *fbdev = ofbi->fbdev;
1213         struct omap_dss_device *display = fb2display(fbi);
1214         int do_update = 0;
1215         int r = 0;
1216
1217         omapfb_lock(fbdev);
1218
1219         switch (blank) {
1220         case FB_BLANK_UNBLANK:
1221                 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1222                         goto exit;
1223
1224                 if (display->resume)
1225                         r = display->resume(display);
1226
1227                 if (r == 0 && display->get_update_mode &&
1228                                 display->get_update_mode(display) ==
1229                                 OMAP_DSS_UPDATE_MANUAL)
1230                         do_update = 1;
1231
1232                 break;
1233
1234         case FB_BLANK_NORMAL:
1235                 /* FB_BLANK_NORMAL could be implemented.
1236                  * Needs DSS additions. */
1237         case FB_BLANK_VSYNC_SUSPEND:
1238         case FB_BLANK_HSYNC_SUSPEND:
1239         case FB_BLANK_POWERDOWN:
1240                 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1241                         goto exit;
1242
1243                 if (display->suspend)
1244                         r = display->suspend(display);
1245
1246                 break;
1247
1248         default:
1249                 r = -EINVAL;
1250         }
1251
1252 exit:
1253         omapfb_unlock(fbdev);
1254
1255         if (r == 0 && do_update && display->update) {
1256                 u16 w, h;
1257                 display->get_resolution(display, &w, &h);
1258
1259                 r = display->update(display, 0, 0, w, h);
1260         }
1261
1262         return r;
1263 }
1264
1265 #if 0
1266 /* XXX fb_read and fb_write are needed for VRFB */
1267 ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1268                 size_t count, loff_t *ppos)
1269 {
1270         DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1271         /* XXX needed for VRFB */
1272         return count;
1273 }
1274 #endif
1275
1276 static struct fb_ops omapfb_ops = {
1277         .owner          = THIS_MODULE,
1278         .fb_open        = omapfb_open,
1279         .fb_release     = omapfb_release,
1280         .fb_fillrect    = cfb_fillrect,
1281         .fb_copyarea    = cfb_copyarea,
1282         .fb_imageblit   = cfb_imageblit,
1283         .fb_blank       = omapfb_blank,
1284         .fb_ioctl       = omapfb_ioctl,
1285         .fb_check_var   = omapfb_check_var,
1286         .fb_set_par     = omapfb_set_par,
1287         .fb_pan_display = omapfb_pan_display,
1288         .fb_mmap        = omapfb_mmap,
1289         .fb_setcolreg   = omapfb_setcolreg,
1290         .fb_setcmap     = omapfb_setcmap,
1291         /*.fb_write     = omapfb_write,*/
1292 };
1293
1294 static void omapfb_free_fbmem(struct fb_info *fbi)
1295 {
1296         struct omapfb_info *ofbi = FB2OFB(fbi);
1297         struct omapfb2_device *fbdev = ofbi->fbdev;
1298         struct omapfb2_mem_region *rg;
1299
1300         rg = &ofbi->region;
1301
1302         if (rg->paddr)
1303                 if (omap_vram_free(rg->paddr, rg->size))
1304                         dev_err(fbdev->dev, "VRAM FREE failed\n");
1305
1306         if (rg->vaddr)
1307                 iounmap(rg->vaddr);
1308
1309         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1310                 /* unmap the 0 angle rotation */
1311                 if (rg->vrfb.vaddr[0]) {
1312                         iounmap(rg->vrfb.vaddr[0]);
1313                         omap_vrfb_release_ctx(&rg->vrfb);
1314                         rg->vrfb.vaddr[0] = NULL;
1315                 }
1316         }
1317
1318         rg->vaddr = NULL;
1319         rg->paddr = 0;
1320         rg->alloc = 0;
1321         rg->size = 0;
1322 }
1323
1324 static void clear_fb_info(struct fb_info *fbi)
1325 {
1326         memset(&fbi->var, 0, sizeof(fbi->var));
1327         memset(&fbi->fix, 0, sizeof(fbi->fix));
1328         strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1329 }
1330
1331 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1332 {
1333         int i;
1334
1335         DBG("free all fbmem\n");
1336
1337         for (i = 0; i < fbdev->num_fbs; i++) {
1338                 struct fb_info *fbi = fbdev->fbs[i];
1339                 omapfb_free_fbmem(fbi);
1340                 clear_fb_info(fbi);
1341         }
1342
1343         return 0;
1344 }
1345
1346 static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1347                 unsigned long paddr)
1348 {
1349         struct omapfb_info *ofbi = FB2OFB(fbi);
1350         struct omapfb2_device *fbdev = ofbi->fbdev;
1351         struct omapfb2_mem_region *rg;
1352         void __iomem *vaddr;
1353         int r;
1354
1355         rg = &ofbi->region;
1356         memset(rg, 0, sizeof(*rg));
1357
1358         size = PAGE_ALIGN(size);
1359
1360         if (!paddr) {
1361                 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1362                 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1363         } else {
1364                 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1365                                 ofbi->id);
1366                 r = omap_vram_reserve(paddr, size);
1367         }
1368
1369         if (r) {
1370                 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1371                 return -ENOMEM;
1372         }
1373
1374         if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1375                 vaddr = ioremap_wc(paddr, size);
1376
1377                 if (!vaddr) {
1378                         dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1379                         omap_vram_free(paddr, size);
1380                         return -ENOMEM;
1381                 }
1382
1383                 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1384         } else {
1385                 r = omap_vrfb_request_ctx(&rg->vrfb);
1386                 if (r) {
1387                         dev_err(fbdev->dev, "vrfb create ctx failed\n");
1388                         return r;
1389                 }
1390
1391                 vaddr = NULL;
1392         }
1393
1394         rg->paddr = paddr;
1395         rg->vaddr = vaddr;
1396         rg->size = size;
1397         rg->alloc = 1;
1398
1399         return 0;
1400 }
1401
1402 /* allocate fbmem using display resolution as reference */
1403 static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1404                 unsigned long paddr)
1405 {
1406         struct omapfb_info *ofbi = FB2OFB(fbi);
1407         struct omap_dss_device *display;
1408         int bytespp;
1409
1410         display =  fb2display(fbi);
1411
1412         if (!display)
1413                 return 0;
1414
1415         switch (display->get_recommended_bpp(display)) {
1416         case 16:
1417                 bytespp = 2;
1418                 break;
1419         case 24:
1420                 bytespp = 4;
1421                 break;
1422         default:
1423                 bytespp = 4;
1424                 break;
1425         }
1426
1427         if (!size) {
1428                 u16 w, h;
1429
1430                 display->get_resolution(display, &w, &h);
1431
1432                 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1433                         size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1434                                         omap_vrfb_min_phys_size(h, w, bytespp));
1435
1436                         DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1437                                         w * h * bytespp, size);
1438                 } else {
1439                         size = w * h * bytespp;
1440                 }
1441         }
1442
1443         if (!size)
1444                 return 0;
1445
1446         return omapfb_alloc_fbmem(fbi, size, paddr);
1447 }
1448
1449 static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1450 {
1451         enum omap_color_mode mode;
1452
1453         switch (fmt) {
1454         case OMAPFB_COLOR_RGB565:
1455                 mode = OMAP_DSS_COLOR_RGB16;
1456                 break;
1457         case OMAPFB_COLOR_YUV422:
1458                 mode = OMAP_DSS_COLOR_YUV2;
1459                 break;
1460         case OMAPFB_COLOR_CLUT_8BPP:
1461                 mode = OMAP_DSS_COLOR_CLUT8;
1462                 break;
1463         case OMAPFB_COLOR_CLUT_4BPP:
1464                 mode = OMAP_DSS_COLOR_CLUT4;
1465                 break;
1466         case OMAPFB_COLOR_CLUT_2BPP:
1467                 mode = OMAP_DSS_COLOR_CLUT2;
1468                 break;
1469         case OMAPFB_COLOR_CLUT_1BPP:
1470                 mode = OMAP_DSS_COLOR_CLUT1;
1471                 break;
1472         case OMAPFB_COLOR_RGB444:
1473                 mode = OMAP_DSS_COLOR_RGB12U;
1474                 break;
1475         case OMAPFB_COLOR_YUY422:
1476                 mode = OMAP_DSS_COLOR_UYVY;
1477                 break;
1478         case OMAPFB_COLOR_ARGB16:
1479                 mode = OMAP_DSS_COLOR_ARGB16;
1480                 break;
1481         case OMAPFB_COLOR_RGB24U:
1482                 mode = OMAP_DSS_COLOR_RGB24U;
1483                 break;
1484         case OMAPFB_COLOR_RGB24P:
1485                 mode = OMAP_DSS_COLOR_RGB24P;
1486                 break;
1487         case OMAPFB_COLOR_ARGB32:
1488                 mode = OMAP_DSS_COLOR_ARGB32;
1489                 break;
1490         case OMAPFB_COLOR_RGBA32:
1491                 mode = OMAP_DSS_COLOR_RGBA32;
1492                 break;
1493         case OMAPFB_COLOR_RGBX32:
1494                 mode = OMAP_DSS_COLOR_RGBX32;
1495                 break;
1496         default:
1497                 mode = -EINVAL;
1498         }
1499
1500         return mode;
1501 }
1502
1503 static int omapfb_parse_vram_param(const char *param, int max_entries,
1504                 unsigned long *sizes, unsigned long *paddrs)
1505 {
1506         int fbnum;
1507         unsigned long size;
1508         unsigned long paddr = 0;
1509         char *p, *start;
1510
1511         start = (char *)param;
1512
1513         while (1) {
1514                 p = start;
1515
1516                 fbnum = simple_strtoul(p, &p, 10);
1517
1518                 if (p == param)
1519                         return -EINVAL;
1520
1521                 if (*p != ':')
1522                         return -EINVAL;
1523
1524                 if (fbnum >= max_entries)
1525                         return -EINVAL;
1526
1527                 size = memparse(p + 1, &p);
1528
1529                 if (!size)
1530                         return -EINVAL;
1531
1532                 paddr = 0;
1533
1534                 if (*p == '@') {
1535                         paddr = simple_strtoul(p + 1, &p, 16);
1536
1537                         if (!paddr)
1538                                 return -EINVAL;
1539
1540                 }
1541
1542                 paddrs[fbnum] = paddr;
1543                 sizes[fbnum] = size;
1544
1545                 if (*p == 0)
1546                         break;
1547
1548                 if (*p != ',')
1549                         return -EINVAL;
1550
1551                 ++p;
1552
1553                 start = p;
1554         }
1555
1556         return 0;
1557 }
1558
1559 static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1560 {
1561         int i, r;
1562         unsigned long vram_sizes[10];
1563         unsigned long vram_paddrs[10];
1564
1565         memset(&vram_sizes, 0, sizeof(vram_sizes));
1566         memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1567
1568         if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1569                                 vram_sizes, vram_paddrs)) {
1570                 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1571
1572                 memset(&vram_sizes, 0, sizeof(vram_sizes));
1573                 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1574         }
1575
1576         if (fbdev->dev->platform_data) {
1577                 struct omapfb_platform_data *opd;
1578                 opd = fbdev->dev->platform_data;
1579                 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1580                         if (!vram_sizes[i]) {
1581                                 unsigned long size;
1582                                 unsigned long paddr;
1583
1584                                 size = opd->mem_desc.region[i].size;
1585                                 paddr = opd->mem_desc.region[i].paddr;
1586
1587                                 vram_sizes[i] = size;
1588                                 vram_paddrs[i] = paddr;
1589                         }
1590                 }
1591         }
1592
1593         for (i = 0; i < fbdev->num_fbs; i++) {
1594                 /* allocate memory automatically only for fb0, or if
1595                  * excplicitly defined with vram or plat data option */
1596                 if (i == 0 || vram_sizes[i] != 0) {
1597                         r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1598                                         vram_sizes[i], vram_paddrs[i]);
1599
1600                         if (r)
1601                                 return r;
1602                 }
1603         }
1604
1605         for (i = 0; i < fbdev->num_fbs; i++) {
1606                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1607                 struct omapfb2_mem_region *rg;
1608                 rg = &ofbi->region;
1609
1610                 DBG("region%d phys %08x virt %p size=%lu\n",
1611                                 i,
1612                                 rg->paddr,
1613                                 rg->vaddr,
1614                                 rg->size);
1615         }
1616
1617         return 0;
1618 }
1619
1620 int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1621 {
1622         struct omapfb_info *ofbi = FB2OFB(fbi);
1623         struct omapfb2_device *fbdev = ofbi->fbdev;
1624         struct omap_dss_device *display = fb2display(fbi);
1625         struct omapfb2_mem_region *rg = &ofbi->region;
1626         unsigned long old_size = rg->size;
1627         unsigned long old_paddr = rg->paddr;
1628         int old_type = rg->type;
1629         int r;
1630
1631         if (type > OMAPFB_MEMTYPE_MAX)
1632                 return -EINVAL;
1633
1634         size = PAGE_ALIGN(size);
1635
1636         if (old_size == size && old_type == type)
1637                 return 0;
1638
1639         if (display && display->sync)
1640                         display->sync(display);
1641
1642         omapfb_free_fbmem(fbi);
1643
1644         if (size == 0) {
1645                 clear_fb_info(fbi);
1646                 return 0;
1647         }
1648
1649         r = omapfb_alloc_fbmem(fbi, size, 0);
1650
1651         if (r) {
1652                 if (old_size)
1653                         omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1654
1655                 if (rg->size == 0)
1656                         clear_fb_info(fbi);
1657
1658                 return r;
1659         }
1660
1661         if (old_size == size)
1662                 return 0;
1663
1664         if (old_size == 0) {
1665                 DBG("initializing fb %d\n", ofbi->id);
1666                 r = omapfb_fb_init(fbdev, fbi);
1667                 if (r) {
1668                         DBG("omapfb_fb_init failed\n");
1669                         goto err;
1670                 }
1671                 r = omapfb_apply_changes(fbi, 1);
1672                 if (r) {
1673                         DBG("omapfb_apply_changes failed\n");
1674                         goto err;
1675                 }
1676         } else {
1677                 struct fb_var_screeninfo new_var;
1678                 memcpy(&new_var, &fbi->var, sizeof(new_var));
1679                 r = check_fb_var(fbi, &new_var);
1680                 if (r)
1681                         goto err;
1682                 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1683                 set_fb_fix(fbi);
1684                 r = setup_vrfb_rotation(fbi);
1685                 if (r)
1686                         goto err;
1687         }
1688
1689         return 0;
1690 err:
1691         omapfb_free_fbmem(fbi);
1692         clear_fb_info(fbi);
1693         return r;
1694 }
1695
1696 /* initialize fb_info, var, fix to something sane based on the display */
1697 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1698 {
1699         struct fb_var_screeninfo *var = &fbi->var;
1700         struct omap_dss_device *display = fb2display(fbi);
1701         struct omapfb_info *ofbi = FB2OFB(fbi);
1702         int r = 0;
1703
1704         fbi->fbops = &omapfb_ops;
1705         fbi->flags = FBINFO_FLAG_DEFAULT;
1706         fbi->pseudo_palette = fbdev->pseudo_palette;
1707
1708         if (ofbi->region.size == 0) {
1709                 clear_fb_info(fbi);
1710                 return 0;
1711         }
1712
1713         var->nonstd = 0;
1714         var->bits_per_pixel = 0;
1715
1716         var->rotate = def_rotate;
1717
1718         /*
1719          * Check if there is a default color format set in the board file,
1720          * and use this format instead the default deducted from the
1721          * display bpp.
1722          */
1723         if (fbdev->dev->platform_data) {
1724                 struct omapfb_platform_data *opd;
1725                 int id = ofbi->id;
1726
1727                 opd = fbdev->dev->platform_data;
1728                 if (opd->mem_desc.region[id].format_used) {
1729                         enum omap_color_mode mode;
1730                         enum omapfb_color_format format;
1731
1732                         format = opd->mem_desc.region[id].format;
1733                         mode = fb_format_to_dss_mode(format);
1734                         if (mode < 0) {
1735                                 r = mode;
1736                                 goto err;
1737                         }
1738                         r = dss_mode_to_fb_mode(mode, var);
1739                         if (r < 0)
1740                                 goto err;
1741                 }
1742         }
1743
1744         if (display) {
1745                 u16 w, h;
1746                 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1747
1748                 display->get_resolution(display, &w, &h);
1749
1750                 if (rotation == FB_ROTATE_CW ||
1751                                 rotation == FB_ROTATE_CCW) {
1752                         var->xres = h;
1753                         var->yres = w;
1754                 } else {
1755                         var->xres = w;
1756                         var->yres = h;
1757                 }
1758
1759                 var->xres_virtual = var->xres;
1760                 var->yres_virtual = var->yres;
1761
1762                 if (!var->bits_per_pixel) {
1763                         switch (display->get_recommended_bpp(display)) {
1764                         case 16:
1765                                 var->bits_per_pixel = 16;
1766                                 break;
1767                         case 24:
1768                                 var->bits_per_pixel = 32;
1769                                 break;
1770                         default:
1771                                 dev_err(fbdev->dev, "illegal display "
1772                                                 "bpp\n");
1773                                 return -EINVAL;
1774                         }
1775                 }
1776         } else {
1777                 /* if there's no display, let's just guess some basic values */
1778                 var->xres = 320;
1779                 var->yres = 240;
1780                 var->xres_virtual = var->xres;
1781                 var->yres_virtual = var->yres;
1782                 if (!var->bits_per_pixel)
1783                         var->bits_per_pixel = 16;
1784         }
1785
1786         r = check_fb_var(fbi, var);
1787         if (r)
1788                 goto err;
1789
1790         set_fb_fix(fbi);
1791         r = setup_vrfb_rotation(fbi);
1792         if (r)
1793                 goto err;
1794
1795         r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1796         if (r)
1797                 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1798
1799 err:
1800         return r;
1801 }
1802
1803 static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1804 {
1805         fb_dealloc_cmap(&fbi->cmap);
1806 }
1807
1808
1809 static void omapfb_free_resources(struct omapfb2_device *fbdev)
1810 {
1811         int i;
1812
1813         DBG("free_resources\n");
1814
1815         if (fbdev == NULL)
1816                 return;
1817
1818         for (i = 0; i < fbdev->num_fbs; i++)
1819                 unregister_framebuffer(fbdev->fbs[i]);
1820
1821         /* free the reserved fbmem */
1822         omapfb_free_all_fbmem(fbdev);
1823
1824         for (i = 0; i < fbdev->num_fbs; i++) {
1825                 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1826                 framebuffer_release(fbdev->fbs[i]);
1827         }
1828
1829         for (i = 0; i < fbdev->num_displays; i++) {
1830                 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1831                         fbdev->displays[i]->disable(fbdev->displays[i]);
1832
1833                 omap_dss_put_device(fbdev->displays[i]);
1834         }
1835
1836         dev_set_drvdata(fbdev->dev, NULL);
1837         kfree(fbdev);
1838 }
1839
1840 static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1841 {
1842         int r, i;
1843
1844         fbdev->num_fbs = 0;
1845
1846         DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1847
1848         /* allocate fb_infos */
1849         for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1850                 struct fb_info *fbi;
1851                 struct omapfb_info *ofbi;
1852
1853                 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1854                                 fbdev->dev);
1855
1856                 if (fbi == NULL) {
1857                         dev_err(fbdev->dev,
1858                                 "unable to allocate memory for plane info\n");
1859                         return -ENOMEM;
1860                 }
1861
1862                 clear_fb_info(fbi);
1863
1864                 fbdev->fbs[i] = fbi;
1865
1866                 ofbi = FB2OFB(fbi);
1867                 ofbi->fbdev = fbdev;
1868                 ofbi->id = i;
1869
1870                 /* assign these early, so that fb alloc can use them */
1871                 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1872                         OMAP_DSS_ROT_DMA;
1873                 ofbi->mirror = def_mirror;
1874
1875                 fbdev->num_fbs++;
1876         }
1877
1878         DBG("fb_infos allocated\n");
1879
1880         /* assign overlays for the fbs */
1881         for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1882                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1883
1884                 ofbi->overlays[0] = fbdev->overlays[i];
1885                 ofbi->num_overlays = 1;
1886         }
1887
1888         /* allocate fb memories */
1889         r = omapfb_allocate_all_fbs(fbdev);
1890         if (r) {
1891                 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1892                 return r;
1893         }
1894
1895         DBG("fbmems allocated\n");
1896
1897         /* setup fb_infos */
1898         for (i = 0; i < fbdev->num_fbs; i++) {
1899                 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1900                 if (r) {
1901                         dev_err(fbdev->dev, "failed to setup fb_info\n");
1902                         return r;
1903                 }
1904         }
1905
1906         DBG("fb_infos initialized\n");
1907
1908         for (i = 0; i < fbdev->num_fbs; i++) {
1909                 r = register_framebuffer(fbdev->fbs[i]);
1910                 if (r != 0) {
1911                         dev_err(fbdev->dev,
1912                                 "registering framebuffer %d failed\n", i);
1913                         return r;
1914                 }
1915         }
1916
1917         DBG("framebuffers registered\n");
1918
1919         for (i = 0; i < fbdev->num_fbs; i++) {
1920                 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1921                 if (r) {
1922                         dev_err(fbdev->dev, "failed to change mode\n");
1923                         return r;
1924                 }
1925         }
1926
1927         DBG("create sysfs for fbs\n");
1928         r = omapfb_create_sysfs(fbdev);
1929         if (r) {
1930                 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1931                 return r;
1932         }
1933
1934         /* Enable fb0 */
1935         if (fbdev->num_fbs > 0) {
1936                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1937
1938                 if (ofbi->num_overlays > 0) {
1939                         struct omap_overlay *ovl = ofbi->overlays[0];
1940
1941                         r = omapfb_overlay_enable(ovl, 1);
1942
1943                         if (r) {
1944                                 dev_err(fbdev->dev,
1945                                                 "failed to enable overlay\n");
1946                                 return r;
1947                         }
1948                 }
1949         }
1950
1951         DBG("create_framebuffers done\n");
1952
1953         return 0;
1954 }
1955
1956 static int omapfb_mode_to_timings(const char *mode_str,
1957                 struct omap_video_timings *timings, u8 *bpp)
1958 {
1959         struct fb_info fbi;
1960         struct fb_var_screeninfo var;
1961         struct fb_ops fbops;
1962         int r;
1963
1964 #ifdef CONFIG_OMAP2_DSS_VENC
1965         if (strcmp(mode_str, "pal") == 0) {
1966                 *timings = omap_dss_pal_timings;
1967                 *bpp = 0;
1968                 return 0;
1969         } else if (strcmp(mode_str, "ntsc") == 0) {
1970                 *timings = omap_dss_ntsc_timings;
1971                 *bpp = 0;
1972                 return 0;
1973         }
1974 #endif
1975
1976         /* this is quite a hack, but I wanted to use the modedb and for
1977          * that we need fb_info and var, so we create dummy ones */
1978
1979         memset(&fbi, 0, sizeof(fbi));
1980         memset(&var, 0, sizeof(var));
1981         memset(&fbops, 0, sizeof(fbops));
1982         fbi.fbops = &fbops;
1983
1984         r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1985
1986         if (r != 0) {
1987                 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1988                 timings->hfp = var.left_margin;
1989                 timings->hbp = var.right_margin;
1990                 timings->vfp = var.upper_margin;
1991                 timings->vbp = var.lower_margin;
1992                 timings->hsw = var.hsync_len;
1993                 timings->vsw = var.vsync_len;
1994                 timings->x_res = var.xres;
1995                 timings->y_res = var.yres;
1996
1997                 switch (var.bits_per_pixel) {
1998                 case 16:
1999                         *bpp = 16;
2000                         break;
2001                 case 24:
2002                 case 32:
2003                 default:
2004                         *bpp = 24;
2005                         break;
2006                 }
2007
2008                 return 0;
2009         } else {
2010                 return -EINVAL;
2011         }
2012 }
2013
2014 static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
2015 {
2016         int r;
2017         u8 bpp;
2018         struct omap_video_timings timings;
2019
2020         r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2021         if (r)
2022                 return r;
2023
2024         display->panel.recommended_bpp = bpp;
2025
2026         if (!display->check_timings || !display->set_timings)
2027                 return -EINVAL;
2028
2029         r = display->check_timings(display, &timings);
2030         if (r)
2031                 return r;
2032
2033         display->set_timings(display, &timings);
2034
2035         return 0;
2036 }
2037
2038 static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2039 {
2040         char *str, *options, *this_opt;
2041         int r = 0;
2042
2043         str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2044         strcpy(str, def_mode);
2045         options = str;
2046
2047         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2048                 char *p, *display_str, *mode_str;
2049                 struct omap_dss_device *display;
2050                 int i;
2051
2052                 p = strchr(this_opt, ':');
2053                 if (!p) {
2054                         r = -EINVAL;
2055                         break;
2056                 }
2057
2058                 *p = 0;
2059                 display_str = this_opt;
2060                 mode_str = p + 1;
2061
2062                 display = NULL;
2063                 for (i = 0; i < fbdev->num_displays; ++i) {
2064                         if (strcmp(fbdev->displays[i]->name,
2065                                                 display_str) == 0) {
2066                                 display = fbdev->displays[i];
2067                                 break;
2068                         }
2069                 }
2070
2071                 if (!display) {
2072                         r = -EINVAL;
2073                         break;
2074                 }
2075
2076                 r = omapfb_set_def_mode(display, mode_str);
2077                 if (r)
2078                         break;
2079         }
2080
2081         kfree(str);
2082
2083         return r;
2084 }
2085
2086 static int omapfb_probe(struct platform_device *pdev)
2087 {
2088         struct omapfb2_device *fbdev = NULL;
2089         int r = 0;
2090         int i;
2091         struct omap_overlay *ovl;
2092         struct omap_dss_device *def_display;
2093         struct omap_dss_device *dssdev;
2094
2095         DBG("omapfb_probe\n");
2096
2097         if (pdev->num_resources != 0) {
2098                 dev_err(&pdev->dev, "probed for an unknown device\n");
2099                 r = -ENODEV;
2100                 goto err0;
2101         }
2102
2103         fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2104         if (fbdev == NULL) {
2105                 r = -ENOMEM;
2106                 goto err0;
2107         }
2108
2109         mutex_init(&fbdev->mtx);
2110
2111         fbdev->dev = &pdev->dev;
2112         platform_set_drvdata(pdev, fbdev);
2113
2114         fbdev->num_displays = 0;
2115         dssdev = NULL;
2116         for_each_dss_dev(dssdev) {
2117                 omap_dss_get_device(dssdev);
2118                 if (!dssdev->driver) {
2119                         dev_err(&pdev->dev, "no driver for display\n");
2120                         r = -EINVAL;
2121                         goto cleanup;
2122                 }
2123                 fbdev->displays[fbdev->num_displays++] = dssdev;
2124         }
2125
2126         if (fbdev->num_displays == 0) {
2127                 dev_err(&pdev->dev, "no displays\n");
2128                 r = -EINVAL;
2129                 goto cleanup;
2130         }
2131
2132         fbdev->num_overlays = omap_dss_get_num_overlays();
2133         for (i = 0; i < fbdev->num_overlays; i++)
2134                 fbdev->overlays[i] = omap_dss_get_overlay(i);
2135
2136         fbdev->num_managers = omap_dss_get_num_overlay_managers();
2137         for (i = 0; i < fbdev->num_managers; i++)
2138                 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2139
2140         if (def_mode && strlen(def_mode) > 0) {
2141                 if (omapfb_parse_def_modes(fbdev))
2142                         dev_warn(&pdev->dev, "cannot parse default modes\n");
2143         }
2144
2145         r = omapfb_create_framebuffers(fbdev);
2146         if (r)
2147                 goto cleanup;
2148
2149         for (i = 0; i < fbdev->num_managers; i++) {
2150                 struct omap_overlay_manager *mgr;
2151                 mgr = fbdev->managers[i];
2152                 r = mgr->apply(mgr);
2153                 if (r)
2154                         dev_warn(fbdev->dev, "failed to apply dispc config\n");
2155         }
2156
2157         DBG("mgr->apply'ed\n");
2158
2159         /* gfx overlay should be the default one. find a display
2160          * connected to that, and use it as default display */
2161         ovl = omap_dss_get_overlay(0);
2162         if (ovl->manager && ovl->manager->device) {
2163                 def_display = ovl->manager->device;
2164         } else {
2165                 dev_warn(&pdev->dev, "cannot find default display\n");
2166                 def_display = NULL;
2167         }
2168
2169         if (def_display) {
2170 #ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2171                 u16 w, h;
2172 #endif
2173                 r = def_display->enable(def_display);
2174                 if (r)
2175                         dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2176                                         def_display->name);
2177
2178                 /* set the update mode */
2179                 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2180 #ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2181                         if (def_display->enable_te)
2182                                 def_display->enable_te(def_display, 1);
2183                         if (def_display->set_update_mode)
2184                                 def_display->set_update_mode(def_display,
2185                                                 OMAP_DSS_UPDATE_AUTO);
2186 #else /* MANUAL_UPDATE */
2187                         if (def_display->enable_te)
2188                                 def_display->enable_te(def_display, 0);
2189                         if (def_display->set_update_mode)
2190                                 def_display->set_update_mode(def_display,
2191                                                 OMAP_DSS_UPDATE_MANUAL);
2192
2193                         def_display->get_resolution(def_display, &w, &h);
2194                         def_display->update(def_display, 0, 0, w, h);
2195 #endif
2196                 } else {
2197                         if (def_display->set_update_mode)
2198                                 def_display->set_update_mode(def_display,
2199                                                 OMAP_DSS_UPDATE_AUTO);
2200                 }
2201         }
2202
2203         return 0;
2204
2205 cleanup:
2206         omapfb_free_resources(fbdev);
2207 err0:
2208         dev_err(&pdev->dev, "failed to setup omapfb\n");
2209         return r;
2210 }
2211
2212 static int omapfb_remove(struct platform_device *pdev)
2213 {
2214         struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2215
2216         /* FIXME: wait till completion of pending events */
2217
2218         omapfb_remove_sysfs(fbdev);
2219
2220         omapfb_free_resources(fbdev);
2221
2222         return 0;
2223 }
2224
2225 static struct platform_driver omapfb_driver = {
2226         .probe          = omapfb_probe,
2227         .remove         = omapfb_remove,
2228         .driver         = {
2229                 .name   = "omapfb",
2230                 .owner  = THIS_MODULE,
2231         },
2232 };
2233
2234 static int __init omapfb_init(void)
2235 {
2236         DBG("omapfb_init\n");
2237
2238         if (platform_driver_register(&omapfb_driver)) {
2239                 printk(KERN_ERR "failed to register omapfb driver\n");
2240                 return -ENODEV;
2241         }
2242
2243         return 0;
2244 }
2245
2246 static void __exit omapfb_exit(void)
2247 {
2248         DBG("omapfb_exit\n");
2249         platform_driver_unregister(&omapfb_driver);
2250 }
2251
2252 module_param_named(mode, def_mode, charp, 0);
2253 module_param_named(vram, def_vram, charp, 0);
2254 module_param_named(rotate, def_rotate, int, 0);
2255 module_param_named(vrfb, def_vrfb, bool, 0);
2256 module_param_named(mirror, def_mirror, bool, 0);
2257
2258 /* late_initcall to let panel/ctrl drivers loaded first.
2259  * I guess better option would be a more dynamic approach,
2260  * so that omapfb reacts to new panels when they are loaded */
2261 late_initcall(omapfb_init);
2262 /*module_init(omapfb_init);*/
2263 module_exit(omapfb_exit);
2264
2265 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2266 MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2267 MODULE_LICENSE("GPL v2");