ef299839858aa5b87c4826fdd1bd36127c5072d1
[cascardo/linux.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                 }
1315         }
1316
1317         rg->vaddr = NULL;
1318         rg->paddr = 0;
1319         rg->alloc = 0;
1320         rg->size = 0;
1321 }
1322
1323 static void clear_fb_info(struct fb_info *fbi)
1324 {
1325         memset(&fbi->var, 0, sizeof(fbi->var));
1326         memset(&fbi->fix, 0, sizeof(fbi->fix));
1327         strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1328 }
1329
1330 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1331 {
1332         int i;
1333
1334         DBG("free all fbmem\n");
1335
1336         for (i = 0; i < fbdev->num_fbs; i++) {
1337                 struct fb_info *fbi = fbdev->fbs[i];
1338                 omapfb_free_fbmem(fbi);
1339                 clear_fb_info(fbi);
1340         }
1341
1342         return 0;
1343 }
1344
1345 static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1346                 unsigned long paddr)
1347 {
1348         struct omapfb_info *ofbi = FB2OFB(fbi);
1349         struct omapfb2_device *fbdev = ofbi->fbdev;
1350         struct omapfb2_mem_region *rg;
1351         void __iomem *vaddr;
1352         int r;
1353
1354         rg = &ofbi->region;
1355         memset(rg, 0, sizeof(*rg));
1356
1357         size = PAGE_ALIGN(size);
1358
1359         if (!paddr) {
1360                 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1361                 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1362         } else {
1363                 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1364                                 ofbi->id);
1365                 r = omap_vram_reserve(paddr, size);
1366         }
1367
1368         if (r) {
1369                 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1370                 return -ENOMEM;
1371         }
1372
1373         if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1374                 vaddr = ioremap_wc(paddr, size);
1375
1376                 if (!vaddr) {
1377                         dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1378                         omap_vram_free(paddr, size);
1379                         return -ENOMEM;
1380                 }
1381
1382                 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1383         } else {
1384                 r = omap_vrfb_request_ctx(&rg->vrfb);
1385                 if (r) {
1386                         dev_err(fbdev->dev, "vrfb create ctx failed\n");
1387                         return r;
1388                 }
1389
1390                 vaddr = NULL;
1391         }
1392
1393         rg->paddr = paddr;
1394         rg->vaddr = vaddr;
1395         rg->size = size;
1396         rg->alloc = 1;
1397
1398         return 0;
1399 }
1400
1401 /* allocate fbmem using display resolution as reference */
1402 static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1403                 unsigned long paddr)
1404 {
1405         struct omapfb_info *ofbi = FB2OFB(fbi);
1406         struct omap_dss_device *display;
1407         int bytespp;
1408
1409         display =  fb2display(fbi);
1410
1411         if (!display)
1412                 return 0;
1413
1414         switch (display->get_recommended_bpp(display)) {
1415         case 16:
1416                 bytespp = 2;
1417                 break;
1418         case 24:
1419                 bytespp = 4;
1420                 break;
1421         default:
1422                 bytespp = 4;
1423                 break;
1424         }
1425
1426         if (!size) {
1427                 u16 w, h;
1428
1429                 display->get_resolution(display, &w, &h);
1430
1431                 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1432                         size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1433                                         omap_vrfb_min_phys_size(h, w, bytespp));
1434
1435                         DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1436                                         w * h * bytespp, size);
1437                 } else {
1438                         size = w * h * bytespp;
1439                 }
1440         }
1441
1442         if (!size)
1443                 return 0;
1444
1445         return omapfb_alloc_fbmem(fbi, size, paddr);
1446 }
1447
1448 static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1449 {
1450         enum omap_color_mode mode;
1451
1452         switch (fmt) {
1453         case OMAPFB_COLOR_RGB565:
1454                 mode = OMAP_DSS_COLOR_RGB16;
1455                 break;
1456         case OMAPFB_COLOR_YUV422:
1457                 mode = OMAP_DSS_COLOR_YUV2;
1458                 break;
1459         case OMAPFB_COLOR_CLUT_8BPP:
1460                 mode = OMAP_DSS_COLOR_CLUT8;
1461                 break;
1462         case OMAPFB_COLOR_CLUT_4BPP:
1463                 mode = OMAP_DSS_COLOR_CLUT4;
1464                 break;
1465         case OMAPFB_COLOR_CLUT_2BPP:
1466                 mode = OMAP_DSS_COLOR_CLUT2;
1467                 break;
1468         case OMAPFB_COLOR_CLUT_1BPP:
1469                 mode = OMAP_DSS_COLOR_CLUT1;
1470                 break;
1471         case OMAPFB_COLOR_RGB444:
1472                 mode = OMAP_DSS_COLOR_RGB12U;
1473                 break;
1474         case OMAPFB_COLOR_YUY422:
1475                 mode = OMAP_DSS_COLOR_UYVY;
1476                 break;
1477         case OMAPFB_COLOR_ARGB16:
1478                 mode = OMAP_DSS_COLOR_ARGB16;
1479                 break;
1480         case OMAPFB_COLOR_RGB24U:
1481                 mode = OMAP_DSS_COLOR_RGB24U;
1482                 break;
1483         case OMAPFB_COLOR_RGB24P:
1484                 mode = OMAP_DSS_COLOR_RGB24P;
1485                 break;
1486         case OMAPFB_COLOR_ARGB32:
1487                 mode = OMAP_DSS_COLOR_ARGB32;
1488                 break;
1489         case OMAPFB_COLOR_RGBA32:
1490                 mode = OMAP_DSS_COLOR_RGBA32;
1491                 break;
1492         case OMAPFB_COLOR_RGBX32:
1493                 mode = OMAP_DSS_COLOR_RGBX32;
1494                 break;
1495         default:
1496                 mode = -EINVAL;
1497         }
1498
1499         return mode;
1500 }
1501
1502 static int omapfb_parse_vram_param(const char *param, int max_entries,
1503                 unsigned long *sizes, unsigned long *paddrs)
1504 {
1505         int fbnum;
1506         unsigned long size;
1507         unsigned long paddr = 0;
1508         char *p, *start;
1509
1510         start = (char *)param;
1511
1512         while (1) {
1513                 p = start;
1514
1515                 fbnum = simple_strtoul(p, &p, 10);
1516
1517                 if (p == param)
1518                         return -EINVAL;
1519
1520                 if (*p != ':')
1521                         return -EINVAL;
1522
1523                 if (fbnum >= max_entries)
1524                         return -EINVAL;
1525
1526                 size = memparse(p + 1, &p);
1527
1528                 if (!size)
1529                         return -EINVAL;
1530
1531                 paddr = 0;
1532
1533                 if (*p == '@') {
1534                         paddr = simple_strtoul(p + 1, &p, 16);
1535
1536                         if (!paddr)
1537                                 return -EINVAL;
1538
1539                 }
1540
1541                 paddrs[fbnum] = paddr;
1542                 sizes[fbnum] = size;
1543
1544                 if (*p == 0)
1545                         break;
1546
1547                 if (*p != ',')
1548                         return -EINVAL;
1549
1550                 ++p;
1551
1552                 start = p;
1553         }
1554
1555         return 0;
1556 }
1557
1558 static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1559 {
1560         int i, r;
1561         unsigned long vram_sizes[10];
1562         unsigned long vram_paddrs[10];
1563
1564         memset(&vram_sizes, 0, sizeof(vram_sizes));
1565         memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1566
1567         if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1568                                 vram_sizes, vram_paddrs)) {
1569                 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1570
1571                 memset(&vram_sizes, 0, sizeof(vram_sizes));
1572                 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1573         }
1574
1575         if (fbdev->dev->platform_data) {
1576                 struct omapfb_platform_data *opd;
1577                 opd = fbdev->dev->platform_data;
1578                 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1579                         if (!vram_sizes[i]) {
1580                                 unsigned long size;
1581                                 unsigned long paddr;
1582
1583                                 size = opd->mem_desc.region[i].size;
1584                                 paddr = opd->mem_desc.region[i].paddr;
1585
1586                                 vram_sizes[i] = size;
1587                                 vram_paddrs[i] = paddr;
1588                         }
1589                 }
1590         }
1591
1592         for (i = 0; i < fbdev->num_fbs; i++) {
1593                 /* allocate memory automatically only for fb0, or if
1594                  * excplicitly defined with vram or plat data option */
1595                 if (i == 0 || vram_sizes[i] != 0) {
1596                         r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1597                                         vram_sizes[i], vram_paddrs[i]);
1598
1599                         if (r)
1600                                 return r;
1601                 }
1602         }
1603
1604         for (i = 0; i < fbdev->num_fbs; i++) {
1605                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1606                 struct omapfb2_mem_region *rg;
1607                 rg = &ofbi->region;
1608
1609                 DBG("region%d phys %08x virt %p size=%lu\n",
1610                                 i,
1611                                 rg->paddr,
1612                                 rg->vaddr,
1613                                 rg->size);
1614         }
1615
1616         return 0;
1617 }
1618
1619 int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1620 {
1621         struct omapfb_info *ofbi = FB2OFB(fbi);
1622         struct omapfb2_device *fbdev = ofbi->fbdev;
1623         struct omap_dss_device *display = fb2display(fbi);
1624         struct omapfb2_mem_region *rg = &ofbi->region;
1625         unsigned long old_size = rg->size;
1626         unsigned long old_paddr = rg->paddr;
1627         int old_type = rg->type;
1628         int r;
1629
1630         if (type > OMAPFB_MEMTYPE_MAX)
1631                 return -EINVAL;
1632
1633         size = PAGE_ALIGN(size);
1634
1635         if (old_size == size && old_type == type)
1636                 return 0;
1637
1638         if (display && display->sync)
1639                         display->sync(display);
1640
1641         omapfb_free_fbmem(fbi);
1642
1643         if (size == 0) {
1644                 clear_fb_info(fbi);
1645                 return 0;
1646         }
1647
1648         r = omapfb_alloc_fbmem(fbi, size, 0);
1649
1650         if (r) {
1651                 if (old_size)
1652                         omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1653
1654                 if (rg->size == 0)
1655                         clear_fb_info(fbi);
1656
1657                 return r;
1658         }
1659
1660         if (old_size == size)
1661                 return 0;
1662
1663         if (old_size == 0) {
1664                 DBG("initializing fb %d\n", ofbi->id);
1665                 r = omapfb_fb_init(fbdev, fbi);
1666                 if (r) {
1667                         DBG("omapfb_fb_init failed\n");
1668                         goto err;
1669                 }
1670                 r = omapfb_apply_changes(fbi, 1);
1671                 if (r) {
1672                         DBG("omapfb_apply_changes failed\n");
1673                         goto err;
1674                 }
1675         } else {
1676                 struct fb_var_screeninfo new_var;
1677                 memcpy(&new_var, &fbi->var, sizeof(new_var));
1678                 r = check_fb_var(fbi, &new_var);
1679                 if (r)
1680                         goto err;
1681                 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1682                 set_fb_fix(fbi);
1683                 r = setup_vrfb_rotation(fbi);
1684                 if (r)
1685                         goto err;
1686         }
1687
1688         return 0;
1689 err:
1690         omapfb_free_fbmem(fbi);
1691         clear_fb_info(fbi);
1692         return r;
1693 }
1694
1695 /* initialize fb_info, var, fix to something sane based on the display */
1696 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1697 {
1698         struct fb_var_screeninfo *var = &fbi->var;
1699         struct omap_dss_device *display = fb2display(fbi);
1700         struct omapfb_info *ofbi = FB2OFB(fbi);
1701         int r = 0;
1702
1703         fbi->fbops = &omapfb_ops;
1704         fbi->flags = FBINFO_FLAG_DEFAULT;
1705         fbi->pseudo_palette = fbdev->pseudo_palette;
1706
1707         if (ofbi->region.size == 0) {
1708                 clear_fb_info(fbi);
1709                 return 0;
1710         }
1711
1712         var->nonstd = 0;
1713         var->bits_per_pixel = 0;
1714
1715         var->rotate = def_rotate;
1716
1717         /*
1718          * Check if there is a default color format set in the board file,
1719          * and use this format instead the default deducted from the
1720          * display bpp.
1721          */
1722         if (fbdev->dev->platform_data) {
1723                 struct omapfb_platform_data *opd;
1724                 int id = ofbi->id;
1725
1726                 opd = fbdev->dev->platform_data;
1727                 if (opd->mem_desc.region[id].format_used) {
1728                         enum omap_color_mode mode;
1729                         enum omapfb_color_format format;
1730
1731                         format = opd->mem_desc.region[id].format;
1732                         mode = fb_format_to_dss_mode(format);
1733                         if (mode < 0) {
1734                                 r = mode;
1735                                 goto err;
1736                         }
1737                         r = dss_mode_to_fb_mode(mode, var);
1738                         if (r < 0)
1739                                 goto err;
1740                 }
1741         }
1742
1743         if (display) {
1744                 u16 w, h;
1745                 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1746
1747                 display->get_resolution(display, &w, &h);
1748
1749                 if (rotation == FB_ROTATE_CW ||
1750                                 rotation == FB_ROTATE_CCW) {
1751                         var->xres = h;
1752                         var->yres = w;
1753                 } else {
1754                         var->xres = w;
1755                         var->yres = h;
1756                 }
1757
1758                 var->xres_virtual = var->xres;
1759                 var->yres_virtual = var->yres;
1760
1761                 if (!var->bits_per_pixel) {
1762                         switch (display->get_recommended_bpp(display)) {
1763                         case 16:
1764                                 var->bits_per_pixel = 16;
1765                                 break;
1766                         case 24:
1767                                 var->bits_per_pixel = 32;
1768                                 break;
1769                         default:
1770                                 dev_err(fbdev->dev, "illegal display "
1771                                                 "bpp\n");
1772                                 return -EINVAL;
1773                         }
1774                 }
1775         } else {
1776                 /* if there's no display, let's just guess some basic values */
1777                 var->xres = 320;
1778                 var->yres = 240;
1779                 var->xres_virtual = var->xres;
1780                 var->yres_virtual = var->yres;
1781                 if (!var->bits_per_pixel)
1782                         var->bits_per_pixel = 16;
1783         }
1784
1785         r = check_fb_var(fbi, var);
1786         if (r)
1787                 goto err;
1788
1789         set_fb_fix(fbi);
1790         r = setup_vrfb_rotation(fbi);
1791         if (r)
1792                 goto err;
1793
1794         r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1795         if (r)
1796                 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1797
1798 err:
1799         return r;
1800 }
1801
1802 static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1803 {
1804         fb_dealloc_cmap(&fbi->cmap);
1805 }
1806
1807
1808 static void omapfb_free_resources(struct omapfb2_device *fbdev)
1809 {
1810         int i;
1811
1812         DBG("free_resources\n");
1813
1814         if (fbdev == NULL)
1815                 return;
1816
1817         for (i = 0; i < fbdev->num_fbs; i++)
1818                 unregister_framebuffer(fbdev->fbs[i]);
1819
1820         /* free the reserved fbmem */
1821         omapfb_free_all_fbmem(fbdev);
1822
1823         for (i = 0; i < fbdev->num_fbs; i++) {
1824                 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1825                 framebuffer_release(fbdev->fbs[i]);
1826         }
1827
1828         for (i = 0; i < fbdev->num_displays; i++) {
1829                 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1830                         fbdev->displays[i]->disable(fbdev->displays[i]);
1831
1832                 omap_dss_put_device(fbdev->displays[i]);
1833         }
1834
1835         dev_set_drvdata(fbdev->dev, NULL);
1836         kfree(fbdev);
1837 }
1838
1839 static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1840 {
1841         int r, i;
1842
1843         fbdev->num_fbs = 0;
1844
1845         DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1846
1847         /* allocate fb_infos */
1848         for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1849                 struct fb_info *fbi;
1850                 struct omapfb_info *ofbi;
1851
1852                 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1853                                 fbdev->dev);
1854
1855                 if (fbi == NULL) {
1856                         dev_err(fbdev->dev,
1857                                 "unable to allocate memory for plane info\n");
1858                         return -ENOMEM;
1859                 }
1860
1861                 clear_fb_info(fbi);
1862
1863                 fbdev->fbs[i] = fbi;
1864
1865                 ofbi = FB2OFB(fbi);
1866                 ofbi->fbdev = fbdev;
1867                 ofbi->id = i;
1868
1869                 /* assign these early, so that fb alloc can use them */
1870                 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1871                         OMAP_DSS_ROT_DMA;
1872                 ofbi->mirror = def_mirror;
1873
1874                 fbdev->num_fbs++;
1875         }
1876
1877         DBG("fb_infos allocated\n");
1878
1879         /* assign overlays for the fbs */
1880         for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1881                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1882
1883                 ofbi->overlays[0] = fbdev->overlays[i];
1884                 ofbi->num_overlays = 1;
1885         }
1886
1887         /* allocate fb memories */
1888         r = omapfb_allocate_all_fbs(fbdev);
1889         if (r) {
1890                 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1891                 return r;
1892         }
1893
1894         DBG("fbmems allocated\n");
1895
1896         /* setup fb_infos */
1897         for (i = 0; i < fbdev->num_fbs; i++) {
1898                 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1899                 if (r) {
1900                         dev_err(fbdev->dev, "failed to setup fb_info\n");
1901                         return r;
1902                 }
1903         }
1904
1905         DBG("fb_infos initialized\n");
1906
1907         for (i = 0; i < fbdev->num_fbs; i++) {
1908                 r = register_framebuffer(fbdev->fbs[i]);
1909                 if (r != 0) {
1910                         dev_err(fbdev->dev,
1911                                 "registering framebuffer %d failed\n", i);
1912                         return r;
1913                 }
1914         }
1915
1916         DBG("framebuffers registered\n");
1917
1918         for (i = 0; i < fbdev->num_fbs; i++) {
1919                 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1920                 if (r) {
1921                         dev_err(fbdev->dev, "failed to change mode\n");
1922                         return r;
1923                 }
1924         }
1925
1926         DBG("create sysfs for fbs\n");
1927         r = omapfb_create_sysfs(fbdev);
1928         if (r) {
1929                 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1930                 return r;
1931         }
1932
1933         /* Enable fb0 */
1934         if (fbdev->num_fbs > 0) {
1935                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1936
1937                 if (ofbi->num_overlays > 0) {
1938                         struct omap_overlay *ovl = ofbi->overlays[0];
1939
1940                         r = omapfb_overlay_enable(ovl, 1);
1941
1942                         if (r) {
1943                                 dev_err(fbdev->dev,
1944                                                 "failed to enable overlay\n");
1945                                 return r;
1946                         }
1947                 }
1948         }
1949
1950         DBG("create_framebuffers done\n");
1951
1952         return 0;
1953 }
1954
1955 static int omapfb_mode_to_timings(const char *mode_str,
1956                 struct omap_video_timings *timings, u8 *bpp)
1957 {
1958         struct fb_info fbi;
1959         struct fb_var_screeninfo var;
1960         struct fb_ops fbops;
1961         int r;
1962
1963 #ifdef CONFIG_OMAP2_DSS_VENC
1964         if (strcmp(mode_str, "pal") == 0) {
1965                 *timings = omap_dss_pal_timings;
1966                 *bpp = 0;
1967                 return 0;
1968         } else if (strcmp(mode_str, "ntsc") == 0) {
1969                 *timings = omap_dss_ntsc_timings;
1970                 *bpp = 0;
1971                 return 0;
1972         }
1973 #endif
1974
1975         /* this is quite a hack, but I wanted to use the modedb and for
1976          * that we need fb_info and var, so we create dummy ones */
1977
1978         memset(&fbi, 0, sizeof(fbi));
1979         memset(&var, 0, sizeof(var));
1980         memset(&fbops, 0, sizeof(fbops));
1981         fbi.fbops = &fbops;
1982
1983         r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1984
1985         if (r != 0) {
1986                 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1987                 timings->hfp = var.left_margin;
1988                 timings->hbp = var.right_margin;
1989                 timings->vfp = var.upper_margin;
1990                 timings->vbp = var.lower_margin;
1991                 timings->hsw = var.hsync_len;
1992                 timings->vsw = var.vsync_len;
1993                 timings->x_res = var.xres;
1994                 timings->y_res = var.yres;
1995
1996                 switch (var.bits_per_pixel) {
1997                 case 16:
1998                         *bpp = 16;
1999                         break;
2000                 case 24:
2001                 case 32:
2002                 default:
2003                         *bpp = 24;
2004                         break;
2005                 }
2006
2007                 return 0;
2008         } else {
2009                 return -EINVAL;
2010         }
2011 }
2012
2013 static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
2014 {
2015         int r;
2016         u8 bpp;
2017         struct omap_video_timings timings;
2018
2019         r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2020         if (r)
2021                 return r;
2022
2023         display->panel.recommended_bpp = bpp;
2024
2025         if (!display->check_timings || !display->set_timings)
2026                 return -EINVAL;
2027
2028         r = display->check_timings(display, &timings);
2029         if (r)
2030                 return r;
2031
2032         display->set_timings(display, &timings);
2033
2034         return 0;
2035 }
2036
2037 static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2038 {
2039         char *str, *options, *this_opt;
2040         int r = 0;
2041
2042         str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2043         strcpy(str, def_mode);
2044         options = str;
2045
2046         while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2047                 char *p, *display_str, *mode_str;
2048                 struct omap_dss_device *display;
2049                 int i;
2050
2051                 p = strchr(this_opt, ':');
2052                 if (!p) {
2053                         r = -EINVAL;
2054                         break;
2055                 }
2056
2057                 *p = 0;
2058                 display_str = this_opt;
2059                 mode_str = p + 1;
2060
2061                 display = NULL;
2062                 for (i = 0; i < fbdev->num_displays; ++i) {
2063                         if (strcmp(fbdev->displays[i]->name,
2064                                                 display_str) == 0) {
2065                                 display = fbdev->displays[i];
2066                                 break;
2067                         }
2068                 }
2069
2070                 if (!display) {
2071                         r = -EINVAL;
2072                         break;
2073                 }
2074
2075                 r = omapfb_set_def_mode(display, mode_str);
2076                 if (r)
2077                         break;
2078         }
2079
2080         kfree(str);
2081
2082         return r;
2083 }
2084
2085 static int omapfb_probe(struct platform_device *pdev)
2086 {
2087         struct omapfb2_device *fbdev = NULL;
2088         int r = 0;
2089         int i;
2090         struct omap_overlay *ovl;
2091         struct omap_dss_device *def_display;
2092         struct omap_dss_device *dssdev;
2093
2094         DBG("omapfb_probe\n");
2095
2096         if (pdev->num_resources != 0) {
2097                 dev_err(&pdev->dev, "probed for an unknown device\n");
2098                 r = -ENODEV;
2099                 goto err0;
2100         }
2101
2102         fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2103         if (fbdev == NULL) {
2104                 r = -ENOMEM;
2105                 goto err0;
2106         }
2107
2108         mutex_init(&fbdev->mtx);
2109
2110         fbdev->dev = &pdev->dev;
2111         platform_set_drvdata(pdev, fbdev);
2112
2113         fbdev->num_displays = 0;
2114         dssdev = NULL;
2115         for_each_dss_dev(dssdev) {
2116                 omap_dss_get_device(dssdev);
2117                 fbdev->displays[fbdev->num_displays++] = dssdev;
2118         }
2119
2120         if (fbdev->num_displays == 0) {
2121                 dev_err(&pdev->dev, "no displays\n");
2122                 r = -EINVAL;
2123                 goto cleanup;
2124         }
2125
2126         fbdev->num_overlays = omap_dss_get_num_overlays();
2127         for (i = 0; i < fbdev->num_overlays; i++)
2128                 fbdev->overlays[i] = omap_dss_get_overlay(i);
2129
2130         fbdev->num_managers = omap_dss_get_num_overlay_managers();
2131         for (i = 0; i < fbdev->num_managers; i++)
2132                 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2133
2134         if (def_mode && strlen(def_mode) > 0) {
2135                 if (omapfb_parse_def_modes(fbdev))
2136                         dev_warn(&pdev->dev, "cannot parse default modes\n");
2137         }
2138
2139         r = omapfb_create_framebuffers(fbdev);
2140         if (r)
2141                 goto cleanup;
2142
2143         for (i = 0; i < fbdev->num_managers; i++) {
2144                 struct omap_overlay_manager *mgr;
2145                 mgr = fbdev->managers[i];
2146                 r = mgr->apply(mgr);
2147                 if (r)
2148                         dev_warn(fbdev->dev, "failed to apply dispc config\n");
2149         }
2150
2151         DBG("mgr->apply'ed\n");
2152
2153         /* gfx overlay should be the default one. find a display
2154          * connected to that, and use it as default display */
2155         ovl = omap_dss_get_overlay(0);
2156         if (ovl->manager && ovl->manager->device) {
2157                 def_display = ovl->manager->device;
2158         } else {
2159                 dev_warn(&pdev->dev, "cannot find default display\n");
2160                 def_display = NULL;
2161         }
2162
2163         if (def_display) {
2164 #ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2165                 u16 w, h;
2166 #endif
2167                 r = def_display->enable(def_display);
2168                 if (r)
2169                         dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2170                                         def_display->name);
2171
2172                 /* set the update mode */
2173                 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2174 #ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2175                         if (def_display->enable_te)
2176                                 def_display->enable_te(def_display, 1);
2177                         if (def_display->set_update_mode)
2178                                 def_display->set_update_mode(def_display,
2179                                                 OMAP_DSS_UPDATE_AUTO);
2180 #else /* MANUAL_UPDATE */
2181                         if (def_display->enable_te)
2182                                 def_display->enable_te(def_display, 0);
2183                         if (def_display->set_update_mode)
2184                                 def_display->set_update_mode(def_display,
2185                                                 OMAP_DSS_UPDATE_MANUAL);
2186
2187                         def_display->get_resolution(def_display, &w, &h);
2188                         def_display->update(def_display, 0, 0, w, h);
2189 #endif
2190                 } else {
2191                         if (def_display->set_update_mode)
2192                                 def_display->set_update_mode(def_display,
2193                                                 OMAP_DSS_UPDATE_AUTO);
2194                 }
2195         }
2196
2197         return 0;
2198
2199 cleanup:
2200         omapfb_free_resources(fbdev);
2201 err0:
2202         dev_err(&pdev->dev, "failed to setup omapfb\n");
2203         return r;
2204 }
2205
2206 static int omapfb_remove(struct platform_device *pdev)
2207 {
2208         struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2209
2210         /* FIXME: wait till completion of pending events */
2211
2212         omapfb_remove_sysfs(fbdev);
2213
2214         omapfb_free_resources(fbdev);
2215
2216         return 0;
2217 }
2218
2219 static struct platform_driver omapfb_driver = {
2220         .probe          = omapfb_probe,
2221         .remove         = omapfb_remove,
2222         .driver         = {
2223                 .name   = "omapfb",
2224                 .owner  = THIS_MODULE,
2225         },
2226 };
2227
2228 static int __init omapfb_init(void)
2229 {
2230         DBG("omapfb_init\n");
2231
2232         if (platform_driver_register(&omapfb_driver)) {
2233                 printk(KERN_ERR "failed to register omapfb driver\n");
2234                 return -ENODEV;
2235         }
2236
2237         return 0;
2238 }
2239
2240 static void __exit omapfb_exit(void)
2241 {
2242         DBG("omapfb_exit\n");
2243         platform_driver_unregister(&omapfb_driver);
2244 }
2245
2246 module_param_named(mode, def_mode, charp, 0);
2247 module_param_named(vram, def_vram, charp, 0);
2248 module_param_named(rotate, def_rotate, int, 0);
2249 module_param_named(vrfb, def_vrfb, bool, 0);
2250 module_param_named(mirror, def_mirror, bool, 0);
2251
2252 /* late_initcall to let panel/ctrl drivers loaded first.
2253  * I guess better option would be a more dynamic approach,
2254  * so that omapfb reacts to new panels when they are loaded */
2255 late_initcall(omapfb_init);
2256 /*module_init(omapfb_init);*/
2257 module_exit(omapfb_exit);
2258
2259 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2260 MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2261 MODULE_LICENSE("GPL v2");