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/slab.h>
21 #include <linux/delay.h>
23 #include <linux/freezer.h>
24 #include <linux/wait.h>
25 #include <linux/msm_mdp.h>
27 #include <linux/uaccess.h>
28 #include <linux/platform_data/video-msm_fb.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 work_struct resume_work
;
84 struct msmfb_callback dma_callback
;
85 struct msmfb_callback vsync_callback
;
86 struct hrtimer fake_vsync
;
87 ktime_t vsync_request_time
;
90 static int msmfb_open(struct fb_info
*info
, int user
)
95 static int msmfb_release(struct fb_info
*info
, int user
)
100 /* Called from dma interrupt handler, must not sleep */
101 static void msmfb_handle_dma_interrupt(struct msmfb_callback
*callback
)
103 unsigned long irq_flags
;
104 struct msmfb_info
*msmfb
= container_of(callback
, struct msmfb_info
,
107 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
108 msmfb
->frame_done
= msmfb
->frame_requested
;
109 if (msmfb
->sleeping
== UPDATING
&&
110 msmfb
->frame_done
== msmfb
->update_frame
) {
111 DLOG(SUSPEND_RESUME
, "full update completed\n");
112 schedule_work(&msmfb
->resume_work
);
114 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
115 wake_up(&msmfb
->frame_wq
);
118 static int msmfb_start_dma(struct msmfb_info
*msmfb
)
122 unsigned long irq_flags
;
124 s64 time_since_request
;
125 struct msm_panel_data
*panel
= msmfb
->panel
;
127 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
128 time_since_request
= ktime_to_ns(ktime_sub(ktime_get(),
129 msmfb
->vsync_request_time
));
130 if (time_since_request
> 20 * NSEC_PER_MSEC
) {
132 us
= do_div(time_since_request
, NSEC_PER_MSEC
) / NSEC_PER_USEC
;
133 printk(KERN_WARNING
"msmfb_start_dma %lld.%03u ms after vsync "
134 "request\n", time_since_request
, us
);
136 if (msmfb
->frame_done
== msmfb
->frame_requested
) {
137 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
140 if (msmfb
->sleeping
== SLEEPING
) {
141 DLOG(SUSPEND_RESUME
, "tried to start dma while asleep\n");
142 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
145 x
= msmfb
->update_info
.left
;
146 y
= msmfb
->update_info
.top
;
147 w
= msmfb
->update_info
.eright
- x
;
148 h
= msmfb
->update_info
.ebottom
- y
;
149 yoffset
= msmfb
->yoffset
;
150 msmfb
->update_info
.left
= msmfb
->xres
+ 1;
151 msmfb
->update_info
.top
= msmfb
->yres
+ 1;
152 msmfb
->update_info
.eright
= 0;
153 msmfb
->update_info
.ebottom
= 0;
154 if (unlikely(w
> msmfb
->xres
|| h
> msmfb
->yres
||
156 printk(KERN_INFO
"invalid update: %d %d %d "
158 msmfb
->frame_done
= msmfb
->frame_requested
;
161 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
163 addr
= ((msmfb
->xres
* (yoffset
+ y
) + x
) * 2);
164 mdp
->dma(mdp
, addr
+ msmfb
->fb
->fix
.smem_start
,
165 msmfb
->xres
* 2, w
, h
, x
, y
, &msmfb
->dma_callback
,
166 panel
->interface_type
);
169 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
170 /* some clients need to clear their vsync interrupt */
171 if (panel
->clear_vsync
)
172 panel
->clear_vsync(panel
);
173 wake_up(&msmfb
->frame_wq
);
177 /* Called from esync interrupt handler, must not sleep */
178 static void msmfb_handle_vsync_interrupt(struct msmfb_callback
*callback
)
180 struct msmfb_info
*msmfb
= container_of(callback
, struct msmfb_info
,
182 msmfb_start_dma(msmfb
);
185 static enum hrtimer_restart
msmfb_fake_vsync(struct hrtimer
*timer
)
187 struct msmfb_info
*msmfb
= container_of(timer
, struct msmfb_info
,
189 msmfb_start_dma(msmfb
);
190 return HRTIMER_NORESTART
;
193 static void msmfb_pan_update(struct fb_info
*info
, uint32_t left
, uint32_t top
,
194 uint32_t eright
, uint32_t ebottom
,
195 uint32_t yoffset
, int pan_display
)
197 struct msmfb_info
*msmfb
= info
->par
;
198 struct msm_panel_data
*panel
= msmfb
->panel
;
199 unsigned long irq_flags
;
203 DLOG(SHOW_UPDATES
, "update %d %d %d %d %d %d\n",
204 left
, top
, eright
, ebottom
, yoffset
, pan_display
);
206 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
208 /* if we are sleeping, on a pan_display wait 10ms (to throttle back
209 * drawing otherwise return */
210 if (msmfb
->sleeping
== SLEEPING
) {
211 DLOG(SUSPEND_RESUME
, "drawing while asleep\n");
212 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
214 wait_event_interruptible_timeout(msmfb
->frame_wq
,
215 msmfb
->sleeping
!= SLEEPING
, HZ
/10);
219 sleeping
= msmfb
->sleeping
;
220 /* on a full update, if the last frame has not completed, wait for it */
221 if ((pan_display
&& msmfb
->frame_requested
!= msmfb
->frame_done
) ||
222 sleeping
== UPDATING
) {
224 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
225 ret
= wait_event_interruptible_timeout(msmfb
->frame_wq
,
226 msmfb
->frame_done
== msmfb
->frame_requested
&&
227 msmfb
->sleeping
!= UPDATING
, 5 * HZ
);
228 if (ret
<= 0 && (msmfb
->frame_requested
!= msmfb
->frame_done
||
229 msmfb
->sleeping
== UPDATING
)) {
230 if (retry
&& panel
->request_vsync
&&
231 (sleeping
== AWAKE
)) {
232 panel
->request_vsync(panel
,
233 &msmfb
->vsync_callback
);
235 printk(KERN_WARNING
"msmfb_pan_display timeout "
236 "rerequest vsync\n");
238 printk(KERN_WARNING
"msmfb_pan_display timeout "
239 "waiting for frame start, %d %d\n",
240 msmfb
->frame_requested
,
249 msmfb
->frame_requested
++;
250 /* if necessary, update the y offset, if this is the
251 * first full update on resume, set the sleeping state */
253 msmfb
->yoffset
= yoffset
;
254 if (left
== 0 && top
== 0 && eright
== info
->var
.xres
&&
255 ebottom
== info
->var
.yres
) {
256 if (sleeping
== WAKING
) {
257 msmfb
->update_frame
= msmfb
->frame_requested
;
258 DLOG(SUSPEND_RESUME
, "full update starting\n");
259 msmfb
->sleeping
= UPDATING
;
264 /* set the update request */
265 if (left
< msmfb
->update_info
.left
)
266 msmfb
->update_info
.left
= left
;
267 if (top
< msmfb
->update_info
.top
)
268 msmfb
->update_info
.top
= top
;
269 if (eright
> msmfb
->update_info
.eright
)
270 msmfb
->update_info
.eright
= eright
;
271 if (ebottom
> msmfb
->update_info
.ebottom
)
272 msmfb
->update_info
.ebottom
= ebottom
;
273 DLOG(SHOW_UPDATES
, "update queued %d %d %d %d %d\n",
274 msmfb
->update_info
.left
, msmfb
->update_info
.top
,
275 msmfb
->update_info
.eright
, msmfb
->update_info
.ebottom
,
277 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
279 /* if the panel is all the way on wait for vsync, otherwise sleep
280 * for 16 ms (long enough for the dma to panel) and then begin dma */
281 msmfb
->vsync_request_time
= ktime_get();
282 if (panel
->request_vsync
&& (sleeping
== AWAKE
)) {
283 panel
->request_vsync(panel
, &msmfb
->vsync_callback
);
285 if (!hrtimer_active(&msmfb
->fake_vsync
)) {
286 hrtimer_start(&msmfb
->fake_vsync
,
287 ktime_set(0, NSEC_PER_SEC
/60),
293 static void msmfb_update(struct fb_info
*info
, uint32_t left
, uint32_t top
,
294 uint32_t eright
, uint32_t ebottom
)
296 msmfb_pan_update(info
, left
, top
, eright
, ebottom
, 0, 0);
299 static void power_on_panel(struct work_struct
*work
)
301 struct msmfb_info
*msmfb
=
302 container_of(work
, struct msmfb_info
, resume_work
);
303 struct msm_panel_data
*panel
= msmfb
->panel
;
304 unsigned long irq_flags
;
306 mutex_lock(&msmfb
->panel_init_lock
);
307 DLOG(SUSPEND_RESUME
, "turning on panel\n");
308 if (msmfb
->sleeping
== UPDATING
) {
309 if (panel
->unblank(panel
)) {
310 printk(KERN_INFO
"msmfb: panel unblank failed,"
311 "not starting drawing\n");
314 spin_lock_irqsave(&msmfb
->update_lock
, irq_flags
);
315 msmfb
->sleeping
= AWAKE
;
316 wake_up(&msmfb
->frame_wq
);
317 spin_unlock_irqrestore(&msmfb
->update_lock
, irq_flags
);
320 mutex_unlock(&msmfb
->panel_init_lock
);
324 static int msmfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
326 if ((var
->xres
!= info
->var
.xres
) ||
327 (var
->yres
!= info
->var
.yres
) ||
328 (var
->xres_virtual
!= info
->var
.xres_virtual
) ||
329 (var
->yres_virtual
!= info
->var
.yres_virtual
) ||
330 (var
->xoffset
!= info
->var
.xoffset
) ||
331 (var
->bits_per_pixel
!= info
->var
.bits_per_pixel
) ||
332 (var
->grayscale
!= info
->var
.grayscale
))
337 int msmfb_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
339 struct msmfb_info
*msmfb
= info
->par
;
340 struct msm_panel_data
*panel
= msmfb
->panel
;
343 if ((panel
->caps
& MSMFB_CAP_PARTIAL_UPDATES
) &&
344 (var
->reserved
[0] == 0x54445055)) {
345 msmfb_pan_update(info
, var
->reserved
[1] & 0xffff,
346 var
->reserved
[1] >> 16,
347 var
->reserved
[2] & 0xffff,
348 var
->reserved
[2] >> 16, var
->yoffset
, 1);
350 msmfb_pan_update(info
, 0, 0, info
->var
.xres
, info
->var
.yres
,
356 static void msmfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
358 cfb_fillrect(p
, rect
);
359 msmfb_update(p
, rect
->dx
, rect
->dy
, rect
->dx
+ rect
->width
,
360 rect
->dy
+ rect
->height
);
363 static void msmfb_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
365 cfb_copyarea(p
, area
);
366 msmfb_update(p
, area
->dx
, area
->dy
, area
->dx
+ area
->width
,
367 area
->dy
+ area
->height
);
370 static void msmfb_imageblit(struct fb_info
*p
, const struct fb_image
*image
)
372 cfb_imageblit(p
, image
);
373 msmfb_update(p
, image
->dx
, image
->dy
, image
->dx
+ image
->width
,
374 image
->dy
+ image
->height
);
378 static int msmfb_blit(struct fb_info
*info
,
381 struct mdp_blit_req req
;
382 struct mdp_blit_req_list req_list
;
386 if (copy_from_user(&req_list
, p
, sizeof(req_list
)))
389 for (i
= 0; i
< req_list
.count
; i
++) {
390 struct mdp_blit_req_list
*list
=
391 (struct mdp_blit_req_list
*)p
;
392 if (copy_from_user(&req
, &list
->req
[i
], sizeof(req
)))
394 ret
= mdp
->blit(mdp
, info
, &req
);
402 DEFINE_MUTEX(mdp_ppp_lock
);
404 static int msmfb_ioctl(struct fb_info
*p
, unsigned int cmd
, unsigned long arg
)
406 void __user
*argp
= (void __user
*)arg
;
411 mdp
->set_grp_disp(mdp
, arg
);
414 ret
= msmfb_blit(p
, argp
);
419 printk(KERN_INFO
"msmfb unknown ioctl: %d\n", cmd
);
425 static struct fb_ops msmfb_ops
= {
426 .owner
= THIS_MODULE
,
427 .fb_open
= msmfb_open
,
428 .fb_release
= msmfb_release
,
429 .fb_check_var
= msmfb_check_var
,
430 .fb_pan_display
= msmfb_pan_display
,
431 .fb_fillrect
= msmfb_fillrect
,
432 .fb_copyarea
= msmfb_copyarea
,
433 .fb_imageblit
= msmfb_imageblit
,
434 .fb_ioctl
= msmfb_ioctl
,
437 static unsigned PP
[16];
441 #define BITS_PER_PIXEL 16
443 static void setup_fb_info(struct msmfb_info
*msmfb
)
445 struct fb_info
*fb_info
= msmfb
->fb
;
448 /* finish setting up the fb_info struct */
449 strncpy(fb_info
->fix
.id
, "msmfb", 16);
450 fb_info
->fix
.ypanstep
= 1;
452 fb_info
->fbops
= &msmfb_ops
;
453 fb_info
->flags
= FBINFO_DEFAULT
;
455 fb_info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
456 fb_info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
457 fb_info
->fix
.line_length
= msmfb
->xres
* 2;
459 fb_info
->var
.xres
= msmfb
->xres
;
460 fb_info
->var
.yres
= msmfb
->yres
;
461 fb_info
->var
.width
= msmfb
->panel
->fb_data
->width
;
462 fb_info
->var
.height
= msmfb
->panel
->fb_data
->height
;
463 fb_info
->var
.xres_virtual
= msmfb
->xres
;
464 fb_info
->var
.yres_virtual
= msmfb
->yres
* 2;
465 fb_info
->var
.bits_per_pixel
= BITS_PER_PIXEL
;
466 fb_info
->var
.accel_flags
= 0;
468 fb_info
->var
.yoffset
= 0;
470 if (msmfb
->panel
->caps
& MSMFB_CAP_PARTIAL_UPDATES
) {
472 * Set the param in the fixed screen, so userspace can't
473 * change it. This will be used to check for the
476 fb_info
->fix
.reserved
[0] = 0x5444;
477 fb_info
->fix
.reserved
[1] = 0x5055;
480 * This preloads the value so that if userspace doesn't
481 * change it, it will be a full update
483 fb_info
->var
.reserved
[0] = 0x54445055;
484 fb_info
->var
.reserved
[1] = 0;
485 fb_info
->var
.reserved
[2] = (uint16_t)msmfb
->xres
|
486 ((uint32_t)msmfb
->yres
<< 16);
489 fb_info
->var
.red
.offset
= 11;
490 fb_info
->var
.red
.length
= 5;
491 fb_info
->var
.red
.msb_right
= 0;
492 fb_info
->var
.green
.offset
= 5;
493 fb_info
->var
.green
.length
= 6;
494 fb_info
->var
.green
.msb_right
= 0;
495 fb_info
->var
.blue
.offset
= 0;
496 fb_info
->var
.blue
.length
= 5;
497 fb_info
->var
.blue
.msb_right
= 0;
499 r
= fb_alloc_cmap(&fb_info
->cmap
, 16, 0);
500 fb_info
->pseudo_palette
= PP
;
503 for (r
= 1; r
< 16; r
++)
507 static int setup_fbmem(struct msmfb_info
*msmfb
, struct platform_device
*pdev
)
509 struct fb_info
*fb
= msmfb
->fb
;
510 struct resource
*resource
;
511 unsigned long size
= msmfb
->xres
* msmfb
->yres
*
512 (BITS_PER_PIXEL
>> 3) * 2;
513 unsigned char *fbram
;
515 /* board file might have attached a resource describing an fb */
516 resource
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
520 /* check the resource is large enough to fit the fb */
521 if (resource
->end
- resource
->start
< size
) {
522 printk(KERN_ERR
"allocated resource is too small for "
526 fb
->fix
.smem_start
= resource
->start
;
527 fb
->fix
.smem_len
= resource_size(resource
);
528 fbram
= ioremap(resource
->start
, resource_size(resource
));
530 printk(KERN_ERR
"msmfb: cannot allocate fbram!\n");
533 fb
->screen_base
= fbram
;
537 static int msmfb_probe(struct platform_device
*pdev
)
540 struct msmfb_info
*msmfb
;
541 struct msm_panel_data
*panel
= pdev
->dev
.platform_data
;
545 pr_err("msmfb_probe: no platform data\n");
548 if (!panel
->fb_data
) {
549 pr_err("msmfb_probe: no fb_data\n");
553 fb
= framebuffer_alloc(sizeof(struct msmfb_info
), &pdev
->dev
);
558 msmfb
->panel
= panel
;
559 msmfb
->xres
= panel
->fb_data
->xres
;
560 msmfb
->yres
= panel
->fb_data
->yres
;
562 ret
= setup_fbmem(msmfb
, pdev
);
564 goto error_setup_fbmem
;
566 setup_fb_info(msmfb
);
568 spin_lock_init(&msmfb
->update_lock
);
569 mutex_init(&msmfb
->panel_init_lock
);
570 init_waitqueue_head(&msmfb
->frame_wq
);
571 INIT_WORK(&msmfb
->resume_work
, power_on_panel
);
572 msmfb
->black
= kzalloc(msmfb
->fb
->var
.bits_per_pixel
*msmfb
->xres
,
575 printk(KERN_INFO
"msmfb_probe() installing %d x %d panel\n",
576 msmfb
->xres
, msmfb
->yres
);
578 msmfb
->dma_callback
.func
= msmfb_handle_dma_interrupt
;
579 msmfb
->vsync_callback
.func
= msmfb_handle_vsync_interrupt
;
580 hrtimer_init(&msmfb
->fake_vsync
, CLOCK_MONOTONIC
,
584 msmfb
->fake_vsync
.function
= msmfb_fake_vsync
;
586 ret
= register_framebuffer(fb
);
588 goto error_register_framebuffer
;
590 msmfb
->sleeping
= WAKING
;
594 error_register_framebuffer
:
595 iounmap(fb
->screen_base
);
597 framebuffer_release(msmfb
->fb
);
601 static struct platform_driver msm_panel_driver
= {
602 /* need to write remove */
603 .probe
= msmfb_probe
,
604 .driver
= {.name
= "msm_panel"},
608 static int msmfb_add_mdp_device(struct device
*dev
,
609 struct class_interface
*class_intf
)
611 /* might need locking if mulitple mdp devices */
614 mdp
= container_of(dev
, struct mdp_device
, dev
);
615 return platform_driver_register(&msm_panel_driver
);
618 static void msmfb_remove_mdp_device(struct device
*dev
,
619 struct class_interface
*class_intf
)
621 /* might need locking if mulitple mdp devices */
622 if (dev
!= &mdp
->dev
)
624 platform_driver_unregister(&msm_panel_driver
);
628 static struct class_interface msm_fb_interface
= {
629 .add_dev
= &msmfb_add_mdp_device
,
630 .remove_dev
= &msmfb_remove_mdp_device
,
633 static int __init
msmfb_init(void)
635 return register_mdp_client(&msm_fb_interface
);
638 module_init(msmfb_init
);