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(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 int omapfb_parse_vram_param(const char *param, int max_entries,
1491                unsigned long *sizes, unsigned long *paddrs)
1492{
1493        int fbnum;
1494        unsigned long size;
1495        unsigned long paddr = 0;
1496        char *p, *start;
1497
1498        start = (char *)param;
1499
1500        while (1) {
1501                p = start;
1502
1503                fbnum = simple_strtoul(p, &p, 10);
1504
1505                if (p == param)
1506                        return -EINVAL;
1507
1508                if (*p != ':')
1509                        return -EINVAL;
1510
1511                if (fbnum >= max_entries)
1512                        return -EINVAL;
1513
1514                size = memparse(p + 1, &p);
1515
1516                if (!size)
1517                        return -EINVAL;
1518
1519                paddr = 0;
1520
1521                if (*p == '@') {
1522                        paddr = simple_strtoul(p + 1, &p, 16);
1523
1524                        if (!paddr)
1525                                return -EINVAL;
1526
1527                }
1528
1529                paddrs[fbnum] = paddr;
1530                sizes[fbnum] = size;
1531
1532                if (*p == 0)
1533                        break;
1534
1535                if (*p != ',')
1536                        return -EINVAL;
1537
1538                ++p;
1539
1540                start = p;
1541        }
1542
1543        return 0;
1544}
1545
1546static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1547{
1548        int i, r;
1549        unsigned long vram_sizes[10];
1550        unsigned long vram_paddrs[10];
1551
1552        memset(&vram_sizes, 0, sizeof(vram_sizes));
1553        memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1554
1555        if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1556                                vram_sizes, vram_paddrs)) {
1557                dev_err(fbdev->dev, "failed to parse vram parameter\n");
1558
1559                memset(&vram_sizes, 0, sizeof(vram_sizes));
1560                memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1561        }
1562
1563        for (i = 0; i < fbdev->num_fbs; i++) {
1564                /* allocate memory automatically only for fb0, or if
1565                 * excplicitly defined with vram or plat data option */
1566                if (i == 0 || vram_sizes[i] != 0) {
1567                        r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1568                                        vram_sizes[i], vram_paddrs[i]);
1569
1570                        if (r)
1571                                return r;
1572                }
1573        }
1574
1575        for (i = 0; i < fbdev->num_fbs; i++) {
1576                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1577                struct omapfb2_mem_region *rg;
1578                rg = ofbi->region;
1579
1580                DBG("region%d phys %08x virt %p size=%lu\n",
1581                                i,
1582                                rg->paddr,
1583                                rg->vaddr,
1584                                rg->size);
1585        }
1586
1587        return 0;
1588}
1589
1590int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1591{
1592        struct omapfb_info *ofbi = FB2OFB(fbi);
1593        struct omapfb2_device *fbdev = ofbi->fbdev;
1594        struct omap_dss_device *display = fb2display(fbi);
1595        struct omapfb2_mem_region *rg = ofbi->region;
1596        unsigned long old_size = rg->size;
1597        unsigned long old_paddr = rg->paddr;
1598        int old_type = rg->type;
1599        int r;
1600
1601        if (type != OMAPFB_MEMTYPE_SDRAM)
1602                return -EINVAL;
1603
1604        size = PAGE_ALIGN(size);
1605
1606        if (old_size == size && old_type == type)
1607                return 0;
1608
1609        if (display && display->driver->sync)
1610                        display->driver->sync(display);
1611
1612        omapfb_free_fbmem(fbi);
1613
1614        if (size == 0) {
1615                clear_fb_info(fbi);
1616                return 0;
1617        }
1618
1619        r = omapfb_alloc_fbmem(fbi, size, 0);
1620
1621        if (r) {
1622                if (old_size)
1623                        omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1624
1625                if (rg->size == 0)
1626                        clear_fb_info(fbi);
1627
1628                return r;
1629        }
1630
1631        if (old_size == size)
1632                return 0;
1633
1634        if (old_size == 0) {
1635                DBG("initializing fb %d\n", ofbi->id);
1636                r = omapfb_fb_init(fbdev, fbi);
1637                if (r) {
1638                        DBG("omapfb_fb_init failed\n");
1639                        goto err;
1640                }
1641                r = omapfb_apply_changes(fbi, 1);
1642                if (r) {
1643                        DBG("omapfb_apply_changes failed\n");
1644                        goto err;
1645                }
1646        } else {
1647                struct fb_var_screeninfo new_var;
1648                memcpy(&new_var, &fbi->var, sizeof(new_var));
1649                r = check_fb_var(fbi, &new_var);
1650                if (r)
1651                        goto err;
1652                memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1653                set_fb_fix(fbi);
1654                r = setup_vrfb_rotation(fbi);
1655                if (r)
1656                        goto err;
1657        }
1658
1659        return 0;
1660err:
1661        omapfb_free_fbmem(fbi);
1662        clear_fb_info(fbi);
1663        return r;
1664}
1665
1666static void omapfb_auto_update_work(struct work_struct *work)
1667{
1668        struct omap_dss_device *dssdev;
1669        struct omap_dss_driver *dssdrv;
1670        struct omapfb_display_data *d;
1671        u16 w, h;
1672        unsigned int freq;
1673        struct omapfb2_device *fbdev;
1674
1675        d = container_of(work, struct omapfb_display_data,
1676                        auto_update_work.work);
1677
1678        dssdev = d->dssdev;
1679        dssdrv = dssdev->driver;
1680        fbdev = d->fbdev;
1681
1682        if (!dssdrv || !dssdrv->update)
1683                return;
1684
1685        if (dssdrv->sync)
1686                dssdrv->sync(dssdev);
1687
1688        dssdrv->get_resolution(dssdev, &w, &h);
1689        dssdrv->update(dssdev, 0, 0, w, h);
1690
1691        freq = auto_update_freq;
1692        if (freq == 0)
1693                freq = 20;
1694        queue_delayed_work(fbdev->auto_update_wq,
1695                        &d->auto_update_work, HZ / freq);
1696}
1697
1698void omapfb_start_auto_update(struct omapfb2_device *fbdev,
1699                struct omap_dss_device *display)
1700{
1701        struct omapfb_display_data *d;
1702
1703        if (fbdev->auto_update_wq == NULL) {
1704                struct workqueue_struct *wq;
1705
1706                wq = create_singlethread_workqueue("omapfb_auto_update");
1707
1708                if (wq == NULL) {
1709                        dev_err(fbdev->dev, "Failed to create workqueue for "
1710                                        "auto-update\n");
1711                        return;
1712                }
1713
1714                fbdev->auto_update_wq = wq;
1715        }
1716
1717        d = get_display_data(fbdev, display);
1718
1719        INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
1720
1721        d->auto_update_work_enabled = true;
1722
1723        omapfb_auto_update_work(&d->auto_update_work.work);
1724}
1725
1726void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
1727                struct omap_dss_device *display)
1728{
1729        struct omapfb_display_data *d;
1730
1731        d = get_display_data(fbdev, display);
1732
1733        cancel_delayed_work_sync(&d->auto_update_work);
1734
1735        d->auto_update_work_enabled = false;
1736}
1737
1738/* initialize fb_info, var, fix to something sane based on the display */
1739static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1740{
1741        struct fb_var_screeninfo *var = &fbi->var;
1742        struct omap_dss_device *display = fb2display(fbi);
1743        struct omapfb_info *ofbi = FB2OFB(fbi);
1744        int r = 0;
1745
1746        fbi->fbops = &omapfb_ops;
1747        fbi->flags = FBINFO_FLAG_DEFAULT;
1748        fbi->pseudo_palette = fbdev->pseudo_palette;
1749
1750        if (ofbi->region->size == 0) {
1751                clear_fb_info(fbi);
1752                return 0;
1753        }
1754
1755        var->nonstd = 0;
1756        var->bits_per_pixel = 0;
1757
1758        var->rotate = def_rotate;
1759
1760        if (display) {
1761                u16 w, h;
1762                int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1763
1764                display->driver->get_resolution(display, &w, &h);
1765
1766                if (rotation == FB_ROTATE_CW ||
1767                                rotation == FB_ROTATE_CCW) {
1768                        var->xres = h;
1769                        var->yres = w;
1770                } else {
1771                        var->xres = w;
1772                        var->yres = h;
1773                }
1774
1775                var->xres_virtual = var->xres;
1776                var->yres_virtual = var->yres;
1777
1778                if (!var->bits_per_pixel) {
1779                        switch (omapfb_get_recommended_bpp(fbdev, display)) {
1780                        case 16:
1781                                var->bits_per_pixel = 16;
1782                                break;
1783                        case 24:
1784                                var->bits_per_pixel = 32;
1785                                break;
1786                        default:
1787                                dev_err(fbdev->dev, "illegal display "
1788                                                "bpp\n");
1789                                return -EINVAL;
1790                        }
1791                }
1792        } else {
1793                /* if there's no display, let's just guess some basic values */
1794                var->xres = 320;
1795                var->yres = 240;
1796                var->xres_virtual = var->xres;
1797                var->yres_virtual = var->yres;
1798                if (!var->bits_per_pixel)
1799                        var->bits_per_pixel = 16;
1800        }
1801
1802        r = check_fb_var(fbi, var);
1803        if (r)
1804                goto err;
1805
1806        set_fb_fix(fbi);
1807        r = setup_vrfb_rotation(fbi);
1808        if (r)
1809                goto err;
1810
1811        r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1812        if (r)
1813                dev_err(fbdev->dev, "unable to allocate color map memory\n");
1814
1815err:
1816        return r;
1817}
1818
1819static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1820{
1821        fb_dealloc_cmap(&fbi->cmap);
1822}
1823
1824
1825static void omapfb_free_resources(struct omapfb2_device *fbdev)
1826{
1827        int i;
1828
1829        DBG("free_resources\n");
1830
1831        if (fbdev == NULL)
1832                return;
1833
1834        for (i = 0; i < fbdev->num_fbs; i++)
1835                unregister_framebuffer(fbdev->fbs[i]);
1836
1837        /* free the reserved fbmem */
1838        omapfb_free_all_fbmem(fbdev);
1839
1840        for (i = 0; i < fbdev->num_fbs; i++) {
1841                fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1842                framebuffer_release(fbdev->fbs[i]);
1843        }
1844
1845        for (i = 0; i < fbdev->num_displays; i++) {
1846                struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
1847
1848                if (fbdev->displays[i].auto_update_work_enabled)
1849                        omapfb_stop_auto_update(fbdev, dssdev);
1850
1851                if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
1852                        dssdev->driver->disable(dssdev);
1853
1854                omap_dss_put_device(dssdev);
1855        }
1856
1857        if (fbdev->auto_update_wq != NULL) {
1858                flush_workqueue(fbdev->auto_update_wq);
1859                destroy_workqueue(fbdev->auto_update_wq);
1860                fbdev->auto_update_wq = NULL;
1861        }
1862
1863        dev_set_drvdata(fbdev->dev, NULL);
1864        kfree(fbdev);
1865}
1866
1867static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1868{
1869        int r, i;
1870
1871        fbdev->num_fbs = 0;
1872
1873        DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1874
1875        /* allocate fb_infos */
1876        for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1877                struct fb_info *fbi;
1878                struct omapfb_info *ofbi;
1879
1880                fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1881                                fbdev->dev);
1882
1883                if (fbi == NULL) {
1884                        dev_err(fbdev->dev,
1885                                "unable to allocate memory for plane info\n");
1886                        return -ENOMEM;
1887                }
1888
1889                clear_fb_info(fbi);
1890
1891                fbdev->fbs[i] = fbi;
1892
1893                ofbi = FB2OFB(fbi);
1894                ofbi->fbdev = fbdev;
1895                ofbi->id = i;
1896
1897                ofbi->region = &fbdev->regions[i];
1898                ofbi->region->id = i;
1899                init_rwsem(&ofbi->region->lock);
1900
1901                /* assign these early, so that fb alloc can use them */
1902                ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1903                        OMAP_DSS_ROT_DMA;
1904                ofbi->mirror = def_mirror;
1905
1906                fbdev->num_fbs++;
1907        }
1908
1909        DBG("fb_infos allocated\n");
1910
1911        /* assign overlays for the fbs */
1912        for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1913                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1914
1915                ofbi->overlays[0] = fbdev->overlays[i];
1916                ofbi->num_overlays = 1;
1917        }
1918
1919        /* allocate fb memories */
1920        r = omapfb_allocate_all_fbs(fbdev);
1921        if (r) {
1922                dev_err(fbdev->dev, "failed to allocate fbmem\n");
1923                return r;
1924        }
1925
1926        DBG("fbmems allocated\n");
1927
1928        /* setup fb_infos */
1929        for (i = 0; i < fbdev->num_fbs; i++) {
1930                struct fb_info *fbi = fbdev->fbs[i];
1931                struct omapfb_info *ofbi = FB2OFB(fbi);
1932
1933                omapfb_get_mem_region(ofbi->region);
1934                r = omapfb_fb_init(fbdev, fbi);
1935                omapfb_put_mem_region(ofbi->region);
1936
1937                if (r) {
1938                        dev_err(fbdev->dev, "failed to setup fb_info\n");
1939                        return r;
1940                }
1941        }
1942
1943        DBG("fb_infos initialized\n");
1944
1945        for (i = 0; i < fbdev->num_fbs; i++) {
1946                r = register_framebuffer(fbdev->fbs[i]);
1947                if (r != 0) {
1948                        dev_err(fbdev->dev,
1949                                "registering framebuffer %d failed\n", i);
1950                        return r;
1951                }
1952        }
1953
1954        DBG("framebuffers registered\n");
1955
1956        for (i = 0; i < fbdev->num_fbs; i++) {
1957                struct fb_info *fbi = fbdev->fbs[i];
1958                struct omapfb_info *ofbi = FB2OFB(fbi);
1959
1960                omapfb_get_mem_region(ofbi->region);
1961                r = omapfb_apply_changes(fbi, 1);
1962                omapfb_put_mem_region(ofbi->region);
1963
1964                if (r) {
1965                        dev_err(fbdev->dev, "failed to change mode\n");
1966                        return r;
1967                }
1968        }
1969
1970        /* Enable fb0 */
1971        if (fbdev->num_fbs > 0) {
1972                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1973
1974                if (ofbi->num_overlays > 0) {
1975                        struct omap_overlay *ovl = ofbi->overlays[0];
1976
1977                        ovl->manager->apply(ovl->manager);
1978
1979                        r = omapfb_overlay_enable(ovl, 1);
1980
1981                        if (r) {
1982                                dev_err(fbdev->dev,
1983                                                "failed to enable overlay\n");
1984                                return r;
1985                        }
1986                }
1987        }
1988
1989        DBG("create_framebuffers done\n");
1990
1991        return 0;
1992}
1993
1994static int omapfb_mode_to_timings(const char *mode_str,
1995                struct omap_video_timings *timings, u8 *bpp)
1996{
1997        struct fb_info *fbi;
1998        struct fb_var_screeninfo *var;
1999        struct fb_ops *fbops;
2000        int r;
2001
2002#ifdef CONFIG_OMAP2_DSS_VENC
2003        if (strcmp(mode_str, "pal") == 0) {
2004                *timings = omap_dss_pal_timings;
2005                *bpp = 24;
2006                return 0;
2007        } else if (strcmp(mode_str, "ntsc") == 0) {
2008                *timings = omap_dss_ntsc_timings;
2009                *bpp = 24;
2010                return 0;
2011        }
2012#endif
2013
2014        /* this is quite a hack, but I wanted to use the modedb and for
2015         * that we need fb_info and var, so we create dummy ones */
2016
2017        *bpp = 0;
2018        fbi = NULL;
2019        var = NULL;
2020        fbops = NULL;
2021
2022        fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
2023        if (fbi == NULL) {
2024                r = -ENOMEM;
2025                goto err;
2026        }
2027
2028        var = kzalloc(sizeof(*var), GFP_KERNEL);
2029        if (var == NULL) {
2030                r = -ENOMEM;
2031                goto err;
2032        }
2033
2034        fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2035        if (fbops == NULL) {
2036                r = -ENOMEM;
2037                goto err;
2038        }
2039
2040        fbi->fbops = fbops;
2041
2042        r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
2043        if (r == 0) {
2044                r = -EINVAL;
2045                goto err;
2046        }
2047
2048        timings->pixel_clock = PICOS2KHZ(var->pixclock);
2049        timings->hbp = var->left_margin;
2050        timings->hfp = var->right_margin;
2051        timings->vbp = var->upper_margin;
2052        timings->vfp = var->lower_margin;
2053        timings->hsw = var->hsync_len;
2054        timings->vsw = var->vsync_len;
2055        timings->x_res = var->xres;
2056        timings->y_res = var->yres;
2057
2058        switch (var->bits_per_pixel) {
2059        case 16:
2060                *bpp = 16;
2061                break;
2062        case 24:
2063        case 32:
2064        default:
2065                *bpp = 24;
2066                break;
2067        }
2068
2069        r = 0;
2070
2071err:
2072        kfree(fbi);
2073        kfree(var);
2074        kfree(fbops);
2075
2076        return r;
2077}
2078
2079static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2080                struct omap_dss_device *display, char *mode_str)
2081{
2082        int r;
2083        u8 bpp;
2084        struct omap_video_timings timings, temp_timings;
2085        struct omapfb_display_data *d;
2086
2087        r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2088        if (r)
2089                return r;
2090
2091        d = get_display_data(fbdev, display);
2092        d->bpp_override = bpp;
2093
2094        if (display->driver->check_timings) {
2095                r = display->driver->check_timings(display, &timings);
2096                if (r)
2097                        return r;
2098        } else {
2099                /* If check_timings is not present compare xres and yres */
2100                if (display->driver->get_timings) {
2101                        display->driver->get_timings(display, &temp_timings);
2102
2103                        if (temp_timings.x_res != timings.x_res ||
2104                                temp_timings.y_res != timings.y_res)
2105                                return -EINVAL;
2106                }
2107        }
2108
2109        if (display->driver->set_timings)
2110                        display->driver->set_timings(display, &timings);
2111
2112        return 0;
2113}
2114
2115static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
2116                struct omap_dss_device *dssdev)
2117{
2118        struct omapfb_display_data *d;
2119
2120        BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
2121
2122        d = get_display_data(fbdev, dssdev);
2123
2124        if (d->bpp_override != 0)
2125                return d->bpp_override;
2126
2127        return dssdev->driver->get_recommended_bpp(dssdev);
2128}
2129
2130static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2131{
2132        char *str, *options, *this_opt;
2133        int r = 0;
2134
2135        str = kstrdup(def_mode, GFP_KERNEL);
2136        if (!str)
2137                return -ENOMEM;
2138        options = str;
2139
2140        while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2141                char *p, *display_str, *mode_str;
2142                struct omap_dss_device *display;
2143                int i;
2144
2145                p = strchr(this_opt, ':');
2146                if (!p) {
2147                        r = -EINVAL;
2148                        break;
2149                }
2150
2151                *p = 0;
2152                display_str = this_opt;
2153                mode_str = p + 1;
2154
2155                display = NULL;
2156                for (i = 0; i < fbdev->num_displays; ++i) {
2157                        if (strcmp(fbdev->displays[i].dssdev->name,
2158                                                display_str) == 0) {
2159                                display = fbdev->displays[i].dssdev;
2160                                break;
2161                        }
2162                }
2163
2164                if (!display) {
2165                        r = -EINVAL;
2166                        break;
2167                }
2168
2169                r = omapfb_set_def_mode(fbdev, display, mode_str);
2170                if (r)
2171                        break;
2172        }
2173
2174        kfree(str);
2175
2176        return r;
2177}
2178
2179static void fb_videomode_to_omap_timings(struct fb_videomode *m,
2180                struct omap_video_timings *t)
2181{
2182        t->x_res = m->xres;
2183        t->y_res = m->yres;
2184        t->pixel_clock = PICOS2KHZ(m->pixclock);
2185        t->hsw = m->hsync_len;
2186        t->hfp = m->right_margin;
2187        t->hbp = m->left_margin;
2188        t->vsw = m->vsync_len;
2189        t->vfp = m->lower_margin;
2190        t->vbp = m->upper_margin;
2191}
2192
2193static int omapfb_find_best_mode(struct omap_dss_device *display,
2194                struct omap_video_timings *timings)
2195{
2196        struct fb_monspecs *specs;
2197        u8 *edid;
2198        int r, i, best_xres, best_idx, len;
2199
2200        if (!display->driver->read_edid)
2201                return -ENODEV;
2202
2203        len = 0x80 * 2;
2204        edid = kmalloc(len, GFP_KERNEL);
2205
2206        r = display->driver->read_edid(display, edid, len);
2207        if (r < 0)
2208                goto err1;
2209
2210        specs = kzalloc(sizeof(*specs), GFP_KERNEL);
2211
2212        fb_edid_to_monspecs(edid, specs);
2213
2214        if (edid[126] > 0)
2215                fb_edid_add_monspecs(edid + 0x80, specs);
2216
2217        best_xres = 0;
2218        best_idx = -1;
2219
2220        for (i = 0; i < specs->modedb_len; ++i) {
2221                struct fb_videomode *m;
2222                struct omap_video_timings t;
2223
2224                m = &specs->modedb[i];
2225
2226                if (m->pixclock == 0)
2227                        continue;
2228
2229                /* skip repeated pixel modes */
2230                if (m->xres == 2880 || m->xres == 1440)
2231                        continue;
2232
2233                fb_videomode_to_omap_timings(m, &t);
2234
2235                r = display->driver->check_timings(display, &t);
2236                if (r == 0 && best_xres < m->xres) {
2237                        best_xres = m->xres;
2238                        best_idx = i;
2239                }
2240        }
2241
2242        if (best_xres == 0) {
2243                r = -ENOENT;
2244                goto err2;
2245        }
2246
2247        fb_videomode_to_omap_timings(&specs->modedb[best_idx], timings);
2248
2249        r = 0;
2250
2251err2:
2252        fb_destroy_modedb(specs->modedb);
2253        kfree(specs);
2254err1:
2255        kfree(edid);
2256
2257        return r;
2258}
2259
2260static int omapfb_init_display(struct omapfb2_device *fbdev,
2261                struct omap_dss_device *dssdev)
2262{
2263        struct omap_dss_driver *dssdrv = dssdev->driver;
2264        struct omapfb_display_data *d;
2265        int r;
2266
2267        r = dssdrv->enable(dssdev);
2268        if (r) {
2269                dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2270                                dssdev->name);
2271                return r;
2272        }
2273
2274        d = get_display_data(fbdev, dssdev);
2275
2276        d->fbdev = fbdev;
2277
2278        if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2279                u16 w, h;
2280
2281                if (auto_update) {
2282                        omapfb_start_auto_update(fbdev, dssdev);
2283                        d->update_mode = OMAPFB_AUTO_UPDATE;
2284                } else {
2285                        d->update_mode = OMAPFB_MANUAL_UPDATE;
2286                }
2287
2288                if (dssdrv->enable_te) {
2289                        r = dssdrv->enable_te(dssdev, 1);
2290                        if (r) {
2291                                dev_err(fbdev->dev, "Failed to set TE\n");
2292                                return r;
2293                        }
2294                }
2295
2296                dssdrv->get_resolution(dssdev, &w, &h);
2297                r = dssdrv->update(dssdev, 0, 0, w, h);
2298                if (r) {
2299                        dev_err(fbdev->dev,
2300                                        "Failed to update display\n");
2301                        return r;
2302                }
2303        } else {
2304                d->update_mode = OMAPFB_AUTO_UPDATE;
2305        }
2306
2307        return 0;
2308}
2309
2310static int omapfb_probe(struct platform_device *pdev)
2311{
2312        struct omapfb2_device *fbdev = NULL;
2313        int r = 0;
2314        int i;
2315        struct omap_overlay *ovl;
2316        struct omap_dss_device *def_display;
2317        struct omap_dss_device *dssdev;
2318
2319        DBG("omapfb_probe\n");
2320
2321        if (pdev->num_resources != 0) {
2322                dev_err(&pdev->dev, "probed for an unknown device\n");
2323                r = -ENODEV;
2324                goto err0;
2325        }
2326
2327        fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2328        if (fbdev == NULL) {
2329                r = -ENOMEM;
2330                goto err0;
2331        }
2332
2333        /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
2334        *        available for OMAP2 and OMAP3
2335        */
2336        if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
2337                def_vrfb = 0;
2338                dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
2339                                "ignoring the module parameter vrfb=y\n");
2340        }
2341
2342
2343        mutex_init(&fbdev->mtx);
2344
2345        fbdev->dev = &pdev->dev;
2346        platform_set_drvdata(pdev, fbdev);
2347
2348        r = 0;
2349        fbdev->num_displays = 0;
2350        dssdev = NULL;
2351        for_each_dss_dev(dssdev) {
2352                struct omapfb_display_data *d;
2353
2354                omap_dss_get_device(dssdev);
2355
2356                if (!dssdev->driver) {
2357                        dev_warn(&pdev->dev, "no driver for display: %s\n",
2358                                dssdev->name);
2359                        omap_dss_put_device(dssdev);
2360                        continue;
2361                }
2362
2363                d = &fbdev->displays[fbdev->num_displays++];
2364                d->dssdev = dssdev;
2365                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
2366                        d->update_mode = OMAPFB_MANUAL_UPDATE;
2367                else
2368                        d->update_mode = OMAPFB_AUTO_UPDATE;
2369        }
2370
2371        if (r)
2372                goto cleanup;
2373
2374        if (fbdev->num_displays == 0) {
2375                dev_err(&pdev->dev, "no displays\n");
2376                r = -EINVAL;
2377                goto cleanup;
2378        }
2379
2380        fbdev->num_overlays = omap_dss_get_num_overlays();
2381        for (i = 0; i < fbdev->num_overlays; i++)
2382                fbdev->overlays[i] = omap_dss_get_overlay(i);
2383
2384        fbdev->num_managers = omap_dss_get_num_overlay_managers();
2385        for (i = 0; i < fbdev->num_managers; i++)
2386                fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2387
2388        /* gfx overlay should be the default one. find a display
2389         * connected to that, and use it as default display */
2390        ovl = omap_dss_get_overlay(0);
2391        if (ovl->manager && ovl->manager->device) {
2392                def_display = ovl->manager->device;
2393        } else {
2394                dev_warn(&pdev->dev, "cannot find default display\n");
2395                def_display = NULL;
2396        }
2397
2398        if (def_mode && strlen(def_mode) > 0) {
2399                if (omapfb_parse_def_modes(fbdev))
2400                        dev_warn(&pdev->dev, "cannot parse default modes\n");
2401        } else if (def_display && def_display->driver->set_timings &&
2402                        def_display->driver->check_timings) {
2403                struct omap_video_timings t;
2404
2405                r = omapfb_find_best_mode(def_display, &t);
2406
2407                if (r == 0)
2408                        def_display->driver->set_timings(def_display, &t);
2409        }
2410
2411        r = omapfb_create_framebuffers(fbdev);
2412        if (r)
2413                goto cleanup;
2414
2415        for (i = 0; i < fbdev->num_managers; i++) {
2416                struct omap_overlay_manager *mgr;
2417                mgr = fbdev->managers[i];
2418                r = mgr->apply(mgr);
2419                if (r)
2420                        dev_warn(fbdev->dev, "failed to apply dispc config\n");
2421        }
2422
2423        DBG("mgr->apply'ed\n");
2424
2425        if (def_display) {
2426                r = omapfb_init_display(fbdev, def_display);
2427                if (r) {
2428                        dev_err(fbdev->dev,
2429                                        "failed to initialize default "
2430                                        "display\n");
2431                        goto cleanup;
2432                }
2433        }
2434
2435        DBG("create sysfs for fbs\n");
2436        r = omapfb_create_sysfs(fbdev);
2437        if (r) {
2438                dev_err(fbdev->dev, "failed to create sysfs entries\n");
2439                goto cleanup;
2440        }
2441
2442        return 0;
2443
2444cleanup:
2445        omapfb_free_resources(fbdev);
2446err0:
2447        dev_err(&pdev->dev, "failed to setup omapfb\n");
2448        return r;
2449}
2450
2451static int omapfb_remove(struct platform_device *pdev)
2452{
2453        struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2454
2455        /* FIXME: wait till completion of pending events */
2456
2457        omapfb_remove_sysfs(fbdev);
2458
2459        omapfb_free_resources(fbdev);
2460
2461        return 0;
2462}
2463
2464static struct platform_driver omapfb_driver = {
2465        .probe          = omapfb_probe,
2466        .remove         = omapfb_remove,
2467        .driver         = {
2468                .name   = "omapfb",
2469                .owner  = THIS_MODULE,
2470        },
2471};
2472
2473static int __init omapfb_init(void)
2474{
2475        DBG("omapfb_init\n");
2476
2477        if (platform_driver_register(&omapfb_driver)) {
2478                printk(KERN_ERR "failed to register omapfb driver\n");
2479                return -ENODEV;
2480        }
2481
2482        return 0;
2483}
2484
2485static void __exit omapfb_exit(void)
2486{
2487        DBG("omapfb_exit\n");
2488        platform_driver_unregister(&omapfb_driver);
2489}
2490
2491module_param_named(mode, def_mode, charp, 0);
2492module_param_named(vram, def_vram, charp, 0);
2493module_param_named(rotate, def_rotate, int, 0);
2494module_param_named(vrfb, def_vrfb, bool, 0);
2495module_param_named(mirror, def_mirror, bool, 0);
2496
2497/* late_initcall to let panel/ctrl drivers loaded first.
2498 * I guess better option would be a more dynamic approach,
2499 * so that omapfb reacts to new panels when they are loaded */
2500late_initcall(omapfb_init);
2501/*module_init(omapfb_init);*/
2502module_exit(omapfb_exit);
2503
2504MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2505MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2506MODULE_LICENSE("GPL v2");
2507