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