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