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