GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / msm / msm_fb.c
blobaf5620e4eee11d30987bd5ed58ac211af97287f7
1 /*
3 * Core MSM framebuffer driver.
5 * Copyright (C) 2007 Google Incorporated
6 * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
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.
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.
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>
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>
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"
51 #ifdef CONFIG_FB_MSM_LOGO
52 #define INIT_IMAGE_FILE "/logo.rle"
53 extern int load_565rle_image(char *filename);
54 #endif
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)
70 static unsigned char *fbram;
71 static unsigned char *fbram_phys;
72 static int fbram_size;
74 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
75 static int pdev_list_cnt;
77 int vsync_mode = 1;
79 #define MAX_FBI_LIST 32
80 static struct fb_info *fbi_list[MAX_FBI_LIST];
81 static int fbi_list_index;
83 static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST];
84 static int mfd_list_index;
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
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;
97 /* Setting mddi_msg_level to 8 prints out ALL messages */
98 u32 mddi_msg_level = 5;
100 extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
101 extern unsigned long mdp_timer_duration;
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);
121 #ifdef MSM_FB_ENABLE_DBGFS
123 #define MSM_FB_MAX_DBGFS 1024
124 #define MAX_BACKLIGHT_BRIGHTNESS 255
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];
130 struct dentry *msm_fb_get_debugfs_root(void)
132 if (msm_fb_debugfs_root == NULL)
133 msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL);
135 return msm_fb_debugfs_root;
138 void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
139 u32 *var)
141 if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS)
142 return;
144 msm_fb_debugfs_file[msm_fb_debugfs_file_index++] =
145 debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var);
147 #endif
149 int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
151 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
153 if (!mfd->cursor_update)
154 return -ENODEV;
156 return mfd->cursor_update(info, cursor);
159 static int msm_fb_resource_initialized;
161 #ifndef CONFIG_FB_BACKLIGHT
162 static int lcd_backlight_registered;
164 static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev,
165 enum led_brightness value)
167 struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
168 int bl_lvl;
170 if (value > MAX_BACKLIGHT_BRIGHTNESS)
171 value = MAX_BACKLIGHT_BRIGHTNESS;
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);
178 if (!bl_lvl && value)
179 bl_lvl = 1;
181 msm_fb_set_backlight(mfd, bl_lvl, 1);
184 static struct led_classdev backlight_led = {
185 .name = "lcd-backlight",
186 .brightness = MAX_BACKLIGHT_BRIGHTNESS,
187 .brightness_set = msm_fb_set_bl_brightness,
189 #endif
191 static struct msm_fb_platform_data *msm_fb_pdata;
193 int msm_fb_detect_client(const char *name)
195 int ret = -EPERM;
196 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
197 u32 id;
198 #endif
200 if (msm_fb_pdata && msm_fb_pdata->detect_client) {
201 ret = msm_fb_pdata->detect_client(name);
203 /* if it's non mddi panel, we need to pre-scan
204 mddi client to see if we can disable mddi host */
206 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
207 if (!ret && msm_fb_pdata->mddi_prescan)
208 id = mddi_get_client_id();
209 #endif
212 return ret;
215 static int msm_fb_probe(struct platform_device *pdev)
217 struct msm_fb_data_type *mfd;
218 int rc;
220 MSM_FB_DEBUG("msm_fb_probe\n");
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);
229 if (!fbram) {
230 printk(KERN_ERR "fbram ioremap failed!\n");
231 return -ENOMEM;
233 MSM_FB_INFO("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n",
234 (int)fbram_phys, (int)fbram);
236 msm_fb_resource_initialized = 1;
237 return 0;
240 if (!msm_fb_resource_initialized)
241 return -EPERM;
243 mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
245 if (!mfd)
246 return -ENODEV;
248 if (mfd->key != MFD_KEY)
249 return -EINVAL;
251 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
252 return -ENOMEM;
254 mfd->panel_info.frame_count = 0;
255 mfd->bl_level = mfd->panel_info.bl_max;
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;
264 rc = msm_fb_register(mfd);
265 if (rc)
266 return rc;
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;
278 #endif
280 pdev_list[pdev_list_cnt++] = pdev;
281 return 0;
284 static int msm_fb_remove(struct platform_device *pdev)
286 struct msm_fb_data_type *mfd;
288 MSM_FB_DEBUG("msm_fb_remove\n");
290 mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
292 if (!mfd)
293 return -ENODEV;
295 if (mfd->key != MFD_KEY)
296 return -EINVAL;
298 if (msm_fb_suspend_sub(mfd))
299 printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index);
301 if (mfd->channel_irq != 0)
302 free_irq(mfd->channel_irq, (void *)mfd);
304 if (mfd->vsync_width_boundary)
305 vfree(mfd->vsync_width_boundary);
307 if (mfd->vsync_resync_timer.function)
308 del_timer(&mfd->vsync_resync_timer);
310 if (mfd->refresh_timer.function)
311 del_timer(&mfd->refresh_timer);
313 if (mfd->dma_hrtimer.function)
314 hrtimer_cancel(&mfd->dma_hrtimer);
316 /* remove /dev/fb* */
317 unregister_framebuffer(mfd->fbi);
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);
327 #endif
329 #ifdef MSM_FB_ENABLE_DBGFS
330 if (mfd->sub_dir)
331 debugfs_remove(mfd->sub_dir);
332 #endif
334 return 0;
337 #if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
338 static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
340 struct msm_fb_data_type *mfd;
341 int ret = 0;
343 MSM_FB_DEBUG("msm_fb_suspend\n");
345 mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
347 if ((!mfd) || (mfd->key != MFD_KEY))
348 return 0;
350 acquire_console_sem();
351 fb_set_suspend(mfd->fbi, 1);
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;
361 release_console_sem();
362 return ret;
364 #else
365 #define msm_fb_suspend NULL
366 #endif
368 static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd)
370 int ret = 0;
372 if ((!mfd) || (mfd->key != MFD_KEY))
373 return 0;
376 * suspend this channel
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;
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;
391 mfd->op_enable = FALSE;
394 * try to power down
396 mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
399 * detach display channel irq if there's any
400 * or wait until vsync-resync completes
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);
416 return 0;
419 #if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
420 static int msm_fb_resume(struct platform_device *pdev)
422 /* This resume function is called when interrupt is enabled.
424 int ret = 0;
425 struct msm_fb_data_type *mfd;
427 MSM_FB_DEBUG("msm_fb_resume\n");
429 mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
431 if ((!mfd) || (mfd->key != MFD_KEY))
432 return 0;
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();
440 return ret;
442 #else
443 #define msm_fb_resume NULL
444 #endif
446 static int msm_fb_resume_sub(struct msm_fb_data_type *mfd)
448 int ret = 0;
450 if ((!mfd) || (mfd->key != MFD_KEY))
451 return 0;
453 /* attach display channel irq if there's any */
454 if (mfd->channel_irq != 0)
455 enable_irq(mfd->channel_irq);
457 /* resume state var recover */
458 mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable;
459 mfd->op_enable = mfd->suspend.op_enable;
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");
469 return ret;
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",
486 #ifdef CONFIG_HAS_EARLYSUSPEND
487 static void msmfb_early_suspend(struct early_suspend *h)
489 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
490 early_suspend);
491 msm_fb_suspend_sub(mfd);
494 static void msmfb_early_resume(struct early_suspend *h)
496 struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
497 early_suspend);
498 msm_fb_resume_sub(mfd);
500 #endif
502 void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save)
504 struct msm_fb_panel_data *pdata;
506 pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
508 if ((pdata) && (pdata->set_backlight)) {
509 down(&mfd->sem);
510 if ((bkl_lvl != mfd->bl_level) || (!save)) {
511 u32 old_lvl;
513 old_lvl = mfd->bl_level;
514 mfd->bl_level = bkl_lvl;
515 pdata->set_backlight(mfd);
517 if (!save)
518 mfd->bl_level = old_lvl;
520 up(&mfd->sem);
524 static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
525 boolean op_enable)
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;
531 if (!op_enable)
532 return -EPERM;
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;
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;
548 msm_fb_set_backlight(mfd,
549 mfd->bl_level, 0);
551 /* ToDo: possible conflict with android which doesn't expect sw refresher */
553 if (!mfd->hw_refresh)
555 if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0)
557 MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret);
563 break;
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;
573 mfd->op_enable = FALSE;
574 curr_pwr_state = mfd->panel_power_on;
575 mfd->panel_power_on = FALSE;
577 mdelay(100);
578 ret = pdata->off(mfd->pdev);
579 if (ret)
580 mfd->panel_power_on = curr_pwr_state;
582 msm_fb_set_backlight(mfd, 0, 0);
583 mfd->op_enable = TRUE;
585 break;
588 return ret;
591 static void msm_fb_fillrect(struct fb_info *info,
592 const struct fb_fillrect *rect)
594 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
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;
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);
607 msm_fb_pan_display(&var, info);
611 static void msm_fb_copyarea(struct fb_info *info,
612 const struct fb_copyarea *area)
614 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
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;
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);
627 msm_fb_pan_display(&var, info);
631 static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image)
633 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
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;
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);
646 msm_fb_pan_display(&var, info);
650 static int msm_fb_blank(int blank_mode, struct fb_info *info)
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);
656 static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info)
658 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
660 if (!mfd->lut_update)
661 return -ENODEV;
663 mfd->lut_update(info, cmap);
664 return 0;
668 * Custom Framebuffer mmap() function for MSM driver.
669 * Differs from standard mmap() function by allowing for customized
670 * page-protection.
672 static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
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;
686 start = info->fix.mmio_start;
687 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
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;
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);
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;
720 return 0;
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,
744 static int msm_fb_register(struct msm_fb_data_type *mfd)
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;
756 * fb info initialization
758 fix = &fbi->fix;
759 var = &fbi->var;
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 */
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;
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;
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;
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;
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;
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;
861 default:
862 MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n",
863 mfd->index);
864 return ret;
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 */
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;
877 fix->smem_len = fix->line_length * panel_info->yres * mfd->fb_page;
879 mfd->var_xres = panel_info->xres;
880 mfd->var_yres = panel_info->yres;
882 var->pixclock = mfd->panel_info.clk_rate;
883 mfd->var_pixclock = var->pixclock;
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 */
891 * id field for fb app
893 id = (int *)&mfd->panel;
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;
910 mfd->ref_cnt = 0;
911 mfd->sw_currently_refreshing = FALSE;
912 mfd->sw_refreshing_enable = TRUE;
913 mfd->panel_power_on = FALSE;
915 mfd->pan_waiting = FALSE;
916 init_completion(&mfd->pan_comp);
917 init_completion(&mfd->refresher_comp);
918 init_MUTEX(&mfd->sem);
920 fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
921 fbram += fbram_offset;
922 fbram_phys += fbram_offset;
923 fbram_size -= fbram_offset;
925 if (fbram_size < fix->smem_len) {
926 printk(KERN_ERR "error: no more framebuffer memory!\n");
927 return -ENOMEM;
930 fbi->screen_base = fbram;
931 fbi->fix.smem_start = (unsigned long)fbram_phys;
933 memset(fbi->screen_base, 0x0, fix->smem_len);
935 mfd->op_enable = TRUE;
936 mfd->panel_power_on = FALSE;
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;
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__);
955 if (register_framebuffer(fbi) < 0) {
956 if (mfd->lut_update)
957 fb_dealloc_cmap(&fbi->cmap);
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);
965 mfd->op_enable = FALSE;
966 return -EPERM;
969 fbram += fix->smem_len;
970 fbram_phys += fix->smem_len;
971 fbram_size -= fix->smem_len;
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);
977 #ifdef CONFIG_FB_MSM_LOGO
978 if (!load_565rle_image(INIT_IMAGE_FILE)) ; /* Flip buffer */
979 #endif
980 ret = 0;
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
989 #ifdef MSM_FB_ENABLE_DBGFS
991 struct dentry *root;
992 struct dentry *sub_dir;
993 char sub_name[2];
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;
1004 mfd->sub_dir = sub_dir;
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);
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);
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;
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;
1109 default:
1110 break;
1114 #endif /* MSM_FB_ENABLE_DBGFS */
1116 return ret;
1119 static int msm_fb_open(struct fb_info *info, int user)
1121 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1123 if (!mfd->ref_cnt) {
1124 mdp_set_dma_pan_info(info, NULL, TRUE);
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;
1132 mfd->ref_cnt++;
1133 return 0;
1136 static int msm_fb_release(struct fb_info *info, int user)
1138 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1139 int ret = 0;
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;
1147 mfd->ref_cnt--;
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;
1158 return ret;
1161 DECLARE_MUTEX(msm_fb_pan_sem);
1163 static int msm_fb_pan_display(struct fb_var_screeninfo *var,
1164 struct fb_info *info)
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;
1170 if ((!mfd->op_enable) || (!mfd->panel_power_on))
1171 return -EPERM;
1173 if (var->xoffset > (info->var.xres_virtual - info->var.xres))
1174 return -EINVAL;
1176 if (var->yoffset > (info->var.yres_virtual - info->var.yres))
1177 return -EINVAL;
1179 if (info->fix.xpanstep)
1180 info->var.xoffset =
1181 (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
1183 if (info->fix.ypanstep)
1184 info->var.yoffset =
1185 (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
1187 /* "UPDT" */
1188 if (var->reserved[0] == 0x54445055) {
1189 dirty.xoffset = var->reserved[1] & 0xffff;
1190 dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
1192 if ((var->reserved[2] & 0xffff) <= dirty.xoffset)
1193 return -EINVAL;
1194 if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset)
1195 return -EINVAL;
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;
1202 if (dirty.xoffset < 0)
1203 return -EINVAL;
1205 if (dirty.yoffset < 0)
1206 return -EINVAL;
1208 if ((dirty.xoffset + dirty.width) > info->var.xres)
1209 return -EINVAL;
1211 if ((dirty.yoffset + dirty.height) > info->var.yres)
1212 return -EINVAL;
1214 if ((dirty.width <= 0) || (dirty.height <= 0))
1215 return -EINVAL;
1217 dirtyPtr = &dirty;
1220 /* Flip */
1221 /* A constant value is used to indicate that we should change the DMA
1222 output buffer instead of just panning */
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;
1230 if (mfd->allow_set_offset) {
1231 imgdata.memory_id = var->reserved[1];
1232 imgdata.priv = var->reserved[2];
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;
1244 } else {
1245 /*get_img(&imgdata, info, &address,
1246 &length, &p_src_file);*/
1247 panic("waaaaaah");
1249 mfd->ibuf.visible_swapped = TRUE;
1250 } else {
1251 /* Flip back to the original address
1252 adjusted for xoffset and yoffset */
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;
1259 mfd->ibuf.visible_swapped = FALSE;
1262 mdp_set_offset_info(info, address,
1263 (var->activate == FB_ACTIVATE_VBL));
1265 mfd->dma_fnc(mfd);
1266 return 0;
1267 } else
1268 return -EINVAL;
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);
1277 ++mfd->panel_info.frame_count;
1278 return 0;
1281 static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1283 struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
1285 if (var->rotate != FB_ROTATE_UR)
1286 return -EINVAL;
1287 if (var->grayscale != info->var.grayscale)
1288 return -EINVAL;
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;
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;
1325 default:
1326 return -EINVAL;
1329 if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
1330 return -EINVAL;
1332 if (info->fix.smem_len <
1333 (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
1334 return -EINVAL;
1336 if ((var->xres == 0) || (var->yres == 0))
1337 return -EINVAL;
1339 if ((var->xres > mfd->panel_info.xres) ||
1340 (var->yres > mfd->panel_info.yres))
1341 return -EINVAL;
1343 if (var->xoffset > (var->xres_virtual - var->xres))
1344 return -EINVAL;
1346 if (var->yoffset > (var->yres_virtual - var->yres))
1347 return -EINVAL;
1349 return 0;
1352 static int msm_fb_set_par(struct fb_info *info)
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;
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;
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;
1376 break;
1378 default:
1379 return -EINVAL;
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;
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);
1398 return 0;
1401 static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd)
1403 if (mfd->hw_refresh)
1404 return -EPERM;
1406 if (mfd->sw_currently_refreshing) {
1407 down(&mfd->sem);
1408 mfd->sw_currently_refreshing = FALSE;
1409 up(&mfd->sem);
1411 /* wait until the refresher finishes the last job */
1412 wait_for_completion_killable(&mfd->refresher_comp);
1415 return 0;
1418 int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd)
1420 boolean do_refresh;
1422 if (mfd->hw_refresh)
1423 return -EPERM;
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;
1432 up(&mfd->sem);
1434 if (do_refresh)
1435 mdp_refresh_screen((unsigned long)mfd);
1437 return 0;
1440 void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file)
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
1450 int mdp_blit(struct fb_info *info, struct mdp_blit_req *req)
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;
1458 if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
1459 return 0;
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;
1466 typedef void (*msm_dma_barrier_function_pointer) (void *, size_t);
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
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.
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);
1488 panic("waaaaah");
1491 static inline void msm_dma_nc_pre(void)
1493 dmb();
1495 static inline void msm_dma_wt_pre(void)
1497 dmb();
1499 static inline void msm_dma_todevice_wb_pre(void *start, size_t size)
1501 #warning this
1502 // dma_cache_pre_ops(start, size, DMA_TO_DEVICE);
1505 static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size)
1507 #warning this
1508 // dma_cache_pre_ops(start, size, DMA_FROM_DEVICE);
1511 static inline void msm_dma_nc_post(void)
1513 dmb();
1516 static inline void msm_dma_fromdevice_wt_post(void *start, size_t size)
1518 #warning this
1519 // dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
1522 static inline void msm_dma_todevice_wb_post(void *start, size_t size)
1524 #warning this
1525 // dma_cache_post_ops(start, size, DMA_TO_DEVICE);
1528 static inline void msm_dma_fromdevice_wb_post(void *start, size_t size)
1530 #warning this
1531 // dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
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.
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)
1546 #ifdef CONFIG_ARCH_QSD8X50
1547 int i;
1550 * Normally, do the requested barriers for each address
1551 * range that corresponds to a rectangle.
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.
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:
1564 * The following barrier is only done at most once,
1565 * since further calls would be redundant.
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;
1574 break;
1576 case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
1578 * The following barrier is only done at most once,
1579 * since further calls would be redundant.
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;
1588 break;
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)) {
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
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
1609 break;
1611 #else
1612 dmb();
1613 #endif
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.
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)
1629 #ifdef CONFIG_ARCH_QSD8X50
1630 int i;
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:
1638 * The following barrier is only done at most once,
1639 * since further calls would be redundant.
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;
1648 break;
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)) {
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
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)) {
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
1676 break;
1678 #else
1679 dmb();
1680 #endif
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)
1687 BUG_ON(!info);
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.
1694 msm_fb_ensure_memory_coherency_after_dma(info,
1695 req_list, req_list_count);
1698 static int msmfb_async_blit(struct fb_info *info, void __user *p)
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.
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;
1710 int count, i, req_list_count;
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) {
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.
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;
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.
1738 msm_fb_ensure_memory_coherency_before_dma(info,
1739 req_list, req_list_count);
1742 * Do the blit DMA, if required -- returning early only if
1743 * there is a failure.
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;
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;
1757 if (unlikely(req_list[i].dst_rect.h == 0 ||
1758 req_list[i].dst_rect.w == 0))
1759 continue;
1761 /* create a new display job */
1762 job = mdp_ppp_new_djob();
1763 if (unlikely(!job))
1764 return -ENOMEM;
1766 job->info = info;
1767 memcpy(&job->req, &req_list[i],
1768 sizeof(struct mdp_blit_req));
1770 /* Do the actual blit. */
1771 ret = mdp_ppp_blit(info, &job->req,
1772 &job->p_src_file, &job->p_dst_file);
1775 * Note that early returns don't guarantee
1776 * memory coherency.
1778 if (ret || mdp_ppp_get_ret_code()) {
1779 mdp_ppp_clear_curr_djob();
1780 return ret;
1785 /* Go to next window of requests. */
1786 count -= req_list_count;
1787 p += sizeof(struct mdp_blit_req)*req_list_count;
1789 return 0;
1791 #else
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.
1802 static int msmfb_blit(struct fb_info *info, void __user *p)
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.
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;
1814 int count, i, req_list_count;
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) {
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.
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;
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.
1842 msm_fb_ensure_memory_coherency_before_dma(info,
1843 req_list, req_list_count);
1846 * Do the blit DMA, if required -- returning early only if
1847 * there is a failure.
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]));
1855 * Note that early returns don't guarantee
1856 * memory coherency.
1858 if (ret)
1859 return ret;
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.
1868 msm_fb_ensure_memory_coherency_after_dma(info,
1869 req_list,
1870 req_list_count);
1872 /* Go to next window of requests. */
1873 count -= req_list_count;
1874 p += sizeof(struct mdp_blit_req)*req_list_count;
1876 return 0;
1878 #endif
1880 #ifdef CONFIG_FB_MSM_OVERLAY
1881 static int msmfb_overlay_get(struct fb_info *info, void __user *p)
1883 struct mdp_overlay req;
1884 int ret;
1886 if (copy_from_user(&req, p, sizeof(req)))
1887 return -EFAULT;
1889 ret = mdp4_overlay_get(info, &req);
1890 if (ret) {
1891 printk(KERN_ERR "%s: ioctl failed \n",
1892 __func__);
1893 return ret;
1895 if (copy_to_user(p, &req, sizeof(req))) {
1896 printk(KERN_ERR "%s: copy2user failed \n",
1897 __func__);
1898 return -EFAULT;
1901 return 0;
1904 static int msmfb_overlay_set(struct fb_info *info, void __user *p)
1906 struct mdp_overlay req;
1907 int ret;
1909 if (copy_from_user(&req, p, sizeof(req)))
1910 return -EFAULT;
1912 ret = mdp4_overlay_set(info, &req);
1913 if (ret) {
1914 printk(KERN_ERR "%s:ioctl failed \n",
1915 __func__);
1916 return ret;
1919 if (copy_to_user(p, &req, sizeof(req))) {
1920 printk(KERN_ERR "%s: copy2user failed \n",
1921 __func__);
1922 return -EFAULT;
1925 return 0;
1928 static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp)
1930 int ret, ndx;
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;
1939 return mdp4_overlay_unset(info, ndx);
1942 static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
1944 int ret;
1945 struct msmfb_overlay_data req;
1946 struct file *p_src_file = 0;
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;
1955 ret = mdp4_overlay_play(info, &req, &p_src_file);
1957 if (p_src_file)
1958 put_pmem_file(p_src_file);
1960 return ret;
1963 #endif
1965 DECLARE_MUTEX(msm_fb_ioctl_ppp_sem);
1966 DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
1967 DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
1969 /* Set color conversion matrix from user space */
1971 #ifndef CONFIG_FB_MSM_MDP40
1972 static void msmfb_set_color_conv(struct mdp_ccs *p)
1974 int i;
1976 if (p->direction == MDP_CCS_RGB2YUV) {
1977 /* MDP cmd block enable */
1978 mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
1980 /* RGB->YUV primary forward matrix */
1981 for (i = 0; i < MDP_CCS_SIZE; i++)
1982 writel(p->ccs[i], MDP_CSC_PFMVn(i));
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
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);
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));
2001 /* MDP cmd block disable */
2002 mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
2005 #endif
2008 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
2009 unsigned long arg)
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;
2022 if (!mfd->op_enable)
2023 return -EPERM;
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);
2058 break;
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;
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;
2077 msmfb_set_color_conv(&ccs_matrix) ;
2078 up(&msm_fb_ioctl_ppp_sem);
2079 #else
2080 ret = -EINVAL;
2081 #endif
2083 break;
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;
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;
2102 ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix));
2104 if (ret) {
2105 printk(KERN_ERR
2106 "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
2107 __func__);
2108 return ret ;
2110 up(&msm_fb_ioctl_ppp_sem);
2111 #else
2112 ret = -EINVAL;
2113 #endif
2115 break;
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;
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
2131 case MSMFB_GRP_DISP:
2132 #ifdef CONFIG_FB_MSM_MDP22
2134 unsigned long grp_id;
2136 ret = copy_from_user(&grp_id, argp, sizeof(grp_id));
2137 if (ret)
2138 return ret;
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;
2146 #else
2147 return -EFAULT;
2148 #endif
2149 case MSMFB_SUSPEND_SW_REFRESHER:
2150 if (!mfd->panel_power_on)
2151 return -EPERM;
2153 mfd->sw_refreshing_enable = FALSE;
2154 ret = msm_fb_stop_sw_refresher(mfd);
2155 break;
2157 case MSMFB_RESUME_SW_REFRESHER:
2158 if (!mfd->panel_power_on)
2159 return -EPERM;
2161 mfd->sw_refreshing_enable = TRUE;
2162 ret = msm_fb_resume_sw_refresher(mfd);
2163 break;
2165 case MSMFB_CURSOR:
2166 ret = copy_from_user(&cursor, argp, sizeof(cursor));
2167 if (ret)
2168 return ret;
2170 ret = msm_fb_cursor(info, &cursor);
2171 break;
2173 case MSMFB_SET_LUT:
2174 ret = copy_from_user(&cmap, argp, sizeof(cmap));
2175 if (ret)
2176 return ret;
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;
2183 case MSMFB_HISTOGRAM:
2184 if (!mfd->do_histogram)
2185 return -ENODEV;
2187 ret = copy_from_user(&hist, argp, sizeof(hist));
2188 if (ret)
2189 return ret;
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;
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;
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;
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;
2228 #else
2230 * Don't allow caching until 7k DMA cache operations are
2231 * available.
2233 ret = -EINVAL;
2234 #endif
2235 break;
2237 default:
2238 MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd);
2239 ret = -EINVAL;
2240 break;
2243 return ret;
2246 static int msm_fb_register_driver(void)
2248 return platform_driver_register(&msm_fb_driver);
2251 void msm_fb_add_device(struct platform_device *pdev)
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;
2259 if (!pdev)
2260 return;
2261 id = pdev->id;
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;
2269 if (fb_num <= 0)
2270 return;
2272 if (fbi_list_index >= MAX_FBI_LIST) {
2273 printk(KERN_ERR "msm_fb: no more framebuffer info list!\n");
2274 return;
2277 * alloc panel device data
2279 this_dev = msm_fb_device_alloc(pdata, type, id);
2281 if (!this_dev) {
2282 printk(KERN_ERR
2283 "%s: msm_fb_device_alloc failed!\n", __func__);
2284 return;
2288 * alloc framebuffer info + par data
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;
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;
2306 /* link to the latest pdev */
2307 mfd->pdev = this_dev;
2309 mfd_list[mfd_list_index++] = mfd;
2310 fbi_list[fbi_list_index++] = fbi;
2313 * set driver data
2315 platform_set_drvdata(this_dev, mfd);
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;
2325 EXPORT_SYMBOL(msm_fb_add_device);
2327 int __init msm_fb_init(void)
2329 int rc = -ENODEV;
2331 if (msm_fb_register_driver())
2332 return rc;
2334 #ifdef MSM_FB_ENABLE_DBGFS
2336 struct dentry *root;
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);
2349 #endif
2351 return 0;
2354 module_init(msm_fb_init);