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