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