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