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