linux/drivers/staging/msm/msm_fb.c
<<
>>
Prefs
   1/*
   2 *
   3 * Core MSM framebuffer driver.
   4 *
   5 * Copyright (C) 2007 Google Incorporated
   6 * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/moduleparam.h>
  20#include <linux/kernel.h>
  21#include <linux/slab.h>
  22#include <linux/delay.h>
  23#include <linux/mm.h>
  24#include <linux/fb.h>
  25#include "msm_mdp.h"
  26#include <linux/init.h>
  27#include <linux/ioport.h>
  28#include <linux/device.h>
  29#include <linux/dma-mapping.h>
  30#include <mach/board.h>
  31#include <linux/uaccess.h>
  32
  33#include <linux/workqueue.h>
  34#include <linux/string.h>
  35#include <linux/version.h>
  36#include <linux/proc_fs.h>
  37#include <linux/vmalloc.h>
  38#include <linux/debugfs.h>
  39#include <linux/console.h>
  40#include <linux/leds.h>
  41#include <asm/dma-mapping.h>
  42
  43
  44#define MSM_FB_C
  45#include "msm_fb.h"
  46#include "mddihosti.h"
  47#include "tvenc.h"
  48#include "mdp.h"
  49#include "mdp4.h"
  50
  51#ifdef CONFIG_FB_MSM_LOGO
  52#define INIT_IMAGE_FILE "/logo.rle"
  53extern int load_565rle_image(char *filename);
  54#endif
  55
  56
  57#define pgprot_noncached(prot) \
  58       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
  59#define pgprot_writecombine(prot) \
  60       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
  61#define pgprot_device(prot) \
  62       __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_DEV_NONSHARED)
  63#define pgprot_writethroughcache(prot) \
  64       __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITETHROUGH)
  65#define pgprot_writebackcache(prot) \
  66       __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEBACK)
  67#define pgprot_writebackwacache(prot) \
  68       __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEALLOC)
  69
  70static unsigned char *fbram;
  71static unsigned char *fbram_phys;
  72static int fbram_size;
  73
  74static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
  75static int pdev_list_cnt;
  76
  77int vsync_mode = 1;
  78
  79#define MAX_FBI_LIST 32
  80static struct fb_info *fbi_list[MAX_FBI_LIST];
  81static int fbi_list_index;
  82
  83static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST];
  84static int mfd_list_index;
  85
  86static u32 msm_fb_pseudo_palette[16] = {
  87        0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
  88        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
  89        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
  90        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
  91};
  92
  93u32 msm_fb_debug_enabled;
  94/* Setting msm_fb_msg_level to 8 prints out ALL messages */
  95u32 msm_fb_msg_level = 7;
  96
  97/* Setting mddi_msg_level to 8 prints out ALL messages */
  98u32 mddi_msg_level = 5;
  99
 100extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
 101extern unsigned long mdp_timer_duration;
 102
 103static int msm_fb_register(struct msm_fb_data_type *mfd);
 104static int msm_fb_open(struct fb_info *info, int user);
 105static int msm_fb_release(struct fb_info *info, int user);
 106static int msm_fb_pan_display(struct fb_var_screeninfo *var,
 107                              struct fb_info *info);
 108static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd);
 109int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd);
 110static int msm_fb_check_var(struct fb_var_screeninfo *var,
 111                            struct fb_info *info);
 112static int msm_fb_set_par(struct fb_info *info);
 113static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
 114                            boolean op_enable);
 115static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd);
 116static int msm_fb_resume_sub(struct msm_fb_data_type *mfd);
 117static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 118                        unsigned long arg);
 119static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
 120
 121#ifdef MSM_FB_ENABLE_DBGFS
 122
 123#define MSM_FB_MAX_DBGFS 1024
 124#define MAX_BACKLIGHT_BRIGHTNESS 255
 125
 126int msm_fb_debugfs_file_index;
 127struct dentry *msm_fb_debugfs_root;
 128struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
 129
 130struct dentry *msm_fb_get_debugfs_root(void)
 131{
 132        if (msm_fb_debugfs_root == NULL)
 133                msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL);
 134
 135        return msm_fb_debugfs_root;
 136}
 137
 138void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
 139                                u32 *var)
 140{
 141        if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS)
 142                return;
 143
 144        msm_fb_debugfs_file[msm_fb_debugfs_file_index++] =
 145            debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var);
 146}
 147#endif
 148
 149int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 150{
 151        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 152
 153        if (!mfd->cursor_update)
 154                return -ENODEV;
 155
 156        return mfd->cursor_update(info, cursor);
 157}
 158
 159static int msm_fb_resource_initialized;
 160
 161#ifndef CONFIG_FB_BACKLIGHT
 162static int lcd_backlight_registered;
 163
 164static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev,
 165                                        enum led_brightness value)
 166{
 167        struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
 168        int bl_lvl;
 169
 170        if (value > MAX_BACKLIGHT_BRIGHTNESS)
 171                value = MAX_BACKLIGHT_BRIGHTNESS;
 172
 173        /* This maps android backlight level 0 to 255 into
 174           driver backlight level 0 to bl_max with rounding */
 175        bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
 176                /(2 * MAX_BACKLIGHT_BRIGHTNESS);
 177
 178        if (!bl_lvl && value)
 179                bl_lvl = 1;
 180
 181        msm_fb_set_backlight(mfd, bl_lvl, 1);
 182}
 183
 184static struct led_classdev backlight_led = {
 185        .name           = "lcd-backlight",
 186        .brightness     = MAX_BACKLIGHT_BRIGHTNESS,
 187        .brightness_set = msm_fb_set_bl_brightness,
 188};
 189#endif
 190
 191static struct msm_fb_platform_data *msm_fb_pdata;
 192
 193int msm_fb_detect_client(const char *name)
 194{
 195        int ret = -EPERM;
 196#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
 197        u32 id;
 198#endif
 199
 200        if (msm_fb_pdata && msm_fb_pdata->detect_client) {
 201                ret = msm_fb_pdata->detect_client(name);
 202
 203                /* if it's non mddi panel, we need to pre-scan
 204                   mddi client to see if we can disable mddi host */
 205
 206#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
 207                if (!ret && msm_fb_pdata->mddi_prescan)
 208                        id = mddi_get_client_id();
 209#endif
 210        }
 211
 212        return ret;
 213}
 214
 215static int msm_fb_probe(struct platform_device *pdev)
 216{
 217        struct msm_fb_data_type *mfd;
 218        int rc;
 219
 220        MSM_FB_DEBUG("msm_fb_probe\n");
 221
 222        if ((pdev->id == 0) && (pdev->num_resources > 0)) {
 223                msm_fb_pdata = pdev->dev.platform_data;
 224                fbram_size =
 225                        pdev->resource[0].end - pdev->resource[0].start + 1;
 226                fbram_phys = (char *)pdev->resource[0].start;
 227                fbram = ioremap((unsigned long)fbram_phys, fbram_size);
 228
 229                if (!fbram) {
 230                        printk(KERN_ERR "fbram ioremap failed!\n");
 231                        return -ENOMEM;
 232                }
 233                MSM_FB_INFO("msm_fb_probe:  phy_Addr = 0x%x virt = 0x%x\n",
 234                             (int)fbram_phys, (int)fbram);
 235
 236                msm_fb_resource_initialized = 1;
 237                return 0;
 238        }
 239
 240        if (!msm_fb_resource_initialized)
 241                return -EPERM;
 242
 243        mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 244
 245        if (!mfd)
 246                return -ENODEV;
 247
 248        if (mfd->key != MFD_KEY)
 249                return -EINVAL;
 250
 251        if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
 252                return -ENOMEM;
 253
 254        mfd->panel_info.frame_count = 0;
 255        mfd->bl_level = mfd->panel_info.bl_max;
 256
 257        if (mfd->panel_info.type == LCDC_PANEL)
 258                mfd->allow_set_offset =
 259                msm_fb_pdata->allow_set_offset != NULL ?
 260                msm_fb_pdata->allow_set_offset() : 0;
 261        else
 262                mfd->allow_set_offset = 0;
 263
 264        rc = msm_fb_register(mfd);
 265        if (rc)
 266                return rc;
 267
 268#ifdef CONFIG_FB_BACKLIGHT
 269        msm_fb_config_backlight(mfd);
 270#else
 271        /* android supports only one lcd-backlight/lcd for now */
 272        if (!lcd_backlight_registered) {
 273                if (led_classdev_register(&pdev->dev, &backlight_led))
 274                        printk(KERN_ERR "led_classdev_register failed\n");
 275                else
 276                        lcd_backlight_registered = 1;
 277        }
 278#endif
 279
 280        pdev_list[pdev_list_cnt++] = pdev;
 281        return 0;
 282}
 283
 284static int msm_fb_remove(struct platform_device *pdev)
 285{
 286        struct msm_fb_data_type *mfd;
 287
 288        MSM_FB_DEBUG("msm_fb_remove\n");
 289
 290        mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 291
 292        if (!mfd)
 293                return -ENODEV;
 294
 295        if (mfd->key != MFD_KEY)
 296                return -EINVAL;
 297
 298        if (msm_fb_suspend_sub(mfd))
 299                printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index);
 300
 301        if (mfd->channel_irq != 0)
 302                free_irq(mfd->channel_irq, (void *)mfd);
 303
 304        if (mfd->vsync_width_boundary)
 305                vfree(mfd->vsync_width_boundary);
 306
 307        if (mfd->vsync_resync_timer.function)
 308                del_timer(&mfd->vsync_resync_timer);
 309
 310        if (mfd->refresh_timer.function)
 311                del_timer(&mfd->refresh_timer);
 312
 313        if (mfd->dma_hrtimer.function)
 314                hrtimer_cancel(&mfd->dma_hrtimer);
 315
 316        /* remove /dev/fb* */
 317        unregister_framebuffer(mfd->fbi);
 318
 319#ifdef CONFIG_FB_BACKLIGHT
 320        /* remove /sys/class/backlight */
 321        backlight_device_unregister(mfd->fbi->bl_dev);
 322#else
 323        if (lcd_backlight_registered) {
 324                lcd_backlight_registered = 0;
 325                led_classdev_unregister(&backlight_led);
 326        }
 327#endif
 328
 329#ifdef MSM_FB_ENABLE_DBGFS
 330        if (mfd->sub_dir)
 331                debugfs_remove(mfd->sub_dir);
 332#endif
 333
 334        return 0;
 335}
 336
 337#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
 338static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
 339{
 340        struct msm_fb_data_type *mfd;
 341        int ret = 0;
 342
 343        MSM_FB_DEBUG("msm_fb_suspend\n");
 344
 345        mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 346
 347        if ((!mfd) || (mfd->key != MFD_KEY))
 348                return 0;
 349
 350        console_lock();
 351        fb_set_suspend(mfd->fbi, 1);
 352
 353        ret = msm_fb_suspend_sub(mfd);
 354        if (ret != 0) {
 355                printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret);
 356                fb_set_suspend(mfd->fbi, 0);
 357        } else {
 358                pdev->dev.power.power_state = state;
 359        }
 360
 361        console_unlock();
 362        return ret;
 363}
 364#else
 365#define msm_fb_suspend NULL
 366#endif
 367
 368static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd)
 369{
 370        int ret = 0;
 371
 372        if ((!mfd) || (mfd->key != MFD_KEY))
 373                return 0;
 374
 375        /*
 376         * suspend this channel
 377         */
 378        mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable;
 379        mfd->suspend.op_enable = mfd->op_enable;
 380        mfd->suspend.panel_power_on = mfd->panel_power_on;
 381
 382        if (mfd->op_enable) {
 383                ret =
 384                     msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
 385                                      mfd->suspend.op_enable);
 386                if (ret) {
 387                        MSM_FB_INFO
 388                            ("msm_fb_suspend: can't turn off display!\n");
 389                        return ret;
 390                }
 391                mfd->op_enable = FALSE;
 392        }
 393        /*
 394         * try to power down
 395         */
 396        mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 397
 398        /*
 399         * detach display channel irq if there's any
 400         * or wait until vsync-resync completes
 401         */
 402        if ((mfd->dest == DISPLAY_LCD)) {
 403                if (mfd->panel_info.lcd.vsync_enable) {
 404                        if (mfd->panel_info.lcd.hw_vsync_mode) {
 405                                if (mfd->channel_irq != 0)
 406                                        disable_irq(mfd->channel_irq);
 407                        } else {
 408                                volatile boolean vh_pending;
 409                                do {
 410                                        vh_pending = mfd->vsync_handler_pending;
 411                                } while (vh_pending);
 412                        }
 413                }
 414        }
 415
 416        return 0;
 417}
 418
 419#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
 420static int msm_fb_resume(struct platform_device *pdev)
 421{
 422        /* This resume function is called when interrupt is enabled.
 423         */
 424        int ret = 0;
 425        struct msm_fb_data_type *mfd;
 426
 427        MSM_FB_DEBUG("msm_fb_resume\n");
 428
 429        mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 430
 431        if ((!mfd) || (mfd->key != MFD_KEY))
 432                return 0;
 433
 434        console_lock();
 435        ret = msm_fb_resume_sub(mfd);
 436        pdev->dev.power.power_state = PMSG_ON;
 437        fb_set_suspend(mfd->fbi, 1);
 438        console_unlock();
 439
 440        return ret;
 441}
 442#else
 443#define msm_fb_resume NULL
 444#endif
 445
 446static int msm_fb_resume_sub(struct msm_fb_data_type *mfd)
 447{
 448        int ret = 0;
 449
 450        if ((!mfd) || (mfd->key != MFD_KEY))
 451                return 0;
 452
 453        /* attach display channel irq if there's any */
 454        if (mfd->channel_irq != 0)
 455                enable_irq(mfd->channel_irq);
 456
 457        /* resume state var recover */
 458        mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable;
 459        mfd->op_enable = mfd->suspend.op_enable;
 460
 461        if (mfd->suspend.panel_power_on) {
 462                ret =
 463                     msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
 464                                      mfd->op_enable);
 465                if (ret)
 466                        MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
 467        }
 468
 469        return ret;
 470}
 471
 472static struct platform_driver msm_fb_driver = {
 473        .probe = msm_fb_probe,
 474        .remove = msm_fb_remove,
 475#ifndef CONFIG_HAS_EARLYSUSPEND
 476        .suspend = msm_fb_suspend,
 477        .resume = msm_fb_resume,
 478#endif
 479        .shutdown = NULL,
 480        .driver = {
 481                   /* Driver name must match the device name added in platform.c. */
 482                   .name = "msm_fb",
 483                   },
 484};
 485
 486#ifdef CONFIG_HAS_EARLYSUSPEND
 487static void msmfb_early_suspend(struct early_suspend *h)
 488{
 489        struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
 490                                                    early_suspend);
 491        msm_fb_suspend_sub(mfd);
 492}
 493
 494static void msmfb_early_resume(struct early_suspend *h)
 495{
 496        struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
 497                                                    early_suspend);
 498        msm_fb_resume_sub(mfd);
 499}
 500#endif
 501
 502void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save)
 503{
 504        struct msm_fb_panel_data *pdata;
 505
 506        pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
 507
 508        if ((pdata) && (pdata->set_backlight)) {
 509                down(&mfd->sem);
 510                if ((bkl_lvl != mfd->bl_level) || (!save)) {
 511                        u32 old_lvl;
 512
 513                        old_lvl = mfd->bl_level;
 514                        mfd->bl_level = bkl_lvl;
 515                        pdata->set_backlight(mfd);
 516
 517                        if (!save)
 518                                mfd->bl_level = old_lvl;
 519                }
 520                up(&mfd->sem);
 521        }
 522}
 523
 524static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
 525                            boolean op_enable)
 526{
 527        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 528        struct msm_fb_panel_data *pdata = NULL;
 529        int ret = 0;
 530
 531        if (!op_enable)
 532                return -EPERM;
 533
 534        pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
 535        if ((!pdata) || (!pdata->on) || (!pdata->off)) {
 536                printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n");
 537                return -ENODEV;
 538        }
 539
 540        switch (blank_mode) {
 541        case FB_BLANK_UNBLANK:
 542                if (!mfd->panel_power_on) {
 543                        mdelay(100);
 544                        ret = pdata->on(mfd->pdev);
 545                        if (ret == 0) {
 546                                mfd->panel_power_on = TRUE;
 547
 548                                msm_fb_set_backlight(mfd,
 549                                                     mfd->bl_level, 0);
 550
 551/* ToDo: possible conflict with android which doesn't expect sw refresher */
 552/*
 553          if (!mfd->hw_refresh)
 554          {
 555            if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0)
 556            {
 557              MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret);
 558            }
 559          }
 560*/
 561                        }
 562                }
 563                break;
 564
 565        case FB_BLANK_VSYNC_SUSPEND:
 566        case FB_BLANK_HSYNC_SUSPEND:
 567        case FB_BLANK_NORMAL:
 568        case FB_BLANK_POWERDOWN:
 569        default:
 570                if (mfd->panel_power_on) {
 571                        int curr_pwr_state;
 572
 573                        mfd->op_enable = FALSE;
 574                        curr_pwr_state = mfd->panel_power_on;
 575                        mfd->panel_power_on = FALSE;
 576
 577                        mdelay(100);
 578                        ret = pdata->off(mfd->pdev);
 579                        if (ret)
 580                                mfd->panel_power_on = curr_pwr_state;
 581
 582                        msm_fb_set_backlight(mfd, 0, 0);
 583                        mfd->op_enable = TRUE;
 584                }
 585                break;
 586        }
 587
 588        return ret;
 589}
 590
 591static void msm_fb_fillrect(struct fb_info *info,
 592                            const struct fb_fillrect *rect)
 593{
 594        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 595
 596        cfb_fillrect(info, rect);
 597        if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 598                !mfd->sw_currently_refreshing) {
 599                struct fb_var_screeninfo var;
 600
 601                var = info->var;
 602                var.reserved[0] = 0x54445055;
 603                var.reserved[1] = (rect->dy << 16) | (rect->dx);
 604                var.reserved[2] = ((rect->dy + rect->height) << 16) |
 605                    (rect->dx + rect->width);
 606
 607                msm_fb_pan_display(&var, info);
 608        }
 609}
 610
 611static void msm_fb_copyarea(struct fb_info *info,
 612                            const struct fb_copyarea *area)
 613{
 614        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 615
 616        cfb_copyarea(info, area);
 617        if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 618                !mfd->sw_currently_refreshing) {
 619                struct fb_var_screeninfo var;
 620
 621                var = info->var;
 622                var.reserved[0] = 0x54445055;
 623                var.reserved[1] = (area->dy << 16) | (area->dx);
 624                var.reserved[2] = ((area->dy + area->height) << 16) |
 625                    (area->dx + area->width);
 626
 627                msm_fb_pan_display(&var, info);
 628        }
 629}
 630
 631static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image)
 632{
 633        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 634
 635        cfb_imageblit(info, image);
 636        if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 637                !mfd->sw_currently_refreshing) {
 638                struct fb_var_screeninfo var;
 639
 640                var = info->var;
 641                var.reserved[0] = 0x54445055;
 642                var.reserved[1] = (image->dy << 16) | (image->dx);
 643                var.reserved[2] = ((image->dy + image->height) << 16) |
 644                    (image->dx + image->width);
 645
 646                msm_fb_pan_display(&var, info);
 647        }
 648}
 649
 650static int msm_fb_blank(int blank_mode, struct fb_info *info)
 651{
 652        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 653        return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
 654}
 655
 656static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info)
 657{
 658        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 659
 660        if (!mfd->lut_update)
 661                return -ENODEV;
 662
 663        mfd->lut_update(info, cmap);
 664        return 0;
 665}
 666
 667/*
 668 * Custom Framebuffer mmap() function for MSM driver.
 669 * Differs from standard mmap() function by allowing for customized
 670 * page-protection.
 671 */
 672static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
 673{
 674        /* Get frame buffer memory range. */
 675        unsigned long start = info->fix.smem_start;
 676        u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
 677        unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 678        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 679        if (off >= len) {
 680                /* memory mapped io */
 681                off -= len;
 682                if (info->var.accel_flags) {
 683                        mutex_unlock(&info->lock);
 684                        return -EINVAL;
 685                }
 686                start = info->fix.mmio_start;
 687                len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
 688        }
 689
 690        /* Set VM flags. */
 691        start &= PAGE_MASK;
 692        if ((vma->vm_end - vma->vm_start + off) > len)
 693                return -EINVAL;
 694        off += start;
 695        vma->vm_pgoff = off >> PAGE_SHIFT;
 696        /* This is an IO map - tell maydump to skip this VMA */
 697        vma->vm_flags |= VM_IO | VM_RESERVED;
 698
 699        /* Set VM page protection */
 700        if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
 701                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 702        else if (mfd->mdp_fb_page_protection ==
 703                        MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
 704                vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
 705        else if (mfd->mdp_fb_page_protection ==
 706                        MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
 707                vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
 708        else if (mfd->mdp_fb_page_protection ==
 709                        MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
 710                vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
 711        else
 712                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 713
 714        /* Remap the frame buffer I/O range */
 715        if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
 716                                vma->vm_end - vma->vm_start,
 717                                vma->vm_page_prot))
 718                return -EAGAIN;
 719
 720        return 0;
 721}
 722
 723static struct fb_ops msm_fb_ops = {
 724        .owner = THIS_MODULE,
 725        .fb_open = msm_fb_open,
 726        .fb_release = msm_fb_release,
 727        .fb_read = NULL,
 728        .fb_write = NULL,
 729        .fb_cursor = NULL,
 730        .fb_check_var = msm_fb_check_var,       /* vinfo check */
 731        .fb_set_par = msm_fb_set_par,   /* set the video mode according to info->var */
 732        .fb_setcolreg = NULL,   /* set color register */
 733        .fb_blank = msm_fb_blank,       /* blank display */
 734        .fb_pan_display = msm_fb_pan_display,   /* pan display */
 735        .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */
 736        .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */
 737        .fb_imageblit = msm_fb_imageblit,       /* Draws a image to the display */
 738        .fb_rotate = NULL,
 739        .fb_sync = NULL,        /* wait for blit idle, optional */
 740        .fb_ioctl = msm_fb_ioctl,       /* perform fb specific ioctl (optional) */
 741        .fb_mmap = msm_fb_mmap,
 742};
 743
 744static int msm_fb_register(struct msm_fb_data_type *mfd)
 745{
 746        int ret = -ENODEV;
 747        int bpp;
 748        struct msm_panel_info *panel_info = &mfd->panel_info;
 749        struct fb_info *fbi = mfd->fbi;
 750        struct fb_fix_screeninfo *fix;
 751        struct fb_var_screeninfo *var;
 752        int *id;
 753        int fbram_offset;
 754
 755        /*
 756         * fb info initialization
 757         */
 758        fix = &fbi->fix;
 759        var = &fbi->var;
 760
 761        fix->type_aux = 0;      /* if type == FB_TYPE_INTERLEAVED_PLANES */
 762        fix->visual = FB_VISUAL_TRUECOLOR;      /* True Color */
 763        fix->ywrapstep = 0;     /* No support */
 764        fix->mmio_start = 0;    /* No MMIO Address */
 765        fix->mmio_len = 0;      /* No MMIO Address */
 766        fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
 767
 768        var->xoffset = 0,       /* Offset from virtual to visible */
 769        var->yoffset = 0,       /* resolution */
 770        var->grayscale = 0,     /* No graylevels */
 771        var->nonstd = 0,        /* standard pixel format */
 772        var->activate = FB_ACTIVATE_VBL,        /* activate it at vsync */
 773        var->height = -1,       /* height of picture in mm */
 774        var->width = -1,        /* width of picture in mm */
 775        var->accel_flags = 0,   /* acceleration flags */
 776        var->sync = 0,  /* see FB_SYNC_* */
 777        var->rotate = 0,        /* angle we rotate counter clockwise */
 778        mfd->op_enable = FALSE;
 779
 780        switch (mfd->fb_imgType) {
 781        case MDP_RGB_565:
 782                fix->type = FB_TYPE_PACKED_PIXELS;
 783                fix->xpanstep = 1;
 784                fix->ypanstep = 1;
 785                var->vmode = FB_VMODE_NONINTERLACED;
 786                var->blue.offset = 0;
 787                var->green.offset = 5;
 788                var->red.offset = 11;
 789                var->blue.length = 5;
 790                var->green.length = 6;
 791                var->red.length = 5;
 792                var->blue.msb_right = 0;
 793                var->green.msb_right = 0;
 794                var->red.msb_right = 0;
 795                var->transp.offset = 0;
 796                var->transp.length = 0;
 797                bpp = 2;
 798                break;
 799
 800        case MDP_RGB_888:
 801                fix->type = FB_TYPE_PACKED_PIXELS;
 802                fix->xpanstep = 1;
 803                fix->ypanstep = 1;
 804                var->vmode = FB_VMODE_NONINTERLACED;
 805                var->blue.offset = 0;
 806                var->green.offset = 8;
 807                var->red.offset = 16;
 808                var->blue.length = 8;
 809                var->green.length = 8;
 810                var->red.length = 8;
 811                var->blue.msb_right = 0;
 812                var->green.msb_right = 0;
 813                var->red.msb_right = 0;
 814                var->transp.offset = 0;
 815                var->transp.length = 0;
 816                bpp = 3;
 817                break;
 818
 819        case MDP_ARGB_8888:
 820                fix->type = FB_TYPE_PACKED_PIXELS;
 821                fix->xpanstep = 1;
 822                fix->ypanstep = 1;
 823                var->vmode = FB_VMODE_NONINTERLACED;
 824                var->blue.offset = 0;
 825                var->green.offset = 8;
 826                var->red.offset = 16;
 827                var->blue.length = 8;
 828                var->green.length = 8;
 829                var->red.length = 8;
 830                var->blue.msb_right = 0;
 831                var->green.msb_right = 0;
 832                var->red.msb_right = 0;
 833                var->transp.offset = 24;
 834                var->transp.length = 8;
 835                bpp = 3;
 836                break;
 837
 838        case MDP_YCRYCB_H2V1:
 839                /* ToDo: need to check TV-Out YUV422i framebuffer format */
 840                /*       we might need to create new type define */
 841                fix->type = FB_TYPE_INTERLEAVED_PLANES;
 842                fix->xpanstep = 2;
 843                fix->ypanstep = 1;
 844                var->vmode = FB_VMODE_NONINTERLACED;
 845
 846                /* how about R/G/B offset? */
 847                var->blue.offset = 0;
 848                var->green.offset = 5;
 849                var->red.offset = 11;
 850                var->blue.length = 5;
 851                var->green.length = 6;
 852                var->red.length = 5;
 853                var->blue.msb_right = 0;
 854                var->green.msb_right = 0;
 855                var->red.msb_right = 0;
 856                var->transp.offset = 0;
 857                var->transp.length = 0;
 858                bpp = 2;
 859                break;
 860
 861        default:
 862                MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n",
 863                           mfd->index);
 864                return ret;
 865        }
 866
 867        /* The adreno GPU hardware requires that the pitch be aligned to
 868           32 pixels for color buffers, so for the cases where the GPU
 869           is writing directly to fb0, the framebuffer pitch
 870           also needs to be 32 pixel aligned */
 871
 872        if (mfd->index == 0)
 873                fix->line_length = ALIGN(panel_info->xres * bpp, 32);
 874        else
 875                fix->line_length = panel_info->xres * bpp;
 876
 877        fix->smem_len = fix->line_length * panel_info->yres * mfd->fb_page;
 878
 879        mfd->var_xres = panel_info->xres;
 880        mfd->var_yres = panel_info->yres;
 881
 882        var->pixclock = mfd->panel_info.clk_rate;
 883        mfd->var_pixclock = var->pixclock;
 884
 885        var->xres = panel_info->xres;
 886        var->yres = panel_info->yres;
 887        var->xres_virtual = panel_info->xres;
 888        var->yres_virtual = panel_info->yres * mfd->fb_page;
 889        var->bits_per_pixel = bpp * 8,  /* FrameBuffer color depth */
 890                /*
 891                 * id field for fb app
 892                 */
 893            id = (int *)&mfd->panel;
 894
 895#if defined(CONFIG_FB_MSM_MDP22)
 896        snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
 897#elif defined(CONFIG_FB_MSM_MDP30)
 898        snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
 899#elif defined(CONFIG_FB_MSM_MDP31)
 900        snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
 901#elif defined(CONFIG_FB_MSM_MDP40)
 902        snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
 903#else
 904        error CONFIG_FB_MSM_MDP undefined !
 905#endif
 906         fbi->fbops = &msm_fb_ops;
 907        fbi->flags = FBINFO_FLAG_DEFAULT;
 908        fbi->pseudo_palette = msm_fb_pseudo_palette;
 909
 910        mfd->ref_cnt = 0;
 911        mfd->sw_currently_refreshing = FALSE;
 912        mfd->sw_refreshing_enable = TRUE;
 913        mfd->panel_power_on = FALSE;
 914
 915        mfd->pan_waiting = FALSE;
 916        init_completion(&mfd->pan_comp);
 917        init_completion(&mfd->refresher_comp);
 918        sema_init(&mfd->sem, 1);
 919
 920        fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
 921        fbram += fbram_offset;
 922        fbram_phys += fbram_offset;
 923        fbram_size -= fbram_offset;
 924
 925        if (fbram_size < fix->smem_len) {
 926                printk(KERN_ERR "error: no more framebuffer memory!\n");
 927                return -ENOMEM;
 928        }
 929
 930        fbi->screen_base = fbram;
 931        fbi->fix.smem_start = (unsigned long)fbram_phys;
 932
 933        memset(fbi->screen_base, 0x0, fix->smem_len);
 934
 935        mfd->op_enable = TRUE;
 936        mfd->panel_power_on = FALSE;
 937
 938        /* cursor memory allocation */
 939        if (mfd->cursor_update) {
 940                mfd->cursor_buf = dma_alloc_coherent(NULL,
 941                                        MDP_CURSOR_SIZE,
 942                                        (dma_addr_t *) &mfd->cursor_buf_phys,
 943                                        GFP_KERNEL);
 944                if (!mfd->cursor_buf)
 945                        mfd->cursor_update = 0;
 946        }
 947
 948        if (mfd->lut_update) {
 949                ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 950                if (ret)
 951                        printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n",
 952                                        __func__);
 953        }
 954
 955        if (register_framebuffer(fbi) < 0) {
 956                if (mfd->lut_update)
 957                        fb_dealloc_cmap(&fbi->cmap);
 958
 959                if (mfd->cursor_buf)
 960                        dma_free_coherent(NULL,
 961                                MDP_CURSOR_SIZE,
 962                                mfd->cursor_buf,
 963                                (dma_addr_t) mfd->cursor_buf_phys);
 964
 965                mfd->op_enable = FALSE;
 966                return -EPERM;
 967        }
 968
 969        fbram += fix->smem_len;
 970        fbram_phys += fix->smem_len;
 971        fbram_size -= fix->smem_len;
 972
 973        MSM_FB_INFO
 974            ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n",
 975             mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len);
 976
 977#ifdef CONFIG_FB_MSM_LOGO
 978        if (!load_565rle_image(INIT_IMAGE_FILE)) ;      /* Flip buffer */
 979#endif
 980        ret = 0;
 981
 982#ifdef CONFIG_HAS_EARLYSUSPEND
 983        mfd->early_suspend.suspend = msmfb_early_suspend;
 984        mfd->early_suspend.resume = msmfb_early_resume;
 985        mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
 986        register_early_suspend(&mfd->early_suspend);
 987#endif
 988
 989#ifdef MSM_FB_ENABLE_DBGFS
 990        {
 991                struct dentry *root;
 992                struct dentry *sub_dir;
 993                char sub_name[2];
 994
 995                root = msm_fb_get_debugfs_root();
 996                if (root != NULL) {
 997                        sub_name[0] = (char)(mfd->index + 0x30);
 998                        sub_name[1] = '\0';
 999                        sub_dir = debugfs_create_dir(sub_name, root);
1000                } else {
1001                        sub_dir = NULL;
1002                }
1003
1004                mfd->sub_dir = sub_dir;
1005
1006                if (sub_dir) {
1007                        msm_fb_debugfs_file_create(sub_dir, "op_enable",
1008                                                   (u32 *) &mfd->op_enable);
1009                        msm_fb_debugfs_file_create(sub_dir, "panel_power_on",
1010                                                   (u32 *) &mfd->
1011                                                   panel_power_on);
1012                        msm_fb_debugfs_file_create(sub_dir, "ref_cnt",
1013                                                   (u32 *) &mfd->ref_cnt);
1014                        msm_fb_debugfs_file_create(sub_dir, "fb_imgType",
1015                                                   (u32 *) &mfd->fb_imgType);
1016                        msm_fb_debugfs_file_create(sub_dir,
1017                                                   "sw_currently_refreshing",
1018                                                   (u32 *) &mfd->
1019                                                   sw_currently_refreshing);
1020                        msm_fb_debugfs_file_create(sub_dir,
1021                                                   "sw_refreshing_enable",
1022                                                   (u32 *) &mfd->
1023                                                   sw_refreshing_enable);
1024
1025                        msm_fb_debugfs_file_create(sub_dir, "xres",
1026                                                   (u32 *) &mfd->panel_info.
1027                                                   xres);
1028                        msm_fb_debugfs_file_create(sub_dir, "yres",
1029                                                   (u32 *) &mfd->panel_info.
1030                                                   yres);
1031                        msm_fb_debugfs_file_create(sub_dir, "bpp",
1032                                                   (u32 *) &mfd->panel_info.
1033                                                   bpp);
1034                        msm_fb_debugfs_file_create(sub_dir, "type",
1035                                                   (u32 *) &mfd->panel_info.
1036                                                   type);
1037                        msm_fb_debugfs_file_create(sub_dir, "wait_cycle",
1038                                                   (u32 *) &mfd->panel_info.
1039                                                   wait_cycle);
1040                        msm_fb_debugfs_file_create(sub_dir, "pdest",
1041                                                   (u32 *) &mfd->panel_info.
1042                                                   pdest);
1043                        msm_fb_debugfs_file_create(sub_dir, "backbuff",
1044                                                   (u32 *) &mfd->panel_info.
1045                                                   fb_num);
1046                        msm_fb_debugfs_file_create(sub_dir, "clk_rate",
1047                                                   (u32 *) &mfd->panel_info.
1048                                                   clk_rate);
1049                        msm_fb_debugfs_file_create(sub_dir, "frame_count",
1050                                                   (u32 *) &mfd->panel_info.
1051                                                   frame_count);
1052
1053
1054                        switch (mfd->dest) {
1055                        case DISPLAY_LCD:
1056                                msm_fb_debugfs_file_create(sub_dir,
1057                                "vsync_enable",
1058                                (u32 *)&mfd->panel_info.lcd.vsync_enable);
1059                                msm_fb_debugfs_file_create(sub_dir,
1060                                "refx100",
1061                                (u32 *) &mfd->panel_info.lcd. refx100);
1062                                msm_fb_debugfs_file_create(sub_dir,
1063                                "v_back_porch",
1064                                (u32 *) &mfd->panel_info.lcd.v_back_porch);
1065                                msm_fb_debugfs_file_create(sub_dir,
1066                                "v_front_porch",
1067                                (u32 *) &mfd->panel_info.lcd.v_front_porch);
1068                                msm_fb_debugfs_file_create(sub_dir,
1069                                "v_pulse_width",
1070                                (u32 *) &mfd->panel_info.lcd.v_pulse_width);
1071                                msm_fb_debugfs_file_create(sub_dir,
1072                                "hw_vsync_mode",
1073                                (u32 *) &mfd->panel_info.lcd.hw_vsync_mode);
1074                                msm_fb_debugfs_file_create(sub_dir,
1075                                "vsync_notifier_period", (u32 *)
1076                                &mfd->panel_info.lcd.vsync_notifier_period);
1077                                break;
1078
1079                        case DISPLAY_LCDC:
1080                                msm_fb_debugfs_file_create(sub_dir,
1081                                "h_back_porch",
1082                                (u32 *) &mfd->panel_info.lcdc.h_back_porch);
1083                                msm_fb_debugfs_file_create(sub_dir,
1084                                "h_front_porch",
1085                                (u32 *) &mfd->panel_info.lcdc.h_front_porch);
1086                                msm_fb_debugfs_file_create(sub_dir,
1087                                "h_pulse_width",
1088                                (u32 *) &mfd->panel_info.lcdc.h_pulse_width);
1089                                msm_fb_debugfs_file_create(sub_dir,
1090                                "v_back_porch",
1091                                (u32 *) &mfd->panel_info.lcdc.v_back_porch);
1092                                msm_fb_debugfs_file_create(sub_dir,
1093                                "v_front_porch",
1094                                (u32 *) &mfd->panel_info.lcdc.v_front_porch);
1095                                msm_fb_debugfs_file_create(sub_dir,
1096                                "v_pulse_width",
1097                                (u32 *) &mfd->panel_info.lcdc.v_pulse_width);
1098                                msm_fb_debugfs_file_create(sub_dir,
1099                                "border_clr",
1100                                (u32 *) &mfd->panel_info.lcdc.border_clr);
1101                                msm_fb_debugfs_file_create(sub_dir,
1102                                "underflow_clr",
1103                                (u32 *) &mfd->panel_info.lcdc.underflow_clr);
1104                                msm_fb_debugfs_file_create(sub_dir,
1105                                "hsync_skew",
1106                                (u32 *) &mfd->panel_info.lcdc.hsync_skew);
1107                                break;
1108
1109                        default:
1110                                break;
1111                        }
1112                }
1113        }
1114#endif /* MSM_FB_ENABLE_DBGFS */
1115
1116        return ret;
1117}
1118
1119static int msm_fb_open(struct fb_info *info, int user)
1120{
1121        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1122
1123        if (!mfd->ref_cnt) {
1124                mdp_set_dma_pan_info(info, NULL, TRUE);
1125
1126                if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
1127                        printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
1128                        return -1;
1129                }
1130        }
1131
1132        mfd->ref_cnt++;
1133        return 0;
1134}
1135
1136static int msm_fb_release(struct fb_info *info, int user)
1137{
1138        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1139        int ret = 0;
1140
1141        if (!mfd->ref_cnt) {
1142                MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n",
1143                            mfd->index);
1144                return -EINVAL;
1145        }
1146
1147        mfd->ref_cnt--;
1148
1149        if (!mfd->ref_cnt) {
1150                if ((ret =
1151                     msm_fb_blank_sub(FB_BLANK_POWERDOWN, info,
1152                                      mfd->op_enable)) != 0) {
1153                        printk(KERN_ERR "msm_fb_release: can't turn off display!\n");
1154                        return ret;
1155                }
1156        }
1157
1158        return ret;
1159}
1160
1161DEFINE_SEMAPHORE(msm_fb_pan_sem);
1162
1163static int msm_fb_pan_display(struct fb_var_screeninfo *var,
1164                              struct fb_info *info)
1165{
1166        struct mdp_dirty_region dirty;
1167        struct mdp_dirty_region *dirtyPtr = NULL;
1168        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1169
1170        if ((!mfd->op_enable) || (!mfd->panel_power_on))
1171                return -EPERM;
1172
1173        if (var->xoffset > (info->var.xres_virtual - info->var.xres))
1174                return -EINVAL;
1175
1176        if (var->yoffset > (info->var.yres_virtual - info->var.yres))
1177                return -EINVAL;
1178
1179        if (info->fix.xpanstep)
1180                info->var.xoffset =
1181                    (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
1182
1183        if (info->fix.ypanstep)
1184                info->var.yoffset =
1185                    (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
1186
1187        /* "UPDT" */
1188        if (var->reserved[0] == 0x54445055) {
1189                dirty.xoffset = var->reserved[1] & 0xffff;
1190                dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
1191
1192                if ((var->reserved[2] & 0xffff) <= dirty.xoffset)
1193                        return -EINVAL;
1194                if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset)
1195                        return -EINVAL;
1196
1197                dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset;
1198                dirty.height =
1199                    ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset;
1200                info->var.yoffset = var->yoffset;
1201
1202                if (dirty.xoffset < 0)
1203                        return -EINVAL;
1204
1205                if (dirty.yoffset < 0)
1206                        return -EINVAL;
1207
1208                if ((dirty.xoffset + dirty.width) > info->var.xres)
1209                        return -EINVAL;
1210
1211                if ((dirty.yoffset + dirty.height) > info->var.yres)
1212                        return -EINVAL;
1213
1214                if ((dirty.width <= 0) || (dirty.height <= 0))
1215                        return -EINVAL;
1216
1217                dirtyPtr = &dirty;
1218        }
1219
1220        /* Flip */
1221        /* A constant value is used to indicate that we should change the DMA
1222           output buffer instead of just panning */
1223
1224        if (var->reserved[0] == 0x466c6970) {
1225                unsigned long length, address;
1226                struct file *p_src_file;
1227                struct mdp_img imgdata;
1228                int bpp;
1229
1230                if (mfd->allow_set_offset) {
1231                        imgdata.memory_id = var->reserved[1];
1232                        imgdata.priv = var->reserved[2];
1233
1234                        /* If there is no memory ID then we want to reset back
1235                           to the original fb visibility */
1236                        if (var->reserved[1]) {
1237                                if (var->reserved[4] == MDP_BLIT_SRC_GEM) {
1238                                        panic("waaaaaaaaaaaaaah");
1239                                        if ( /*get_gem_img(&imgdata,
1240                                                (unsigned long *) &address,
1241                                                 &length)*/ -1 < 0) {
1242                                                return -1;
1243                                        }
1244                                } else {
1245                                        /*get_img(&imgdata, info, &address,
1246                                                        &length, &p_src_file);*/
1247                                        panic("waaaaaah");
1248                                }
1249                                mfd->ibuf.visible_swapped = TRUE;
1250                        } else {
1251                                /* Flip back to the original address
1252                                   adjusted for xoffset and yoffset */
1253
1254                                bpp = info->var.bits_per_pixel / 8;
1255                                address = (unsigned long) info->fix.smem_start;
1256                                address += info->var.xoffset * bpp +
1257                                info->var.yoffset * info->fix.line_length;
1258
1259                                mfd->ibuf.visible_swapped = FALSE;
1260                        }
1261
1262                        mdp_set_offset_info(info, address,
1263                                (var->activate == FB_ACTIVATE_VBL));
1264
1265                        mfd->dma_fnc(mfd);
1266                        return 0;
1267                } else
1268                        return -EINVAL;
1269        }
1270
1271        down(&msm_fb_pan_sem);
1272        mdp_set_dma_pan_info(info, dirtyPtr,
1273                             (var->activate == FB_ACTIVATE_VBL));
1274        mdp_dma_pan_update(info);
1275        up(&msm_fb_pan_sem);
1276
1277        ++mfd->panel_info.frame_count;
1278        return 0;
1279}
1280
1281static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1282{
1283        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1284
1285        if (var->rotate != FB_ROTATE_UR)
1286                return -EINVAL;
1287        if (var->grayscale != info->var.grayscale)
1288                return -EINVAL;
1289
1290        switch (var->bits_per_pixel) {
1291        case 16:
1292                if ((var->green.offset != 5) ||
1293                        !((var->blue.offset == 11)
1294                                || (var->blue.offset == 0)) ||
1295                        !((var->red.offset == 11)
1296                                || (var->red.offset == 0)) ||
1297                        (var->blue.length != 5) ||
1298                        (var->green.length != 6) ||
1299                        (var->red.length != 5) ||
1300                        (var->blue.msb_right != 0) ||
1301                        (var->green.msb_right != 0) ||
1302                        (var->red.msb_right != 0) ||
1303                        (var->transp.offset != 0) ||
1304                        (var->transp.length != 0))
1305                                return -EINVAL;
1306                break;
1307
1308        case 24:
1309                if ((var->blue.offset != 0) ||
1310                        (var->green.offset != 8) ||
1311                        (var->red.offset != 16) ||
1312                        (var->blue.length != 8) ||
1313                        (var->green.length != 8) ||
1314                        (var->red.length != 8) ||
1315                        (var->blue.msb_right != 0) ||
1316                        (var->green.msb_right != 0) ||
1317                        (var->red.msb_right != 0) ||
1318                        !(((var->transp.offset == 0) &&
1319                                (var->transp.length == 0)) ||
1320                          ((var->transp.offset == 24) &&
1321                                (var->transp.length == 8))))
1322                                return -EINVAL;
1323                break;
1324
1325        default:
1326                return -EINVAL;
1327        }
1328
1329        if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
1330                return -EINVAL;
1331
1332        if (info->fix.smem_len <
1333                (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
1334                return -EINVAL;
1335
1336        if ((var->xres == 0) || (var->yres == 0))
1337                return -EINVAL;
1338
1339        if ((var->xres > mfd->panel_info.xres) ||
1340                (var->yres > mfd->panel_info.yres))
1341                return -EINVAL;
1342
1343        if (var->xoffset > (var->xres_virtual - var->xres))
1344                return -EINVAL;
1345
1346        if (var->yoffset > (var->yres_virtual - var->yres))
1347                return -EINVAL;
1348
1349        return 0;
1350}
1351
1352static int msm_fb_set_par(struct fb_info *info)
1353{
1354        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1355        struct fb_var_screeninfo *var = &info->var;
1356        int old_imgType;
1357        int blank = 0;
1358
1359        old_imgType = mfd->fb_imgType;
1360        switch (var->bits_per_pixel) {
1361        case 16:
1362                if (var->red.offset == 0)
1363                        mfd->fb_imgType = MDP_BGR_565;
1364                else
1365                        mfd->fb_imgType = MDP_RGB_565;
1366                break;
1367
1368        case 24:
1369                if ((var->transp.offset == 0) && (var->transp.length == 0))
1370                        mfd->fb_imgType = MDP_RGB_888;
1371                else if ((var->transp.offset == 24) &&
1372                                (var->transp.length == 8)) {
1373                        mfd->fb_imgType = MDP_ARGB_8888;
1374                        info->var.bits_per_pixel = 32;
1375                }
1376                break;
1377
1378        default:
1379                return -EINVAL;
1380        }
1381
1382        if ((mfd->var_pixclock != var->pixclock) ||
1383                (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
1384                                (mfd->var_pixclock != var->pixclock) ||
1385                                (mfd->var_xres != var->xres) ||
1386                                (mfd->var_yres != var->yres)))) {
1387                mfd->var_xres = var->xres;
1388                mfd->var_yres = var->yres;
1389                mfd->var_pixclock = var->pixclock;
1390                blank = 1;
1391        }
1392
1393        if (blank) {
1394                msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
1395                msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
1396        }
1397
1398        return 0;
1399}
1400
1401static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd)
1402{
1403        if (mfd->hw_refresh)
1404                return -EPERM;
1405
1406        if (mfd->sw_currently_refreshing) {
1407                down(&mfd->sem);
1408                mfd->sw_currently_refreshing = FALSE;
1409                up(&mfd->sem);
1410
1411                /* wait until the refresher finishes the last job */
1412                wait_for_completion_killable(&mfd->refresher_comp);
1413        }
1414
1415        return 0;
1416}
1417
1418int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd)
1419{
1420        boolean do_refresh;
1421
1422        if (mfd->hw_refresh)
1423                return -EPERM;
1424
1425        down(&mfd->sem);
1426        if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
1427                do_refresh = TRUE;
1428                mfd->sw_currently_refreshing = TRUE;
1429        } else {
1430                do_refresh = FALSE;
1431        }
1432        up(&mfd->sem);
1433
1434        if (do_refresh)
1435                mdp_refresh_screen((unsigned long)mfd);
1436
1437        return 0;
1438}
1439
1440void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file)
1441{
1442#ifdef CONFIG_ANDROID_PMEM
1443        if (p_src_file)
1444                put_pmem_file(p_src_file);
1445        if (p_dst_file)
1446                put_pmem_file(p_dst_file);
1447#endif
1448}
1449
1450int mdp_blit(struct fb_info *info, struct mdp_blit_req *req)
1451{
1452        int ret;
1453        struct file *p_src_file = 0, *p_dst_file = 0;
1454        if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
1455                printk(KERN_ERR "mpd_ppp: src img of zero size!\n");
1456                return -EINVAL;
1457        }
1458        if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
1459                return 0;
1460
1461        ret = mdp_ppp_blit(info, req, &p_src_file, &p_dst_file);
1462        mdp_ppp_put_img(p_src_file, p_dst_file);
1463        return ret;
1464}
1465
1466typedef void (*msm_dma_barrier_function_pointer) (void *, size_t);
1467
1468static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info,
1469                        struct mdp_img *img, struct mdp_rect *rect,
1470                        msm_dma_barrier_function_pointer dma_barrier_fp
1471                        )
1472{
1473        /*
1474         * Compute the start and end addresses of the rectangles.
1475         * NOTE: As currently implemented, the data between
1476         *       the end of one row and the start of the next is
1477         *       included in the address range rather than
1478         *       doing multiple calls for each row.
1479         */
1480
1481        char * const pmem_start = info->screen_base;
1482/*      int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format);
1483        unsigned long start = (unsigned long)pmem_start + img->offset +
1484                (img->width * rect->y + rect->x) * bytes_per_pixel;
1485        size_t size  = ((rect->h - 1) * img->width + rect->w) * bytes_per_pixel;
1486        (*dma_barrier_fp) ((void *) start, size);
1487*/
1488        panic("waaaaah");
1489}
1490
1491static inline void msm_dma_nc_pre(void)
1492{
1493        dmb();
1494}
1495static inline void msm_dma_wt_pre(void)
1496{
1497        dmb();
1498}
1499static inline void msm_dma_todevice_wb_pre(void *start, size_t size)
1500{
1501        #warning this
1502//      dma_cache_pre_ops(start, size, DMA_TO_DEVICE);
1503}
1504
1505static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size)
1506{
1507        #warning this
1508//      dma_cache_pre_ops(start, size, DMA_FROM_DEVICE);
1509}
1510
1511static inline void msm_dma_nc_post(void)
1512{
1513        dmb();
1514}
1515
1516static inline void msm_dma_fromdevice_wt_post(void *start, size_t size)
1517{
1518        #warning this
1519//      dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
1520}
1521
1522static inline void msm_dma_todevice_wb_post(void *start, size_t size)
1523{
1524        #warning this
1525//      dma_cache_post_ops(start, size, DMA_TO_DEVICE);
1526}
1527
1528static inline void msm_dma_fromdevice_wb_post(void *start, size_t size)
1529{
1530        #warning this
1531//      dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
1532}
1533
1534/*
1535 * Do the write barriers required to guarantee data is committed to RAM
1536 * (from CPU cache or internal buffers) before a DMA operation starts.
1537 * NOTE: As currently implemented, the data between
1538 *       the end of one row and the start of the next is
1539 *       included in the address range rather than
1540 *       doing multiple calls for each row.
1541*/
1542static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info,
1543                struct mdp_blit_req *req_list,
1544                int req_list_count)
1545{
1546#ifdef CONFIG_ARCH_QSD8X50
1547        int i;
1548
1549        /*
1550         * Normally, do the requested barriers for each address
1551         * range that corresponds to a rectangle.
1552         *
1553         * But if at least one write barrier is requested for data
1554         * going to or from the device but no address range is
1555         * needed for that barrier, then do the barrier, but do it
1556         * only once, no matter how many requests there are.
1557         */
1558        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1559        switch (mfd->mdp_fb_page_protection)    {
1560        default:
1561        case MDP_FB_PAGE_PROTECTION_NONCACHED:
1562        case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
1563                /*
1564                 * The following barrier is only done at most once,
1565                 * since further calls would be redundant.
1566                 */
1567                for (i = 0; i < req_list_count; i++) {
1568                        if (!(req_list[i].flags
1569                                & MDP_NO_DMA_BARRIER_START)) {
1570                                msm_dma_nc_pre();
1571                                break;
1572                        }
1573                }
1574                break;
1575
1576        case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
1577                /*
1578                 * The following barrier is only done at most once,
1579                 * since further calls would be redundant.
1580                 */
1581                for (i = 0; i < req_list_count; i++) {
1582                        if (!(req_list[i].flags
1583                                & MDP_NO_DMA_BARRIER_START)) {
1584                                msm_dma_wt_pre();
1585                                break;
1586                        }
1587                }
1588                break;
1589
1590        case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
1591        case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
1592                for (i = 0; i < req_list_count; i++) {
1593                        if (!(req_list[i].flags &
1594                                        MDP_NO_DMA_BARRIER_START)) {
1595
1596                                msm_fb_dma_barrier_for_rect(info,
1597                                                &(req_list[i].src),
1598                                                &(req_list[i].src_rect),
1599                                                msm_dma_todevice_wb_pre
1600                                                );
1601
1602                                msm_fb_dma_barrier_for_rect(info,
1603                                                &(req_list[i].dst),
1604                                                &(req_list[i].dst_rect),
1605                                                msm_dma_todevice_wb_pre
1606                                                );
1607                        }
1608                }
1609                break;
1610        }
1611#else
1612        dmb();
1613#endif
1614}
1615
1616
1617/*
1618 * Do the write barriers required to guarantee data will be re-read from RAM by
1619 * the CPU after a DMA operation ends.
1620 * NOTE: As currently implemented, the data between
1621 *       the end of one row and the start of the next is
1622 *       included in the address range rather than
1623 *       doing multiple calls for each row.
1624*/
1625static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info,
1626                struct mdp_blit_req *req_list,
1627                int req_list_count)
1628{
1629#ifdef CONFIG_ARCH_QSD8X50
1630        int i;
1631
1632        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1633        switch (mfd->mdp_fb_page_protection)    {
1634        default:
1635        case MDP_FB_PAGE_PROTECTION_NONCACHED:
1636        case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
1637                /*
1638                 * The following barrier is only done at most once,
1639                 * since further calls would be redundant.
1640                 */
1641                for (i = 0; i < req_list_count; i++) {
1642                        if (!(req_list[i].flags
1643                                & MDP_NO_DMA_BARRIER_END)) {
1644                                msm_dma_nc_post();
1645                                break;
1646                        }
1647                }
1648                break;
1649
1650        case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
1651                for (i = 0; i < req_list_count; i++) {
1652                        if (!(req_list[i].flags &
1653                                        MDP_NO_DMA_BARRIER_END)) {
1654
1655                                msm_fb_dma_barrier_for_rect(info,
1656                                                &(req_list[i].dst),
1657                                                &(req_list[i].dst_rect),
1658                                                msm_dma_fromdevice_wt_post
1659                                                );
1660                        }
1661                }
1662                break;
1663        case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
1664        case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
1665                for (i = 0; i < req_list_count; i++) {
1666                        if (!(req_list[i].flags &
1667                                        MDP_NO_DMA_BARRIER_END)) {
1668
1669                                msm_fb_dma_barrier_for_rect(info,
1670                                                &(req_list[i].dst),
1671                                                &(req_list[i].dst_rect),
1672                                                msm_dma_fromdevice_wb_post
1673                                                );
1674                        }
1675                }
1676                break;
1677        }
1678#else
1679        dmb();
1680#endif
1681}
1682
1683#ifdef CONFIG_MDP_PPP_ASYNC_OP
1684void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info,
1685        struct mdp_blit_req *req_list, int req_list_count)
1686{
1687        BUG_ON(!info);
1688
1689        /*
1690         * Ensure that CPU cache and other internal CPU state is
1691         * updated to reflect any change in memory modified by MDP blit
1692         * DMA.
1693         */
1694        msm_fb_ensure_memory_coherency_after_dma(info,
1695                        req_list, req_list_count);
1696}
1697
1698static int msmfb_async_blit(struct fb_info *info, void __user *p)
1699{
1700        /*
1701         * CAUTION: The names of the struct types intentionally *DON'T* match
1702         * the names of the variables declared -- they appear to be swapped.
1703         * Read the code carefully and you should see that the variable names
1704         * make sense.
1705         */
1706        const int MAX_LIST_WINDOW = 16;
1707        struct mdp_blit_req req_list[MAX_LIST_WINDOW];
1708        struct mdp_blit_req_list req_list_header;
1709
1710        int count, i, req_list_count;
1711
1712        /* Get the count size for the total BLIT request. */
1713        if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
1714                return -EFAULT;
1715        p += sizeof(req_list_header);
1716        count = req_list_header.count;
1717        while (count > 0) {
1718                /*
1719                 * Access the requests through a narrow window to decrease copy
1720                 * overhead and make larger requests accessible to the
1721                 * coherency management code.
1722                 * NOTE: The window size is intended to be larger than the
1723                 *       typical request size, but not require more than 2
1724                 *       kbytes of stack storage.
1725                 */
1726                req_list_count = count;
1727                if (req_list_count > MAX_LIST_WINDOW)
1728                        req_list_count = MAX_LIST_WINDOW;
1729                if (copy_from_user(&req_list, p,
1730                                sizeof(struct mdp_blit_req)*req_list_count))
1731                        return -EFAULT;
1732
1733                /*
1734                 * Ensure that any data CPU may have previously written to
1735                 * internal state (but not yet committed to memory) is
1736                 * guaranteed to be committed to memory now.
1737                 */
1738                msm_fb_ensure_memory_coherency_before_dma(info,
1739                                req_list, req_list_count);
1740
1741                /*
1742                 * Do the blit DMA, if required -- returning early only if
1743                 * there is a failure.
1744                 */
1745                for (i = 0; i < req_list_count; i++) {
1746                        if (!(req_list[i].flags & MDP_NO_BLIT)) {
1747                                int ret = 0;
1748                                struct mdp_ppp_djob *job = NULL;
1749
1750                                if (unlikely(req_list[i].src_rect.h == 0 ||
1751                                        req_list[i].src_rect.w == 0)) {
1752                                        MSM_FB_ERR("mpd_ppp: "
1753                                                "src img of zero size!\n");
1754                                        return -EINVAL;
1755                                }
1756
1757                                if (unlikely(req_list[i].dst_rect.h == 0 ||
1758                                        req_list[i].dst_rect.w == 0))
1759                                        continue;
1760
1761                                /* create a new display job */
1762                                job = mdp_ppp_new_djob();
1763                                if (unlikely(!job))
1764                                        return -ENOMEM;
1765
1766                                job->info = info;
1767                                memcpy(&job->req, &req_list[i],
1768                                        sizeof(struct mdp_blit_req));
1769
1770                                /* Do the actual blit. */
1771                                ret = mdp_ppp_blit(info, &job->req,
1772                                        &job->p_src_file, &job->p_dst_file);
1773
1774                                /*
1775                                 * Note that early returns don't guarantee
1776                                 * memory coherency.
1777                                 */
1778                                if (ret || mdp_ppp_get_ret_code()) {
1779                                        mdp_ppp_clear_curr_djob();
1780                                        return ret;
1781                                }
1782                        }
1783                }
1784
1785                /* Go to next window of requests. */
1786                count -= req_list_count;
1787                p += sizeof(struct mdp_blit_req)*req_list_count;
1788        }
1789        return 0;
1790}
1791#else
1792
1793/*
1794 * NOTE: The userspace issues blit operations in a sequence, the sequence
1795 * start with a operation marked START and ends in an operation marked
1796 * END. It is guranteed by the userspace that all the blit operations
1797 * between START and END are only within the regions of areas designated
1798 * by the START and END operations and that the userspace doesnt modify
1799 * those areas. Hence it would be enough to perform barrier/cache operations
1800 * only on the START and END operations.
1801 */
1802static int msmfb_blit(struct fb_info *info, void __user *p)
1803{
1804        /*
1805         * CAUTION: The names of the struct types intentionally *DON'T* match
1806         * the names of the variables declared -- they appear to be swapped.
1807         * Read the code carefully and you should see that the variable names
1808         * make sense.
1809         */
1810        const int MAX_LIST_WINDOW = 16;
1811        struct mdp_blit_req req_list[MAX_LIST_WINDOW];
1812        struct mdp_blit_req_list req_list_header;
1813
1814        int count, i, req_list_count;
1815
1816        /* Get the count size for the total BLIT request. */
1817        if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
1818                return -EFAULT;
1819        p += sizeof(req_list_header);
1820        count = req_list_header.count;
1821        while (count > 0) {
1822                /*
1823                 * Access the requests through a narrow window to decrease copy
1824                 * overhead and make larger requests accessible to the
1825                 * coherency management code.
1826                 * NOTE: The window size is intended to be larger than the
1827                 *       typical request size, but not require more than 2
1828                 *       kbytes of stack storage.
1829                 */
1830                req_list_count = count;
1831                if (req_list_count > MAX_LIST_WINDOW)
1832                        req_list_count = MAX_LIST_WINDOW;
1833                if (copy_from_user(&req_list, p,
1834                                sizeof(struct mdp_blit_req)*req_list_count))
1835                        return -EFAULT;
1836
1837                /*
1838                 * Ensure that any data CPU may have previously written to
1839                 * internal state (but not yet committed to memory) is
1840                 * guaranteed to be committed to memory now.
1841                 */
1842                msm_fb_ensure_memory_coherency_before_dma(info,
1843                                req_list, req_list_count);
1844
1845                /*
1846                 * Do the blit DMA, if required -- returning early only if
1847                 * there is a failure.
1848                 */
1849                for (i = 0; i < req_list_count; i++) {
1850                        if (!(req_list[i].flags & MDP_NO_BLIT)) {
1851                                /* Do the actual blit. */
1852                                int ret = mdp_blit(info, &(req_list[i]));
1853
1854                                /*
1855                                 * Note that early returns don't guarantee
1856                                 * memory coherency.
1857                                 */
1858                                if (ret)
1859                                        return ret;
1860                        }
1861                }
1862
1863                /*
1864                 * Ensure that CPU cache and other internal CPU state is
1865                 * updated to reflect any change in memory modified by MDP blit
1866                 * DMA.
1867                 */
1868                msm_fb_ensure_memory_coherency_after_dma(info,
1869                                req_list,
1870                                req_list_count);
1871
1872                /* Go to next window of requests. */
1873                count -= req_list_count;
1874                p += sizeof(struct mdp_blit_req)*req_list_count;
1875        }
1876        return 0;
1877}
1878#endif
1879
1880#ifdef CONFIG_FB_MSM_OVERLAY
1881static int msmfb_overlay_get(struct fb_info *info, void __user *p)
1882{
1883        struct mdp_overlay req;
1884        int ret;
1885
1886        if (copy_from_user(&req, p, sizeof(req)))
1887                return -EFAULT;
1888
1889        ret = mdp4_overlay_get(info, &req);
1890        if (ret) {
1891                printk(KERN_ERR "%s: ioctl failed \n",
1892                        __func__);
1893                return ret;
1894        }
1895        if (copy_to_user(p, &req, sizeof(req))) {
1896                printk(KERN_ERR "%s: copy2user failed \n",
1897                        __func__);
1898                return -EFAULT;
1899        }
1900
1901        return 0;
1902}
1903
1904static int msmfb_overlay_set(struct fb_info *info, void __user *p)
1905{
1906        struct mdp_overlay req;
1907        int ret;
1908
1909        if (copy_from_user(&req, p, sizeof(req)))
1910                return -EFAULT;
1911
1912        ret = mdp4_overlay_set(info, &req);
1913        if (ret) {
1914                printk(KERN_ERR "%s:ioctl failed \n",
1915                        __func__);
1916                return ret;
1917        }
1918
1919        if (copy_to_user(p, &req, sizeof(req))) {
1920                printk(KERN_ERR "%s: copy2user failed \n",
1921                        __func__);
1922                return -EFAULT;
1923        }
1924
1925        return 0;
1926}
1927
1928static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp)
1929{
1930        int     ret, ndx;
1931
1932        ret = copy_from_user(&ndx, argp, sizeof(ndx));
1933        if (ret) {
1934                printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n",
1935                        __func__);
1936                return ret;
1937        }
1938
1939        return mdp4_overlay_unset(info, ndx);
1940}
1941
1942static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
1943{
1944        int     ret;
1945        struct msmfb_overlay_data req;
1946        struct file *p_src_file = 0;
1947
1948        ret = copy_from_user(&req, argp, sizeof(req));
1949        if (ret) {
1950                printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n",
1951                        __func__);
1952                return ret;
1953        }
1954
1955        ret = mdp4_overlay_play(info, &req, &p_src_file);
1956
1957        if (p_src_file)
1958                put_pmem_file(p_src_file);
1959
1960        return ret;
1961}
1962
1963#endif
1964
1965DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
1966DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
1967DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
1968
1969/* Set color conversion matrix from user space */
1970
1971#ifndef CONFIG_FB_MSM_MDP40
1972static void msmfb_set_color_conv(struct mdp_ccs *p)
1973{
1974        int i;
1975
1976        if (p->direction == MDP_CCS_RGB2YUV) {
1977                /* MDP cmd block enable */
1978                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
1979
1980                /* RGB->YUV primary forward matrix */
1981                for (i = 0; i < MDP_CCS_SIZE; i++)
1982                        writel(p->ccs[i], MDP_CSC_PFMVn(i));
1983
1984                #ifdef CONFIG_FB_MSM_MDP31
1985                for (i = 0; i < MDP_BV_SIZE; i++)
1986                        writel(p->bv[i], MDP_CSC_POST_BV2n(i));
1987                #endif
1988
1989                /* MDP cmd block disable */
1990                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
1991        } else {
1992                /* MDP cmd block enable */
1993                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
1994
1995                /* YUV->RGB primary reverse matrix */
1996                for (i = 0; i < MDP_CCS_SIZE; i++)
1997                        writel(p->ccs[i], MDP_CSC_PRMVn(i));
1998                for (i = 0; i < MDP_BV_SIZE; i++)
1999                        writel(p->bv[i], MDP_CSC_PRE_BV1n(i));
2000
2001                /* MDP cmd block disable */
2002                mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
2003        }
2004}
2005#endif
2006
2007
2008static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
2009                        unsigned long arg)
2010{
2011        struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
2012        void __user *argp = (void __user *)arg;
2013        struct fb_cursor cursor;
2014        struct fb_cmap cmap;
2015        struct mdp_histogram hist;
2016#ifndef CONFIG_FB_MSM_MDP40
2017        struct mdp_ccs ccs_matrix;
2018#endif
2019        struct mdp_page_protection fb_page_protection;
2020        int ret = 0;
2021
2022        if (!mfd->op_enable)
2023                return -EPERM;
2024
2025        switch (cmd) {
2026#ifdef CONFIG_FB_MSM_OVERLAY
2027        case MSMFB_OVERLAY_GET:
2028                down(&msm_fb_ioctl_ppp_sem);
2029                ret = msmfb_overlay_get(info, argp);
2030                up(&msm_fb_ioctl_ppp_sem);
2031                break;
2032        case MSMFB_OVERLAY_SET:
2033                down(&msm_fb_ioctl_ppp_sem);
2034                ret = msmfb_overlay_set(info, argp);
2035                up(&msm_fb_ioctl_ppp_sem);
2036                break;
2037        case MSMFB_OVERLAY_UNSET:
2038                down(&msm_fb_ioctl_ppp_sem);
2039                ret = msmfb_overlay_unset(info, argp);
2040                up(&msm_fb_ioctl_ppp_sem);
2041                break;
2042        case MSMFB_OVERLAY_PLAY:
2043                down(&msm_fb_ioctl_ppp_sem);
2044                ret = msmfb_overlay_play(info, argp);
2045                up(&msm_fb_ioctl_ppp_sem);
2046                break;
2047#endif
2048        case MSMFB_BLIT:
2049                down(&msm_fb_ioctl_ppp_sem);
2050#ifdef CONFIG_MDP_PPP_ASYNC_OP
2051                ret = msmfb_async_blit(info, argp);
2052                mdp_ppp_wait(); /* Wait for all blits to be finished. */
2053#else
2054                ret = msmfb_blit(info, argp);
2055#endif
2056                up(&msm_fb_ioctl_ppp_sem);
2057
2058                break;
2059
2060        /* Ioctl for setting ccs matrix from user space */
2061        case MSMFB_SET_CCS_MATRIX:
2062#ifndef CONFIG_FB_MSM_MDP40
2063                ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix));
2064                if (ret) {
2065                        printk(KERN_ERR
2066                                "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n",
2067                                __func__);
2068                        return ret;
2069                }
2070
2071                down(&msm_fb_ioctl_ppp_sem);
2072                if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
2073                        mdp_ccs_rgb2yuv = ccs_matrix;
2074                else
2075                        mdp_ccs_yuv2rgb = ccs_matrix;
2076
2077                msmfb_set_color_conv(&ccs_matrix) ;
2078                up(&msm_fb_ioctl_ppp_sem);
2079#else
2080                ret = -EINVAL;
2081#endif
2082
2083                break;
2084
2085        /* Ioctl for getting ccs matrix to user space */
2086        case MSMFB_GET_CCS_MATRIX:
2087#ifndef CONFIG_FB_MSM_MDP40
2088                ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ;
2089                if (ret) {
2090                        printk(KERN_ERR
2091                                "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
2092                                 __func__);
2093                        return ret;
2094                }
2095
2096                down(&msm_fb_ioctl_ppp_sem);
2097                if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
2098                        ccs_matrix = mdp_ccs_rgb2yuv;
2099                 else
2100                        ccs_matrix =  mdp_ccs_yuv2rgb;
2101
2102                ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix));
2103
2104                if (ret)        {
2105                        printk(KERN_ERR
2106                                "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
2107                                 __func__);
2108                        return ret ;
2109                }
2110                up(&msm_fb_ioctl_ppp_sem);
2111#else
2112                ret = -EINVAL;
2113#endif
2114
2115                break;
2116
2117#ifdef CONFIG_MDP_PPP_ASYNC_OP
2118        case MSMFB_ASYNC_BLIT:
2119                down(&msm_fb_ioctl_ppp_sem);
2120                ret = msmfb_async_blit(info, argp);
2121                up(&msm_fb_ioctl_ppp_sem);
2122                break;
2123
2124        case MSMFB_BLIT_FLUSH:
2125                down(&msm_fb_ioctl_ppp_sem);
2126                mdp_ppp_wait();
2127                up(&msm_fb_ioctl_ppp_sem);
2128                break;
2129#endif
2130
2131        case MSMFB_GRP_DISP:
2132#ifdef CONFIG_FB_MSM_MDP22
2133                {
2134                        unsigned long grp_id;
2135
2136                        ret = copy_from_user(&grp_id, argp, sizeof(grp_id));
2137                        if (ret)
2138                                return ret;
2139
2140                        mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
2141                        writel(grp_id, MDP_FULL_BYPASS_WORD43);
2142                        mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
2143                                      FALSE);
2144                        break;
2145                }
2146#else
2147                return -EFAULT;
2148#endif
2149        case MSMFB_SUSPEND_SW_REFRESHER:
2150                if (!mfd->panel_power_on)
2151                        return -EPERM;
2152
2153                mfd->sw_refreshing_enable = FALSE;
2154                ret = msm_fb_stop_sw_refresher(mfd);
2155                break;
2156
2157        case MSMFB_RESUME_SW_REFRESHER:
2158                if (!mfd->panel_power_on)
2159                        return -EPERM;
2160
2161                mfd->sw_refreshing_enable = TRUE;
2162                ret = msm_fb_resume_sw_refresher(mfd);
2163                break;
2164
2165        case MSMFB_CURSOR:
2166                ret = copy_from_user(&cursor, argp, sizeof(cursor));
2167                if (ret)
2168                        return ret;
2169
2170                ret = msm_fb_cursor(info, &cursor);
2171                break;
2172
2173        case MSMFB_SET_LUT:
2174                ret = copy_from_user(&cmap, argp, sizeof(cmap));
2175                if (ret)
2176                        return ret;
2177
2178                mutex_lock(&msm_fb_ioctl_lut_sem);
2179                ret = msm_fb_set_lut(&cmap, info);
2180                mutex_unlock(&msm_fb_ioctl_lut_sem);
2181                break;
2182
2183        case MSMFB_HISTOGRAM:
2184                if (!mfd->do_histogram)
2185                        return -ENODEV;
2186
2187                ret = copy_from_user(&hist, argp, sizeof(hist));
2188                if (ret)
2189                        return ret;
2190
2191                mutex_lock(&msm_fb_ioctl_hist_sem);
2192                ret = mfd->do_histogram(info, &hist);
2193                mutex_unlock(&msm_fb_ioctl_hist_sem);
2194                break;
2195
2196        case MSMFB_GET_PAGE_PROTECTION:
2197                fb_page_protection.page_protection
2198                        = mfd->mdp_fb_page_protection;
2199                ret = copy_to_user(argp, &fb_page_protection,
2200                                sizeof(fb_page_protection));
2201                if (ret)
2202                                return ret;
2203                break;
2204
2205        case MSMFB_SET_PAGE_PROTECTION:
2206#ifdef CONFIG_ARCH_QSD8X50
2207                ret = copy_from_user(&fb_page_protection, argp,
2208                                sizeof(fb_page_protection));
2209                if (ret)
2210                                return ret;
2211
2212                /* Validate the proposed page protection settings. */
2213                switch (fb_page_protection.page_protection)     {
2214                case MDP_FB_PAGE_PROTECTION_NONCACHED:
2215                case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
2216                case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
2217                /* Write-back cache (read allocate)  */
2218                case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
2219                /* Write-back cache (write allocate) */
2220                case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
2221                        mfd->mdp_fb_page_protection =
2222                                fb_page_protection.page_protection;
2223                        break;
2224                default:
2225                        ret = -EINVAL;
2226                        break;
2227                }
2228#else
2229                /*
2230                 * Don't allow caching until 7k DMA cache operations are
2231                 * available.
2232                 */
2233                ret = -EINVAL;
2234#endif
2235                break;
2236
2237        default:
2238                MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd);
2239                ret = -EINVAL;
2240                break;
2241        }
2242
2243        return ret;
2244}
2245
2246static int msm_fb_register_driver(void)
2247{
2248        return platform_driver_register(&msm_fb_driver);
2249}
2250
2251void msm_fb_add_device(struct platform_device *pdev)
2252{
2253        struct msm_fb_panel_data *pdata;
2254        struct platform_device *this_dev = NULL;
2255        struct fb_info *fbi;
2256        struct msm_fb_data_type *mfd = NULL;
2257        u32 type, id, fb_num;
2258
2259        if (!pdev)
2260                return;
2261        id = pdev->id;
2262
2263        pdata = pdev->dev.platform_data;
2264        if (!pdata)
2265                return;
2266        type = pdata->panel_info.type;
2267        fb_num = pdata->panel_info.fb_num;
2268
2269        if (fb_num <= 0)
2270                return;
2271
2272        if (fbi_list_index >= MAX_FBI_LIST) {
2273                printk(KERN_ERR "msm_fb: no more framebuffer info list!\n");
2274                return;
2275        }
2276        /*
2277         * alloc panel device data
2278         */
2279        this_dev = msm_fb_device_alloc(pdata, type, id);
2280
2281        if (!this_dev) {
2282                printk(KERN_ERR
2283                "%s: msm_fb_device_alloc failed!\n", __func__);
2284                return;
2285        }
2286
2287        /*
2288         * alloc framebuffer info + par data
2289         */
2290        fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
2291        if (fbi == NULL) {
2292                platform_device_put(this_dev);
2293                printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n");
2294                return;
2295        }
2296
2297        mfd = (struct msm_fb_data_type *)fbi->par;
2298        mfd->key = MFD_KEY;
2299        mfd->fbi = fbi;
2300        mfd->panel.type = type;
2301        mfd->panel.id = id;
2302        mfd->fb_page = fb_num;
2303        mfd->index = fbi_list_index;
2304        mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
2305
2306        /* link to the latest pdev */
2307        mfd->pdev = this_dev;
2308
2309        mfd_list[mfd_list_index++] = mfd;
2310        fbi_list[fbi_list_index++] = fbi;
2311
2312        /*
2313         * set driver data
2314         */
2315        platform_set_drvdata(this_dev, mfd);
2316
2317        if (platform_device_add(this_dev)) {
2318                printk(KERN_ERR "msm_fb: platform_device_add failed!\n");
2319                platform_device_put(this_dev);
2320                framebuffer_release(fbi);
2321                fbi_list_index--;
2322                return;
2323        }
2324}
2325EXPORT_SYMBOL(msm_fb_add_device);
2326
2327int __init msm_fb_init(void)
2328{
2329        int rc = -ENODEV;
2330
2331        if (msm_fb_register_driver())
2332                return rc;
2333
2334#ifdef MSM_FB_ENABLE_DBGFS
2335        {
2336                struct dentry *root;
2337
2338                if ((root = msm_fb_get_debugfs_root()) != NULL) {
2339                        msm_fb_debugfs_file_create(root,
2340                                                   "msm_fb_msg_printing_level",
2341                                                   (u32 *) &msm_fb_msg_level);
2342                        msm_fb_debugfs_file_create(root,
2343                                                   "mddi_msg_printing_level",
2344                                                   (u32 *) &mddi_msg_level);
2345                        msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled",
2346                                                   (u32 *) &msm_fb_debug_enabled);
2347                }
2348        }
2349#endif
2350
2351        return 0;
2352}
2353
2354module_init(msm_fb_init);
2355