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