1 /* drivers/video/msm/msm_fb.c
3 * Core MSM framebuffer driver.
5 * Copyright (C) 2007 Google Incorporated
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/platform_device.h>
18 #include <linux/module.h>
20 #include <linux/delay.h>
22 #include <linux/freezer.h>
23 #include <linux/wait.h>
24 #include <linux/msm_mdp.h>
26 #include <linux/uaccess.h>
27 #include <mach/msm_fb.h>
28 #include <mach/board.h>
29 #include <linux/workqueue.h>
30 #include <linux/clk.h>
31 #include <linux/debugfs.h>
32 #include <linux/dma-mapping.h>
35 #define PRINT_BLIT_TIME 0
39 #define FULL_UPDATE_DONE 0x2
44 #define SUSPEND_RESUME 0x1
47 #define SHOW_UPDATES 0x8
49 #define DLOG(mask, fmt, args...) \
51 if (msmfb_debug_mask & mask) \
52 printk(KERN_INFO "msmfb: "fmt, ##args); \
55 static int msmfb_debug_mask
;
56 module_param_named(msmfb_debug_mask
, msmfb_debug_mask
, int,
57 S_IRUGO
| S_IWUSR
| S_IWGRP
);
59 struct mdp_device
*mdp
;
63 struct msm_panel_data
*panel
;
66 unsigned output_format
;
68 unsigned frame_requested
;
71 unsigned update_frame
;
75 int eright
; /* exclusive */
76 int ebottom
; /* exclusive */
80 spinlock_t update_lock
;
81 struct mutex panel_init_lock
;
82 wait_queue_head_t frame_wq
;
83 struct workqueue_struct
*resume_workqueue
;
84 struct work_struct resume_work
;
85 struct msmfb_callback dma_callback
;
86 struct msmfb_callback vsync_callback
;
87 struct hrtimer fake_vsync
;
88 ktime_t vsync_request_time
;
91 static int msmfb_open(struct fb_info
*info
, int user
)
96 static int msmfb_release(struct fb_info
*info
, int user
)
101 /* Called from dma interrupt handler, must not sleep */
102 static void msmfb_handle_dma_interrupt(struct msmfb_callback
*callback
)
104 unsigned long irq_flags
;
105 struct msmfb_info
*msmfb
= container_of(callback
, struct msmfb_info
,
108 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
109 msmfb
->frame_done
= msmfb
->frame_requested
;
110 if (msmfb
->sleeping
== UPDATING
&&
111 msmfb
->frame_done
== msmfb
->update_frame
) {
112 DLOG(SUSPEND_RESUME
, "full update completed\n");
113 queue_work(msmfb
->resume_workqueue
, &msmfb
->resume_work
);
115 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
116 wake_up(&msmfb
->frame_wq
);
119 static int msmfb_start_dma(struct msmfb_info
*msmfb
)
123 unsigned long irq_flags
;
125 s64 time_since_request
;
126 struct msm_panel_data
*panel
= msmfb
->panel
;
128 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
129 time_since_request
= ktime_to_ns(ktime_sub(ktime_get(),
130 msmfb
->vsync_request_time
));
131 if (time_since_request
> 20 * NSEC_PER_MSEC
) {
133 us
= do_div(time_since_request
, NSEC_PER_MSEC
) / NSEC_PER_USEC
;
134 printk(KERN_WARNING
"msmfb_start_dma %lld.%03u ms after vsync "
135 "request\n", time_since_request
, us
);
137 if (msmfb
->frame_done
== msmfb
->frame_requested
) {
138 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
141 if (msmfb
->sleeping
== SLEEPING
) {
142 DLOG(SUSPEND_RESUME
, "tried to start dma while asleep\n");
143 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
146 x
= msmfb
->update_info
.left
;
147 y
= msmfb
->update_info
.top
;
148 w
= msmfb
->update_info
.eright
- x
;
149 h
= msmfb
->update_info
.ebottom
- y
;
150 yoffset
= msmfb
->yoffset
;
151 msmfb
->update_info
.left
= msmfb
->xres
+ 1;
152 msmfb
->update_info
.top
= msmfb
->yres
+ 1;
153 msmfb
->update_info
.eright
= 0;
154 msmfb
->update_info
.ebottom
= 0;
155 if (unlikely(w
> msmfb
->xres
|| h
> msmfb
->yres
||
157 printk(KERN_INFO
"invalid update: %d %d %d "
159 msmfb
->frame_done
= msmfb
->frame_requested
;
162 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
164 addr
= ((msmfb
->xres
* (yoffset
+ y
) + x
) * 2);
165 mdp
->dma(mdp
, addr
+ msmfb
->fb
->fix
.smem_start
,
166 msmfb
->xres
* 2, w
, h
, x
, y
, &msmfb
->dma_callback
,
167 panel
->interface_type
);
170 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
171 /* some clients need to clear their vsync interrupt */
172 if (panel
->clear_vsync
)
173 panel
->clear_vsync(panel
);
174 wake_up(&msmfb
->frame_wq
);
178 /* Called from esync interrupt handler, must not sleep */
179 static void msmfb_handle_vsync_interrupt(struct msmfb_callback
*callback
)
181 struct msmfb_info
*msmfb
= container_of(callback
, struct msmfb_info
,
183 msmfb_start_dma(msmfb
);
186 static enum hrtimer_restart
msmfb_fake_vsync(struct hrtimer
*timer
)
188 struct msmfb_info
*msmfb
= container_of(timer
, struct msmfb_info
,
190 msmfb_start_dma(msmfb
);
191 return HRTIMER_NORESTART
;
194 static void msmfb_pan_update(struct fb_info
*info
, uint32_t left
, uint32_t top
,
195 uint32_t eright
, uint32_t ebottom
,
196 uint32_t yoffset
, int pan_display
)
198 struct msmfb_info
*msmfb
= info
->par
;
199 struct msm_panel_data
*panel
= msmfb
->panel
;
200 unsigned long irq_flags
;
204 DLOG(SHOW_UPDATES
, "update %d %d %d %d %d %d\n",
205 left
, top
, eright
, ebottom
, yoffset
, pan_display
);
207 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
209 /* if we are sleeping, on a pan_display wait 10ms (to throttle back
210 * drawing otherwise return */
211 if (msmfb
->sleeping
== SLEEPING
) {
212 DLOG(SUSPEND_RESUME
, "drawing while asleep\n");
213 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
215 wait_event_interruptible_timeout(msmfb
->frame_wq
,
216 msmfb
->sleeping
!= SLEEPING
, HZ
/10);
220 sleeping
= msmfb
->sleeping
;
221 /* on a full update, if the last frame has not completed, wait for it */
222 if (pan_display
&& (msmfb
->frame_requested
!= msmfb
->frame_done
||
223 sleeping
== UPDATING
)) {
225 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
226 ret
= wait_event_interruptible_timeout(msmfb
->frame_wq
,
227 msmfb
->frame_done
== msmfb
->frame_requested
&&
228 msmfb
->sleeping
!= UPDATING
, 5 * HZ
);
229 if (ret
<= 0 && (msmfb
->frame_requested
!= msmfb
->frame_done
||
230 msmfb
->sleeping
== UPDATING
)) {
231 if (retry
&& panel
->request_vsync
&&
232 (sleeping
== AWAKE
)) {
233 panel
->request_vsync(panel
,
234 &msmfb
->vsync_callback
);
236 printk(KERN_WARNING
"msmfb_pan_display timeout "
237 "rerequest vsync\n");
239 printk(KERN_WARNING
"msmfb_pan_display timeout "
240 "waiting for frame start, %d %d\n",
241 msmfb
->frame_requested
,
250 msmfb
->frame_requested
++;
251 /* if necessary, update the y offset, if this is the
252 * first full update on resume, set the sleeping state */
254 msmfb
->yoffset
= yoffset
;
255 if (left
== 0 && top
== 0 && eright
== info
->var
.xres
&&
256 ebottom
== info
->var
.yres
) {
257 if (sleeping
== WAKING
) {
258 msmfb
->update_frame
= msmfb
->frame_requested
;
259 DLOG(SUSPEND_RESUME
, "full update starting\n");
260 msmfb
->sleeping
= UPDATING
;
265 /* set the update request */
266 if (left
< msmfb
->update_info
.left
)
267 msmfb
->update_info
.left
= left
;
268 if (top
< msmfb
->update_info
.top
)
269 msmfb
->update_info
.top
= top
;
270 if (eright
> msmfb
->update_info
.eright
)
271 msmfb
->update_info
.eright
= eright
;
272 if (ebottom
> msmfb
->update_info
.ebottom
)
273 msmfb
->update_info
.ebottom
= ebottom
;
274 DLOG(SHOW_UPDATES
, "update queued %d %d %d %d %d\n",
275 msmfb
->update_info
.left
, msmfb
->update_info
.top
,
276 msmfb
->update_info
.eright
, msmfb
->update_info
.ebottom
,
278 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
280 /* if the panel is all the way on wait for vsync, otherwise sleep
281 * for 16 ms (long enough for the dma to panel) and then begin dma */
282 msmfb
->vsync_request_time
= ktime_get();
283 if (panel
->request_vsync
&& (sleeping
== AWAKE
)) {
284 panel
->request_vsync(panel
, &msmfb
->vsync_callback
);
286 if (!hrtimer_active(&msmfb
->fake_vsync
)) {
287 hrtimer_start(&msmfb
->fake_vsync
,
288 ktime_set(0, NSEC_PER_SEC
/60),
294 static void msmfb_update(struct fb_info
*info
, uint32_t left
, uint32_t top
,
295 uint32_t eright
, uint32_t ebottom
)
297 msmfb_pan_update(info
, left
, top
, eright
, ebottom
, 0, 0);
300 static void power_on_panel(struct work_struct
*work
)
302 struct msmfb_info
*msmfb
=
303 container_of(work
, struct msmfb_info
, resume_work
);
304 struct msm_panel_data
*panel
= msmfb
->panel
;
305 unsigned long irq_flags
;
307 mutex_lock(&msmfb
->panel_init_lock
);
308 DLOG(SUSPEND_RESUME
, "turning on panel\n");
309 if (msmfb
->sleeping
== UPDATING
) {
310 if (panel
->unblank(panel
)) {
311 printk(KERN_INFO
"msmfb: panel unblank failed,"
312 "not starting drawing\n");
315 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
316 msmfb
->sleeping
= AWAKE
;
317 wake_up(&msmfb
->frame_wq
);
318 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
321 mutex_unlock(&msmfb
->panel_init_lock
);
325 static int msmfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
327 if ((var
->xres
!= info
->var
.xres
) ||
328 (var
->yres
!= info
->var
.yres
) ||
329 (var
->xres_virtual
!= info
->var
.xres_virtual
) ||
330 (var
->yres_virtual
!= info
->var
.yres_virtual
) ||
331 (var
->xoffset
!= info
->var
.xoffset
) ||
332 (var
->bits_per_pixel
!= info
->var
.bits_per_pixel
) ||
333 (var
->grayscale
!= info
->var
.grayscale
))
338 int msmfb_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
340 struct msmfb_info
*msmfb
= info
->par
;
341 struct msm_panel_data
*panel
= msmfb
->panel
;
344 if ((panel
->caps
& MSMFB_CAP_PARTIAL_UPDATES
) &&
345 (var
->reserved
[0] == 0x54445055)) {
346 msmfb_pan_update(info
, var
->reserved
[1] & 0xffff,
347 var
->reserved
[1] >> 16,
348 var
->reserved
[2] & 0xffff,
349 var
->reserved
[2] >> 16, var
->yoffset
, 1);
351 msmfb_pan_update(info
, 0, 0, info
->var
.xres
, info
->var
.yres
,
357 static void msmfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
359 cfb_fillrect(p
, rect
);
360 msmfb_update(p
, rect
->dx
, rect
->dy
, rect
->dx
+ rect
->width
,
361 rect
->dy
+ rect
->height
);
364 static void msmfb_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
366 cfb_copyarea(p
, area
);
367 msmfb_update(p
, area
->dx
, area
->dy
, area
->dx
+ area
->width
,
368 area
->dy
+ area
->height
);
371 static void msmfb_imageblit(struct fb_info
*p
, const struct fb_image
*image
)
373 cfb_imageblit(p
, image
);
374 msmfb_update(p
, image
->dx
, image
->dy
, image
->dx
+ image
->width
,
375 image
->dy
+ image
->height
);
379 static int msmfb_blit(struct fb_info
*info
,
382 struct mdp_blit_req req
;
383 struct mdp_blit_req_list req_list
;
387 if (copy_from_user(&req_list
, p
, sizeof(req_list
)))
390 for (i
= 0; i
< req_list
.count
; i
++) {
391 struct mdp_blit_req_list
*list
=
392 (struct mdp_blit_req_list
*)p
;
393 if (copy_from_user(&req
, &list
->req
[i
], sizeof(req
)))
395 ret
= mdp
->blit(mdp
, info
, &req
);
403 DEFINE_MUTEX(mdp_ppp_lock
);
405 static int msmfb_ioctl(struct fb_info
*p
, unsigned int cmd
, unsigned long arg
)
407 void __user
*argp
= (void __user
*)arg
;
412 mdp
->set_grp_disp(mdp
, arg
);
415 ret
= msmfb_blit(p
, argp
);
420 printk(KERN_INFO
"msmfb unknown ioctl: %d\n", cmd
);
426 static struct fb_ops msmfb_ops
= {
427 .owner
= THIS_MODULE
,
428 .fb_open
= msmfb_open
,
429 .fb_release
= msmfb_release
,
430 .fb_check_var
= msmfb_check_var
,
431 .fb_pan_display
= msmfb_pan_display
,
432 .fb_fillrect
= msmfb_fillrect
,
433 .fb_copyarea
= msmfb_copyarea
,
434 .fb_imageblit
= msmfb_imageblit
,
435 .fb_ioctl
= msmfb_ioctl
,
438 static unsigned PP
[16];
442 #define BITS_PER_PIXEL 16
444 static void setup_fb_info(struct msmfb_info
*msmfb
)
446 struct fb_info
*fb_info
= msmfb
->fb
;
449 /* finish setting up the fb_info struct */
450 strncpy(fb_info
->fix
.id
, "msmfb", 16);
451 fb_info
->fix
.ypanstep
= 1;
453 fb_info
->fbops
= &msmfb_ops
;
454 fb_info
->flags
= FBINFO_DEFAULT
;
456 fb_info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
457 fb_info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
458 fb_info
->fix
.line_length
= msmfb
->xres
* 2;
460 fb_info
->var
.xres
= msmfb
->xres
;
461 fb_info
->var
.yres
= msmfb
->yres
;
462 fb_info
->var
.width
= msmfb
->panel
->fb_data
->width
;
463 fb_info
->var
.height
= msmfb
->panel
->fb_data
->height
;
464 fb_info
->var
.xres_virtual
= msmfb
->xres
;
465 fb_info
->var
.yres_virtual
= msmfb
->yres
* 2;
466 fb_info
->var
.bits_per_pixel
= BITS_PER_PIXEL
;
467 fb_info
->var
.accel_flags
= 0;
469 fb_info
->var
.yoffset
= 0;
471 if (msmfb
->panel
->caps
& MSMFB_CAP_PARTIAL_UPDATES
) {
472 fb_info
->var
.reserved
[0] = 0x54445055;
473 fb_info
->var
.reserved
[1] = 0;
474 fb_info
->var
.reserved
[2] = (uint16_t)msmfb
->xres
|
475 ((uint32_t)msmfb
->yres
<< 16);
478 fb_info
->var
.red
.offset
= 11;
479 fb_info
->var
.red
.length
= 5;
480 fb_info
->var
.red
.msb_right
= 0;
481 fb_info
->var
.green
.offset
= 5;
482 fb_info
->var
.green
.length
= 6;
483 fb_info
->var
.green
.msb_right
= 0;
484 fb_info
->var
.blue
.offset
= 0;
485 fb_info
->var
.blue
.length
= 5;
486 fb_info
->var
.blue
.msb_right
= 0;
488 r
= fb_alloc_cmap(&fb_info
->cmap
, 16, 0);
489 fb_info
->pseudo_palette
= PP
;
492 for (r
= 1; r
< 16; r
++)
496 static int setup_fbmem(struct msmfb_info
*msmfb
, struct platform_device
*pdev
)
498 struct fb_info
*fb
= msmfb
->fb
;
499 struct resource
*resource
;
500 unsigned long size
= msmfb
->xres
* msmfb
->yres
*
501 (BITS_PER_PIXEL
>> 3) * 2;
502 unsigned char *fbram
;
504 /* board file might have attached a resource describing an fb */
505 resource
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
509 /* check the resource is large enough to fit the fb */
510 if (resource
->end
- resource
->start
< size
) {
511 printk(KERN_ERR
"allocated resource is too small for "
515 fb
->fix
.smem_start
= resource
->start
;
516 fb
->fix
.smem_len
= resource
->end
- resource
->start
;
517 fbram
= ioremap(resource
->start
,
518 resource
->end
- resource
->start
);
520 printk(KERN_ERR
"msmfb: cannot allocate fbram!\n");
523 fb
->screen_base
= fbram
;
527 static int msmfb_probe(struct platform_device
*pdev
)
530 struct msmfb_info
*msmfb
;
531 struct msm_panel_data
*panel
= pdev
->dev
.platform_data
;
535 pr_err("msmfb_probe: no platform data\n");
538 if (!panel
->fb_data
) {
539 pr_err("msmfb_probe: no fb_data\n");
543 fb
= framebuffer_alloc(sizeof(struct msmfb_info
), &pdev
->dev
);
548 msmfb
->panel
= panel
;
549 msmfb
->xres
= panel
->fb_data
->xres
;
550 msmfb
->yres
= panel
->fb_data
->yres
;
552 ret
= setup_fbmem(msmfb
, pdev
);
554 goto error_setup_fbmem
;
556 setup_fb_info(msmfb
);
558 spin_lock_init(&msmfb
->update_lock
);
559 mutex_init(&msmfb
->panel_init_lock
);
560 init_waitqueue_head(&msmfb
->frame_wq
);
561 msmfb
->resume_workqueue
= create_workqueue("panel_on");
562 if (msmfb
->resume_workqueue
== NULL
) {
563 printk(KERN_ERR
"failed to create panel_on workqueue\n");
565 goto error_create_workqueue
;
567 INIT_WORK(&msmfb
->resume_work
, power_on_panel
);
568 msmfb
->black
= kzalloc(msmfb
->fb
->var
.bits_per_pixel
*msmfb
->xres
,
571 printk(KERN_INFO
"msmfb_probe() installing %d x %d panel\n",
572 msmfb
->xres
, msmfb
->yres
);
574 msmfb
->dma_callback
.func
= msmfb_handle_dma_interrupt
;
575 msmfb
->vsync_callback
.func
= msmfb_handle_vsync_interrupt
;
576 hrtimer_init(&msmfb
->fake_vsync
, CLOCK_MONOTONIC
,
580 msmfb
->fake_vsync
.function
= msmfb_fake_vsync
;
582 ret
= register_framebuffer(fb
);
584 goto error_register_framebuffer
;
586 msmfb
->sleeping
= WAKING
;
590 error_register_framebuffer
:
591 destroy_workqueue(msmfb
->resume_workqueue
);
592 error_create_workqueue
:
593 iounmap(fb
->screen_base
);
595 framebuffer_release(msmfb
->fb
);
599 static struct platform_driver msm_panel_driver
= {
600 /* need to write remove */
601 .probe
= msmfb_probe
,
602 .driver
= {.name
= "msm_panel"},
606 static int msmfb_add_mdp_device(struct device
*dev
,
607 struct class_interface
*class_intf
)
609 /* might need locking if mulitple mdp devices */
612 mdp
= container_of(dev
, struct mdp_device
, dev
);
613 return platform_driver_register(&msm_panel_driver
);
616 static void msmfb_remove_mdp_device(struct device
*dev
,
617 struct class_interface
*class_intf
)
619 /* might need locking if mulitple mdp devices */
620 if (dev
!= &mdp
->dev
)
622 platform_driver_unregister(&msm_panel_driver
);
626 static struct class_interface msm_fb_interface
= {
627 .add_dev
= &msmfb_add_mdp_device
,
628 .remove_dev
= &msmfb_remove_mdp_device
,
631 static int __init
msmfb_init(void)
633 return register_mdp_client(&msm_fb_interface
);
636 module_init(msmfb_init
);