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