Merge branches 'irq-core-for-linus' and 'core-locking-for-linus' of git://git.kernel...
[pandora-kernel.git] / drivers / staging / msm / msm_fb.c
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"
53 extern 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
70 static unsigned char *fbram;
71 static unsigned char *fbram_phys;
72 static int fbram_size;
73
74 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
75 static int pdev_list_cnt;
76
77 int vsync_mode = 1;
78
79 #define MAX_FBI_LIST 32
80 static struct fb_info *fbi_list[MAX_FBI_LIST];
81 static int fbi_list_index;
82
83 static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST];
84 static int mfd_list_index;
85
86 static 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
93 u32 msm_fb_debug_enabled;
94 /* Setting msm_fb_msg_level to 8 prints out ALL messages */
95 u32 msm_fb_msg_level = 7;
96
97 /* Setting mddi_msg_level to 8 prints out ALL messages */
98 u32 mddi_msg_level = 5;
99
100 extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
101 extern unsigned long mdp_timer_duration;
102
103 static int msm_fb_register(struct msm_fb_data_type *mfd);
104 static int msm_fb_open(struct fb_info *info, int user);
105 static int msm_fb_release(struct fb_info *info, int user);
106 static int msm_fb_pan_display(struct fb_var_screeninfo *var,
107                               struct fb_info *info);
108 static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd);
109 int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd);
110 static int msm_fb_check_var(struct fb_var_screeninfo *var,
111                             struct fb_info *info);
112 static int msm_fb_set_par(struct fb_info *info);
113 static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
114                             boolean op_enable);
115 static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd);
116 static int msm_fb_resume_sub(struct msm_fb_data_type *mfd);
117 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
118                         unsigned long arg);
119 static 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
126 int msm_fb_debugfs_file_index;
127 struct dentry *msm_fb_debugfs_root;
128 struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
129
130 struct 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
138 void 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
149 int 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
159 static int msm_fb_resource_initialized;
160
161 #ifndef CONFIG_FB_BACKLIGHT
162 static int lcd_backlight_registered;
163
164 static 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
184 static 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
191 static struct msm_fb_platform_data *msm_fb_pdata;
192
193 int 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
215 static 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
284 static 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)
338 static 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         acquire_console_sem();
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         release_console_sem();
362         return ret;
363 }
364 #else
365 #define msm_fb_suspend NULL
366 #endif
367
368 static 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)
420 static 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         acquire_console_sem();
435         ret = msm_fb_resume_sub(mfd);
436         pdev->dev.power.power_state = PMSG_ON;
437         fb_set_suspend(mfd->fbi, 1);
438         release_console_sem();
439
440         return ret;
441 }
442 #else
443 #define msm_fb_resume NULL
444 #endif
445
446 static 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
472 static 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
487 static 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
494 static 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
502 void 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
524 static 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
591 static 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
611 static 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
631 static 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
650 static 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
656 static 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  */
672 static 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
723 static 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
744 static 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
1119 static 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
1136 static 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
1161 DEFINE_SEMAPHORE(msm_fb_pan_sem);
1162
1163 static 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
1281 static 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
1352 static 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
1401 static 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
1418 int 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
1440 void 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
1450 int 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
1466 typedef void (*msm_dma_barrier_function_pointer) (void *, size_t);
1467
1468 static 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
1491 static inline void msm_dma_nc_pre(void)
1492 {
1493         dmb();
1494 }
1495 static inline void msm_dma_wt_pre(void)
1496 {
1497         dmb();
1498 }
1499 static 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
1505 static 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
1511 static inline void msm_dma_nc_post(void)
1512 {
1513         dmb();
1514 }
1515
1516 static 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
1522 static 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
1528 static 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 */
1542 static 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 */
1625 static 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
1684 void 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
1698 static 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  */
1802 static 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
1881 static 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
1904 static 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
1928 static 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
1942 static 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
1965 DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
1966 DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
1967 DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
1968
1969 /* Set color conversion matrix from user space */
1970
1971 #ifndef CONFIG_FB_MSM_MDP40
1972 static 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
2008 static 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
2246 static int msm_fb_register_driver(void)
2247 {
2248         return platform_driver_register(&msm_fb_driver);
2249 }
2250
2251 void 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 }
2325 EXPORT_SYMBOL(msm_fb_add_device);
2326
2327 int __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
2354 module_init(msm_fb_init);