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>
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>
46 #include "mddihosti.h"
51 #ifdef CONFIG_FB_MSM_LOGO
52 #define INIT_IMAGE_FILE "/logo.rle"
53 extern int load_565rle_image(char *filename
);
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
;
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
,
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
,
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
,
141 if (msm_fb_debugfs_file_index
>= MSM_FB_MAX_DBGFS
)
144 msm_fb_debugfs_file
[msm_fb_debugfs_file_index
++] =
145 debugfs_create_u32(name
, S_IRUGO
| S_IWUSR
, root
, var
);
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
)
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
);
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
)
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
,
191 static struct msm_fb_platform_data
*msm_fb_pdata
;
193 int msm_fb_detect_client(const char *name
)
196 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
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();
215 static int msm_fb_probe(struct platform_device
*pdev
)
217 struct msm_fb_data_type
*mfd
;
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
;
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
);
230 printk(KERN_ERR
"fbram ioremap failed!\n");
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;
240 if (!msm_fb_resource_initialized
)
243 mfd
= (struct msm_fb_data_type
*)platform_get_drvdata(pdev
);
248 if (mfd
->key
!= MFD_KEY
)
251 if (pdev_list_cnt
>= MSM_FB_MAX_DEV_LIST
)
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;
262 mfd
->allow_set_offset
= 0;
264 rc
= msm_fb_register(mfd
);
268 #ifdef CONFIG_FB_BACKLIGHT
269 msm_fb_config_backlight(mfd
);
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");
276 lcd_backlight_registered
= 1;
280 pdev_list
[pdev_list_cnt
++] = pdev
;
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
);
295 if (mfd
->key
!= MFD_KEY
)
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
);
323 if (lcd_backlight_registered
) {
324 lcd_backlight_registered
= 0;
325 led_classdev_unregister(&backlight_led
);
329 #ifdef MSM_FB_ENABLE_DBGFS
331 debugfs_remove(mfd
->sub_dir
);
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
;
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
))
351 fb_set_suspend(mfd
->fbi
, 1);
353 ret
= msm_fb_suspend_sub(mfd
);
355 printk(KERN_ERR
"msm_fb: failed to suspend! %d\n", ret
);
356 fb_set_suspend(mfd
->fbi
, 0);
358 pdev
->dev
.power
.power_state
= state
;
365 #define msm_fb_suspend NULL
368 static int msm_fb_suspend_sub(struct msm_fb_data_type
*mfd
)
372 if ((!mfd
) || (mfd
->key
!= MFD_KEY
))
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
) {
384 msm_fb_blank_sub(FB_BLANK_POWERDOWN
, mfd
->fbi
,
385 mfd
->suspend
.op_enable
);
388 ("msm_fb_suspend: can't turn off display!\n");
391 mfd
->op_enable
= FALSE
;
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
);
408 volatile boolean vh_pending
;
410 vh_pending
= mfd
->vsync_handler_pending
;
411 } while (vh_pending
);
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.
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
))
435 ret
= msm_fb_resume_sub(mfd
);
436 pdev
->dev
.power
.power_state
= PMSG_ON
;
437 fb_set_suspend(mfd
->fbi
, 1);
443 #define msm_fb_resume NULL
446 static int msm_fb_resume_sub(struct msm_fb_data_type
*mfd
)
450 if ((!mfd
) || (mfd
->key
!= MFD_KEY
))
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
) {
463 msm_fb_blank_sub(FB_BLANK_UNBLANK
, mfd
->fbi
,
466 MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
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
,
481 /* Driver name must match the device name added in platform.c. */
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
,
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
,
498 msm_fb_resume_sub(mfd
);
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
)) {
510 if ((bkl_lvl
!= mfd
->bl_level
) || (!save
)) {
513 old_lvl
= mfd
->bl_level
;
514 mfd
->bl_level
= bkl_lvl
;
515 pdata
->set_backlight(mfd
);
518 mfd
->bl_level
= old_lvl
;
524 static int msm_fb_blank_sub(int blank_mode
, struct fb_info
*info
,
527 struct msm_fb_data_type
*mfd
= (struct msm_fb_data_type
*)info
->par
;
528 struct msm_fb_panel_data
*pdata
= NULL
;
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");
540 switch (blank_mode
) {
541 case FB_BLANK_UNBLANK
:
542 if (!mfd
->panel_power_on
) {
544 ret
= pdata
->on(mfd
->pdev
);
546 mfd
->panel_power_on
= TRUE
;
548 msm_fb_set_backlight(mfd
,
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);
565 case FB_BLANK_VSYNC_SUSPEND
:
566 case FB_BLANK_HSYNC_SUSPEND
:
567 case FB_BLANK_NORMAL
:
568 case FB_BLANK_POWERDOWN
:
570 if (mfd
->panel_power_on
) {
573 mfd
->op_enable
= FALSE
;
574 curr_pwr_state
= mfd
->panel_power_on
;
575 mfd
->panel_power_on
= FALSE
;
578 ret
= pdata
->off(mfd
->pdev
);
580 mfd
->panel_power_on
= curr_pwr_state
;
582 msm_fb_set_backlight(mfd
, 0, 0);
583 mfd
->op_enable
= TRUE
;
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
;
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
;
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
;
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
)
663 mfd
->lut_update(info
, cmap
);
668 * Custom Framebuffer mmap() function for MSM driver.
669 * Differs from standard mmap() function by allowing for customized
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
;
680 /* memory mapped io */
682 if (info
->var
.accel_flags
) {
683 mutex_unlock(&info
->lock
);
686 start
= info
->fix
.mmio_start
;
687 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + info
->fix
.mmio_len
);
692 if ((vma
->vm_end
- vma
->vm_start
+ off
) > len
)
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
);
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
,
723 static struct fb_ops msm_fb_ops
= {
724 .owner
= THIS_MODULE
,
725 .fb_open
= msm_fb_open
,
726 .fb_release
= msm_fb_release
,
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 */
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
)
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
;
756 * fb info initialization
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
) {
782 fix
->type
= FB_TYPE_PACKED_PIXELS
;
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;
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;
801 fix
->type
= FB_TYPE_PACKED_PIXELS
;
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;
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;
820 fix
->type
= FB_TYPE_PACKED_PIXELS
;
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;
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;
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
;
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;
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;
862 MSM_FB_ERR("msm_fb_init: fb %d unknown image type!\n",
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 */
873 fix
->line_length
= ALIGN(panel_info
->xres
* bpp
, 32);
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
);
904 error CONFIG_FB_MSM_MDP undefined
!
906 fbi
->fbops
= &msm_fb_ops
;
907 fbi
->flags
= FBINFO_FLAG_DEFAULT
;
908 fbi
->pseudo_palette
= msm_fb_pseudo_palette
;
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 sema_init(&mfd
->sem
, 1);
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");
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
,
942 (dma_addr_t
*) &mfd
->cursor_buf_phys
,
944 if (!mfd
->cursor_buf
)
945 mfd
->cursor_update
= 0;
948 if (mfd
->lut_update
) {
949 ret
= fb_alloc_cmap(&fbi
->cmap
, 256, 0);
951 printk(KERN_ERR
"%s: fb_alloc_cmap() failed!\n",
955 if (register_framebuffer(fbi
) < 0) {
957 fb_dealloc_cmap(&fbi
->cmap
);
960 dma_free_coherent(NULL
,
963 (dma_addr_t
) mfd
->cursor_buf_phys
);
965 mfd
->op_enable
= FALSE
;
969 fbram
+= fix
->smem_len
;
970 fbram_phys
+= fix
->smem_len
;
971 fbram_size
-= fix
->smem_len
;
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 */
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
);
989 #ifdef MSM_FB_ENABLE_DBGFS
992 struct dentry
*sub_dir
;
995 root
= msm_fb_get_debugfs_root();
997 sub_name
[0] = (char)(mfd
->index
+ 0x30);
999 sub_dir
= debugfs_create_dir(sub_name
, root
);
1004 mfd
->sub_dir
= 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",
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",
1019 sw_currently_refreshing
);
1020 msm_fb_debugfs_file_create(sub_dir
,
1021 "sw_refreshing_enable",
1023 sw_refreshing_enable
);
1025 msm_fb_debugfs_file_create(sub_dir
, "xres",
1026 (u32
*) &mfd
->panel_info
.
1028 msm_fb_debugfs_file_create(sub_dir
, "yres",
1029 (u32
*) &mfd
->panel_info
.
1031 msm_fb_debugfs_file_create(sub_dir
, "bpp",
1032 (u32
*) &mfd
->panel_info
.
1034 msm_fb_debugfs_file_create(sub_dir
, "type",
1035 (u32
*) &mfd
->panel_info
.
1037 msm_fb_debugfs_file_create(sub_dir
, "wait_cycle",
1038 (u32
*) &mfd
->panel_info
.
1040 msm_fb_debugfs_file_create(sub_dir
, "pdest",
1041 (u32
*) &mfd
->panel_info
.
1043 msm_fb_debugfs_file_create(sub_dir
, "backbuff",
1044 (u32
*) &mfd
->panel_info
.
1046 msm_fb_debugfs_file_create(sub_dir
, "clk_rate",
1047 (u32
*) &mfd
->panel_info
.
1049 msm_fb_debugfs_file_create(sub_dir
, "frame_count",
1050 (u32
*) &mfd
->panel_info
.
1054 switch (mfd
->dest
) {
1056 msm_fb_debugfs_file_create(sub_dir
,
1058 (u32
*)&mfd
->panel_info
.lcd
.vsync_enable
);
1059 msm_fb_debugfs_file_create(sub_dir
,
1061 (u32
*) &mfd
->panel_info
.lcd
. refx100
);
1062 msm_fb_debugfs_file_create(sub_dir
,
1064 (u32
*) &mfd
->panel_info
.lcd
.v_back_porch
);
1065 msm_fb_debugfs_file_create(sub_dir
,
1067 (u32
*) &mfd
->panel_info
.lcd
.v_front_porch
);
1068 msm_fb_debugfs_file_create(sub_dir
,
1070 (u32
*) &mfd
->panel_info
.lcd
.v_pulse_width
);
1071 msm_fb_debugfs_file_create(sub_dir
,
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
);
1080 msm_fb_debugfs_file_create(sub_dir
,
1082 (u32
*) &mfd
->panel_info
.lcdc
.h_back_porch
);
1083 msm_fb_debugfs_file_create(sub_dir
,
1085 (u32
*) &mfd
->panel_info
.lcdc
.h_front_porch
);
1086 msm_fb_debugfs_file_create(sub_dir
,
1088 (u32
*) &mfd
->panel_info
.lcdc
.h_pulse_width
);
1089 msm_fb_debugfs_file_create(sub_dir
,
1091 (u32
*) &mfd
->panel_info
.lcdc
.v_back_porch
);
1092 msm_fb_debugfs_file_create(sub_dir
,
1094 (u32
*) &mfd
->panel_info
.lcdc
.v_front_porch
);
1095 msm_fb_debugfs_file_create(sub_dir
,
1097 (u32
*) &mfd
->panel_info
.lcdc
.v_pulse_width
);
1098 msm_fb_debugfs_file_create(sub_dir
,
1100 (u32
*) &mfd
->panel_info
.lcdc
.border_clr
);
1101 msm_fb_debugfs_file_create(sub_dir
,
1103 (u32
*) &mfd
->panel_info
.lcdc
.underflow_clr
);
1104 msm_fb_debugfs_file_create(sub_dir
,
1106 (u32
*) &mfd
->panel_info
.lcdc
.hsync_skew
);
1114 #endif /* MSM_FB_ENABLE_DBGFS */
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");
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
;
1141 if (!mfd
->ref_cnt
) {
1142 MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n",
1149 if (!mfd
->ref_cnt
) {
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");
1161 DEFINE_SEMAPHORE(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
))
1173 if (var
->xoffset
> (info
->var
.xres_virtual
- info
->var
.xres
))
1176 if (var
->yoffset
> (info
->var
.yres_virtual
- info
->var
.yres
))
1179 if (info
->fix
.xpanstep
)
1181 (var
->xoffset
/ info
->fix
.xpanstep
) * info
->fix
.xpanstep
;
1183 if (info
->fix
.ypanstep
)
1185 (var
->yoffset
/ info
->fix
.ypanstep
) * info
->fix
.ypanstep
;
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
)
1194 if (((var
->reserved
[2] >> 16) & 0xffff) <= dirty
.yoffset
)
1197 dirty
.width
= (var
->reserved
[2] & 0xffff) - dirty
.xoffset
;
1199 ((var
->reserved
[2] >> 16) & 0xffff) - dirty
.yoffset
;
1200 info
->var
.yoffset
= var
->yoffset
;
1202 if (dirty
.xoffset
< 0)
1205 if (dirty
.yoffset
< 0)
1208 if ((dirty
.xoffset
+ dirty
.width
) > info
->var
.xres
)
1211 if ((dirty
.yoffset
+ dirty
.height
) > info
->var
.yres
)
1214 if ((dirty
.width
<= 0) || (dirty
.height
<= 0))
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
;
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) {
1245 /*get_img(&imgdata, info, &address,
1246 &length, &p_src_file);*/
1249 mfd
->ibuf
.visible_swapped
= TRUE
;
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
));
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
;
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
)
1287 if (var
->grayscale
!= info
->var
.grayscale
)
1290 switch (var
->bits_per_pixel
) {
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))
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))))
1329 if ((var
->xres_virtual
<= 0) || (var
->yres_virtual
<= 0))
1332 if (info
->fix
.smem_len
<
1333 (var
->xres_virtual
*var
->yres_virtual
*(var
->bits_per_pixel
/8)))
1336 if ((var
->xres
== 0) || (var
->yres
== 0))
1339 if ((var
->xres
> mfd
->panel_info
.xres
) ||
1340 (var
->yres
> mfd
->panel_info
.yres
))
1343 if (var
->xoffset
> (var
->xres_virtual
- var
->xres
))
1346 if (var
->yoffset
> (var
->yres_virtual
- var
->yres
))
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
;
1359 old_imgType
= mfd
->fb_imgType
;
1360 switch (var
->bits_per_pixel
) {
1362 if (var
->red
.offset
== 0)
1363 mfd
->fb_imgType
= MDP_BGR_565
;
1365 mfd
->fb_imgType
= MDP_RGB_565
;
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;
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
;
1394 msm_fb_blank_sub(FB_BLANK_POWERDOWN
, info
, mfd
->op_enable
);
1395 msm_fb_blank_sub(FB_BLANK_UNBLANK
, info
, mfd
->op_enable
);
1401 static int msm_fb_stop_sw_refresher(struct msm_fb_data_type
*mfd
)
1403 if (mfd
->hw_refresh
)
1406 if (mfd
->sw_currently_refreshing
) {
1408 mfd
->sw_currently_refreshing
= FALSE
;
1411 /* wait until the refresher finishes the last job */
1412 wait_for_completion_killable(&mfd
->refresher_comp
);
1418 int msm_fb_resume_sw_refresher(struct msm_fb_data_type
*mfd
)
1422 if (mfd
->hw_refresh
)
1426 if ((!mfd
->sw_currently_refreshing
) && (mfd
->sw_refreshing_enable
)) {
1428 mfd
->sw_currently_refreshing
= TRUE
;
1435 mdp_refresh_screen((unsigned long)mfd
);
1440 void mdp_ppp_put_img(struct file
*p_src_file
, struct file
*p_dst_file
)
1442 #ifdef CONFIG_ANDROID_PMEM
1444 put_pmem_file(p_src_file
);
1446 put_pmem_file(p_dst_file
);
1450 int mdp_blit(struct fb_info
*info
, struct mdp_blit_req
*req
)
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");
1458 if (unlikely(req
->dst_rect
.h
== 0 || req
->dst_rect
.w
== 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
);
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);
1491 static inline void msm_dma_nc_pre(void)
1495 static inline void msm_dma_wt_pre(void)
1499 static inline void msm_dma_todevice_wb_pre(void *start
, size_t size
)
1502 // dma_cache_pre_ops(start, size, DMA_TO_DEVICE);
1505 static inline void msm_dma_fromdevice_wb_pre(void *start
, size_t size
)
1508 // dma_cache_pre_ops(start, size, DMA_FROM_DEVICE);
1511 static inline void msm_dma_nc_post(void)
1516 static inline void msm_dma_fromdevice_wt_post(void *start
, size_t size
)
1519 // dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
1522 static inline void msm_dma_todevice_wb_post(void *start
, size_t size
)
1525 // dma_cache_post_ops(start, size, DMA_TO_DEVICE);
1528 static inline void msm_dma_fromdevice_wb_post(void *start
, size_t size
)
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
,
1546 #ifdef CONFIG_ARCH_QSD8X50
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
) {
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
)) {
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
)) {
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
,
1598 &(req_list
[i
].src_rect
),
1599 msm_dma_todevice_wb_pre
1602 msm_fb_dma_barrier_for_rect(info
,
1604 &(req_list
[i
].dst_rect
),
1605 msm_dma_todevice_wb_pre
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
,
1629 #ifdef CONFIG_ARCH_QSD8X50
1632 struct msm_fb_data_type
*mfd
= (struct msm_fb_data_type
*)info
->par
;
1633 switch (mfd
->mdp_fb_page_protection
) {
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
)) {
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
,
1657 &(req_list
[i
].dst_rect
),
1658 msm_dma_fromdevice_wt_post
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
,
1671 &(req_list
[i
].dst_rect
),
1672 msm_dma_fromdevice_wb_post
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
)
1690 * Ensure that CPU cache and other internal CPU state is
1691 * updated to reflect any change in memory modified by MDP blit
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
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
)))
1715 p
+= sizeof(req_list_header
);
1716 count
= req_list_header
.count
;
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
))
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
)) {
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");
1757 if (unlikely(req_list
[i
].dst_rect
.h
== 0 ||
1758 req_list
[i
].dst_rect
.w
== 0))
1761 /* create a new display job */
1762 job
= mdp_ppp_new_djob();
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
1778 if (ret
|| mdp_ppp_get_ret_code()) {
1779 mdp_ppp_clear_curr_djob();
1785 /* Go to next window of requests. */
1786 count
-= req_list_count
;
1787 p
+= sizeof(struct mdp_blit_req
)*req_list_count
;
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 guaranteed 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 doesn't 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
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
)))
1819 p
+= sizeof(req_list_header
);
1820 count
= req_list_header
.count
;
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
))
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
1864 * Ensure that CPU cache and other internal CPU state is
1865 * updated to reflect any change in memory modified by MDP blit
1868 msm_fb_ensure_memory_coherency_after_dma(info
,
1872 /* Go to next window of requests. */
1873 count
-= req_list_count
;
1874 p
+= sizeof(struct mdp_blit_req
)*req_list_count
;
1880 #ifdef CONFIG_FB_MSM_OVERLAY
1881 static int msmfb_overlay_get(struct fb_info
*info
, void __user
*p
)
1883 struct mdp_overlay req
;
1886 if (copy_from_user(&req
, p
, sizeof(req
)))
1889 ret
= mdp4_overlay_get(info
, &req
);
1891 printk(KERN_ERR
"%s: ioctl failed \n",
1895 if (copy_to_user(p
, &req
, sizeof(req
))) {
1896 printk(KERN_ERR
"%s: copy2user failed \n",
1904 static int msmfb_overlay_set(struct fb_info
*info
, void __user
*p
)
1906 struct mdp_overlay req
;
1909 if (copy_from_user(&req
, p
, sizeof(req
)))
1912 ret
= mdp4_overlay_set(info
, &req
);
1914 printk(KERN_ERR
"%s:ioctl failed \n",
1919 if (copy_to_user(p
, &req
, sizeof(req
))) {
1920 printk(KERN_ERR
"%s: copy2user failed \n",
1928 static int msmfb_overlay_unset(struct fb_info
*info
, unsigned long *argp
)
1932 ret
= copy_from_user(&ndx
, argp
, sizeof(ndx
));
1934 printk(KERN_ERR
"%s:msmfb_overlay_unset ioctl failed \n",
1939 return mdp4_overlay_unset(info
, ndx
);
1942 static int msmfb_overlay_play(struct fb_info
*info
, unsigned long *argp
)
1945 struct msmfb_overlay_data req
;
1946 struct file
*p_src_file
= 0;
1948 ret
= copy_from_user(&req
, argp
, sizeof(req
));
1950 printk(KERN_ERR
"%s:msmfb_overlay_play ioctl failed \n",
1955 ret
= mdp4_overlay_play(info
, &req
, &p_src_file
);
1958 put_pmem_file(p_src_file
);
1965 DEFINE_SEMAPHORE(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
)
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
));
1989 /* MDP cmd block disable */
1990 mdp_pipe_ctrl(MDP_CMD_BLOCK
, MDP_BLOCK_POWER_OFF
, FALSE
);
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
);
2008 static int msm_fb_ioctl(struct fb_info
*info
, unsigned int cmd
,
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
;
2019 struct mdp_page_protection fb_page_protection
;
2022 if (!mfd
->op_enable
)
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
);
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
);
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
);
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
);
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. */
2054 ret
= msmfb_blit(info
, argp
);
2056 up(&msm_fb_ioctl_ppp_sem
);
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
));
2066 "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n",
2071 down(&msm_fb_ioctl_ppp_sem
);
2072 if (ccs_matrix
.direction
== MDP_CCS_RGB2YUV
)
2073 mdp_ccs_rgb2yuv
= ccs_matrix
;
2075 mdp_ccs_yuv2rgb
= ccs_matrix
;
2077 msmfb_set_color_conv(&ccs_matrix
) ;
2078 up(&msm_fb_ioctl_ppp_sem
);
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
)) ;
2091 "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
2096 down(&msm_fb_ioctl_ppp_sem
);
2097 if (ccs_matrix
.direction
== MDP_CCS_RGB2YUV
)
2098 ccs_matrix
= mdp_ccs_rgb2yuv
;
2100 ccs_matrix
= mdp_ccs_yuv2rgb
;
2102 ret
= copy_to_user(argp
, &ccs_matrix
, sizeof(ccs_matrix
));
2106 "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
2110 up(&msm_fb_ioctl_ppp_sem
);
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
);
2124 case MSMFB_BLIT_FLUSH
:
2125 down(&msm_fb_ioctl_ppp_sem
);
2127 up(&msm_fb_ioctl_ppp_sem
);
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
));
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
,
2149 case MSMFB_SUSPEND_SW_REFRESHER
:
2150 if (!mfd
->panel_power_on
)
2153 mfd
->sw_refreshing_enable
= FALSE
;
2154 ret
= msm_fb_stop_sw_refresher(mfd
);
2157 case MSMFB_RESUME_SW_REFRESHER
:
2158 if (!mfd
->panel_power_on
)
2161 mfd
->sw_refreshing_enable
= TRUE
;
2162 ret
= msm_fb_resume_sw_refresher(mfd
);
2166 ret
= copy_from_user(&cursor
, argp
, sizeof(cursor
));
2170 ret
= msm_fb_cursor(info
, &cursor
);
2174 ret
= copy_from_user(&cmap
, argp
, sizeof(cmap
));
2178 mutex_lock(&msm_fb_ioctl_lut_sem
);
2179 ret
= msm_fb_set_lut(&cmap
, info
);
2180 mutex_unlock(&msm_fb_ioctl_lut_sem
);
2183 case MSMFB_HISTOGRAM
:
2184 if (!mfd
->do_histogram
)
2187 ret
= copy_from_user(&hist
, argp
, sizeof(hist
));
2191 mutex_lock(&msm_fb_ioctl_hist_sem
);
2192 ret
= mfd
->do_histogram(info
, &hist
);
2193 mutex_unlock(&msm_fb_ioctl_hist_sem
);
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
));
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
));
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
;
2230 * Don't allow caching until 7k DMA cache operations are
2238 MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd
);
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
;
2263 pdata
= pdev
->dev
.platform_data
;
2266 type
= pdata
->panel_info
.type
;
2267 fb_num
= pdata
->panel_info
.fb_num
;
2272 if (fbi_list_index
>= MAX_FBI_LIST
) {
2273 printk(KERN_ERR
"msm_fb: no more framebuffer info list!\n");
2277 * alloc panel device data
2279 this_dev
= msm_fb_device_alloc(pdata
, type
, id
);
2283 "%s: msm_fb_device_alloc failed!\n", __func__
);
2288 * alloc framebuffer info + par data
2290 fbi
= framebuffer_alloc(sizeof(struct msm_fb_data_type
), NULL
);
2292 platform_device_put(this_dev
);
2293 printk(KERN_ERR
"msm_fb: can't alloca framebuffer info data!\n");
2297 mfd
= (struct msm_fb_data_type
*)fbi
->par
;
2300 mfd
->panel
.type
= type
;
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
;
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
);
2325 EXPORT_SYMBOL(msm_fb_add_device
);
2327 int __init
msm_fb_init(void)
2331 if (msm_fb_register_driver())
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
);
2354 module_init(msm_fb_init
);