1/* drivers/video/msm/msm_fb.c 2 * 3 * Core MSM framebuffer driver. 4 * 5 * Copyright (C) 2007 Google Incorporated 6 * 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. 10 * 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. 15 */ 16 17#include <linux/platform_device.h> 18#include <linux/module.h> 19#include <linux/fb.h> 20#include <linux/slab.h> 21#include <linux/delay.h> 22 23#include <linux/freezer.h> 24#include <linux/wait.h> 25#include <linux/msm_mdp.h> 26#include <linux/io.h> 27#include <linux/uaccess.h> 28#include <mach/msm_fb.h> 29#include <mach/board.h> 30#include <linux/workqueue.h> 31#include <linux/clk.h> 32#include <linux/debugfs.h> 33#include <linux/dma-mapping.h> 34 35#define PRINT_FPS 0 36#define PRINT_BLIT_TIME 0 37 38#define SLEEPING 0x4 39#define UPDATING 0x3 40#define FULL_UPDATE_DONE 0x2 41#define WAKING 0x1 42#define AWAKE 0x0 43 44#define NONE 0 45#define SUSPEND_RESUME 0x1 46#define FPS 0x2 47#define BLIT_TIME 0x4 48#define SHOW_UPDATES 0x8 49 50#define DLOG(mask, fmt, args...) \ 51do { \ 52 if (msmfb_debug_mask & mask) \ 53 printk(KERN_INFO "msmfb: "fmt, ##args); \ 54} while (0) 55 56static int msmfb_debug_mask; 57module_param_named(msmfb_debug_mask, msmfb_debug_mask, int, 58 S_IRUGO | S_IWUSR | S_IWGRP); 59 60struct mdp_device *mdp; 61 62struct msmfb_info { 63 struct fb_info *fb; 64 struct msm_panel_data *panel; 65 int xres; 66 int yres; 67 unsigned output_format; 68 unsigned yoffset; 69 unsigned frame_requested; 70 unsigned frame_done; 71 int sleeping; 72 unsigned update_frame; 73 struct { 74 int left; 75 int top; 76 int eright; /* exclusive */ 77 int ebottom; /* exclusive */ 78 } update_info; 79 char *black; 80 81 spinlock_t update_lock; 82 struct mutex panel_init_lock; 83 wait_queue_head_t frame_wq; 84 struct workqueue_struct *resume_workqueue; 85 struct work_struct resume_work; 86 struct msmfb_callback dma_callback; 87 struct msmfb_callback vsync_callback; 88 struct hrtimer fake_vsync; 89 ktime_t vsync_request_time; 90}; 91 92static int msmfb_open(struct fb_info *info, int user) 93{ 94 return 0; 95} 96 97static int msmfb_release(struct fb_info *info, int user) 98{ 99 return 0; 100} 101 102/* Called from dma interrupt handler, must not sleep */ 103static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) 104{ 105 unsigned long irq_flags; 106 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, 107 dma_callback); 108 109 spin_lock_irqsave(&msmfb->update_lock, irq_flags); 110 msmfb->frame_done = msmfb->frame_requested; 111 if (msmfb->sleeping == UPDATING && 112 msmfb->frame_done == msmfb->update_frame) { 113 DLOG(SUSPEND_RESUME, "full update completed\n"); 114 queue_work(msmfb->resume_workqueue, &msmfb->resume_work); 115 } 116 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 117 wake_up(&msmfb->frame_wq); 118} 119 120static int msmfb_start_dma(struct msmfb_info *msmfb) 121{ 122 uint32_t x, y, w, h; 123 unsigned addr; 124 unsigned long irq_flags; 125 uint32_t yoffset; 126 s64 time_since_request; 127 struct msm_panel_data *panel = msmfb->panel; 128 129 spin_lock_irqsave(&msmfb->update_lock, irq_flags); 130 time_since_request = ktime_to_ns(ktime_sub(ktime_get(), 131 msmfb->vsync_request_time)); 132 if (time_since_request > 20 * NSEC_PER_MSEC) { 133 uint32_t us; 134 us = do_div(time_since_request, NSEC_PER_MSEC) / NSEC_PER_USEC; 135 printk(KERN_WARNING "msmfb_start_dma %lld.%03u ms after vsync " 136 "request\n", time_since_request, us); 137 } 138 if (msmfb->frame_done == msmfb->frame_requested) { 139 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 140 return -1; 141 } 142 if (msmfb->sleeping == SLEEPING) { 143 DLOG(SUSPEND_RESUME, "tried to start dma while asleep\n"); 144 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 145 return -1; 146 } 147 x = msmfb->update_info.left; 148 y = msmfb->update_info.top; 149 w = msmfb->update_info.eright - x; 150 h = msmfb->update_info.ebottom - y; 151 yoffset = msmfb->yoffset; 152 msmfb->update_info.left = msmfb->xres + 1; 153 msmfb->update_info.top = msmfb->yres + 1; 154 msmfb->update_info.eright = 0; 155 msmfb->update_info.ebottom = 0; 156 if (unlikely(w > msmfb->xres || h > msmfb->yres || 157 w == 0 || h == 0)) { 158 printk(KERN_INFO "invalid update: %d %d %d " 159 "%d\n", x, y, w, h); 160 msmfb->frame_done = msmfb->frame_requested; 161 goto error; 162 } 163 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 164 165 addr = ((msmfb->xres * (yoffset + y) + x) * 2); 166 mdp->dma(mdp, addr + msmfb->fb->fix.smem_start, 167 msmfb->xres * 2, w, h, x, y, &msmfb->dma_callback, 168 panel->interface_type); 169 return 0; 170error: 171 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 172 /* some clients need to clear their vsync interrupt */ 173 if (panel->clear_vsync) 174 panel->clear_vsync(panel); 175 wake_up(&msmfb->frame_wq); 176 return 0; 177} 178 179/* Called from esync interrupt handler, must not sleep */ 180static void msmfb_handle_vsync_interrupt(struct msmfb_callback *callback) 181{ 182 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, 183 vsync_callback); 184 msmfb_start_dma(msmfb); 185} 186 187static enum hrtimer_restart msmfb_fake_vsync(struct hrtimer *timer) 188{ 189 struct msmfb_info *msmfb = container_of(timer, struct msmfb_info, 190 fake_vsync); 191 msmfb_start_dma(msmfb); 192 return HRTIMER_NORESTART; 193} 194 195static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top, 196 uint32_t eright, uint32_t ebottom, 197 uint32_t yoffset, int pan_display) 198{ 199 struct msmfb_info *msmfb = info->par; 200 struct msm_panel_data *panel = msmfb->panel; 201 unsigned long irq_flags; 202 int sleeping; 203 int retry = 1; 204 205 DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n", 206 left, top, eright, ebottom, yoffset, pan_display); 207restart: 208 spin_lock_irqsave(&msmfb->update_lock, irq_flags); 209 210 /* if we are sleeping, on a pan_display wait 10ms (to throttle back 211 * drawing otherwise return */ 212 if (msmfb->sleeping == SLEEPING) { 213 DLOG(SUSPEND_RESUME, "drawing while asleep\n"); 214 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 215 if (pan_display) 216 wait_event_interruptible_timeout(msmfb->frame_wq, 217 msmfb->sleeping != SLEEPING, HZ/10); 218 return; 219 } 220 221 sleeping = msmfb->sleeping; 222 /* on a full update, if the last frame has not completed, wait for it */ 223 if (pan_display && (msmfb->frame_requested != msmfb->frame_done || 224 sleeping == UPDATING)) { 225 int ret; 226 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 227 ret = wait_event_interruptible_timeout(msmfb->frame_wq, 228 msmfb->frame_done == msmfb->frame_requested && 229 msmfb->sleeping != UPDATING, 5 * HZ); 230 if (ret <= 0 && (msmfb->frame_requested != msmfb->frame_done || 231 msmfb->sleeping == UPDATING)) { 232 if (retry && panel->request_vsync && 233 (sleeping == AWAKE)) { 234 panel->request_vsync(panel, 235 &msmfb->vsync_callback); 236 retry = 0; 237 printk(KERN_WARNING "msmfb_pan_display timeout " 238 "rerequest vsync\n"); 239 } else { 240 printk(KERN_WARNING "msmfb_pan_display timeout " 241 "waiting for frame start, %d %d\n", 242 msmfb->frame_requested, 243 msmfb->frame_done); 244 return; 245 } 246 } 247 goto restart; 248 } 249 250 251 msmfb->frame_requested++; 252 /* if necessary, update the y offset, if this is the 253 * first full update on resume, set the sleeping state */ 254 if (pan_display) { 255 msmfb->yoffset = yoffset; 256 if (left == 0 && top == 0 && eright == info->var.xres && 257 ebottom == info->var.yres) { 258 if (sleeping == WAKING) { 259 msmfb->update_frame = msmfb->frame_requested; 260 DLOG(SUSPEND_RESUME, "full update starting\n"); 261 msmfb->sleeping = UPDATING; 262 } 263 } 264 } 265 266 /* set the update request */ 267 if (left < msmfb->update_info.left) 268 msmfb->update_info.left = left; 269 if (top < msmfb->update_info.top) 270 msmfb->update_info.top = top; 271 if (eright > msmfb->update_info.eright) 272 msmfb->update_info.eright = eright; 273 if (ebottom > msmfb->update_info.ebottom) 274 msmfb->update_info.ebottom = ebottom; 275 DLOG(SHOW_UPDATES, "update queued %d %d %d %d %d\n", 276 msmfb->update_info.left, msmfb->update_info.top, 277 msmfb->update_info.eright, msmfb->update_info.ebottom, 278 msmfb->yoffset); 279 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 280 281 /* if the panel is all the way on wait for vsync, otherwise sleep 282 * for 16 ms (long enough for the dma to panel) and then begin dma */ 283 msmfb->vsync_request_time = ktime_get(); 284 if (panel->request_vsync && (sleeping == AWAKE)) { 285 panel->request_vsync(panel, &msmfb->vsync_callback); 286 } else { 287 if (!hrtimer_active(&msmfb->fake_vsync)) { 288 hrtimer_start(&msmfb->fake_vsync, 289 ktime_set(0, NSEC_PER_SEC/60), 290 HRTIMER_MODE_REL); 291 } 292 } 293} 294 295static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top, 296 uint32_t eright, uint32_t ebottom) 297{ 298 msmfb_pan_update(info, left, top, eright, ebottom, 0, 0); 299} 300 301static void power_on_panel(struct work_struct *work) 302{ 303 struct msmfb_info *msmfb = 304 container_of(work, struct msmfb_info, resume_work); 305 struct msm_panel_data *panel = msmfb->panel; 306 unsigned long irq_flags; 307 308 mutex_lock(&msmfb->panel_init_lock); 309 DLOG(SUSPEND_RESUME, "turning on panel\n"); 310 if (msmfb->sleeping == UPDATING) { 311 if (panel->unblank(panel)) { 312 printk(KERN_INFO "msmfb: panel unblank failed," 313 "not starting drawing\n"); 314 goto error; 315 } 316 spin_lock_irqsave(&msmfb->update_lock, irq_flags); 317 msmfb->sleeping = AWAKE; 318 wake_up(&msmfb->frame_wq); 319 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 320 } 321error: 322 mutex_unlock(&msmfb->panel_init_lock); 323} 324 325 326static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 327{ 328 if ((var->xres != info->var.xres) || 329 (var->yres != info->var.yres) || 330 (var->xres_virtual != info->var.xres_virtual) || 331 (var->yres_virtual != info->var.yres_virtual) || 332 (var->xoffset != info->var.xoffset) || 333 (var->bits_per_pixel != info->var.bits_per_pixel) || 334 (var->grayscale != info->var.grayscale)) 335 return -EINVAL; 336 return 0; 337} 338 339int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 340{ 341 struct msmfb_info *msmfb = info->par; 342 struct msm_panel_data *panel = msmfb->panel; 343 344 /* "UPDT" */ 345 if ((panel->caps & MSMFB_CAP_PARTIAL_UPDATES) && 346 (var->reserved[0] == 0x54445055)) { 347 msmfb_pan_update(info, var->reserved[1] & 0xffff, 348 var->reserved[1] >> 16, 349 var->reserved[2] & 0xffff, 350 var->reserved[2] >> 16, var->yoffset, 1); 351 } else { 352 msmfb_pan_update(info, 0, 0, info->var.xres, info->var.yres, 353 var->yoffset, 1); 354 } 355 return 0; 356} 357 358static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 359{ 360 cfb_fillrect(p, rect); 361 msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width, 362 rect->dy + rect->height); 363} 364 365static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 366{ 367 cfb_copyarea(p, area); 368 msmfb_update(p, area->dx, area->dy, area->dx + area->width, 369 area->dy + area->height); 370} 371 372static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image) 373{ 374 cfb_imageblit(p, image); 375 msmfb_update(p, image->dx, image->dy, image->dx + image->width, 376 image->dy + image->height); 377} 378 379 380static int msmfb_blit(struct fb_info *info, 381 void __user *p) 382{ 383 struct mdp_blit_req req; 384 struct mdp_blit_req_list req_list; 385 int i; 386 int ret; 387 388 if (copy_from_user(&req_list, p, sizeof(req_list))) 389 return -EFAULT; 390 391 for (i = 0; i < req_list.count; i++) { 392 struct mdp_blit_req_list *list = 393 (struct mdp_blit_req_list *)p; 394 if (copy_from_user(&req, &list->req[i], sizeof(req))) 395 return -EFAULT; 396 ret = mdp->blit(mdp, info, &req); 397 if (ret) 398 return ret; 399 } 400 return 0; 401} 402 403 404DEFINE_MUTEX(mdp_ppp_lock); 405 406static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) 407{ 408 void __user *argp = (void __user *)arg; 409 int ret; 410 411 switch (cmd) { 412 case MSMFB_GRP_DISP: 413 mdp->set_grp_disp(mdp, arg); 414 break; 415 case MSMFB_BLIT: 416 ret = msmfb_blit(p, argp); 417 if (ret) 418 return ret; 419 break; 420 default: 421 printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd); 422 return -EINVAL; 423 } 424 return 0; 425} 426 427static struct fb_ops msmfb_ops = { 428 .owner = THIS_MODULE, 429 .fb_open = msmfb_open, 430 .fb_release = msmfb_release, 431 .fb_check_var = msmfb_check_var, 432 .fb_pan_display = msmfb_pan_display, 433 .fb_fillrect = msmfb_fillrect, 434 .fb_copyarea = msmfb_copyarea, 435 .fb_imageblit = msmfb_imageblit, 436 .fb_ioctl = msmfb_ioctl, 437}; 438 439static unsigned PP[16]; 440 441 442 443#define BITS_PER_PIXEL 16 444 445static void setup_fb_info(struct msmfb_info *msmfb) 446{ 447 struct fb_info *fb_info = msmfb->fb; 448 int r; 449 450 /* finish setting up the fb_info struct */ 451 strncpy(fb_info->fix.id, "msmfb", 16); 452 fb_info->fix.ypanstep = 1; 453 454 fb_info->fbops = &msmfb_ops; 455 fb_info->flags = FBINFO_DEFAULT; 456 457 fb_info->fix.type = FB_TYPE_PACKED_PIXELS; 458 fb_info->fix.visual = FB_VISUAL_TRUECOLOR; 459 fb_info->fix.line_length = msmfb->xres * 2; 460 461 fb_info->var.xres = msmfb->xres; 462 fb_info->var.yres = msmfb->yres; 463 fb_info->var.width = msmfb->panel->fb_data->width; 464 fb_info->var.height = msmfb->panel->fb_data->height; 465 fb_info->var.xres_virtual = msmfb->xres; 466 fb_info->var.yres_virtual = msmfb->yres * 2; 467 fb_info->var.bits_per_pixel = BITS_PER_PIXEL; 468 fb_info->var.accel_flags = 0; 469 470 fb_info->var.yoffset = 0; 471 472 if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) { 473 fb_info->var.reserved[0] = 0x54445055; 474 fb_info->var.reserved[1] = 0; 475 fb_info->var.reserved[2] = (uint16_t)msmfb->xres | 476 ((uint32_t)msmfb->yres << 16); 477 } 478 479 fb_info->var.red.offset = 11; 480 fb_info->var.red.length = 5; 481 fb_info->var.red.msb_right = 0; 482 fb_info->var.green.offset = 5; 483 fb_info->var.green.length = 6; 484 fb_info->var.green.msb_right = 0; 485 fb_info->var.blue.offset = 0; 486 fb_info->var.blue.length = 5; 487 fb_info->var.blue.msb_right = 0; 488 489 r = fb_alloc_cmap(&fb_info->cmap, 16, 0); 490 fb_info->pseudo_palette = PP; 491 492 PP[0] = 0; 493 for (r = 1; r < 16; r++) 494 PP[r] = 0xffffffff; 495} 496 497static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev) 498{ 499 struct fb_info *fb = msmfb->fb; 500 struct resource *resource; 501 unsigned long size = msmfb->xres * msmfb->yres * 502 (BITS_PER_PIXEL >> 3) * 2; 503 unsigned char *fbram; 504 505 /* board file might have attached a resource describing an fb */ 506 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 507 if (!resource) 508 return -EINVAL; 509 510 /* check the resource is large enough to fit the fb */ 511 if (resource->end - resource->start < size) { 512 printk(KERN_ERR "allocated resource is too small for " 513 "fb\n"); 514 return -ENOMEM; 515 } 516 fb->fix.smem_start = resource->start; 517 fb->fix.smem_len = resource->end - resource->start; 518 fbram = ioremap(resource->start, 519 resource->end - resource->start); 520 if (fbram == 0) { 521 printk(KERN_ERR "msmfb: cannot allocate fbram!\n"); 522 return -ENOMEM; 523 } 524 fb->screen_base = fbram; 525 return 0; 526} 527 528static int msmfb_probe(struct platform_device *pdev) 529{ 530 struct fb_info *fb; 531 struct msmfb_info *msmfb; 532 struct msm_panel_data *panel = pdev->dev.platform_data; 533 int ret; 534 535 if (!panel) { 536 pr_err("msmfb_probe: no platform data\n"); 537 return -EINVAL; 538 } 539 if (!panel->fb_data) { 540 pr_err("msmfb_probe: no fb_data\n"); 541 return -EINVAL; 542 } 543 544 fb = framebuffer_alloc(sizeof(struct msmfb_info), &pdev->dev); 545 if (!fb) 546 return -ENOMEM; 547 msmfb = fb->par; 548 msmfb->fb = fb; 549 msmfb->panel = panel; 550 msmfb->xres = panel->fb_data->xres; 551 msmfb->yres = panel->fb_data->yres; 552 553 ret = setup_fbmem(msmfb, pdev); 554 if (ret) 555 goto error_setup_fbmem; 556 557 setup_fb_info(msmfb); 558 559 spin_lock_init(&msmfb->update_lock); 560 mutex_init(&msmfb->panel_init_lock); 561 init_waitqueue_head(&msmfb->frame_wq); 562 msmfb->resume_workqueue = create_workqueue("panel_on"); 563 if (msmfb->resume_workqueue == NULL) { 564 printk(KERN_ERR "failed to create panel_on workqueue\n"); 565 ret = -ENOMEM; 566 goto error_create_workqueue; 567 } 568 INIT_WORK(&msmfb->resume_work, power_on_panel); 569 msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres, 570 GFP_KERNEL); 571 572 printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n", 573 msmfb->xres, msmfb->yres); 574 575 msmfb->dma_callback.func = msmfb_handle_dma_interrupt; 576 msmfb->vsync_callback.func = msmfb_handle_vsync_interrupt; 577 hrtimer_init(&msmfb->fake_vsync, CLOCK_MONOTONIC, 578 HRTIMER_MODE_REL); 579 580 581 msmfb->fake_vsync.function = msmfb_fake_vsync; 582 583 ret = register_framebuffer(fb); 584 if (ret) 585 goto error_register_framebuffer; 586 587 msmfb->sleeping = WAKING; 588 589 return 0; 590 591error_register_framebuffer: 592 destroy_workqueue(msmfb->resume_workqueue); 593error_create_workqueue: 594 iounmap(fb->screen_base); 595error_setup_fbmem: 596 framebuffer_release(msmfb->fb); 597 return ret; 598} 599 600static struct platform_driver msm_panel_driver = { 601 /* need to write remove */ 602 .probe = msmfb_probe, 603 .driver = {.name = "msm_panel"}, 604}; 605 606 607static int msmfb_add_mdp_device(struct device *dev, 608 struct class_interface *class_intf) 609{ 610 /* might need locking if mulitple mdp devices */ 611 if (mdp) 612 return 0; 613 mdp = container_of(dev, struct mdp_device, dev); 614 return platform_driver_register(&msm_panel_driver); 615} 616 617static void msmfb_remove_mdp_device(struct device *dev, 618 struct class_interface *class_intf) 619{ 620 /* might need locking if mulitple mdp devices */ 621 if (dev != &mdp->dev) 622 return; 623 platform_driver_unregister(&msm_panel_driver); 624 mdp = NULL; 625} 626 627static struct class_interface msm_fb_interface = { 628 .add_dev = &msmfb_add_mdp_device, 629 .remove_dev = &msmfb_remove_mdp_device, 630}; 631 632static int __init msmfb_init(void) 633{ 634 return register_mdp_client(&msm_fb_interface); 635} 636 637module_init(msmfb_init); 638