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