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