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                fallthrough;
 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                r = -EINVAL;
1158                break;
1159        case OMAPFB_COLOR_RGB565:
1160        case OMAPFB_COLOR_RGB444:
1161        case OMAPFB_COLOR_RGB24P:
1162        case OMAPFB_COLOR_RGB24U:
1163                if (regno < 16) {
1164                        u32 pal;
1165                        pal = ((red >> (16 - var->red.length)) <<
1166                                        var->red.offset) |
1167                                ((green >> (16 - var->green.length)) <<
1168                                 var->green.offset) |
1169                                (blue >> (16 - var->blue.length));
1170                        ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1171                }
1172                break;
1173        default:
1174                BUG();
1175        }
1176        return r;
1177}
1178
1179static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1180                u_int transp, struct fb_info *info)
1181{
1182        DBG("setcolreg\n");
1183
1184        return _setcolreg(info, regno, red, green, blue, transp, 1);
1185}
1186
1187static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1188{
1189        int count, index, r;
1190        u16 *red, *green, *blue, *transp;
1191        u16 trans = 0xffff;
1192
1193        DBG("setcmap\n");
1194
1195        red     = cmap->red;
1196        green   = cmap->green;
1197        blue    = cmap->blue;
1198        transp  = cmap->transp;
1199        index   = cmap->start;
1200
1201        for (count = 0; count < cmap->len; count++) {
1202                if (transp)
1203                        trans = *transp++;
1204                r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1205                                count == cmap->len - 1);
1206                if (r != 0)
1207                        return r;
1208        }
1209
1210        return 0;
1211}
1212
1213static int omapfb_blank(int blank, struct fb_info *fbi)
1214{
1215        struct omapfb_info *ofbi = FB2OFB(fbi);
1216        struct omapfb2_device *fbdev = ofbi->fbdev;
1217        struct omap_dss_device *display = fb2display(fbi);
1218        struct omapfb_display_data *d;
1219        int r = 0;
1220
1221        if (!display)
1222                return -EINVAL;
1223
1224        omapfb_lock(fbdev);
1225
1226        d = get_display_data(fbdev, display);
1227
1228        switch (blank) {
1229        case FB_BLANK_UNBLANK:
1230                if (display->state == OMAP_DSS_DISPLAY_ACTIVE)
1231                        goto exit;
1232
1233                r = display->driver->enable(display);
1234
1235                if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
1236                                d->update_mode == OMAPFB_AUTO_UPDATE &&
1237                                !d->auto_update_work_enabled)
1238                        omapfb_start_auto_update(fbdev, display);
1239
1240                break;
1241
1242        case FB_BLANK_NORMAL:
1243                /* FB_BLANK_NORMAL could be implemented.
1244                 * Needs DSS additions. */
1245        case FB_BLANK_VSYNC_SUSPEND:
1246        case FB_BLANK_HSYNC_SUSPEND:
1247        case FB_BLANK_POWERDOWN:
1248                if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1249                        goto exit;
1250
1251                if (d->auto_update_work_enabled)
1252                        omapfb_stop_auto_update(fbdev, display);
1253
1254                display->driver->disable(display);
1255
1256                break;
1257
1258        default:
1259                r = -EINVAL;
1260        }
1261
1262exit:
1263        omapfb_unlock(fbdev);
1264
1265        return r;
1266}
1267
1268#if 0
1269/* XXX fb_read and fb_write are needed for VRFB */
1270ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1271                size_t count, loff_t *ppos)
1272{
1273        DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1274        /* XXX needed for VRFB */
1275        return count;
1276}
1277#endif
1278
1279static const struct fb_ops omapfb_ops = {
1280        .owner          = THIS_MODULE,
1281        .fb_open        = omapfb_open,
1282        .fb_release     = omapfb_release,
1283        .fb_fillrect    = cfb_fillrect,
1284        .fb_copyarea    = cfb_copyarea,
1285        .fb_imageblit   = cfb_imageblit,
1286        .fb_blank       = omapfb_blank,
1287        .fb_ioctl       = omapfb_ioctl,
1288        .fb_check_var   = omapfb_check_var,
1289        .fb_set_par     = omapfb_set_par,
1290        .fb_pan_display = omapfb_pan_display,
1291        .fb_mmap        = omapfb_mmap,
1292        .fb_setcolreg   = omapfb_setcolreg,
1293        .fb_setcmap     = omapfb_setcmap,
1294        /*.fb_write     = omapfb_write,*/
1295};
1296
1297static void omapfb_free_fbmem(struct fb_info *fbi)
1298{
1299        struct omapfb_info *ofbi = FB2OFB(fbi);
1300        struct omapfb2_device *fbdev = ofbi->fbdev;
1301        struct omapfb2_mem_region *rg;
1302
1303        rg = ofbi->region;
1304
1305        if (rg->token == NULL)
1306                return;
1307
1308        WARN_ON(atomic_read(&rg->map_count));
1309
1310        if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1311                /* unmap the 0 angle rotation */
1312                if (rg->vrfb.vaddr[0]) {
1313                        iounmap(rg->vrfb.vaddr[0]);
1314                        rg->vrfb.vaddr[0] = NULL;
1315                }
1316
1317                omap_vrfb_release_ctx(&rg->vrfb);
1318        }
1319
1320        dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
1321                        rg->attrs);
1322
1323        rg->token = NULL;
1324        rg->vaddr = NULL;
1325        rg->paddr = 0;
1326        rg->alloc = 0;
1327        rg->size = 0;
1328}
1329
1330static void clear_fb_info(struct fb_info *fbi)
1331{
1332        memset(&fbi->var, 0, sizeof(fbi->var));
1333        memset(&fbi->fix, 0, sizeof(fbi->fix));
1334        strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1335}
1336
1337static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1338{
1339        int i;
1340
1341        DBG("free all fbmem\n");
1342
1343        for (i = 0; i < fbdev->num_fbs; i++) {
1344                struct fb_info *fbi = fbdev->fbs[i];
1345                omapfb_free_fbmem(fbi);
1346                clear_fb_info(fbi);
1347        }
1348
1349        return 0;
1350}
1351
1352static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1353                unsigned long paddr)
1354{
1355        struct omapfb_info *ofbi = FB2OFB(fbi);
1356        struct omapfb2_device *fbdev = ofbi->fbdev;
1357        struct omapfb2_mem_region *rg;
1358        void *token;
1359        unsigned long attrs;
1360        dma_addr_t dma_handle;
1361        int r;
1362
1363        rg = ofbi->region;
1364
1365        rg->paddr = 0;
1366        rg->vaddr = NULL;
1367        memset(&rg->vrfb, 0, sizeof rg->vrfb);
1368        rg->size = 0;
1369        rg->type = 0;
1370        rg->alloc = false;
1371        rg->map = false;
1372
1373        size = PAGE_ALIGN(size);
1374
1375        attrs = DMA_ATTR_WRITE_COMBINE;
1376
1377        if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
1378                attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
1379
1380        DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1381
1382        token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
1383                        GFP_KERNEL, attrs);
1384
1385        if (token == NULL) {
1386                dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1387                return -ENOMEM;
1388        }
1389
1390        DBG("allocated VRAM paddr %lx, vaddr %p\n",
1391                        (unsigned long)dma_handle, token);
1392
1393        if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1394                r = omap_vrfb_request_ctx(&rg->vrfb);
1395                if (r) {
1396                        dma_free_attrs(fbdev->dev, size, token, dma_handle,
1397                                        attrs);
1398                        dev_err(fbdev->dev, "vrfb create ctx failed\n");
1399                        return r;
1400                }
1401        }
1402
1403        rg->attrs = attrs;
1404        rg->token = token;
1405        rg->dma_handle = dma_handle;
1406
1407        rg->paddr = (unsigned long)dma_handle;
1408        rg->vaddr = (void __iomem *)token;
1409        rg->size = size;
1410        rg->alloc = 1;
1411
1412        return 0;
1413}
1414
1415/* allocate fbmem using display resolution as reference */
1416static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1417                unsigned long paddr)
1418{
1419        struct omapfb_info *ofbi = FB2OFB(fbi);
1420        struct omapfb2_device *fbdev = ofbi->fbdev;
1421        struct omap_dss_device *display;
1422        int bytespp;
1423
1424        display =  fb2display(fbi);
1425
1426        if (!display)
1427                return 0;
1428
1429        switch (omapfb_get_recommended_bpp(fbdev, display)) {
1430        case 16:
1431                bytespp = 2;
1432                break;
1433        case 24:
1434                bytespp = 4;
1435                break;
1436        default:
1437                bytespp = 4;
1438                break;
1439        }
1440
1441        if (!size) {
1442                u16 w, h;
1443
1444                display->driver->get_resolution(display, &w, &h);
1445
1446                if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1447                        size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1448                                        omap_vrfb_min_phys_size(h, w, bytespp));
1449
1450                        DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1451                                        w * h * bytespp, size);
1452                } else {
1453                        size = w * h * bytespp;
1454                }
1455        }
1456
1457        if (!size)
1458                return 0;
1459
1460        return omapfb_alloc_fbmem(fbi, size, paddr);
1461}
1462
1463static int omapfb_parse_vram_param(const char *param, int max_entries,
1464                unsigned long *sizes, unsigned long *paddrs)
1465{
1466        unsigned int fbnum;
1467        unsigned long size;
1468        unsigned long paddr = 0;
1469        char *p, *start;
1470
1471        start = (char *)param;
1472
1473        while (1) {
1474                p = start;
1475
1476                fbnum = simple_strtoul(p, &p, 10);
1477
1478                if (p == start)
1479                        return -EINVAL;
1480
1481                if (*p != ':')
1482                        return -EINVAL;
1483
1484                if (fbnum >= max_entries)
1485                        return -EINVAL;
1486
1487                size = memparse(p + 1, &p);
1488
1489                if (!size)
1490                        return -EINVAL;
1491
1492                paddr = 0;
1493
1494                if (*p == '@') {
1495                        paddr = simple_strtoul(p + 1, &p, 16);
1496
1497                        if (!paddr)
1498                                return -EINVAL;
1499
1500                }
1501
1502                WARN_ONCE(paddr,
1503                        "reserving memory at predefined address not supported\n");
1504
1505                paddrs[fbnum] = paddr;
1506                sizes[fbnum] = size;
1507
1508                if (*p == 0)
1509                        break;
1510
1511                if (*p != ',')
1512                        return -EINVAL;
1513
1514                ++p;
1515
1516                start = p;
1517        }
1518
1519        return 0;
1520}
1521
1522static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1523{
1524        int i, r;
1525        unsigned long vram_sizes[10];
1526        unsigned long vram_paddrs[10];
1527
1528        memset(&vram_sizes, 0, sizeof(vram_sizes));
1529        memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1530
1531        if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1532                                vram_sizes, vram_paddrs)) {
1533                dev_err(fbdev->dev, "failed to parse vram parameter\n");
1534
1535                memset(&vram_sizes, 0, sizeof(vram_sizes));
1536                memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1537        }
1538
1539        for (i = 0; i < fbdev->num_fbs; i++) {
1540                /* allocate memory automatically only for fb0, or if
1541                 * excplicitly defined with vram or plat data option */
1542                if (i == 0 || vram_sizes[i] != 0) {
1543                        r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1544                                        vram_sizes[i], vram_paddrs[i]);
1545
1546                        if (r)
1547                                return r;
1548                }
1549        }
1550
1551        for (i = 0; i < fbdev->num_fbs; i++) {
1552                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1553                struct omapfb2_mem_region *rg;
1554                rg = ofbi->region;
1555
1556                DBG("region%d phys %08x virt %p size=%lu\n",
1557                                i,
1558                                rg->paddr,
1559                                rg->vaddr,
1560                                rg->size);
1561        }
1562
1563        return 0;
1564}
1565
1566static void omapfb_clear_fb(struct fb_info *fbi)
1567{
1568        const struct fb_fillrect rect = {
1569                .dx = 0,
1570                .dy = 0,
1571                .width = fbi->var.xres_virtual,
1572                .height = fbi->var.yres_virtual,
1573                .color = 0,
1574                .rop = ROP_COPY,
1575        };
1576
1577        cfb_fillrect(fbi, &rect);
1578}
1579
1580int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1581{
1582        struct omapfb_info *ofbi = FB2OFB(fbi);
1583        struct omapfb2_device *fbdev = ofbi->fbdev;
1584        struct omapfb2_mem_region *rg = ofbi->region;
1585        unsigned long old_size = rg->size;
1586        unsigned long old_paddr = rg->paddr;
1587        int old_type = rg->type;
1588        int r;
1589
1590        if (type != OMAPFB_MEMTYPE_SDRAM)
1591                return -EINVAL;
1592
1593        size = PAGE_ALIGN(size);
1594
1595        if (old_size == size && old_type == type)
1596                return 0;
1597
1598        omapfb_free_fbmem(fbi);
1599
1600        if (size == 0) {
1601                clear_fb_info(fbi);
1602                return 0;
1603        }
1604
1605        r = omapfb_alloc_fbmem(fbi, size, 0);
1606
1607        if (r) {
1608                if (old_size)
1609                        omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1610
1611                if (rg->size == 0)
1612                        clear_fb_info(fbi);
1613
1614                return r;
1615        }
1616
1617        if (old_size == size)
1618                return 0;
1619
1620        if (old_size == 0) {
1621                DBG("initializing fb %d\n", ofbi->id);
1622                r = omapfb_fb_init(fbdev, fbi);
1623                if (r) {
1624                        DBG("omapfb_fb_init failed\n");
1625                        goto err;
1626                }
1627                r = omapfb_apply_changes(fbi, 1);
1628                if (r) {
1629                        DBG("omapfb_apply_changes failed\n");
1630                        goto err;
1631                }
1632        } else {
1633                struct fb_var_screeninfo new_var;
1634                memcpy(&new_var, &fbi->var, sizeof(new_var));
1635                r = check_fb_var(fbi, &new_var);
1636                if (r)
1637                        goto err;
1638                memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1639                set_fb_fix(fbi);
1640                r = setup_vrfb_rotation(fbi);
1641                if (r)
1642                        goto err;
1643        }
1644
1645        omapfb_clear_fb(fbi);
1646
1647        return 0;
1648err:
1649        omapfb_free_fbmem(fbi);
1650        clear_fb_info(fbi);
1651        return r;
1652}
1653
1654static void omapfb_auto_update_work(struct work_struct *work)
1655{
1656        struct omap_dss_device *dssdev;
1657        struct omap_dss_driver *dssdrv;
1658        struct omapfb_display_data *d;
1659        u16 w, h;
1660        unsigned int freq;
1661        struct omapfb2_device *fbdev;
1662
1663        d = container_of(work, struct omapfb_display_data,
1664                        auto_update_work.work);
1665
1666        dssdev = d->dssdev;
1667        dssdrv = dssdev->driver;
1668        fbdev = d->fbdev;
1669
1670        if (!dssdrv || !dssdrv->update)
1671                return;
1672
1673        if (dssdrv->sync)
1674                dssdrv->sync(dssdev);
1675
1676        dssdrv->get_resolution(dssdev, &w, &h);
1677        dssdrv->update(dssdev, 0, 0, w, h);
1678
1679        freq = auto_update_freq;
1680        if (freq == 0)
1681                freq = 20;
1682        queue_delayed_work(fbdev->auto_update_wq,
1683                        &d->auto_update_work, HZ / freq);
1684}
1685
1686void omapfb_start_auto_update(struct omapfb2_device *fbdev,
1687                struct omap_dss_device *display)
1688{
1689        struct omapfb_display_data *d;
1690
1691        if (fbdev->auto_update_wq == NULL) {
1692                struct workqueue_struct *wq;
1693
1694                wq = create_singlethread_workqueue("omapfb_auto_update");
1695
1696                if (wq == NULL) {
1697                        dev_err(fbdev->dev, "Failed to create workqueue for "
1698                                        "auto-update\n");
1699                        return;
1700                }
1701
1702                fbdev->auto_update_wq = wq;
1703        }
1704
1705        d = get_display_data(fbdev, display);
1706
1707        INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
1708
1709        d->auto_update_work_enabled = true;
1710
1711        omapfb_auto_update_work(&d->auto_update_work.work);
1712}
1713
1714void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
1715                struct omap_dss_device *display)
1716{
1717        struct omapfb_display_data *d;
1718
1719        d = get_display_data(fbdev, display);
1720
1721        cancel_delayed_work_sync(&d->auto_update_work);
1722
1723        d->auto_update_work_enabled = false;
1724}
1725
1726/* initialize fb_info, var, fix to something sane based on the display */
1727static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1728{
1729        struct fb_var_screeninfo *var = &fbi->var;
1730        struct omap_dss_device *display = fb2display(fbi);
1731        struct omapfb_info *ofbi = FB2OFB(fbi);
1732        int r = 0;
1733
1734        fbi->fbops = &omapfb_ops;
1735        fbi->flags = FBINFO_FLAG_DEFAULT;
1736        fbi->pseudo_palette = fbdev->pseudo_palette;
1737
1738        if (ofbi->region->size == 0) {
1739                clear_fb_info(fbi);
1740                return 0;
1741        }
1742
1743        var->nonstd = 0;
1744        var->bits_per_pixel = 0;
1745
1746        var->rotate = def_rotate;
1747
1748        if (display) {
1749                u16 w, h;
1750                int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1751
1752                display->driver->get_resolution(display, &w, &h);
1753
1754                if (rotation == FB_ROTATE_CW ||
1755                                rotation == FB_ROTATE_CCW) {
1756                        var->xres = h;
1757                        var->yres = w;
1758                } else {
1759                        var->xres = w;
1760                        var->yres = h;
1761                }
1762
1763                var->xres_virtual = var->xres;
1764                var->yres_virtual = var->yres;
1765
1766                if (!var->bits_per_pixel) {
1767                        switch (omapfb_get_recommended_bpp(fbdev, display)) {
1768                        case 16:
1769                                var->bits_per_pixel = 16;
1770                                break;
1771                        case 24:
1772                                var->bits_per_pixel = 32;
1773                                break;
1774                        default:
1775                                dev_err(fbdev->dev, "illegal display "
1776                                                "bpp\n");
1777                                return -EINVAL;
1778                        }
1779                }
1780        } else {
1781                /* if there's no display, let's just guess some basic values */
1782                var->xres = 320;
1783                var->yres = 240;
1784                var->xres_virtual = var->xres;
1785                var->yres_virtual = var->yres;
1786                if (!var->bits_per_pixel)
1787                        var->bits_per_pixel = 16;
1788        }
1789
1790        r = check_fb_var(fbi, var);
1791        if (r)
1792                goto err;
1793
1794        set_fb_fix(fbi);
1795        r = setup_vrfb_rotation(fbi);
1796        if (r)
1797                goto err;
1798
1799        r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1800        if (r)
1801                dev_err(fbdev->dev, "unable to allocate color map memory\n");
1802
1803err:
1804        return r;
1805}
1806
1807static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1808{
1809        fb_dealloc_cmap(&fbi->cmap);
1810}
1811
1812
1813static void omapfb_free_resources(struct omapfb2_device *fbdev)
1814{
1815        int i;
1816
1817        DBG("free_resources\n");
1818
1819        if (fbdev == NULL)
1820                return;
1821
1822        for (i = 0; i < fbdev->num_overlays; i++) {
1823                struct omap_overlay *ovl = fbdev->overlays[i];
1824
1825                ovl->disable(ovl);
1826
1827                if (ovl->manager)
1828                        ovl->unset_manager(ovl);
1829        }
1830
1831        for (i = 0; i < fbdev->num_fbs; i++)
1832                unregister_framebuffer(fbdev->fbs[i]);
1833
1834        /* free the reserved fbmem */
1835        omapfb_free_all_fbmem(fbdev);
1836
1837        for (i = 0; i < fbdev->num_fbs; i++) {
1838                fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1839                framebuffer_release(fbdev->fbs[i]);
1840        }
1841
1842        for (i = 0; i < fbdev->num_displays; i++) {
1843                struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
1844
1845                if (fbdev->displays[i].auto_update_work_enabled)
1846                        omapfb_stop_auto_update(fbdev, dssdev);
1847
1848                if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
1849                        dssdev->driver->disable(dssdev);
1850
1851                dssdev->driver->disconnect(dssdev);
1852
1853                omap_dss_put_device(dssdev);
1854        }
1855
1856        if (fbdev->auto_update_wq != NULL) {
1857                flush_workqueue(fbdev->auto_update_wq);
1858                destroy_workqueue(fbdev->auto_update_wq);
1859                fbdev->auto_update_wq = NULL;
1860        }
1861
1862        dev_set_drvdata(fbdev->dev, NULL);
1863}
1864
1865static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1866{
1867        int r, i;
1868
1869        fbdev->num_fbs = 0;
1870
1871        DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1872
1873        /* allocate fb_infos */
1874        for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1875                struct fb_info *fbi;
1876                struct omapfb_info *ofbi;
1877
1878                fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1879                                fbdev->dev);
1880                if (!fbi)
1881                        return -ENOMEM;
1882
1883                clear_fb_info(fbi);
1884
1885                fbdev->fbs[i] = fbi;
1886
1887                ofbi = FB2OFB(fbi);
1888                ofbi->fbdev = fbdev;
1889                ofbi->id = i;
1890
1891                ofbi->region = &fbdev->regions[i];
1892                ofbi->region->id = i;
1893                init_rwsem(&ofbi->region->lock);
1894
1895                /* assign these early, so that fb alloc can use them */
1896                ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1897                        OMAP_DSS_ROT_DMA;
1898                ofbi->mirror = def_mirror;
1899
1900                fbdev->num_fbs++;
1901        }
1902
1903        DBG("fb_infos allocated\n");
1904
1905        /* assign overlays for the fbs */
1906        for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1907                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1908
1909                ofbi->overlays[0] = fbdev->overlays[i];
1910                ofbi->num_overlays = 1;
1911        }
1912
1913        /* allocate fb memories */
1914        r = omapfb_allocate_all_fbs(fbdev);
1915        if (r) {
1916                dev_err(fbdev->dev, "failed to allocate fbmem\n");
1917                return r;
1918        }
1919
1920        DBG("fbmems allocated\n");
1921
1922        /* setup fb_infos */
1923        for (i = 0; i < fbdev->num_fbs; i++) {
1924                struct fb_info *fbi = fbdev->fbs[i];
1925                struct omapfb_info *ofbi = FB2OFB(fbi);
1926
1927                omapfb_get_mem_region(ofbi->region);
1928                r = omapfb_fb_init(fbdev, fbi);
1929                omapfb_put_mem_region(ofbi->region);
1930
1931                if (r) {
1932                        dev_err(fbdev->dev, "failed to setup fb_info\n");
1933                        return r;
1934                }
1935        }
1936
1937        for (i = 0; i < fbdev->num_fbs; i++) {
1938                struct fb_info *fbi = fbdev->fbs[i];
1939                struct omapfb_info *ofbi = FB2OFB(fbi);
1940
1941                if (ofbi->region->size == 0)
1942                        continue;
1943
1944                omapfb_clear_fb(fbi);
1945        }
1946
1947        DBG("fb_infos initialized\n");
1948
1949        for (i = 0; i < fbdev->num_fbs; i++) {
1950                r = register_framebuffer(fbdev->fbs[i]);
1951                if (r != 0) {
1952                        dev_err(fbdev->dev,
1953                                "registering framebuffer %d failed\n", i);
1954                        return r;
1955                }
1956        }
1957
1958        DBG("framebuffers registered\n");
1959
1960        for (i = 0; i < fbdev->num_fbs; i++) {
1961                struct fb_info *fbi = fbdev->fbs[i];
1962                struct omapfb_info *ofbi = FB2OFB(fbi);
1963
1964                omapfb_get_mem_region(ofbi->region);
1965                r = omapfb_apply_changes(fbi, 1);
1966                omapfb_put_mem_region(ofbi->region);
1967
1968                if (r) {
1969                        dev_err(fbdev->dev, "failed to change mode\n");
1970                        return r;
1971                }
1972        }
1973
1974        /* Enable fb0 */
1975        if (fbdev->num_fbs > 0) {
1976                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1977
1978                if (ofbi->num_overlays > 0) {
1979                        struct omap_overlay *ovl = ofbi->overlays[0];
1980
1981                        ovl->manager->apply(ovl->manager);
1982
1983                        r = omapfb_overlay_enable(ovl, 1);
1984
1985                        if (r) {
1986                                dev_err(fbdev->dev,
1987                                                "failed to enable overlay\n");
1988                                return r;
1989                        }
1990                }
1991        }
1992
1993        DBG("create_framebuffers done\n");
1994
1995        return 0;
1996}
1997
1998static int omapfb_mode_to_timings(const char *mode_str,
1999                struct omap_dss_device *display,
2000                struct omap_video_timings *timings, u8 *bpp)
2001{
2002        struct fb_info *fbi;
2003        struct fb_var_screeninfo *var;
2004        struct fb_ops *fbops;
2005        int r;
2006
2007#ifdef CONFIG_OMAP2_DSS_VENC
2008        if (strcmp(mode_str, "pal") == 0) {
2009                *timings = omap_dss_pal_timings;
2010                *bpp = 24;
2011                return 0;
2012        } else if (strcmp(mode_str, "ntsc") == 0) {
2013                *timings = omap_dss_ntsc_timings;
2014                *bpp = 24;
2015                return 0;
2016        }
2017#endif
2018
2019        /* this is quite a hack, but I wanted to use the modedb and for
2020         * that we need fb_info and var, so we create dummy ones */
2021
2022        *bpp = 0;
2023        fbi = NULL;
2024        var = NULL;
2025        fbops = NULL;
2026
2027        fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
2028        if (fbi == NULL) {
2029                r = -ENOMEM;
2030                goto err;
2031        }
2032
2033        var = kzalloc(sizeof(*var), GFP_KERNEL);
2034        if (var == NULL) {
2035                r = -ENOMEM;
2036                goto err;
2037        }
2038
2039        fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2040        if (fbops == NULL) {
2041                r = -ENOMEM;
2042                goto err;
2043        }
2044
2045        fbi->fbops = fbops;
2046
2047        r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
2048        if (r == 0) {
2049                r = -EINVAL;
2050                goto err;
2051        }
2052
2053        if (display->driver->get_timings) {
2054                display->driver->get_timings(display, timings);
2055        } else {
2056                timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2057                timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2058                timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
2059        }
2060
2061        timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000;
2062        timings->hbp = var->left_margin;
2063        timings->hfp = var->right_margin;
2064        timings->vbp = var->upper_margin;
2065        timings->vfp = var->lower_margin;
2066        timings->hsw = var->hsync_len;
2067        timings->vsw = var->vsync_len;
2068        timings->x_res = var->xres;
2069        timings->y_res = var->yres;
2070        timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ?
2071                                OMAPDSS_SIG_ACTIVE_HIGH :
2072                                OMAPDSS_SIG_ACTIVE_LOW;
2073        timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ?
2074                                OMAPDSS_SIG_ACTIVE_HIGH :
2075                                OMAPDSS_SIG_ACTIVE_LOW;
2076        timings->interlace = var->vmode & FB_VMODE_INTERLACED;
2077
2078        switch (var->bits_per_pixel) {
2079        case 16:
2080                *bpp = 16;
2081                break;
2082        case 24:
2083        case 32:
2084        default:
2085                *bpp = 24;
2086                break;
2087        }
2088
2089        r = 0;
2090
2091err:
2092        kfree(fbi);
2093        kfree(var);
2094        kfree(fbops);
2095
2096        return r;
2097}
2098
2099static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2100                struct omap_dss_device *display, char *mode_str)
2101{
2102        int r;
2103        u8 bpp;
2104        struct omap_video_timings timings, temp_timings;
2105        struct omapfb_display_data *d;
2106
2107        r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);
2108        if (r)
2109                return r;
2110
2111        d = get_display_data(fbdev, display);
2112        d->bpp_override = bpp;
2113
2114        if (display->driver->check_timings) {
2115                r = display->driver->check_timings(display, &timings);
2116                if (r)
2117                        return r;
2118        } else {
2119                /* If check_timings is not present compare xres and yres */
2120                if (display->driver->get_timings) {
2121                        display->driver->get_timings(display, &temp_timings);
2122
2123                        if (temp_timings.x_res != timings.x_res ||
2124                                temp_timings.y_res != timings.y_res)
2125                                return -EINVAL;
2126                }
2127        }
2128
2129        if (display->driver->set_timings)
2130                        display->driver->set_timings(display, &timings);
2131
2132        return 0;
2133}
2134
2135static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
2136                struct omap_dss_device *dssdev)
2137{
2138        struct omapfb_display_data *d;
2139
2140        BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
2141
2142        d = get_display_data(fbdev, dssdev);
2143
2144        if (d->bpp_override != 0)
2145                return d->bpp_override;
2146
2147        return dssdev->driver->get_recommended_bpp(dssdev);
2148}
2149
2150static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2151{
2152        char *str, *options, *this_opt;
2153        int r = 0;
2154
2155        str = kstrdup(def_mode, GFP_KERNEL);
2156        if (!str)
2157                return -ENOMEM;
2158        options = str;
2159
2160        while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2161                char *p, *display_str, *mode_str;
2162                struct omap_dss_device *display;
2163                int i;
2164
2165                p = strchr(this_opt, ':');
2166                if (!p) {
2167                        r = -EINVAL;
2168                        break;
2169                }
2170
2171                *p = 0;
2172                display_str = this_opt;
2173                mode_str = p + 1;
2174
2175                display = NULL;
2176                for (i = 0; i < fbdev->num_displays; ++i) {
2177                        if (strcmp(fbdev->displays[i].dssdev->name,
2178                                                display_str) == 0) {
2179                                display = fbdev->displays[i].dssdev;
2180                                break;
2181                        }
2182                }
2183
2184                if (!display) {
2185                        r = -EINVAL;
2186                        break;
2187                }
2188
2189                r = omapfb_set_def_mode(fbdev, display, mode_str);
2190                if (r)
2191                        break;
2192        }
2193
2194        kfree(str);
2195
2196        return r;
2197}
2198
2199static void fb_videomode_to_omap_timings(struct fb_videomode *m,
2200                struct omap_dss_device *display,
2201                struct omap_video_timings *t)
2202{
2203        if (display->driver->get_timings) {
2204                display->driver->get_timings(display, t);
2205        } else {
2206                t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2207                t->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2208                t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
2209        }
2210
2211        t->x_res = m->xres;
2212        t->y_res = m->yres;
2213        t->pixelclock = PICOS2KHZ(m->pixclock) * 1000;
2214        t->hsw = m->hsync_len;
2215        t->hfp = m->right_margin;
2216        t->hbp = m->left_margin;
2217        t->vsw = m->vsync_len;
2218        t->vfp = m->lower_margin;
2219        t->vbp = m->upper_margin;
2220        t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ?
2221                                OMAPDSS_SIG_ACTIVE_HIGH :
2222                                OMAPDSS_SIG_ACTIVE_LOW;
2223        t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ?
2224                                OMAPDSS_SIG_ACTIVE_HIGH :
2225                                OMAPDSS_SIG_ACTIVE_LOW;
2226        t->interlace = m->vmode & FB_VMODE_INTERLACED;
2227}
2228
2229static int omapfb_find_best_mode(struct omap_dss_device *display,
2230                struct omap_video_timings *timings)
2231{
2232        struct fb_monspecs *specs;
2233        u8 *edid;
2234        int r, i, best_idx, len;
2235
2236        if (!display->driver->read_edid)
2237                return -ENODEV;
2238
2239        len = 0x80 * 2;
2240        edid = kmalloc(len, GFP_KERNEL);
2241        if (edid == NULL)
2242                return -ENOMEM;
2243
2244        r = display->driver->read_edid(display, edid, len);
2245        if (r < 0)
2246                goto err1;
2247
2248        specs = kzalloc(sizeof(*specs), GFP_KERNEL);
2249        if (specs == NULL) {
2250                r = -ENOMEM;
2251                goto err1;
2252        }
2253
2254        fb_edid_to_monspecs(edid, specs);
2255
2256        best_idx = -1;
2257
2258        for (i = 0; i < specs->modedb_len; ++i) {
2259                struct fb_videomode *m;
2260                struct omap_video_timings t;
2261
2262                m = &specs->modedb[i];
2263
2264                if (m->pixclock == 0)
2265                        continue;
2266
2267                /* skip repeated pixel modes */
2268                if (m->xres == 2880 || m->xres == 1440)
2269                        continue;
2270
2271                if (m->vmode & FB_VMODE_INTERLACED ||
2272                                m->vmode & FB_VMODE_DOUBLE)
2273                        continue;
2274
2275                fb_videomode_to_omap_timings(m, display, &t);
2276
2277                r = display->driver->check_timings(display, &t);
2278                if (r == 0) {
2279                        best_idx = i;
2280                        break;
2281                }
2282        }
2283
2284        if (best_idx == -1) {
2285                r = -ENOENT;
2286                goto err2;
2287        }
2288
2289        fb_videomode_to_omap_timings(&specs->modedb[best_idx], display,
2290                timings);
2291
2292        r = 0;
2293
2294err2:
2295        fb_destroy_modedb(specs->modedb);
2296        kfree(specs);
2297err1:
2298        kfree(edid);
2299
2300        return r;
2301}
2302
2303static int omapfb_init_display(struct omapfb2_device *fbdev,
2304                struct omap_dss_device *dssdev)
2305{
2306        struct omap_dss_driver *dssdrv = dssdev->driver;
2307        struct omapfb_display_data *d;
2308        int r;
2309
2310        r = dssdrv->enable(dssdev);
2311        if (r) {
2312                dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2313                                dssdev->name);
2314                return r;
2315        }
2316
2317        d = get_display_data(fbdev, dssdev);
2318
2319        d->fbdev = fbdev;
2320
2321        if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2322                u16 w, h;
2323
2324                if (auto_update) {
2325                        omapfb_start_auto_update(fbdev, dssdev);
2326                        d->update_mode = OMAPFB_AUTO_UPDATE;
2327                } else {
2328                        d->update_mode = OMAPFB_MANUAL_UPDATE;
2329                }
2330
2331                if (dssdrv->enable_te) {
2332                        r = dssdrv->enable_te(dssdev, 1);
2333                        if (r) {
2334                                dev_err(fbdev->dev, "Failed to set TE\n");
2335                                return r;
2336                        }
2337                }
2338
2339                dssdrv->get_resolution(dssdev, &w, &h);
2340                r = dssdrv->update(dssdev, 0, 0, w, h);
2341                if (r) {
2342                        dev_err(fbdev->dev,
2343                                        "Failed to update display\n");
2344                        return r;
2345                }
2346        } else {
2347                d->update_mode = OMAPFB_AUTO_UPDATE;
2348        }
2349
2350        return 0;
2351}
2352
2353static int omapfb_init_connections(struct omapfb2_device *fbdev,
2354                struct omap_dss_device *def_dssdev)
2355{
2356        int i, r;
2357        struct omap_overlay_manager *mgr;
2358
2359        r = def_dssdev->driver->connect(def_dssdev);
2360        if (r) {
2361                dev_err(fbdev->dev, "failed to connect default display\n");
2362                return r;
2363        }
2364
2365        for (i = 0; i < fbdev->num_displays; ++i) {
2366                struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
2367
2368                if (dssdev == def_dssdev)
2369                        continue;
2370
2371                /*
2372                 * We don't care if the connect succeeds or not. We just want to
2373                 * connect as many displays as possible.
2374                 */
2375                dssdev->driver->connect(dssdev);
2376        }
2377
2378        mgr = omapdss_find_mgr_from_display(def_dssdev);
2379
2380        if (!mgr) {
2381                dev_err(fbdev->dev, "no ovl manager for the default display\n");
2382                return -EINVAL;
2383        }
2384
2385        for (i = 0; i < fbdev->num_overlays; i++) {
2386                struct omap_overlay *ovl = fbdev->overlays[i];
2387
2388                if (ovl->manager)
2389                        ovl->unset_manager(ovl);
2390
2391                r = ovl->set_manager(ovl, mgr);
2392                if (r)
2393                        dev_warn(fbdev->dev,
2394                                        "failed to connect overlay %s to manager %s\n",
2395                                        ovl->name, mgr->name);
2396        }
2397
2398        return 0;
2399}
2400
2401static struct omap_dss_device *
2402omapfb_find_default_display(struct omapfb2_device *fbdev)
2403{
2404        const char *def_name;
2405        int i;
2406
2407        /*
2408         * Search with the display name from the user or the board file,
2409         * comparing to display names and aliases
2410         */
2411
2412        def_name = omapdss_get_default_display_name();
2413
2414        if (def_name) {
2415                for (i = 0; i < fbdev->num_displays; ++i) {
2416                        struct omap_dss_device *dssdev;
2417
2418                        dssdev = fbdev->displays[i].dssdev;
2419
2420                        if (dssdev->name && strcmp(def_name, dssdev->name) == 0)
2421                                return dssdev;
2422
2423                        if (strcmp(def_name, dssdev->alias) == 0)
2424                                return dssdev;
2425                }
2426
2427                /* def_name given but not found */
2428                return NULL;
2429        }
2430
2431        /* then look for DT alias display0 */
2432        for (i = 0; i < fbdev->num_displays; ++i) {
2433                struct omap_dss_device *dssdev;
2434                int id;
2435
2436                dssdev = fbdev->displays[i].dssdev;
2437
2438                if (dssdev->dev->of_node == NULL)
2439                        continue;
2440
2441                id = of_alias_get_id(dssdev->dev->of_node, "display");
2442                if (id == 0)
2443                        return dssdev;
2444        }
2445
2446        /* return the first display we have in the list */
2447        return fbdev->displays[0].dssdev;
2448}
2449
2450static int omapfb_probe(struct platform_device *pdev)
2451{
2452        struct omapfb2_device *fbdev = NULL;
2453        int r = 0;
2454        int i;
2455        struct omap_dss_device *def_display;
2456        struct omap_dss_device *dssdev;
2457
2458        DBG("omapfb_probe\n");
2459
2460        if (omapdss_is_initialized() == false)
2461                return -EPROBE_DEFER;
2462
2463        if (pdev->num_resources != 0) {
2464                dev_err(&pdev->dev, "probed for an unknown device\n");
2465                r = -ENODEV;
2466                goto err0;
2467        }
2468
2469        fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device),
2470                        GFP_KERNEL);
2471        if (fbdev == NULL) {
2472                r = -ENOMEM;
2473                goto err0;
2474        }
2475
2476        if (def_vrfb && !omap_vrfb_supported()) {
2477                def_vrfb = 0;
2478                dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
2479                                "ignoring the module parameter vrfb=y\n");
2480        }
2481
2482        r = omapdss_compat_init();
2483        if (r)
2484                goto err0;
2485
2486        mutex_init(&fbdev->mtx);
2487
2488        fbdev->dev = &pdev->dev;
2489        platform_set_drvdata(pdev, fbdev);
2490
2491        fbdev->num_displays = 0;
2492        dssdev = NULL;
2493        for_each_dss_dev(dssdev) {
2494                struct omapfb_display_data *d;
2495
2496                omap_dss_get_device(dssdev);
2497
2498                if (!dssdev->driver) {
2499                        dev_warn(&pdev->dev, "no driver for display: %s\n",
2500                                dssdev->name);
2501                        omap_dss_put_device(dssdev);
2502                        continue;
2503                }
2504
2505                d = &fbdev->displays[fbdev->num_displays++];
2506                d->dssdev = dssdev;
2507                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
2508                        d->update_mode = OMAPFB_MANUAL_UPDATE;
2509                else
2510                        d->update_mode = OMAPFB_AUTO_UPDATE;
2511        }
2512
2513        if (fbdev->num_displays == 0) {
2514                dev_err(&pdev->dev, "no displays\n");
2515                r = -EPROBE_DEFER;
2516                goto cleanup;
2517        }
2518
2519        fbdev->num_overlays = omap_dss_get_num_overlays();
2520        for (i = 0; i < fbdev->num_overlays; i++)
2521                fbdev->overlays[i] = omap_dss_get_overlay(i);
2522
2523        fbdev->num_managers = omap_dss_get_num_overlay_managers();
2524        for (i = 0; i < fbdev->num_managers; i++)
2525                fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2526
2527        def_display = omapfb_find_default_display(fbdev);
2528        if (def_display == NULL) {
2529                dev_err(fbdev->dev, "failed to find default display\n");
2530                r = -EPROBE_DEFER;
2531                goto cleanup;
2532        }
2533
2534        r = omapfb_init_connections(fbdev, def_display);
2535        if (r) {
2536                dev_err(fbdev->dev, "failed to init overlay connections\n");
2537                goto cleanup;
2538        }
2539
2540        if (def_mode && strlen(def_mode) > 0) {
2541                if (omapfb_parse_def_modes(fbdev))
2542                        dev_warn(&pdev->dev, "cannot parse default modes\n");
2543        } else if (def_display && def_display->driver->set_timings &&
2544                        def_display->driver->check_timings) {
2545                struct omap_video_timings t;
2546
2547                r = omapfb_find_best_mode(def_display, &t);
2548
2549                if (r == 0)
2550                        def_display->driver->set_timings(def_display, &t);
2551        }
2552
2553        r = omapfb_create_framebuffers(fbdev);
2554        if (r)
2555                goto cleanup;
2556
2557        for (i = 0; i < fbdev->num_managers; i++) {
2558                struct omap_overlay_manager *mgr;
2559                mgr = fbdev->managers[i];
2560                r = mgr->apply(mgr);
2561                if (r)
2562                        dev_warn(fbdev->dev, "failed to apply dispc config\n");
2563        }
2564
2565        DBG("mgr->apply'ed\n");
2566
2567        if (def_display) {
2568                r = omapfb_init_display(fbdev, def_display);
2569                if (r) {
2570                        dev_err(fbdev->dev,
2571                                        "failed to initialize default "
2572                                        "display\n");
2573                        goto cleanup;
2574                }
2575        }
2576
2577        DBG("create sysfs for fbs\n");
2578        r = omapfb_create_sysfs(fbdev);
2579        if (r) {
2580                dev_err(fbdev->dev, "failed to create sysfs entries\n");
2581                goto cleanup;
2582        }
2583
2584        if (def_display) {
2585                u16 w, h;
2586
2587                def_display->driver->get_resolution(def_display, &w, &h);
2588
2589                dev_info(fbdev->dev, "using display '%s' mode %dx%d\n",
2590                        def_display->name, w, h);
2591        }
2592
2593        return 0;
2594
2595cleanup:
2596        omapfb_free_resources(fbdev);
2597        omapdss_compat_uninit();
2598err0:
2599        dev_err(&pdev->dev, "failed to setup omapfb\n");
2600        return r;
2601}
2602
2603static int omapfb_remove(struct platform_device *pdev)
2604{
2605        struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2606
2607        /* FIXME: wait till completion of pending events */
2608
2609        omapfb_remove_sysfs(fbdev);
2610
2611        omapfb_free_resources(fbdev);
2612
2613        omapdss_compat_uninit();
2614
2615        return 0;
2616}
2617
2618static struct platform_driver omapfb_driver = {
2619        .probe          = omapfb_probe,
2620        .remove         = omapfb_remove,
2621        .driver         = {
2622                .name   = "omapfb",
2623        },
2624};
2625
2626module_param_named(mode, def_mode, charp, 0);
2627module_param_named(vram, def_vram, charp, 0);
2628module_param_named(rotate, def_rotate, int, 0);
2629module_param_named(vrfb, def_vrfb, bool, 0);
2630module_param_named(mirror, def_mirror, bool, 0);
2631
2632module_platform_driver(omapfb_driver);
2633
2634MODULE_ALIAS("platform:omapfb");
2635MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2636MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2637MODULE_LICENSE("GPL v2");
2638