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 <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> 33 34#define PRINT_FPS 0 35#define PRINT_BLIT_TIME 0 36 37#define SLEEPING 0x4 38#define UPDATING 0x3 39#define FULL_UPDATE_DONE 0x2 40#define WAKING 0x1 41#define AWAKE 0x0 42 43#define NONE 0 44#define SUSPEND_RESUME 0x1 45#define FPS 0x2 46#define BLIT_TIME 0x4 47#define SHOW_UPDATES 0x8 48 49#define DLOG(mask, fmt, args...) \ 50do { \ 51 if (msmfb_debug_mask & mask) \ 52 printk(KERN_INFO "msmfb: "fmt, ##args); \ 53} while (0) 54 55static int msmfb_debug_mask; 56module_param_named(msmfb_debug_mask, msmfb_debug_mask, int, 57 S_IRUGO | S_IWUSR | S_IWGRP); 58 59struct mdp_device *mdp; 60 61struct msmfb_info { 62 struct fb_info *fb; 63 struct msm_panel_data *panel; 64 int xres; 65 int yres; 66 unsigned output_format; 67 unsigned yoffset; 68 unsigned frame_requested; 69 unsigned frame_done; 70 int sleeping; 71 unsigned update_frame; 72 struct { 73 int left; 74 int top; 75 int eright; /* exclusive */ 76 int ebottom; /* exclusive */ 77 } update_info; 78 char *black; 79 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; 88}; 89 90static int msmfb_open(struct fb_info *info, int user) 91{ 92 return 0; 93} 94 95static int msmfb_release(struct fb_info *info, int user) 96{ 97 return 0; 98} 99 100/* Called from dma interrupt handler, must not sleep */ 101static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) 102{ 103 unsigned long irq_flags; 104 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, 105 dma_callback); 106 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); 113 } 114 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 115 wake_up(&msmfb->frame_wq); 116} 117 118static int msmfb_start_dma(struct msmfb_info *msmfb) 119{ 120 uint32_t x, y, w, h; 121 unsigned addr; 122 unsigned long irq_flags; 123 uint32_t yoffset; 124 s64 time_since_request; 125 struct msm_panel_data *panel = msmfb->panel; 126 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) { 131 uint32_t us; 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); 135 } 136 if (msmfb->frame_done == msmfb->frame_requested) { 137 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 138 return -1; 139 } 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); 143 return -1; 144 } 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 || 155 w == 0 || h == 0)) { 156 printk(KERN_INFO "invalid update: %d %d %d " 157 "%d\n", x, y, w, h); 158 msmfb->frame_done = msmfb->frame_requested; 159 goto error; 160 } 161 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 162 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); 167 return 0; 168error: 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); 174 return 0; 175} 176 177/* Called from esync interrupt handler, must not sleep */ 178static void msmfb_handle_vsync_interrupt(struct msmfb_callback *callback) 179{ 180 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info, 181 vsync_callback); 182 msmfb_start_dma(msmfb); 183} 184 185static enum hrtimer_restart msmfb_fake_vsync(struct hrtimer *timer) 186{ 187 struct msmfb_info *msmfb = container_of(timer, struct msmfb_info, 188 fake_vsync); 189 msmfb_start_dma(msmfb); 190 return HRTIMER_NORESTART; 191} 192 193static 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) 196{ 197 struct msmfb_info *msmfb = info->par; 198 struct msm_panel_data *panel = msmfb->panel; 199 unsigned long irq_flags; 200 int sleeping; 201 int retry = 1; 202 203 DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n", 204 left, top, eright, ebottom, yoffset, pan_display); 205restart: 206 spin_lock_irqsave(&msmfb->update_lock, irq_flags); 207 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); 213 if (pan_display) 214 wait_event_interruptible_timeout(msmfb->frame_wq, 215 msmfb->sleeping != SLEEPING, HZ/10); 216 return; 217 } 218 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) { 223 int ret; 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); 234 retry = 0; 235 printk(KERN_WARNING "msmfb_pan_display timeout " 236 "rerequest vsync\n"); 237 } else { 238 printk(KERN_WARNING "msmfb_pan_display timeout " 239 "waiting for frame start, %d %d\n", 240 msmfb->frame_requested, 241 msmfb->frame_done); 242 return; 243 } 244 } 245 goto restart; 246 } 247 248 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 */ 252 if (pan_display) { 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; 260 } 261 } 262 } 263 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, 276 msmfb->yoffset); 277 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); 278 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); 284 } else { 285 if (!hrtimer_active(&msmfb->fake_vsync)) { 286 hrtimer_start(&msmfb->fake_vsync, 287 ktime_set(0, NSEC_PER_SEC/60), 288 HRTIMER_MODE_REL); 289 } 290 } 291} 292 293static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top, 294 uint32_t eright, uint32_t ebottom) 295{ 296 msmfb_pan_update(info, left, top, eright, ebottom, 0, 0); 297} 298 299static void power_on_panel(struct work_struct *work) 300{ 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; 305 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"); 312 goto error; 313 } 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); 318 } 319error: 320 mutex_unlock(&msmfb->panel_init_lock); 321} 322 323 324static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 325{ 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)) 333 return -EINVAL; 334 return 0; 335} 336 337int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 338{ 339 struct msmfb_info *msmfb = info->par; 340 struct msm_panel_data *panel = msmfb->panel; 341 342 /* "UPDT" */ 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); 349 } else { 350 msmfb_pan_update(info, 0, 0, info->var.xres, info->var.yres, 351 var->yoffset, 1); 352 } 353 return 0; 354} 355 356static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 357{ 358 cfb_fillrect(p, rect); 359 msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width, 360 rect->dy + rect->height); 361} 362 363static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 364{ 365 cfb_copyarea(p, area); 366 msmfb_update(p, area->dx, area->dy, area->dx + area->width, 367 area->dy + area->height); 368} 369 370static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image) 371{ 372 cfb_imageblit(p, image); 373 msmfb_update(p, image->dx, image->dy, image->dx + image->width, 374 image->dy + image->height); 375} 376 377 378static int msmfb_blit(struct fb_info *info, 379 void __user *p) 380{ 381 struct mdp_blit_req req; 382 struct mdp_blit_req_list req_list; 383 int i; 384 int ret; 385 386 if (copy_from_user(&req_list, p, sizeof(req_list))) 387 return -EFAULT; 388 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))) 393 return -EFAULT; 394 ret = mdp->blit(mdp, info, &req); 395 if (ret) 396 return ret; 397 } 398 return 0; 399} 400 401 402DEFINE_MUTEX(mdp_ppp_lock); 403 404static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) 405{ 406 void __user *argp = (void __user *)arg; 407 int ret; 408 409 switch (cmd) { 410 case MSMFB_GRP_DISP: 411 mdp->set_grp_disp(mdp, arg); 412 break; 413 case MSMFB_BLIT: 414 ret = msmfb_blit(p, argp); 415 if (ret) 416 return ret; 417 break; 418 default: 419 printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd); 420 return -EINVAL; 421 } 422 return 0; 423} 424 425static 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, 435}; 436 437static unsigned PP[16]; 438 439 440 441#define BITS_PER_PIXEL 16 442 443static void setup_fb_info(struct msmfb_info *msmfb) 444{ 445 struct fb_info *fb_info = msmfb->fb; 446 int r; 447 448 /* finish setting up the fb_info struct */ 449 strncpy(fb_info->fix.id, "msmfb", 16); 450 fb_info->fix.ypanstep = 1; 451 452 fb_info->fbops = &msmfb_ops; 453 fb_info->flags = FBINFO_DEFAULT; 454 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; 458 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; 467 468 fb_info->var.yoffset = 0; 469 470 if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) { 471 /* 472 * Set the param in the fixed screen, so userspace can't 473 * change it. This will be used to check for the 474 * capability. 475 */ 476 fb_info->fix.reserved[0] = 0x5444; 477 fb_info->fix.reserved[1] = 0x5055; 478 479 /* 480 * This preloads the value so that if userspace doesn't 481 * change it, it will be a full update 482 */ 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); 487 } 488 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; 498 499 r = fb_alloc_cmap(&fb_info->cmap, 16, 0); 500 fb_info->pseudo_palette = PP; 501 502 PP[0] = 0; 503 for (r = 1; r < 16; r++) 504 PP[r] = 0xffffffff; 505} 506 507static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev) 508{ 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; 514 515 /* board file might have attached a resource describing an fb */ 516 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 517 if (!resource) 518 return -EINVAL; 519 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 " 523 "fb\n"); 524 return -ENOMEM; 525 } 526 fb->fix.smem_start = resource->start; 527 fb->fix.smem_len = resource_size(resource); 528 fbram = ioremap(resource->start, resource_size(resource)); 529 if (fbram == NULL) { 530 printk(KERN_ERR "msmfb: cannot allocate fbram!\n"); 531 return -ENOMEM; 532 } 533 fb->screen_base = fbram; 534 return 0; 535} 536 537static int msmfb_probe(struct platform_device *pdev) 538{ 539 struct fb_info *fb; 540 struct msmfb_info *msmfb; 541 struct msm_panel_data *panel = pdev->dev.platform_data; 542 int ret; 543 544 if (!panel) { 545 pr_err("msmfb_probe: no platform data\n"); 546 return -EINVAL; 547 } 548 if (!panel->fb_data) { 549 pr_err("msmfb_probe: no fb_data\n"); 550 return -EINVAL; 551 } 552 553 fb = framebuffer_alloc(sizeof(struct msmfb_info), &pdev->dev); 554 if (!fb) 555 return -ENOMEM; 556 msmfb = fb->par; 557 msmfb->fb = fb; 558 msmfb->panel = panel; 559 msmfb->xres = panel->fb_data->xres; 560 msmfb->yres = panel->fb_data->yres; 561 562 ret = setup_fbmem(msmfb, pdev); 563 if (ret) 564 goto error_setup_fbmem; 565 566 setup_fb_info(msmfb); 567 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 = devm_kzalloc(&pdev->dev, 573 msmfb->fb->var.bits_per_pixel*msmfb->xres, 574 GFP_KERNEL); 575 if (!msmfb->black) { 576 ret = -ENOMEM; 577 goto error_register_framebuffer; 578 } 579 580 printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n", 581 msmfb->xres, msmfb->yres); 582 583 msmfb->dma_callback.func = msmfb_handle_dma_interrupt; 584 msmfb->vsync_callback.func = msmfb_handle_vsync_interrupt; 585 hrtimer_init(&msmfb->fake_vsync, CLOCK_MONOTONIC, 586 HRTIMER_MODE_REL); 587 588 589 msmfb->fake_vsync.function = msmfb_fake_vsync; 590 591 ret = register_framebuffer(fb); 592 if (ret) 593 goto error_register_framebuffer; 594 595 msmfb->sleeping = WAKING; 596 597 platform_set_drvdata(pdev, msmfb); 598 599 return 0; 600 601error_register_framebuffer: 602 iounmap(fb->screen_base); 603error_setup_fbmem: 604 framebuffer_release(msmfb->fb); 605 return ret; 606} 607 608static int msmfb_remove(struct platform_device *pdev) 609{ 610 struct msmfb_info *msmfb; 611 612 msmfb = platform_get_drvdata(pdev); 613 614 unregister_framebuffer(msmfb->fb); 615 iounmap(msmfb->fb->screen_base); 616 framebuffer_release(msmfb->fb); 617 618 return 0; 619} 620 621static struct platform_driver msm_panel_driver = { 622 /* need to write remove */ 623 .probe = msmfb_probe, 624 .remove = msmfb_remove, 625 .driver = {.name = "msm_panel"}, 626}; 627 628 629static int msmfb_add_mdp_device(struct device *dev, 630 struct class_interface *class_intf) 631{ 632 /* might need locking if mulitple mdp devices */ 633 if (mdp) 634 return 0; 635 mdp = container_of(dev, struct mdp_device, dev); 636 return platform_driver_register(&msm_panel_driver); 637} 638 639static void msmfb_remove_mdp_device(struct device *dev, 640 struct class_interface *class_intf) 641{ 642 /* might need locking if mulitple mdp devices */ 643 if (dev != &mdp->dev) 644 return; 645 platform_driver_unregister(&msm_panel_driver); 646 mdp = NULL; 647} 648 649static struct class_interface msm_fb_interface = { 650 .add_dev = &msmfb_add_mdp_device, 651 .remove_dev = &msmfb_remove_mdp_device, 652}; 653 654static int __init msmfb_init(void) 655{ 656 return register_mdp_client(&msm_fb_interface); 657} 658 659module_init(msmfb_init); 660