Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/drivers/video/omap2/omapfb-main.c
0004  *
0005  * Copyright (C) 2008 Nokia Corporation
0006  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
0007  *
0008  * Some code and ideas taken from drivers/video/omap/ driver
0009  * by Imre Deak.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/delay.h>
0014 #include <linux/slab.h>
0015 #include <linux/fb.h>
0016 #include <linux/dma-mapping.h>
0017 #include <linux/vmalloc.h>
0018 #include <linux/device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/omapfb.h>
0021 
0022 #include <video/omapfb_dss.h>
0023 #include <video/omapvrfb.h>
0024 
0025 #include "omapfb.h"
0026 
0027 #define MODULE_NAME     "omapfb"
0028 
0029 #define OMAPFB_PLANE_XRES_MIN       8
0030 #define OMAPFB_PLANE_YRES_MIN       8
0031 
0032 static char *def_mode;
0033 static char *def_vram;
0034 static bool def_vrfb;
0035 static int def_rotate;
0036 static bool def_mirror;
0037 static bool auto_update;
0038 static unsigned int auto_update_freq;
0039 module_param(auto_update, bool, 0);
0040 module_param(auto_update_freq, uint, 0644);
0041 
0042 #ifdef DEBUG
0043 bool omapfb_debug;
0044 module_param_named(debug, omapfb_debug, bool, 0644);
0045 static bool omapfb_test_pattern;
0046 module_param_named(test, omapfb_test_pattern, bool, 0644);
0047 #endif
0048 
0049 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
0050 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
0051         struct omap_dss_device *dssdev);
0052 
0053 #ifdef DEBUG
0054 static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
0055 {
0056     struct fb_var_screeninfo *var = &fbi->var;
0057     struct fb_fix_screeninfo *fix = &fbi->fix;
0058     void __iomem *addr = fbi->screen_base;
0059     const unsigned bytespp = var->bits_per_pixel >> 3;
0060     const unsigned line_len = fix->line_length / bytespp;
0061 
0062     int r = (color >> 16) & 0xff;
0063     int g = (color >> 8) & 0xff;
0064     int b = (color >> 0) & 0xff;
0065 
0066     if (var->bits_per_pixel == 16) {
0067         u16 __iomem *p = (u16 __iomem *)addr;
0068         p += y * line_len + x;
0069 
0070         r = r * 32 / 256;
0071         g = g * 64 / 256;
0072         b = b * 32 / 256;
0073 
0074         __raw_writew((r << 11) | (g << 5) | (b << 0), p);
0075     } else if (var->bits_per_pixel == 24) {
0076         u8 __iomem *p = (u8 __iomem *)addr;
0077         p += (y * line_len + x) * 3;
0078 
0079         __raw_writeb(b, p + 0);
0080         __raw_writeb(g, p + 1);
0081         __raw_writeb(r, p + 2);
0082     } else if (var->bits_per_pixel == 32) {
0083         u32 __iomem *p = (u32 __iomem *)addr;
0084         p += y * line_len + x;
0085         __raw_writel(color, p);
0086     }
0087 }
0088 
0089 static void fill_fb(struct fb_info *fbi)
0090 {
0091     struct fb_var_screeninfo *var = &fbi->var;
0092     const short w = var->xres_virtual;
0093     const short h = var->yres_virtual;
0094     void __iomem *addr = fbi->screen_base;
0095     int y, x;
0096 
0097     if (!addr)
0098         return;
0099 
0100     DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
0101 
0102     for (y = 0; y < h; y++) {
0103         for (x = 0; x < w; x++) {
0104             if (x < 20 && y < 20)
0105                 draw_pixel(fbi, x, y, 0xffffff);
0106             else if (x < 20 && (y > 20 && y < h - 20))
0107                 draw_pixel(fbi, x, y, 0xff);
0108             else if (y < 20 && (x > 20 && x < w - 20))
0109                 draw_pixel(fbi, x, y, 0xff00);
0110             else if (x > w - 20 && (y > 20 && y < h - 20))
0111                 draw_pixel(fbi, x, y, 0xff0000);
0112             else if (y > h - 20 && (x > 20 && x < w - 20))
0113                 draw_pixel(fbi, x, y, 0xffff00);
0114             else if (x == 20 || x == w - 20 ||
0115                     y == 20 || y == h - 20)
0116                 draw_pixel(fbi, x, y, 0xffffff);
0117             else if (x == y || w - x == h - y)
0118                 draw_pixel(fbi, x, y, 0xff00ff);
0119             else if (w - x == y || x == h - y)
0120                 draw_pixel(fbi, x, y, 0x00ffff);
0121             else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
0122                 int t = x * 3 / w;
0123                 unsigned r = 0, g = 0, b = 0;
0124                 unsigned c;
0125                 if (var->bits_per_pixel == 16) {
0126                     if (t == 0)
0127                         b = (y % 32) * 256 / 32;
0128                     else if (t == 1)
0129                         g = (y % 64) * 256 / 64;
0130                     else if (t == 2)
0131                         r = (y % 32) * 256 / 32;
0132                 } else {
0133                     if (t == 0)
0134                         b = (y % 256);
0135                     else if (t == 1)
0136                         g = (y % 256);
0137                     else if (t == 2)
0138                         r = (y % 256);
0139                 }
0140                 c = (r << 16) | (g << 8) | (b << 0);
0141                 draw_pixel(fbi, x, y, c);
0142             } else {
0143                 draw_pixel(fbi, x, y, 0);
0144             }
0145         }
0146     }
0147 }
0148 #endif
0149 
0150 static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
0151 {
0152     const struct vrfb *vrfb = &ofbi->region->vrfb;
0153     unsigned offset;
0154 
0155     switch (rot) {
0156     case FB_ROTATE_UR:
0157         offset = 0;
0158         break;
0159     case FB_ROTATE_CW:
0160         offset = vrfb->yoffset;
0161         break;
0162     case FB_ROTATE_UD:
0163         offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
0164         break;
0165     case FB_ROTATE_CCW:
0166         offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
0167         break;
0168     default:
0169         BUG();
0170         return 0;
0171     }
0172 
0173     offset *= vrfb->bytespp;
0174 
0175     return offset;
0176 }
0177 
0178 static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
0179 {
0180     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
0181         return ofbi->region->vrfb.paddr[rot]
0182             + omapfb_get_vrfb_offset(ofbi, rot);
0183     } else {
0184         return ofbi->region->paddr;
0185     }
0186 }
0187 
0188 static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
0189 {
0190     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
0191         return ofbi->region->vrfb.paddr[0];
0192     else
0193         return ofbi->region->paddr;
0194 }
0195 
0196 static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
0197 {
0198     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
0199         return ofbi->region->vrfb.vaddr[0];
0200     else
0201         return ofbi->region->vaddr;
0202 }
0203 
0204 static struct omapfb_colormode omapfb_colormodes[] = {
0205     {
0206         .dssmode = OMAP_DSS_COLOR_UYVY,
0207         .bits_per_pixel = 16,
0208         .nonstd = OMAPFB_COLOR_YUV422,
0209     }, {
0210         .dssmode = OMAP_DSS_COLOR_YUV2,
0211         .bits_per_pixel = 16,
0212         .nonstd = OMAPFB_COLOR_YUY422,
0213     }, {
0214         .dssmode = OMAP_DSS_COLOR_ARGB16,
0215         .bits_per_pixel = 16,
0216         .red    = { .length = 4, .offset = 8, .msb_right = 0 },
0217         .green  = { .length = 4, .offset = 4, .msb_right = 0 },
0218         .blue   = { .length = 4, .offset = 0, .msb_right = 0 },
0219         .transp = { .length = 4, .offset = 12, .msb_right = 0 },
0220     }, {
0221         .dssmode = OMAP_DSS_COLOR_RGB16,
0222         .bits_per_pixel = 16,
0223         .red    = { .length = 5, .offset = 11, .msb_right = 0 },
0224         .green  = { .length = 6, .offset = 5, .msb_right = 0 },
0225         .blue   = { .length = 5, .offset = 0, .msb_right = 0 },
0226         .transp = { .length = 0, .offset = 0, .msb_right = 0 },
0227     }, {
0228         .dssmode = OMAP_DSS_COLOR_RGB24P,
0229         .bits_per_pixel = 24,
0230         .red    = { .length = 8, .offset = 16, .msb_right = 0 },
0231         .green  = { .length = 8, .offset = 8, .msb_right = 0 },
0232         .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
0233         .transp = { .length = 0, .offset = 0, .msb_right = 0 },
0234     }, {
0235         .dssmode = OMAP_DSS_COLOR_RGB24U,
0236         .bits_per_pixel = 32,
0237         .red    = { .length = 8, .offset = 16, .msb_right = 0 },
0238         .green  = { .length = 8, .offset = 8, .msb_right = 0 },
0239         .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
0240         .transp = { .length = 0, .offset = 0, .msb_right = 0 },
0241     }, {
0242         .dssmode = OMAP_DSS_COLOR_ARGB32,
0243         .bits_per_pixel = 32,
0244         .red    = { .length = 8, .offset = 16, .msb_right = 0 },
0245         .green  = { .length = 8, .offset = 8, .msb_right = 0 },
0246         .blue   = { .length = 8, .offset = 0, .msb_right = 0 },
0247         .transp = { .length = 8, .offset = 24, .msb_right = 0 },
0248     }, {
0249         .dssmode = OMAP_DSS_COLOR_RGBA32,
0250         .bits_per_pixel = 32,
0251         .red    = { .length = 8, .offset = 24, .msb_right = 0 },
0252         .green  = { .length = 8, .offset = 16, .msb_right = 0 },
0253         .blue   = { .length = 8, .offset = 8, .msb_right = 0 },
0254         .transp = { .length = 8, .offset = 0, .msb_right = 0 },
0255     }, {
0256         .dssmode = OMAP_DSS_COLOR_RGBX32,
0257         .bits_per_pixel = 32,
0258         .red    = { .length = 8, .offset = 24, .msb_right = 0 },
0259         .green  = { .length = 8, .offset = 16, .msb_right = 0 },
0260         .blue   = { .length = 8, .offset = 8, .msb_right = 0 },
0261         .transp = { .length = 0, .offset = 0, .msb_right = 0 },
0262     },
0263 };
0264 
0265 static bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
0266 {
0267     return f1->length == f2->length &&
0268         f1->offset == f2->offset &&
0269         f1->msb_right == f2->msb_right;
0270 }
0271 
0272 static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
0273         struct omapfb_colormode *color)
0274 {
0275     if (var->bits_per_pixel == 0 ||
0276             var->red.length == 0 ||
0277             var->blue.length == 0 ||
0278             var->green.length == 0)
0279         return false;
0280 
0281     return var->bits_per_pixel == color->bits_per_pixel &&
0282         cmp_component(&var->red, &color->red) &&
0283         cmp_component(&var->green, &color->green) &&
0284         cmp_component(&var->blue, &color->blue) &&
0285         cmp_component(&var->transp, &color->transp);
0286 }
0287 
0288 static void assign_colormode_to_var(struct fb_var_screeninfo *var,
0289         struct omapfb_colormode *color)
0290 {
0291     var->bits_per_pixel = color->bits_per_pixel;
0292     var->nonstd = color->nonstd;
0293     var->red = color->red;
0294     var->green = color->green;
0295     var->blue = color->blue;
0296     var->transp = color->transp;
0297 }
0298 
0299 static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
0300         enum omap_color_mode *mode)
0301 {
0302     enum omap_color_mode dssmode;
0303     int i;
0304 
0305     /* first match with nonstd field */
0306     if (var->nonstd) {
0307         for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
0308             struct omapfb_colormode *m = &omapfb_colormodes[i];
0309             if (var->nonstd == m->nonstd) {
0310                 assign_colormode_to_var(var, m);
0311                 *mode = m->dssmode;
0312                 return 0;
0313             }
0314         }
0315 
0316         return -EINVAL;
0317     }
0318 
0319     /* then try exact match of bpp and colors */
0320     for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
0321         struct omapfb_colormode *m = &omapfb_colormodes[i];
0322         if (cmp_var_to_colormode(var, m)) {
0323             assign_colormode_to_var(var, m);
0324             *mode = m->dssmode;
0325             return 0;
0326         }
0327     }
0328 
0329     /* match with bpp if user has not filled color fields
0330      * properly */
0331     switch (var->bits_per_pixel) {
0332     case 1:
0333         dssmode = OMAP_DSS_COLOR_CLUT1;
0334         break;
0335     case 2:
0336         dssmode = OMAP_DSS_COLOR_CLUT2;
0337         break;
0338     case 4:
0339         dssmode = OMAP_DSS_COLOR_CLUT4;
0340         break;
0341     case 8:
0342         dssmode = OMAP_DSS_COLOR_CLUT8;
0343         break;
0344     case 12:
0345         dssmode = OMAP_DSS_COLOR_RGB12U;
0346         break;
0347     case 16:
0348         dssmode = OMAP_DSS_COLOR_RGB16;
0349         break;
0350     case 24:
0351         dssmode = OMAP_DSS_COLOR_RGB24P;
0352         break;
0353     case 32:
0354         dssmode = OMAP_DSS_COLOR_RGB24U;
0355         break;
0356     default:
0357         return -EINVAL;
0358     }
0359 
0360     for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
0361         struct omapfb_colormode *m = &omapfb_colormodes[i];
0362         if (dssmode == m->dssmode) {
0363             assign_colormode_to_var(var, m);
0364             *mode = m->dssmode;
0365             return 0;
0366         }
0367     }
0368 
0369     return -EINVAL;
0370 }
0371 
0372 static int check_fb_res_bounds(struct fb_var_screeninfo *var)
0373 {
0374     int xres_min = OMAPFB_PLANE_XRES_MIN;
0375     int xres_max = 2048;
0376     int yres_min = OMAPFB_PLANE_YRES_MIN;
0377     int yres_max = 2048;
0378 
0379     /* XXX: some applications seem to set virtual res to 0. */
0380     if (var->xres_virtual == 0)
0381         var->xres_virtual = var->xres;
0382 
0383     if (var->yres_virtual == 0)
0384         var->yres_virtual = var->yres;
0385 
0386     if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
0387         return -EINVAL;
0388 
0389     if (var->xres < xres_min)
0390         var->xres = xres_min;
0391     if (var->yres < yres_min)
0392         var->yres = yres_min;
0393     if (var->xres > xres_max)
0394         var->xres = xres_max;
0395     if (var->yres > yres_max)
0396         var->yres = yres_max;
0397 
0398     if (var->xres > var->xres_virtual)
0399         var->xres = var->xres_virtual;
0400     if (var->yres > var->yres_virtual)
0401         var->yres = var->yres_virtual;
0402 
0403     return 0;
0404 }
0405 
0406 static void shrink_height(unsigned long max_frame_size,
0407         struct fb_var_screeninfo *var)
0408 {
0409     DBG("can't fit FB into memory, reducing y\n");
0410     var->yres_virtual = max_frame_size /
0411         (var->xres_virtual * var->bits_per_pixel >> 3);
0412 
0413     if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
0414         var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
0415 
0416     if (var->yres > var->yres_virtual)
0417         var->yres = var->yres_virtual;
0418 }
0419 
0420 static void shrink_width(unsigned long max_frame_size,
0421         struct fb_var_screeninfo *var)
0422 {
0423     DBG("can't fit FB into memory, reducing x\n");
0424     var->xres_virtual = max_frame_size / var->yres_virtual /
0425         (var->bits_per_pixel >> 3);
0426 
0427     if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
0428         var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
0429 
0430     if (var->xres > var->xres_virtual)
0431         var->xres = var->xres_virtual;
0432 }
0433 
0434 static int check_vrfb_fb_size(unsigned long region_size,
0435         const struct fb_var_screeninfo *var)
0436 {
0437     unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
0438         var->yres_virtual, var->bits_per_pixel >> 3);
0439 
0440     return min_phys_size > region_size ? -EINVAL : 0;
0441 }
0442 
0443 static int check_fb_size(const struct omapfb_info *ofbi,
0444         struct fb_var_screeninfo *var)
0445 {
0446     unsigned long max_frame_size = ofbi->region->size;
0447     int bytespp = var->bits_per_pixel >> 3;
0448     unsigned long line_size = var->xres_virtual * bytespp;
0449 
0450     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
0451         /* One needs to check for both VRFB and OMAPFB limitations. */
0452         if (check_vrfb_fb_size(max_frame_size, var))
0453             shrink_height(omap_vrfb_max_height(
0454                 max_frame_size, var->xres_virtual, bytespp) *
0455                 line_size, var);
0456 
0457         if (check_vrfb_fb_size(max_frame_size, var)) {
0458             DBG("cannot fit FB to memory\n");
0459             return -EINVAL;
0460         }
0461 
0462         return 0;
0463     }
0464 
0465     DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
0466 
0467     if (line_size * var->yres_virtual > max_frame_size)
0468         shrink_height(max_frame_size, var);
0469 
0470     if (line_size * var->yres_virtual > max_frame_size) {
0471         shrink_width(max_frame_size, var);
0472         line_size = var->xres_virtual * bytespp;
0473     }
0474 
0475     if (line_size * var->yres_virtual > max_frame_size) {
0476         DBG("cannot fit FB to memory\n");
0477         return -EINVAL;
0478     }
0479 
0480     return 0;
0481 }
0482 
0483 /*
0484  * Consider if VRFB assisted rotation is in use and if the virtual space for
0485  * the zero degree view needs to be mapped. The need for mapping also acts as
0486  * the trigger for setting up the hardware on the context in question. This
0487  * ensures that one does not attempt to access the virtual view before the
0488  * hardware is serving the address translations.
0489  */
0490 static int setup_vrfb_rotation(struct fb_info *fbi)
0491 {
0492     struct omapfb_info *ofbi = FB2OFB(fbi);
0493     struct omapfb2_mem_region *rg = ofbi->region;
0494     struct vrfb *vrfb = &rg->vrfb;
0495     struct fb_var_screeninfo *var = &fbi->var;
0496     struct fb_fix_screeninfo *fix = &fbi->fix;
0497     unsigned bytespp;
0498     bool yuv_mode;
0499     enum omap_color_mode mode;
0500     int r;
0501     bool reconf;
0502 
0503     if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
0504         return 0;
0505 
0506     DBG("setup_vrfb_rotation\n");
0507 
0508     r = fb_mode_to_dss_mode(var, &mode);
0509     if (r)
0510         return r;
0511 
0512     bytespp = var->bits_per_pixel >> 3;
0513 
0514     yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
0515 
0516     /* We need to reconfigure VRFB if the resolution changes, if yuv mode
0517      * is enabled/disabled, or if bytes per pixel changes */
0518 
0519     /* XXX we shouldn't allow this when framebuffer is mmapped */
0520 
0521     reconf = false;
0522 
0523     if (yuv_mode != vrfb->yuv_mode)
0524         reconf = true;
0525     else if (bytespp != vrfb->bytespp)
0526         reconf = true;
0527     else if (vrfb->xres != var->xres_virtual ||
0528             vrfb->yres != var->yres_virtual)
0529         reconf = true;
0530 
0531     if (vrfb->vaddr[0] && reconf) {
0532         fbi->screen_base = NULL;
0533         fix->smem_start = 0;
0534         fix->smem_len = 0;
0535         iounmap(vrfb->vaddr[0]);
0536         vrfb->vaddr[0] = NULL;
0537         DBG("setup_vrfb_rotation: reset fb\n");
0538     }
0539 
0540     if (vrfb->vaddr[0])
0541         return 0;
0542 
0543     omap_vrfb_setup(&rg->vrfb, rg->paddr,
0544             var->xres_virtual,
0545             var->yres_virtual,
0546             bytespp, yuv_mode);
0547 
0548     /* Now one can ioremap the 0 angle view */
0549     r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
0550     if (r)
0551         return r;
0552 
0553     /* used by open/write in fbmem.c */
0554     fbi->screen_base = ofbi->region->vrfb.vaddr[0];
0555 
0556     fix->smem_start = ofbi->region->vrfb.paddr[0];
0557 
0558     switch (var->nonstd) {
0559     case OMAPFB_COLOR_YUV422:
0560     case OMAPFB_COLOR_YUY422:
0561         fix->line_length =
0562             (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
0563         break;
0564     default:
0565         fix->line_length =
0566             (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
0567         break;
0568     }
0569 
0570     fix->smem_len = var->yres_virtual * fix->line_length;
0571 
0572     return 0;
0573 }
0574 
0575 int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
0576             struct fb_var_screeninfo *var)
0577 {
0578     int i;
0579 
0580     for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
0581         struct omapfb_colormode *mode = &omapfb_colormodes[i];
0582         if (dssmode == mode->dssmode) {
0583             assign_colormode_to_var(var, mode);
0584             return 0;
0585         }
0586     }
0587     return -ENOENT;
0588 }
0589 
0590 void set_fb_fix(struct fb_info *fbi)
0591 {
0592     struct fb_fix_screeninfo *fix = &fbi->fix;
0593     struct fb_var_screeninfo *var = &fbi->var;
0594     struct omapfb_info *ofbi = FB2OFB(fbi);
0595     struct omapfb2_mem_region *rg = ofbi->region;
0596 
0597     DBG("set_fb_fix\n");
0598 
0599     /* used by open/write in fbmem.c */
0600     fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
0601 
0602     /* used by mmap in fbmem.c */
0603     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
0604         switch (var->nonstd) {
0605         case OMAPFB_COLOR_YUV422:
0606         case OMAPFB_COLOR_YUY422:
0607             fix->line_length =
0608                 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
0609             break;
0610         default:
0611             fix->line_length =
0612                 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
0613             break;
0614         }
0615 
0616         fix->smem_len = var->yres_virtual * fix->line_length;
0617     } else {
0618         fix->line_length =
0619             (var->xres_virtual * var->bits_per_pixel) >> 3;
0620         fix->smem_len = rg->size;
0621     }
0622 
0623     fix->smem_start = omapfb_get_region_paddr(ofbi);
0624 
0625     fix->type = FB_TYPE_PACKED_PIXELS;
0626 
0627     if (var->nonstd)
0628         fix->visual = FB_VISUAL_PSEUDOCOLOR;
0629     else {
0630         switch (var->bits_per_pixel) {
0631         case 32:
0632         case 24:
0633         case 16:
0634         case 12:
0635             fix->visual = FB_VISUAL_TRUECOLOR;
0636             /* 12bpp is stored in 16 bits */
0637             break;
0638         case 1:
0639         case 2:
0640         case 4:
0641         case 8:
0642             fix->visual = FB_VISUAL_PSEUDOCOLOR;
0643             break;
0644         }
0645     }
0646 
0647     fix->accel = FB_ACCEL_NONE;
0648 
0649     fix->xpanstep = 1;
0650     fix->ypanstep = 1;
0651 }
0652 
0653 /* check new var and possibly modify it to be ok */
0654 int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
0655 {
0656     struct omapfb_info *ofbi = FB2OFB(fbi);
0657     struct omap_dss_device *display = fb2display(fbi);
0658     enum omap_color_mode mode = 0;
0659     int i;
0660     int r;
0661 
0662     DBG("check_fb_var %d\n", ofbi->id);
0663 
0664     WARN_ON(!atomic_read(&ofbi->region->lock_count));
0665 
0666     r = fb_mode_to_dss_mode(var, &mode);
0667     if (r) {
0668         DBG("cannot convert var to omap dss mode\n");
0669         return r;
0670     }
0671 
0672     for (i = 0; i < ofbi->num_overlays; ++i) {
0673         if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
0674             DBG("invalid mode\n");
0675             return -EINVAL;
0676         }
0677     }
0678 
0679     if (var->rotate > 3)
0680         return -EINVAL;
0681 
0682     if (check_fb_res_bounds(var))
0683         return -EINVAL;
0684 
0685     /* When no memory is allocated ignore the size check */
0686     if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
0687         return -EINVAL;
0688 
0689     if (var->xres + var->xoffset > var->xres_virtual)
0690         var->xoffset = var->xres_virtual - var->xres;
0691     if (var->yres + var->yoffset > var->yres_virtual)
0692         var->yoffset = var->yres_virtual - var->yres;
0693 
0694     DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
0695             var->xres, var->yres,
0696             var->xres_virtual, var->yres_virtual);
0697 
0698     if (display && display->driver->get_dimensions) {
0699         u32 w, h;
0700         display->driver->get_dimensions(display, &w, &h);
0701         var->width = DIV_ROUND_CLOSEST(w, 1000);
0702         var->height = DIV_ROUND_CLOSEST(h, 1000);
0703     } else {
0704         var->height = -1;
0705         var->width = -1;
0706     }
0707 
0708     var->grayscale          = 0;
0709 
0710     if (display && display->driver->get_timings) {
0711         struct omap_video_timings timings;
0712         display->driver->get_timings(display, &timings);
0713 
0714         /* pixclock in ps, the rest in pixclock */
0715         var->pixclock = timings.pixelclock != 0 ?
0716             KHZ2PICOS(timings.pixelclock / 1000) :
0717             0;
0718         var->left_margin = timings.hbp;
0719         var->right_margin = timings.hfp;
0720         var->upper_margin = timings.vbp;
0721         var->lower_margin = timings.vfp;
0722         var->hsync_len = timings.hsw;
0723         var->vsync_len = timings.vsw;
0724         var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
0725                 FB_SYNC_HOR_HIGH_ACT : 0;
0726         var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
0727                 FB_SYNC_VERT_HIGH_ACT : 0;
0728         var->vmode = timings.interlace ?
0729                 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
0730     } else {
0731         var->pixclock = 0;
0732         var->left_margin = 0;
0733         var->right_margin = 0;
0734         var->upper_margin = 0;
0735         var->lower_margin = 0;
0736         var->hsync_len = 0;
0737         var->vsync_len = 0;
0738         var->sync = 0;
0739         var->vmode = FB_VMODE_NONINTERLACED;
0740     }
0741 
0742     return 0;
0743 }
0744 
0745 /*
0746  * ---------------------------------------------------------------------------
0747  * fbdev framework callbacks
0748  * ---------------------------------------------------------------------------
0749  */
0750 static int omapfb_open(struct fb_info *fbi, int user)
0751 {
0752     return 0;
0753 }
0754 
0755 static int omapfb_release(struct fb_info *fbi, int user)
0756 {
0757     return 0;
0758 }
0759 
0760 static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
0761         const struct fb_fix_screeninfo *fix, int rotation)
0762 {
0763     unsigned offset;
0764 
0765     offset = var->yoffset * fix->line_length +
0766         var->xoffset * (var->bits_per_pixel >> 3);
0767 
0768     return offset;
0769 }
0770 
0771 static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
0772         const struct fb_fix_screeninfo *fix, int rotation)
0773 {
0774     unsigned offset;
0775 
0776     if (rotation == FB_ROTATE_UD)
0777         offset = (var->yres_virtual - var->yres) *
0778             fix->line_length;
0779     else if (rotation == FB_ROTATE_CW)
0780         offset = (var->yres_virtual - var->yres) *
0781             (var->bits_per_pixel >> 3);
0782     else
0783         offset = 0;
0784 
0785     if (rotation == FB_ROTATE_UR)
0786         offset += var->yoffset * fix->line_length +
0787             var->xoffset * (var->bits_per_pixel >> 3);
0788     else if (rotation == FB_ROTATE_UD)
0789         offset -= var->yoffset * fix->line_length +
0790             var->xoffset * (var->bits_per_pixel >> 3);
0791     else if (rotation == FB_ROTATE_CW)
0792         offset -= var->xoffset * fix->line_length +
0793             var->yoffset * (var->bits_per_pixel >> 3);
0794     else if (rotation == FB_ROTATE_CCW)
0795         offset += var->xoffset * fix->line_length +
0796             var->yoffset * (var->bits_per_pixel >> 3);
0797 
0798     return offset;
0799 }
0800 
0801 static void omapfb_calc_addr(const struct omapfb_info *ofbi,
0802                  const struct fb_var_screeninfo *var,
0803                  const struct fb_fix_screeninfo *fix,
0804                  int rotation, u32 *paddr)
0805 {
0806     u32 data_start_p;
0807     int offset;
0808 
0809     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
0810         data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
0811     else
0812         data_start_p = omapfb_get_region_paddr(ofbi);
0813 
0814     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
0815         offset = calc_rotation_offset_vrfb(var, fix, rotation);
0816     else
0817         offset = calc_rotation_offset_dma(var, fix, rotation);
0818 
0819     data_start_p += offset;
0820 
0821     if (offset)
0822         DBG("offset %d, %d = %d\n",
0823             var->xoffset, var->yoffset, offset);
0824 
0825     DBG("paddr %x\n", data_start_p);
0826 
0827     *paddr = data_start_p;
0828 }
0829 
0830 /* setup overlay according to the fb */
0831 int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
0832         u16 posx, u16 posy, u16 outw, u16 outh)
0833 {
0834     int r = 0;
0835     struct omapfb_info *ofbi = FB2OFB(fbi);
0836     struct fb_var_screeninfo *var = &fbi->var;
0837     struct fb_fix_screeninfo *fix = &fbi->fix;
0838     enum omap_color_mode mode = 0;
0839     u32 data_start_p = 0;
0840     struct omap_overlay_info info;
0841     int xres, yres;
0842     int screen_width;
0843     int mirror;
0844     int rotation = var->rotate;
0845     int i;
0846 
0847     WARN_ON(!atomic_read(&ofbi->region->lock_count));
0848 
0849     for (i = 0; i < ofbi->num_overlays; i++) {
0850         if (ovl != ofbi->overlays[i])
0851             continue;
0852 
0853         rotation = (rotation + ofbi->rotation[i]) % 4;
0854         break;
0855     }
0856 
0857     DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
0858             posx, posy, outw, outh);
0859 
0860     if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
0861         xres = var->yres;
0862         yres = var->xres;
0863     } else {
0864         xres = var->xres;
0865         yres = var->yres;
0866     }
0867 
0868     if (ofbi->region->size)
0869         omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p);
0870 
0871     r = fb_mode_to_dss_mode(var, &mode);
0872     if (r) {
0873         DBG("fb_mode_to_dss_mode failed");
0874         goto err;
0875     }
0876 
0877     switch (var->nonstd) {
0878     case OMAPFB_COLOR_YUV422:
0879     case OMAPFB_COLOR_YUY422:
0880         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
0881             screen_width = fix->line_length
0882                 / (var->bits_per_pixel >> 2);
0883             break;
0884         }
0885         fallthrough;
0886     default:
0887         screen_width = fix->line_length / (var->bits_per_pixel >> 3);
0888         break;
0889     }
0890 
0891     ovl->get_overlay_info(ovl, &info);
0892 
0893     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
0894         mirror = 0;
0895     else
0896         mirror = ofbi->mirror;
0897 
0898     info.paddr = data_start_p;
0899     info.screen_width = screen_width;
0900     info.width = xres;
0901     info.height = yres;
0902     info.color_mode = mode;
0903     info.rotation_type = ofbi->rotation_type;
0904     info.rotation = rotation;
0905     info.mirror = mirror;
0906 
0907     info.pos_x = posx;
0908     info.pos_y = posy;
0909     info.out_width = outw;
0910     info.out_height = outh;
0911 
0912     r = ovl->set_overlay_info(ovl, &info);
0913     if (r) {
0914         DBG("ovl->setup_overlay_info failed\n");
0915         goto err;
0916     }
0917 
0918     return 0;
0919 
0920 err:
0921     DBG("setup_overlay failed\n");
0922     return r;
0923 }
0924 
0925 /* apply var to the overlay */
0926 int omapfb_apply_changes(struct fb_info *fbi, int init)
0927 {
0928     int r = 0;
0929     struct omapfb_info *ofbi = FB2OFB(fbi);
0930     struct fb_var_screeninfo *var = &fbi->var;
0931     struct omap_overlay *ovl;
0932     u16 posx, posy;
0933     u16 outw, outh;
0934     int i;
0935 
0936 #ifdef DEBUG
0937     if (omapfb_test_pattern)
0938         fill_fb(fbi);
0939 #endif
0940 
0941     WARN_ON(!atomic_read(&ofbi->region->lock_count));
0942 
0943     for (i = 0; i < ofbi->num_overlays; i++) {
0944         ovl = ofbi->overlays[i];
0945 
0946         DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
0947 
0948         if (ofbi->region->size == 0) {
0949             /* the fb is not available. disable the overlay */
0950             omapfb_overlay_enable(ovl, 0);
0951             if (!init && ovl->manager)
0952                 ovl->manager->apply(ovl->manager);
0953             continue;
0954         }
0955 
0956         if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
0957             int rotation = (var->rotate + ofbi->rotation[i]) % 4;
0958             if (rotation == FB_ROTATE_CW ||
0959                     rotation == FB_ROTATE_CCW) {
0960                 outw = var->yres;
0961                 outh = var->xres;
0962             } else {
0963                 outw = var->xres;
0964                 outh = var->yres;
0965             }
0966         } else {
0967             struct omap_overlay_info info;
0968             ovl->get_overlay_info(ovl, &info);
0969             outw = info.out_width;
0970             outh = info.out_height;
0971         }
0972 
0973         if (init) {
0974             posx = 0;
0975             posy = 0;
0976         } else {
0977             struct omap_overlay_info info;
0978             ovl->get_overlay_info(ovl, &info);
0979             posx = info.pos_x;
0980             posy = info.pos_y;
0981         }
0982 
0983         r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
0984         if (r)
0985             goto err;
0986 
0987         if (!init && ovl->manager)
0988             ovl->manager->apply(ovl->manager);
0989     }
0990     return 0;
0991 err:
0992     DBG("apply_changes failed\n");
0993     return r;
0994 }
0995 
0996 /* checks var and eventually tweaks it to something supported,
0997  * DO NOT MODIFY PAR */
0998 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
0999 {
1000     struct omapfb_info *ofbi = FB2OFB(fbi);
1001     int r;
1002 
1003     DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1004 
1005     omapfb_get_mem_region(ofbi->region);
1006 
1007     r = check_fb_var(fbi, var);
1008 
1009     omapfb_put_mem_region(ofbi->region);
1010 
1011     return r;
1012 }
1013 
1014 /* set the video mode according to info->var */
1015 static int omapfb_set_par(struct fb_info *fbi)
1016 {
1017     struct omapfb_info *ofbi = FB2OFB(fbi);
1018     int r;
1019 
1020     DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1021 
1022     omapfb_get_mem_region(ofbi->region);
1023 
1024     set_fb_fix(fbi);
1025 
1026     r = setup_vrfb_rotation(fbi);
1027     if (r)
1028         goto out;
1029 
1030     r = omapfb_apply_changes(fbi, 0);
1031 
1032  out:
1033     omapfb_put_mem_region(ofbi->region);
1034 
1035     return r;
1036 }
1037 
1038 static int omapfb_pan_display(struct fb_var_screeninfo *var,
1039         struct fb_info *fbi)
1040 {
1041     struct omapfb_info *ofbi = FB2OFB(fbi);
1042     struct fb_var_screeninfo new_var;
1043     int r;
1044 
1045     DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1046 
1047     if (var->xoffset == fbi->var.xoffset &&
1048         var->yoffset == fbi->var.yoffset)
1049         return 0;
1050 
1051     new_var = fbi->var;
1052     new_var.xoffset = var->xoffset;
1053     new_var.yoffset = var->yoffset;
1054 
1055     fbi->var = new_var;
1056 
1057     omapfb_get_mem_region(ofbi->region);
1058 
1059     r = omapfb_apply_changes(fbi, 0);
1060 
1061     omapfb_put_mem_region(ofbi->region);
1062 
1063     return r;
1064 }
1065 
1066 static void mmap_user_open(struct vm_area_struct *vma)
1067 {
1068     struct omapfb2_mem_region *rg = vma->vm_private_data;
1069 
1070     omapfb_get_mem_region(rg);
1071     atomic_inc(&rg->map_count);
1072     omapfb_put_mem_region(rg);
1073 }
1074 
1075 static void mmap_user_close(struct vm_area_struct *vma)
1076 {
1077     struct omapfb2_mem_region *rg = vma->vm_private_data;
1078 
1079     omapfb_get_mem_region(rg);
1080     atomic_dec(&rg->map_count);
1081     omapfb_put_mem_region(rg);
1082 }
1083 
1084 static const struct vm_operations_struct mmap_user_ops = {
1085     .open = mmap_user_open,
1086     .close = mmap_user_close,
1087 };
1088 
1089 static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1090 {
1091     struct omapfb_info *ofbi = FB2OFB(fbi);
1092     struct fb_fix_screeninfo *fix = &fbi->fix;
1093     struct omapfb2_mem_region *rg;
1094     unsigned long start;
1095     u32 len;
1096     int r;
1097 
1098     rg = omapfb_get_mem_region(ofbi->region);
1099 
1100     start = omapfb_get_region_paddr(ofbi);
1101     len = fix->smem_len;
1102 
1103     DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
1104             vma->vm_pgoff << PAGE_SHIFT);
1105 
1106     vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1107     vma->vm_ops = &mmap_user_ops;
1108     vma->vm_private_data = rg;
1109 
1110     r = vm_iomap_memory(vma, start, len);
1111     if (r)
1112         goto error;
1113 
1114     /* vm_ops.open won't be called for mmap itself. */
1115     atomic_inc(&rg->map_count);
1116 
1117     omapfb_put_mem_region(rg);
1118 
1119     return 0;
1120 
1121 error:
1122     omapfb_put_mem_region(ofbi->region);
1123 
1124     return r;
1125 }
1126 
1127 /* Store a single color palette entry into a pseudo palette or the hardware
1128  * palette if one is available. For now we support only 16bpp and thus store
1129  * the entry only to the pseudo palette.
1130  */
1131 static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1132         u_int blue, u_int transp, int update_hw_pal)
1133 {
1134     /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1135     /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1136     struct fb_var_screeninfo *var = &fbi->var;
1137     int r = 0;
1138 
1139     enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1140 
1141     /*switch (plane->color_mode) {*/
1142     switch (mode) {
1143     case OMAPFB_COLOR_YUV422:
1144     case OMAPFB_COLOR_YUV420:
1145     case OMAPFB_COLOR_YUY422:
1146         r = -EINVAL;
1147         break;
1148     case OMAPFB_COLOR_CLUT_8BPP:
1149     case OMAPFB_COLOR_CLUT_4BPP:
1150     case OMAPFB_COLOR_CLUT_2BPP:
1151     case OMAPFB_COLOR_CLUT_1BPP:
1152         /*
1153            if (fbdev->ctrl->setcolreg)
1154            r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1155            transp, update_hw_pal);
1156            */
1157         r = -EINVAL;
1158         break;
1159     case OMAPFB_COLOR_RGB565:
1160     case OMAPFB_COLOR_RGB444:
1161     case OMAPFB_COLOR_RGB24P:
1162     case OMAPFB_COLOR_RGB24U:
1163         if (regno < 16) {
1164             u32 pal;
1165             pal = ((red >> (16 - var->red.length)) <<
1166                     var->red.offset) |
1167                 ((green >> (16 - var->green.length)) <<
1168                  var->green.offset) |
1169                 (blue >> (16 - var->blue.length));
1170             ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1171         }
1172         break;
1173     default:
1174         BUG();
1175     }
1176     return r;
1177 }
1178 
1179 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1180         u_int transp, struct fb_info *info)
1181 {
1182     DBG("setcolreg\n");
1183 
1184     return _setcolreg(info, regno, red, green, blue, transp, 1);
1185 }
1186 
1187 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1188 {
1189     int count, index, r;
1190     u16 *red, *green, *blue, *transp;
1191     u16 trans = 0xffff;
1192 
1193     DBG("setcmap\n");
1194 
1195     red     = cmap->red;
1196     green   = cmap->green;
1197     blue    = cmap->blue;
1198     transp  = cmap->transp;
1199     index   = cmap->start;
1200 
1201     for (count = 0; count < cmap->len; count++) {
1202         if (transp)
1203             trans = *transp++;
1204         r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1205                 count == cmap->len - 1);
1206         if (r != 0)
1207             return r;
1208     }
1209 
1210     return 0;
1211 }
1212 
1213 static int omapfb_blank(int blank, struct fb_info *fbi)
1214 {
1215     struct omapfb_info *ofbi = FB2OFB(fbi);
1216     struct omapfb2_device *fbdev = ofbi->fbdev;
1217     struct omap_dss_device *display = fb2display(fbi);
1218     struct omapfb_display_data *d;
1219     int r = 0;
1220 
1221     if (!display)
1222         return -EINVAL;
1223 
1224     omapfb_lock(fbdev);
1225 
1226     d = get_display_data(fbdev, display);
1227 
1228     switch (blank) {
1229     case FB_BLANK_UNBLANK:
1230         if (display->state == OMAP_DSS_DISPLAY_ACTIVE)
1231             goto exit;
1232 
1233         r = display->driver->enable(display);
1234 
1235         if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
1236                 d->update_mode == OMAPFB_AUTO_UPDATE &&
1237                 !d->auto_update_work_enabled)
1238             omapfb_start_auto_update(fbdev, display);
1239 
1240         break;
1241 
1242     case FB_BLANK_NORMAL:
1243         /* FB_BLANK_NORMAL could be implemented.
1244          * Needs DSS additions. */
1245     case FB_BLANK_VSYNC_SUSPEND:
1246     case FB_BLANK_HSYNC_SUSPEND:
1247     case FB_BLANK_POWERDOWN:
1248         if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1249             goto exit;
1250 
1251         if (d->auto_update_work_enabled)
1252             omapfb_stop_auto_update(fbdev, display);
1253 
1254         display->driver->disable(display);
1255 
1256         break;
1257 
1258     default:
1259         r = -EINVAL;
1260     }
1261 
1262 exit:
1263     omapfb_unlock(fbdev);
1264 
1265     return r;
1266 }
1267 
1268 #if 0
1269 /* XXX fb_read and fb_write are needed for VRFB */
1270 ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1271         size_t count, loff_t *ppos)
1272 {
1273     DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1274     /* XXX needed for VRFB */
1275     return count;
1276 }
1277 #endif
1278 
1279 static const struct fb_ops omapfb_ops = {
1280     .owner          = THIS_MODULE,
1281     .fb_open        = omapfb_open,
1282     .fb_release     = omapfb_release,
1283     .fb_fillrect    = cfb_fillrect,
1284     .fb_copyarea    = cfb_copyarea,
1285     .fb_imageblit   = cfb_imageblit,
1286     .fb_blank       = omapfb_blank,
1287     .fb_ioctl       = omapfb_ioctl,
1288     .fb_check_var   = omapfb_check_var,
1289     .fb_set_par     = omapfb_set_par,
1290     .fb_pan_display = omapfb_pan_display,
1291     .fb_mmap    = omapfb_mmap,
1292     .fb_setcolreg   = omapfb_setcolreg,
1293     .fb_setcmap = omapfb_setcmap,
1294     /*.fb_write = omapfb_write,*/
1295 };
1296 
1297 static void omapfb_free_fbmem(struct fb_info *fbi)
1298 {
1299     struct omapfb_info *ofbi = FB2OFB(fbi);
1300     struct omapfb2_device *fbdev = ofbi->fbdev;
1301     struct omapfb2_mem_region *rg;
1302 
1303     rg = ofbi->region;
1304 
1305     if (rg->token == NULL)
1306         return;
1307 
1308     WARN_ON(atomic_read(&rg->map_count));
1309 
1310     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1311         /* unmap the 0 angle rotation */
1312         if (rg->vrfb.vaddr[0]) {
1313             iounmap(rg->vrfb.vaddr[0]);
1314             rg->vrfb.vaddr[0] = NULL;
1315         }
1316 
1317         omap_vrfb_release_ctx(&rg->vrfb);
1318     }
1319 
1320     dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
1321             rg->attrs);
1322 
1323     rg->token = NULL;
1324     rg->vaddr = NULL;
1325     rg->paddr = 0;
1326     rg->alloc = 0;
1327     rg->size = 0;
1328 }
1329 
1330 static void clear_fb_info(struct fb_info *fbi)
1331 {
1332     memset(&fbi->var, 0, sizeof(fbi->var));
1333     memset(&fbi->fix, 0, sizeof(fbi->fix));
1334     strscpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1335 }
1336 
1337 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1338 {
1339     int i;
1340 
1341     DBG("free all fbmem\n");
1342 
1343     for (i = 0; i < fbdev->num_fbs; i++) {
1344         struct fb_info *fbi = fbdev->fbs[i];
1345         omapfb_free_fbmem(fbi);
1346         clear_fb_info(fbi);
1347     }
1348 
1349     return 0;
1350 }
1351 
1352 static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1353         unsigned long paddr)
1354 {
1355     struct omapfb_info *ofbi = FB2OFB(fbi);
1356     struct omapfb2_device *fbdev = ofbi->fbdev;
1357     struct omapfb2_mem_region *rg;
1358     void *token;
1359     unsigned long attrs;
1360     dma_addr_t dma_handle;
1361     int r;
1362 
1363     rg = ofbi->region;
1364 
1365     rg->paddr = 0;
1366     rg->vaddr = NULL;
1367     memset(&rg->vrfb, 0, sizeof rg->vrfb);
1368     rg->size = 0;
1369     rg->type = 0;
1370     rg->alloc = false;
1371     rg->map = false;
1372 
1373     size = PAGE_ALIGN(size);
1374 
1375     attrs = DMA_ATTR_WRITE_COMBINE;
1376 
1377     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
1378         attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
1379 
1380     DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1381 
1382     token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
1383             GFP_KERNEL, attrs);
1384 
1385     if (token == NULL) {
1386         dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1387         return -ENOMEM;
1388     }
1389 
1390     DBG("allocated VRAM paddr %lx, vaddr %p\n",
1391             (unsigned long)dma_handle, token);
1392 
1393     if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1394         r = omap_vrfb_request_ctx(&rg->vrfb);
1395         if (r) {
1396             dma_free_attrs(fbdev->dev, size, token, dma_handle,
1397                     attrs);
1398             dev_err(fbdev->dev, "vrfb create ctx failed\n");
1399             return r;
1400         }
1401     }
1402 
1403     rg->attrs = attrs;
1404     rg->token = token;
1405     rg->dma_handle = dma_handle;
1406 
1407     rg->paddr = (unsigned long)dma_handle;
1408     rg->vaddr = (void __iomem *)token;
1409     rg->size = size;
1410     rg->alloc = 1;
1411 
1412     return 0;
1413 }
1414 
1415 /* allocate fbmem using display resolution as reference */
1416 static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1417         unsigned long paddr)
1418 {
1419     struct omapfb_info *ofbi = FB2OFB(fbi);
1420     struct omapfb2_device *fbdev = ofbi->fbdev;
1421     struct omap_dss_device *display;
1422     int bytespp;
1423 
1424     display =  fb2display(fbi);
1425 
1426     if (!display)
1427         return 0;
1428 
1429     switch (omapfb_get_recommended_bpp(fbdev, display)) {
1430     case 16:
1431         bytespp = 2;
1432         break;
1433     case 24:
1434         bytespp = 4;
1435         break;
1436     default:
1437         bytespp = 4;
1438         break;
1439     }
1440 
1441     if (!size) {
1442         u16 w, h;
1443 
1444         display->driver->get_resolution(display, &w, &h);
1445 
1446         if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1447             size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1448                     omap_vrfb_min_phys_size(h, w, bytespp));
1449 
1450             DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1451                     w * h * bytespp, size);
1452         } else {
1453             size = w * h * bytespp;
1454         }
1455     }
1456 
1457     if (!size)
1458         return 0;
1459 
1460     return omapfb_alloc_fbmem(fbi, size, paddr);
1461 }
1462 
1463 static int omapfb_parse_vram_param(const char *param, int max_entries,
1464         unsigned long *sizes, unsigned long *paddrs)
1465 {
1466     unsigned int fbnum;
1467     unsigned long size;
1468     unsigned long paddr = 0;
1469     char *p, *start;
1470 
1471     start = (char *)param;
1472 
1473     while (1) {
1474         p = start;
1475 
1476         fbnum = simple_strtoul(p, &p, 10);
1477 
1478         if (p == start)
1479             return -EINVAL;
1480 
1481         if (*p != ':')
1482             return -EINVAL;
1483 
1484         if (fbnum >= max_entries)
1485             return -EINVAL;
1486 
1487         size = memparse(p + 1, &p);
1488 
1489         if (!size)
1490             return -EINVAL;
1491 
1492         paddr = 0;
1493 
1494         if (*p == '@') {
1495             paddr = simple_strtoul(p + 1, &p, 16);
1496 
1497             if (!paddr)
1498                 return -EINVAL;
1499 
1500         }
1501 
1502         WARN_ONCE(paddr,
1503             "reserving memory at predefined address not supported\n");
1504 
1505         paddrs[fbnum] = paddr;
1506         sizes[fbnum] = size;
1507 
1508         if (*p == 0)
1509             break;
1510 
1511         if (*p != ',')
1512             return -EINVAL;
1513 
1514         ++p;
1515 
1516         start = p;
1517     }
1518 
1519     return 0;
1520 }
1521 
1522 static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1523 {
1524     int i, r;
1525     unsigned long vram_sizes[10];
1526     unsigned long vram_paddrs[10];
1527 
1528     memset(&vram_sizes, 0, sizeof(vram_sizes));
1529     memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1530 
1531     if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1532                 vram_sizes, vram_paddrs)) {
1533         dev_err(fbdev->dev, "failed to parse vram parameter\n");
1534 
1535         memset(&vram_sizes, 0, sizeof(vram_sizes));
1536         memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1537     }
1538 
1539     for (i = 0; i < fbdev->num_fbs; i++) {
1540         /* allocate memory automatically only for fb0, or if
1541          * excplicitly defined with vram or plat data option */
1542         if (i == 0 || vram_sizes[i] != 0) {
1543             r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1544                     vram_sizes[i], vram_paddrs[i]);
1545 
1546             if (r)
1547                 return r;
1548         }
1549     }
1550 
1551     for (i = 0; i < fbdev->num_fbs; i++) {
1552         struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1553         struct omapfb2_mem_region *rg;
1554         rg = ofbi->region;
1555 
1556         DBG("region%d phys %08x virt %p size=%lu\n",
1557                 i,
1558                 rg->paddr,
1559                 rg->vaddr,
1560                 rg->size);
1561     }
1562 
1563     return 0;
1564 }
1565 
1566 static void omapfb_clear_fb(struct fb_info *fbi)
1567 {
1568     const struct fb_fillrect rect = {
1569         .dx = 0,
1570         .dy = 0,
1571         .width = fbi->var.xres_virtual,
1572         .height = fbi->var.yres_virtual,
1573         .color = 0,
1574         .rop = ROP_COPY,
1575     };
1576 
1577     cfb_fillrect(fbi, &rect);
1578 }
1579 
1580 int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1581 {
1582     struct omapfb_info *ofbi = FB2OFB(fbi);
1583     struct omapfb2_device *fbdev = ofbi->fbdev;
1584     struct omapfb2_mem_region *rg = ofbi->region;
1585     unsigned long old_size = rg->size;
1586     unsigned long old_paddr = rg->paddr;
1587     int old_type = rg->type;
1588     int r;
1589 
1590     if (type != OMAPFB_MEMTYPE_SDRAM)
1591         return -EINVAL;
1592 
1593     size = PAGE_ALIGN(size);
1594 
1595     if (old_size == size && old_type == type)
1596         return 0;
1597 
1598     omapfb_free_fbmem(fbi);
1599 
1600     if (size == 0) {
1601         clear_fb_info(fbi);
1602         return 0;
1603     }
1604 
1605     r = omapfb_alloc_fbmem(fbi, size, 0);
1606 
1607     if (r) {
1608         if (old_size)
1609             omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1610 
1611         if (rg->size == 0)
1612             clear_fb_info(fbi);
1613 
1614         return r;
1615     }
1616 
1617     if (old_size == size)
1618         return 0;
1619 
1620     if (old_size == 0) {
1621         DBG("initializing fb %d\n", ofbi->id);
1622         r = omapfb_fb_init(fbdev, fbi);
1623         if (r) {
1624             DBG("omapfb_fb_init failed\n");
1625             goto err;
1626         }
1627         r = omapfb_apply_changes(fbi, 1);
1628         if (r) {
1629             DBG("omapfb_apply_changes failed\n");
1630             goto err;
1631         }
1632     } else {
1633         struct fb_var_screeninfo new_var;
1634         memcpy(&new_var, &fbi->var, sizeof(new_var));
1635         r = check_fb_var(fbi, &new_var);
1636         if (r)
1637             goto err;
1638         memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1639         set_fb_fix(fbi);
1640         r = setup_vrfb_rotation(fbi);
1641         if (r)
1642             goto err;
1643     }
1644 
1645     omapfb_clear_fb(fbi);
1646 
1647     return 0;
1648 err:
1649     omapfb_free_fbmem(fbi);
1650     clear_fb_info(fbi);
1651     return r;
1652 }
1653 
1654 static void omapfb_auto_update_work(struct work_struct *work)
1655 {
1656     struct omap_dss_device *dssdev;
1657     struct omap_dss_driver *dssdrv;
1658     struct omapfb_display_data *d;
1659     u16 w, h;
1660     unsigned int freq;
1661     struct omapfb2_device *fbdev;
1662 
1663     d = container_of(work, struct omapfb_display_data,
1664             auto_update_work.work);
1665 
1666     dssdev = d->dssdev;
1667     dssdrv = dssdev->driver;
1668     fbdev = d->fbdev;
1669 
1670     if (!dssdrv || !dssdrv->update)
1671         return;
1672 
1673     if (dssdrv->sync)
1674         dssdrv->sync(dssdev);
1675 
1676     dssdrv->get_resolution(dssdev, &w, &h);
1677     dssdrv->update(dssdev, 0, 0, w, h);
1678 
1679     freq = auto_update_freq;
1680     if (freq == 0)
1681         freq = 20;
1682     queue_delayed_work(fbdev->auto_update_wq,
1683             &d->auto_update_work, HZ / freq);
1684 }
1685 
1686 void omapfb_start_auto_update(struct omapfb2_device *fbdev,
1687         struct omap_dss_device *display)
1688 {
1689     struct omapfb_display_data *d;
1690 
1691     if (fbdev->auto_update_wq == NULL) {
1692         struct workqueue_struct *wq;
1693 
1694         wq = create_singlethread_workqueue("omapfb_auto_update");
1695 
1696         if (wq == NULL) {
1697             dev_err(fbdev->dev, "Failed to create workqueue for "
1698                     "auto-update\n");
1699             return;
1700         }
1701 
1702         fbdev->auto_update_wq = wq;
1703     }
1704 
1705     d = get_display_data(fbdev, display);
1706 
1707     INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
1708 
1709     d->auto_update_work_enabled = true;
1710 
1711     omapfb_auto_update_work(&d->auto_update_work.work);
1712 }
1713 
1714 void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
1715         struct omap_dss_device *display)
1716 {
1717     struct omapfb_display_data *d;
1718 
1719     d = get_display_data(fbdev, display);
1720 
1721     cancel_delayed_work_sync(&d->auto_update_work);
1722 
1723     d->auto_update_work_enabled = false;
1724 }
1725 
1726 /* initialize fb_info, var, fix to something sane based on the display */
1727 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1728 {
1729     struct fb_var_screeninfo *var = &fbi->var;
1730     struct omap_dss_device *display = fb2display(fbi);
1731     struct omapfb_info *ofbi = FB2OFB(fbi);
1732     int r = 0;
1733 
1734     fbi->fbops = &omapfb_ops;
1735     fbi->flags = FBINFO_FLAG_DEFAULT;
1736     fbi->pseudo_palette = fbdev->pseudo_palette;
1737 
1738     if (ofbi->region->size == 0) {
1739         clear_fb_info(fbi);
1740         return 0;
1741     }
1742 
1743     var->nonstd = 0;
1744     var->bits_per_pixel = 0;
1745 
1746     var->rotate = def_rotate;
1747 
1748     if (display) {
1749         u16 w, h;
1750         int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1751 
1752         display->driver->get_resolution(display, &w, &h);
1753 
1754         if (rotation == FB_ROTATE_CW ||
1755                 rotation == FB_ROTATE_CCW) {
1756             var->xres = h;
1757             var->yres = w;
1758         } else {
1759             var->xres = w;
1760             var->yres = h;
1761         }
1762 
1763         var->xres_virtual = var->xres;
1764         var->yres_virtual = var->yres;
1765 
1766         if (!var->bits_per_pixel) {
1767             switch (omapfb_get_recommended_bpp(fbdev, display)) {
1768             case 16:
1769                 var->bits_per_pixel = 16;
1770                 break;
1771             case 24:
1772                 var->bits_per_pixel = 32;
1773                 break;
1774             default:
1775                 dev_err(fbdev->dev, "illegal display "
1776                         "bpp\n");
1777                 return -EINVAL;
1778             }
1779         }
1780     } else {
1781         /* if there's no display, let's just guess some basic values */
1782         var->xres = 320;
1783         var->yres = 240;
1784         var->xres_virtual = var->xres;
1785         var->yres_virtual = var->yres;
1786         if (!var->bits_per_pixel)
1787             var->bits_per_pixel = 16;
1788     }
1789 
1790     r = check_fb_var(fbi, var);
1791     if (r)
1792         goto err;
1793 
1794     set_fb_fix(fbi);
1795     r = setup_vrfb_rotation(fbi);
1796     if (r)
1797         goto err;
1798 
1799     r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1800     if (r)
1801         dev_err(fbdev->dev, "unable to allocate color map memory\n");
1802 
1803 err:
1804     return r;
1805 }
1806 
1807 static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1808 {
1809     fb_dealloc_cmap(&fbi->cmap);
1810 }
1811 
1812 
1813 static void omapfb_free_resources(struct omapfb2_device *fbdev)
1814 {
1815     int i;
1816 
1817     DBG("free_resources\n");
1818 
1819     if (fbdev == NULL)
1820         return;
1821 
1822     for (i = 0; i < fbdev->num_overlays; i++) {
1823         struct omap_overlay *ovl = fbdev->overlays[i];
1824 
1825         ovl->disable(ovl);
1826 
1827         if (ovl->manager)
1828             ovl->unset_manager(ovl);
1829     }
1830 
1831     for (i = 0; i < fbdev->num_fbs; i++)
1832         unregister_framebuffer(fbdev->fbs[i]);
1833 
1834     /* free the reserved fbmem */
1835     omapfb_free_all_fbmem(fbdev);
1836 
1837     for (i = 0; i < fbdev->num_fbs; i++) {
1838         fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1839         framebuffer_release(fbdev->fbs[i]);
1840     }
1841 
1842     for (i = 0; i < fbdev->num_displays; i++) {
1843         struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
1844 
1845         if (fbdev->displays[i].auto_update_work_enabled)
1846             omapfb_stop_auto_update(fbdev, dssdev);
1847 
1848         if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
1849             dssdev->driver->disable(dssdev);
1850 
1851         dssdev->driver->disconnect(dssdev);
1852 
1853         omap_dss_put_device(dssdev);
1854     }
1855 
1856     if (fbdev->auto_update_wq != NULL) {
1857         destroy_workqueue(fbdev->auto_update_wq);
1858         fbdev->auto_update_wq = NULL;
1859     }
1860 
1861     dev_set_drvdata(fbdev->dev, NULL);
1862 }
1863 
1864 static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1865 {
1866     int r, i;
1867 
1868     fbdev->num_fbs = 0;
1869 
1870     DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1871 
1872     /* allocate fb_infos */
1873     for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1874         struct fb_info *fbi;
1875         struct omapfb_info *ofbi;
1876 
1877         fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1878                 fbdev->dev);
1879         if (!fbi)
1880             return -ENOMEM;
1881 
1882         clear_fb_info(fbi);
1883 
1884         fbdev->fbs[i] = fbi;
1885 
1886         ofbi = FB2OFB(fbi);
1887         ofbi->fbdev = fbdev;
1888         ofbi->id = i;
1889 
1890         ofbi->region = &fbdev->regions[i];
1891         ofbi->region->id = i;
1892         init_rwsem(&ofbi->region->lock);
1893 
1894         /* assign these early, so that fb alloc can use them */
1895         ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1896             OMAP_DSS_ROT_DMA;
1897         ofbi->mirror = def_mirror;
1898 
1899         fbdev->num_fbs++;
1900     }
1901 
1902     DBG("fb_infos allocated\n");
1903 
1904     /* assign overlays for the fbs */
1905     for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1906         struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1907 
1908         ofbi->overlays[0] = fbdev->overlays[i];
1909         ofbi->num_overlays = 1;
1910     }
1911 
1912     /* allocate fb memories */
1913     r = omapfb_allocate_all_fbs(fbdev);
1914     if (r) {
1915         dev_err(fbdev->dev, "failed to allocate fbmem\n");
1916         return r;
1917     }
1918 
1919     DBG("fbmems allocated\n");
1920 
1921     /* setup fb_infos */
1922     for (i = 0; i < fbdev->num_fbs; i++) {
1923         struct fb_info *fbi = fbdev->fbs[i];
1924         struct omapfb_info *ofbi = FB2OFB(fbi);
1925 
1926         omapfb_get_mem_region(ofbi->region);
1927         r = omapfb_fb_init(fbdev, fbi);
1928         omapfb_put_mem_region(ofbi->region);
1929 
1930         if (r) {
1931             dev_err(fbdev->dev, "failed to setup fb_info\n");
1932             return r;
1933         }
1934     }
1935 
1936     for (i = 0; i < fbdev->num_fbs; i++) {
1937         struct fb_info *fbi = fbdev->fbs[i];
1938         struct omapfb_info *ofbi = FB2OFB(fbi);
1939 
1940         if (ofbi->region->size == 0)
1941             continue;
1942 
1943         omapfb_clear_fb(fbi);
1944     }
1945 
1946     DBG("fb_infos initialized\n");
1947 
1948     for (i = 0; i < fbdev->num_fbs; i++) {
1949         r = register_framebuffer(fbdev->fbs[i]);
1950         if (r != 0) {
1951             dev_err(fbdev->dev,
1952                 "registering framebuffer %d failed\n", i);
1953             return r;
1954         }
1955     }
1956 
1957     DBG("framebuffers registered\n");
1958 
1959     for (i = 0; i < fbdev->num_fbs; i++) {
1960         struct fb_info *fbi = fbdev->fbs[i];
1961         struct omapfb_info *ofbi = FB2OFB(fbi);
1962 
1963         omapfb_get_mem_region(ofbi->region);
1964         r = omapfb_apply_changes(fbi, 1);
1965         omapfb_put_mem_region(ofbi->region);
1966 
1967         if (r) {
1968             dev_err(fbdev->dev, "failed to change mode\n");
1969             return r;
1970         }
1971     }
1972 
1973     /* Enable fb0 */
1974     if (fbdev->num_fbs > 0) {
1975         struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1976 
1977         if (ofbi->num_overlays > 0) {
1978             struct omap_overlay *ovl = ofbi->overlays[0];
1979 
1980             ovl->manager->apply(ovl->manager);
1981 
1982             r = omapfb_overlay_enable(ovl, 1);
1983 
1984             if (r) {
1985                 dev_err(fbdev->dev,
1986                         "failed to enable overlay\n");
1987                 return r;
1988             }
1989         }
1990     }
1991 
1992     DBG("create_framebuffers done\n");
1993 
1994     return 0;
1995 }
1996 
1997 static int omapfb_mode_to_timings(const char *mode_str,
1998         struct omap_dss_device *display,
1999         struct omap_video_timings *timings, u8 *bpp)
2000 {
2001     struct fb_info *fbi;
2002     struct fb_var_screeninfo *var;
2003     struct fb_ops *fbops;
2004     int r;
2005 
2006 #ifdef CONFIG_OMAP2_DSS_VENC
2007     if (strcmp(mode_str, "pal") == 0) {
2008         *timings = omap_dss_pal_timings;
2009         *bpp = 24;
2010         return 0;
2011     } else if (strcmp(mode_str, "ntsc") == 0) {
2012         *timings = omap_dss_ntsc_timings;
2013         *bpp = 24;
2014         return 0;
2015     }
2016 #endif
2017 
2018     /* this is quite a hack, but I wanted to use the modedb and for
2019      * that we need fb_info and var, so we create dummy ones */
2020 
2021     *bpp = 0;
2022     fbi = NULL;
2023     var = NULL;
2024     fbops = NULL;
2025 
2026     fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
2027     if (fbi == NULL) {
2028         r = -ENOMEM;
2029         goto err;
2030     }
2031 
2032     var = kzalloc(sizeof(*var), GFP_KERNEL);
2033     if (var == NULL) {
2034         r = -ENOMEM;
2035         goto err;
2036     }
2037 
2038     fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2039     if (fbops == NULL) {
2040         r = -ENOMEM;
2041         goto err;
2042     }
2043 
2044     fbi->fbops = fbops;
2045 
2046     r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
2047     if (r == 0) {
2048         r = -EINVAL;
2049         goto err;
2050     }
2051 
2052     if (display->driver->get_timings) {
2053         display->driver->get_timings(display, timings);
2054     } else {
2055         timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2056         timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2057         timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
2058     }
2059 
2060     timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000;
2061     timings->hbp = var->left_margin;
2062     timings->hfp = var->right_margin;
2063     timings->vbp = var->upper_margin;
2064     timings->vfp = var->lower_margin;
2065     timings->hsw = var->hsync_len;
2066     timings->vsw = var->vsync_len;
2067     timings->x_res = var->xres;
2068     timings->y_res = var->yres;
2069     timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ?
2070                 OMAPDSS_SIG_ACTIVE_HIGH :
2071                 OMAPDSS_SIG_ACTIVE_LOW;
2072     timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ?
2073                 OMAPDSS_SIG_ACTIVE_HIGH :
2074                 OMAPDSS_SIG_ACTIVE_LOW;
2075     timings->interlace = var->vmode & FB_VMODE_INTERLACED;
2076 
2077     switch (var->bits_per_pixel) {
2078     case 16:
2079         *bpp = 16;
2080         break;
2081     case 24:
2082     case 32:
2083     default:
2084         *bpp = 24;
2085         break;
2086     }
2087 
2088     r = 0;
2089 
2090 err:
2091     kfree(fbi);
2092     kfree(var);
2093     kfree(fbops);
2094 
2095     return r;
2096 }
2097 
2098 static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2099         struct omap_dss_device *display, char *mode_str)
2100 {
2101     int r;
2102     u8 bpp;
2103     struct omap_video_timings timings, temp_timings;
2104     struct omapfb_display_data *d;
2105 
2106     r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);
2107     if (r)
2108         return r;
2109 
2110     d = get_display_data(fbdev, display);
2111     d->bpp_override = bpp;
2112 
2113     if (display->driver->check_timings) {
2114         r = display->driver->check_timings(display, &timings);
2115         if (r)
2116             return r;
2117     } else {
2118         /* If check_timings is not present compare xres and yres */
2119         if (display->driver->get_timings) {
2120             display->driver->get_timings(display, &temp_timings);
2121 
2122             if (temp_timings.x_res != timings.x_res ||
2123                 temp_timings.y_res != timings.y_res)
2124                 return -EINVAL;
2125         }
2126     }
2127 
2128     if (display->driver->set_timings)
2129             display->driver->set_timings(display, &timings);
2130 
2131     return 0;
2132 }
2133 
2134 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
2135         struct omap_dss_device *dssdev)
2136 {
2137     struct omapfb_display_data *d;
2138 
2139     BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
2140 
2141     d = get_display_data(fbdev, dssdev);
2142 
2143     if (d->bpp_override != 0)
2144         return d->bpp_override;
2145 
2146     return dssdev->driver->get_recommended_bpp(dssdev);
2147 }
2148 
2149 static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2150 {
2151     char *str, *options, *this_opt;
2152     int r = 0;
2153 
2154     str = kstrdup(def_mode, GFP_KERNEL);
2155     if (!str)
2156         return -ENOMEM;
2157     options = str;
2158 
2159     while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2160         char *p, *display_str, *mode_str;
2161         struct omap_dss_device *display;
2162         int i;
2163 
2164         p = strchr(this_opt, ':');
2165         if (!p) {
2166             r = -EINVAL;
2167             break;
2168         }
2169 
2170         *p = 0;
2171         display_str = this_opt;
2172         mode_str = p + 1;
2173 
2174         display = NULL;
2175         for (i = 0; i < fbdev->num_displays; ++i) {
2176             if (strcmp(fbdev->displays[i].dssdev->name,
2177                         display_str) == 0) {
2178                 display = fbdev->displays[i].dssdev;
2179                 break;
2180             }
2181         }
2182 
2183         if (!display) {
2184             r = -EINVAL;
2185             break;
2186         }
2187 
2188         r = omapfb_set_def_mode(fbdev, display, mode_str);
2189         if (r)
2190             break;
2191     }
2192 
2193     kfree(str);
2194 
2195     return r;
2196 }
2197 
2198 static void fb_videomode_to_omap_timings(struct fb_videomode *m,
2199         struct omap_dss_device *display,
2200         struct omap_video_timings *t)
2201 {
2202     if (display->driver->get_timings) {
2203         display->driver->get_timings(display, t);
2204     } else {
2205         t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2206         t->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2207         t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
2208     }
2209 
2210     t->x_res = m->xres;
2211     t->y_res = m->yres;
2212     t->pixelclock = PICOS2KHZ(m->pixclock) * 1000;
2213     t->hsw = m->hsync_len;
2214     t->hfp = m->right_margin;
2215     t->hbp = m->left_margin;
2216     t->vsw = m->vsync_len;
2217     t->vfp = m->lower_margin;
2218     t->vbp = m->upper_margin;
2219     t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ?
2220                 OMAPDSS_SIG_ACTIVE_HIGH :
2221                 OMAPDSS_SIG_ACTIVE_LOW;
2222     t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ?
2223                 OMAPDSS_SIG_ACTIVE_HIGH :
2224                 OMAPDSS_SIG_ACTIVE_LOW;
2225     t->interlace = m->vmode & FB_VMODE_INTERLACED;
2226 }
2227 
2228 static int omapfb_find_best_mode(struct omap_dss_device *display,
2229         struct omap_video_timings *timings)
2230 {
2231     struct fb_monspecs *specs;
2232     u8 *edid;
2233     int r, i, best_idx, len;
2234 
2235     if (!display->driver->read_edid)
2236         return -ENODEV;
2237 
2238     len = 0x80 * 2;
2239     edid = kmalloc(len, GFP_KERNEL);
2240     if (edid == NULL)
2241         return -ENOMEM;
2242 
2243     r = display->driver->read_edid(display, edid, len);
2244     if (r < 0)
2245         goto err1;
2246 
2247     specs = kzalloc(sizeof(*specs), GFP_KERNEL);
2248     if (specs == NULL) {
2249         r = -ENOMEM;
2250         goto err1;
2251     }
2252 
2253     fb_edid_to_monspecs(edid, specs);
2254 
2255     best_idx = -1;
2256 
2257     for (i = 0; i < specs->modedb_len; ++i) {
2258         struct fb_videomode *m;
2259         struct omap_video_timings t;
2260 
2261         m = &specs->modedb[i];
2262 
2263         if (m->pixclock == 0)
2264             continue;
2265 
2266         /* skip repeated pixel modes */
2267         if (m->xres == 2880 || m->xres == 1440)
2268             continue;
2269 
2270         if (m->vmode & FB_VMODE_INTERLACED ||
2271                 m->vmode & FB_VMODE_DOUBLE)
2272             continue;
2273 
2274         fb_videomode_to_omap_timings(m, display, &t);
2275 
2276         r = display->driver->check_timings(display, &t);
2277         if (r == 0) {
2278             best_idx = i;
2279             break;
2280         }
2281     }
2282 
2283     if (best_idx == -1) {
2284         r = -ENOENT;
2285         goto err2;
2286     }
2287 
2288     fb_videomode_to_omap_timings(&specs->modedb[best_idx], display,
2289         timings);
2290 
2291     r = 0;
2292 
2293 err2:
2294     fb_destroy_modedb(specs->modedb);
2295     kfree(specs);
2296 err1:
2297     kfree(edid);
2298 
2299     return r;
2300 }
2301 
2302 static int omapfb_init_display(struct omapfb2_device *fbdev,
2303         struct omap_dss_device *dssdev)
2304 {
2305     struct omap_dss_driver *dssdrv = dssdev->driver;
2306     struct omapfb_display_data *d;
2307     int r;
2308 
2309     r = dssdrv->enable(dssdev);
2310     if (r) {
2311         dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2312                 dssdev->name);
2313         return r;
2314     }
2315 
2316     d = get_display_data(fbdev, dssdev);
2317 
2318     d->fbdev = fbdev;
2319 
2320     if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2321         u16 w, h;
2322 
2323         if (auto_update) {
2324             omapfb_start_auto_update(fbdev, dssdev);
2325             d->update_mode = OMAPFB_AUTO_UPDATE;
2326         } else {
2327             d->update_mode = OMAPFB_MANUAL_UPDATE;
2328         }
2329 
2330         if (dssdrv->enable_te) {
2331             r = dssdrv->enable_te(dssdev, 1);
2332             if (r) {
2333                 dev_err(fbdev->dev, "Failed to set TE\n");
2334                 return r;
2335             }
2336         }
2337 
2338         dssdrv->get_resolution(dssdev, &w, &h);
2339         r = dssdrv->update(dssdev, 0, 0, w, h);
2340         if (r) {
2341             dev_err(fbdev->dev,
2342                     "Failed to update display\n");
2343             return r;
2344         }
2345     } else {
2346         d->update_mode = OMAPFB_AUTO_UPDATE;
2347     }
2348 
2349     return 0;
2350 }
2351 
2352 static int omapfb_init_connections(struct omapfb2_device *fbdev,
2353         struct omap_dss_device *def_dssdev)
2354 {
2355     int i, r;
2356     struct omap_overlay_manager *mgr;
2357 
2358     r = def_dssdev->driver->connect(def_dssdev);
2359     if (r) {
2360         dev_err(fbdev->dev, "failed to connect default display\n");
2361         return r;
2362     }
2363 
2364     for (i = 0; i < fbdev->num_displays; ++i) {
2365         struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
2366 
2367         if (dssdev == def_dssdev)
2368             continue;
2369 
2370         /*
2371          * We don't care if the connect succeeds or not. We just want to
2372          * connect as many displays as possible.
2373          */
2374         dssdev->driver->connect(dssdev);
2375     }
2376 
2377     mgr = omapdss_find_mgr_from_display(def_dssdev);
2378 
2379     if (!mgr) {
2380         dev_err(fbdev->dev, "no ovl manager for the default display\n");
2381         return -EINVAL;
2382     }
2383 
2384     for (i = 0; i < fbdev->num_overlays; i++) {
2385         struct omap_overlay *ovl = fbdev->overlays[i];
2386 
2387         if (ovl->manager)
2388             ovl->unset_manager(ovl);
2389 
2390         r = ovl->set_manager(ovl, mgr);
2391         if (r)
2392             dev_warn(fbdev->dev,
2393                     "failed to connect overlay %s to manager %s\n",
2394                     ovl->name, mgr->name);
2395     }
2396 
2397     return 0;
2398 }
2399 
2400 static struct omap_dss_device *
2401 omapfb_find_default_display(struct omapfb2_device *fbdev)
2402 {
2403     const char *def_name;
2404     int i;
2405 
2406     /*
2407      * Search with the display name from the user or the board file,
2408      * comparing to display names and aliases
2409      */
2410 
2411     def_name = omapdss_get_default_display_name();
2412 
2413     if (def_name) {
2414         for (i = 0; i < fbdev->num_displays; ++i) {
2415             struct omap_dss_device *dssdev;
2416 
2417             dssdev = fbdev->displays[i].dssdev;
2418 
2419             if (dssdev->name && strcmp(def_name, dssdev->name) == 0)
2420                 return dssdev;
2421 
2422             if (strcmp(def_name, dssdev->alias) == 0)
2423                 return dssdev;
2424         }
2425 
2426         /* def_name given but not found */
2427         return NULL;
2428     }
2429 
2430     /* then look for DT alias display0 */
2431     for (i = 0; i < fbdev->num_displays; ++i) {
2432         struct omap_dss_device *dssdev;
2433         int id;
2434 
2435         dssdev = fbdev->displays[i].dssdev;
2436 
2437         if (dssdev->dev->of_node == NULL)
2438             continue;
2439 
2440         id = of_alias_get_id(dssdev->dev->of_node, "display");
2441         if (id == 0)
2442             return dssdev;
2443     }
2444 
2445     /* return the first display we have in the list */
2446     return fbdev->displays[0].dssdev;
2447 }
2448 
2449 static int omapfb_probe(struct platform_device *pdev)
2450 {
2451     struct omapfb2_device *fbdev = NULL;
2452     int r = 0;
2453     int i;
2454     struct omap_dss_device *def_display;
2455     struct omap_dss_device *dssdev;
2456 
2457     DBG("omapfb_probe\n");
2458 
2459     if (omapdss_is_initialized() == false)
2460         return -EPROBE_DEFER;
2461 
2462     if (pdev->num_resources != 0) {
2463         dev_err(&pdev->dev, "probed for an unknown device\n");
2464         r = -ENODEV;
2465         goto err0;
2466     }
2467 
2468     fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device),
2469             GFP_KERNEL);
2470     if (fbdev == NULL) {
2471         r = -ENOMEM;
2472         goto err0;
2473     }
2474 
2475     if (def_vrfb && !omap_vrfb_supported()) {
2476         def_vrfb = 0;
2477         dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
2478                 "ignoring the module parameter vrfb=y\n");
2479     }
2480 
2481     r = omapdss_compat_init();
2482     if (r)
2483         goto err0;
2484 
2485     mutex_init(&fbdev->mtx);
2486 
2487     fbdev->dev = &pdev->dev;
2488     platform_set_drvdata(pdev, fbdev);
2489 
2490     fbdev->num_displays = 0;
2491     dssdev = NULL;
2492     for_each_dss_dev(dssdev) {
2493         struct omapfb_display_data *d;
2494 
2495         omap_dss_get_device(dssdev);
2496 
2497         if (!dssdev->driver) {
2498             dev_warn(&pdev->dev, "no driver for display: %s\n",
2499                 dssdev->name);
2500             omap_dss_put_device(dssdev);
2501             continue;
2502         }
2503 
2504         d = &fbdev->displays[fbdev->num_displays++];
2505         d->dssdev = dssdev;
2506         if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
2507             d->update_mode = OMAPFB_MANUAL_UPDATE;
2508         else
2509             d->update_mode = OMAPFB_AUTO_UPDATE;
2510     }
2511 
2512     if (fbdev->num_displays == 0) {
2513         dev_err(&pdev->dev, "no displays\n");
2514         r = -EPROBE_DEFER;
2515         goto cleanup;
2516     }
2517 
2518     fbdev->num_overlays = omap_dss_get_num_overlays();
2519     for (i = 0; i < fbdev->num_overlays; i++)
2520         fbdev->overlays[i] = omap_dss_get_overlay(i);
2521 
2522     fbdev->num_managers = omap_dss_get_num_overlay_managers();
2523     for (i = 0; i < fbdev->num_managers; i++)
2524         fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2525 
2526     def_display = omapfb_find_default_display(fbdev);
2527     if (def_display == NULL) {
2528         dev_err(fbdev->dev, "failed to find default display\n");
2529         r = -EPROBE_DEFER;
2530         goto cleanup;
2531     }
2532 
2533     r = omapfb_init_connections(fbdev, def_display);
2534     if (r) {
2535         dev_err(fbdev->dev, "failed to init overlay connections\n");
2536         goto cleanup;
2537     }
2538 
2539     if (def_mode && strlen(def_mode) > 0) {
2540         if (omapfb_parse_def_modes(fbdev))
2541             dev_warn(&pdev->dev, "cannot parse default modes\n");
2542     } else if (def_display && def_display->driver->set_timings &&
2543             def_display->driver->check_timings) {
2544         struct omap_video_timings t;
2545 
2546         r = omapfb_find_best_mode(def_display, &t);
2547 
2548         if (r == 0)
2549             def_display->driver->set_timings(def_display, &t);
2550     }
2551 
2552     r = omapfb_create_framebuffers(fbdev);
2553     if (r)
2554         goto cleanup;
2555 
2556     for (i = 0; i < fbdev->num_managers; i++) {
2557         struct omap_overlay_manager *mgr;
2558         mgr = fbdev->managers[i];
2559         r = mgr->apply(mgr);
2560         if (r)
2561             dev_warn(fbdev->dev, "failed to apply dispc config\n");
2562     }
2563 
2564     DBG("mgr->apply'ed\n");
2565 
2566     if (def_display) {
2567         r = omapfb_init_display(fbdev, def_display);
2568         if (r) {
2569             dev_err(fbdev->dev,
2570                     "failed to initialize default "
2571                     "display\n");
2572             goto cleanup;
2573         }
2574     }
2575 
2576     DBG("create sysfs for fbs\n");
2577     r = omapfb_create_sysfs(fbdev);
2578     if (r) {
2579         dev_err(fbdev->dev, "failed to create sysfs entries\n");
2580         goto cleanup;
2581     }
2582 
2583     if (def_display) {
2584         u16 w, h;
2585 
2586         def_display->driver->get_resolution(def_display, &w, &h);
2587 
2588         dev_info(fbdev->dev, "using display '%s' mode %dx%d\n",
2589             def_display->name, w, h);
2590     }
2591 
2592     return 0;
2593 
2594 cleanup:
2595     omapfb_free_resources(fbdev);
2596     omapdss_compat_uninit();
2597 err0:
2598     dev_err(&pdev->dev, "failed to setup omapfb\n");
2599     return r;
2600 }
2601 
2602 static int omapfb_remove(struct platform_device *pdev)
2603 {
2604     struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2605 
2606     /* FIXME: wait till completion of pending events */
2607 
2608     omapfb_remove_sysfs(fbdev);
2609 
2610     omapfb_free_resources(fbdev);
2611 
2612     omapdss_compat_uninit();
2613 
2614     return 0;
2615 }
2616 
2617 static struct platform_driver omapfb_driver = {
2618     .probe      = omapfb_probe,
2619     .remove         = omapfb_remove,
2620     .driver         = {
2621         .name   = "omapfb",
2622     },
2623 };
2624 
2625 module_param_named(mode, def_mode, charp, 0);
2626 module_param_named(vram, def_vram, charp, 0);
2627 module_param_named(rotate, def_rotate, int, 0);
2628 module_param_named(vrfb, def_vrfb, bool, 0);
2629 module_param_named(mirror, def_mirror, bool, 0);
2630 
2631 module_platform_driver(omapfb_driver);
2632 
2633 MODULE_ALIAS("platform:omapfb");
2634 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2635 MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2636 MODULE_LICENSE("GPL v2");