1 /* $NetBSD: vmwgfx_fb.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 3 /************************************************************************** 4 * 5 * Copyright 2007 David Airlie 6 * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 7 * All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the 11 * "Software"), to deal in the Software without restriction, including 12 * without limitation the rights to use, copy, modify, merge, publish, 13 * distribute, sub license, and/or sell copies of the Software, and to 14 * permit persons to whom the Software is furnished to do so, subject to 15 * the following conditions: 16 * 17 * The above copyright notice and this permission notice (including the 18 * next paragraph) shall be included in all copies or substantial portions 19 * of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 24 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 25 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 26 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 27 * USE OR OTHER DEALINGS IN THE SOFTWARE. 28 * 29 **************************************************************************/ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vmwgfx_fb.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 33 34 #include <linux/pci.h> 35 36 #include <drm/drm_fourcc.h> 37 #include <drm/ttm/ttm_placement.h> 38 39 #include "vmwgfx_drv.h" 40 #include "vmwgfx_kms.h" 41 42 #define VMW_DIRTY_DELAY (HZ / 30) 43 44 struct vmw_fb_par { 45 struct vmw_private *vmw_priv; 46 47 void *vmalloc; 48 49 struct mutex bo_mutex; 50 struct vmw_buffer_object *vmw_bo; 51 unsigned bo_size; 52 struct drm_framebuffer *set_fb; 53 struct drm_display_mode *set_mode; 54 u32 fb_x; 55 u32 fb_y; 56 bool bo_iowrite; 57 58 u32 pseudo_palette[17]; 59 60 unsigned max_width; 61 unsigned max_height; 62 63 struct { 64 spinlock_t lock; 65 bool active; 66 unsigned x1; 67 unsigned y1; 68 unsigned x2; 69 unsigned y2; 70 } dirty; 71 72 struct drm_crtc *crtc; 73 struct drm_connector *con; 74 struct delayed_work local_work; 75 }; 76 77 static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, 78 unsigned blue, unsigned transp, 79 struct fb_info *info) 80 { 81 struct vmw_fb_par *par = info->par; 82 u32 *pal = par->pseudo_palette; 83 84 if (regno > 15) { 85 DRM_ERROR("Bad regno %u.\n", regno); 86 return 1; 87 } 88 89 switch (par->set_fb->format->depth) { 90 case 24: 91 case 32: 92 pal[regno] = ((red & 0xff00) << 8) | 93 (green & 0xff00) | 94 ((blue & 0xff00) >> 8); 95 break; 96 default: 97 DRM_ERROR("Bad depth %u, bpp %u.\n", 98 par->set_fb->format->depth, 99 par->set_fb->format->cpp[0] * 8); 100 return 1; 101 } 102 103 return 0; 104 } 105 106 static int vmw_fb_check_var(struct fb_var_screeninfo *var, 107 struct fb_info *info) 108 { 109 int depth = var->bits_per_pixel; 110 struct vmw_fb_par *par = info->par; 111 struct vmw_private *vmw_priv = par->vmw_priv; 112 113 switch (var->bits_per_pixel) { 114 case 32: 115 depth = (var->transp.length > 0) ? 32 : 24; 116 break; 117 default: 118 DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); 119 return -EINVAL; 120 } 121 122 switch (depth) { 123 case 24: 124 var->red.offset = 16; 125 var->green.offset = 8; 126 var->blue.offset = 0; 127 var->red.length = 8; 128 var->green.length = 8; 129 var->blue.length = 8; 130 var->transp.length = 0; 131 var->transp.offset = 0; 132 break; 133 case 32: 134 var->red.offset = 16; 135 var->green.offset = 8; 136 var->blue.offset = 0; 137 var->red.length = 8; 138 var->green.length = 8; 139 var->blue.length = 8; 140 var->transp.length = 8; 141 var->transp.offset = 24; 142 break; 143 default: 144 DRM_ERROR("Bad depth %u.\n", depth); 145 return -EINVAL; 146 } 147 148 if ((var->xoffset + var->xres) > par->max_width || 149 (var->yoffset + var->yres) > par->max_height) { 150 DRM_ERROR("Requested geom can not fit in framebuffer\n"); 151 return -EINVAL; 152 } 153 154 if (!vmw_kms_validate_mode_vram(vmw_priv, 155 var->xres * var->bits_per_pixel/8, 156 var->yoffset + var->yres)) { 157 DRM_ERROR("Requested geom can not fit in framebuffer\n"); 158 return -EINVAL; 159 } 160 161 return 0; 162 } 163 164 static int vmw_fb_blank(int blank, struct fb_info *info) 165 { 166 return 0; 167 } 168 169 /** 170 * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer 171 * 172 * @work: The struct work_struct associated with this task. 173 * 174 * This function flushes the dirty regions of the vmalloc framebuffer to the 175 * kms framebuffer, and if the kms framebuffer is visible, also updated the 176 * corresponding displays. Note that this function runs even if the kms 177 * framebuffer is not bound to a crtc and thus not visible, but it's turned 178 * off during hibernation using the par->dirty.active bool. 179 */ 180 static void vmw_fb_dirty_flush(struct work_struct *work) 181 { 182 struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, 183 local_work.work); 184 struct vmw_private *vmw_priv = par->vmw_priv; 185 struct fb_info *info = vmw_priv->fb_info; 186 unsigned long irq_flags; 187 s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0; 188 u32 cpp, max_x, max_y; 189 struct drm_clip_rect clip; 190 struct drm_framebuffer *cur_fb; 191 u8 *src_ptr, *dst_ptr; 192 struct vmw_buffer_object *vbo = par->vmw_bo; 193 void *virtual; 194 195 if (!READ_ONCE(par->dirty.active)) 196 return; 197 198 mutex_lock(&par->bo_mutex); 199 cur_fb = par->set_fb; 200 if (!cur_fb) 201 goto out_unlock; 202 203 (void) ttm_read_lock(&vmw_priv->reservation_sem, false); 204 (void) ttm_bo_reserve(&vbo->base, false, false, NULL); 205 virtual = vmw_bo_map_and_cache(vbo); 206 if (!virtual) 207 goto out_unreserve; 208 209 spin_lock_irqsave(&par->dirty.lock, irq_flags); 210 if (!par->dirty.active) { 211 spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 212 goto out_unreserve; 213 } 214 215 /* 216 * Handle panning when copying from vmalloc to framebuffer. 217 * Clip dirty area to framebuffer. 218 */ 219 cpp = cur_fb->format->cpp[0]; 220 max_x = par->fb_x + cur_fb->width; 221 max_y = par->fb_y + cur_fb->height; 222 223 dst_x1 = par->dirty.x1 - par->fb_x; 224 dst_y1 = par->dirty.y1 - par->fb_y; 225 dst_x1 = max_t(s32, dst_x1, 0); 226 dst_y1 = max_t(s32, dst_y1, 0); 227 228 dst_x2 = par->dirty.x2 - par->fb_x; 229 dst_y2 = par->dirty.y2 - par->fb_y; 230 dst_x2 = min_t(s32, dst_x2, max_x); 231 dst_y2 = min_t(s32, dst_y2, max_y); 232 w = dst_x2 - dst_x1; 233 h = dst_y2 - dst_y1; 234 w = max_t(s32, 0, w); 235 h = max_t(s32, 0, h); 236 237 par->dirty.x1 = par->dirty.x2 = 0; 238 par->dirty.y1 = par->dirty.y2 = 0; 239 spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 240 241 if (w && h) { 242 dst_ptr = (u8 *)virtual + 243 (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); 244 src_ptr = (u8 *)par->vmalloc + 245 ((dst_y1 + par->fb_y) * info->fix.line_length + 246 (dst_x1 + par->fb_x) * cpp); 247 248 while (h-- > 0) { 249 memcpy(dst_ptr, src_ptr, w*cpp); 250 dst_ptr += par->set_fb->pitches[0]; 251 src_ptr += info->fix.line_length; 252 } 253 254 clip.x1 = dst_x1; 255 clip.x2 = dst_x2; 256 clip.y1 = dst_y1; 257 clip.y2 = dst_y2; 258 } 259 260 out_unreserve: 261 ttm_bo_unreserve(&vbo->base); 262 ttm_read_unlock(&vmw_priv->reservation_sem); 263 if (w && h) { 264 WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, 265 &clip, 1)); 266 vmw_fifo_flush(vmw_priv, false); 267 } 268 out_unlock: 269 mutex_unlock(&par->bo_mutex); 270 } 271 272 static void vmw_fb_dirty_mark(struct vmw_fb_par *par, 273 unsigned x1, unsigned y1, 274 unsigned width, unsigned height) 275 { 276 unsigned long flags; 277 unsigned x2 = x1 + width; 278 unsigned y2 = y1 + height; 279 280 spin_lock_irqsave(&par->dirty.lock, flags); 281 if (par->dirty.x1 == par->dirty.x2) { 282 par->dirty.x1 = x1; 283 par->dirty.y1 = y1; 284 par->dirty.x2 = x2; 285 par->dirty.y2 = y2; 286 /* if we are active start the dirty work 287 * we share the work with the defio system */ 288 if (par->dirty.active) 289 schedule_delayed_work(&par->local_work, 290 VMW_DIRTY_DELAY); 291 } else { 292 if (x1 < par->dirty.x1) 293 par->dirty.x1 = x1; 294 if (y1 < par->dirty.y1) 295 par->dirty.y1 = y1; 296 if (x2 > par->dirty.x2) 297 par->dirty.x2 = x2; 298 if (y2 > par->dirty.y2) 299 par->dirty.y2 = y2; 300 } 301 spin_unlock_irqrestore(&par->dirty.lock, flags); 302 } 303 304 static int vmw_fb_pan_display(struct fb_var_screeninfo *var, 305 struct fb_info *info) 306 { 307 struct vmw_fb_par *par = info->par; 308 309 if ((var->xoffset + var->xres) > var->xres_virtual || 310 (var->yoffset + var->yres) > var->yres_virtual) { 311 DRM_ERROR("Requested panning can not fit in framebuffer\n"); 312 return -EINVAL; 313 } 314 315 mutex_lock(&par->bo_mutex); 316 par->fb_x = var->xoffset; 317 par->fb_y = var->yoffset; 318 if (par->set_fb) 319 vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, 320 par->set_fb->height); 321 mutex_unlock(&par->bo_mutex); 322 323 return 0; 324 } 325 326 static void vmw_deferred_io(struct fb_info *info, 327 struct list_head *pagelist) 328 { 329 struct vmw_fb_par *par = info->par; 330 unsigned long start, end, min, max; 331 unsigned long flags; 332 struct page *page; 333 int y1, y2; 334 335 min = ULONG_MAX; 336 max = 0; 337 list_for_each_entry(page, pagelist, lru) { 338 start = page->index << PAGE_SHIFT; 339 end = start + PAGE_SIZE - 1; 340 min = min(min, start); 341 max = max(max, end); 342 } 343 344 if (min < max) { 345 y1 = min / info->fix.line_length; 346 y2 = (max / info->fix.line_length) + 1; 347 348 spin_lock_irqsave(&par->dirty.lock, flags); 349 par->dirty.x1 = 0; 350 par->dirty.y1 = y1; 351 par->dirty.x2 = info->var.xres; 352 par->dirty.y2 = y2; 353 spin_unlock_irqrestore(&par->dirty.lock, flags); 354 355 /* 356 * Since we've already waited on this work once, try to 357 * execute asap. 358 */ 359 cancel_delayed_work(&par->local_work); 360 schedule_delayed_work(&par->local_work, 0); 361 } 362 }; 363 364 static struct fb_deferred_io vmw_defio = { 365 .delay = VMW_DIRTY_DELAY, 366 .deferred_io = vmw_deferred_io, 367 }; 368 369 /* 370 * Draw code 371 */ 372 373 static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 374 { 375 cfb_fillrect(info, rect); 376 vmw_fb_dirty_mark(info->par, rect->dx, rect->dy, 377 rect->width, rect->height); 378 } 379 380 static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) 381 { 382 cfb_copyarea(info, region); 383 vmw_fb_dirty_mark(info->par, region->dx, region->dy, 384 region->width, region->height); 385 } 386 387 static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) 388 { 389 cfb_imageblit(info, image); 390 vmw_fb_dirty_mark(info->par, image->dx, image->dy, 391 image->width, image->height); 392 } 393 394 /* 395 * Bring up code 396 */ 397 398 static int vmw_fb_create_bo(struct vmw_private *vmw_priv, 399 size_t size, struct vmw_buffer_object **out) 400 { 401 struct vmw_buffer_object *vmw_bo; 402 int ret; 403 404 (void) ttm_write_lock(&vmw_priv->reservation_sem, false); 405 406 vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL); 407 if (!vmw_bo) { 408 ret = -ENOMEM; 409 goto err_unlock; 410 } 411 412 ret = vmw_bo_init(vmw_priv, vmw_bo, size, 413 &vmw_sys_placement, 414 false, 415 &vmw_bo_bo_free); 416 if (unlikely(ret != 0)) 417 goto err_unlock; /* init frees the buffer on failure */ 418 419 *out = vmw_bo; 420 ttm_write_unlock(&vmw_priv->reservation_sem); 421 422 return 0; 423 424 err_unlock: 425 ttm_write_unlock(&vmw_priv->reservation_sem); 426 return ret; 427 } 428 429 static int vmw_fb_compute_depth(struct fb_var_screeninfo *var, 430 int *depth) 431 { 432 switch (var->bits_per_pixel) { 433 case 32: 434 *depth = (var->transp.length > 0) ? 32 : 24; 435 break; 436 default: 437 DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); 438 return -EINVAL; 439 } 440 441 return 0; 442 } 443 444 static int vmwgfx_set_config_internal(struct drm_mode_set *set) 445 { 446 struct drm_crtc *crtc = set->crtc; 447 struct drm_modeset_acquire_ctx ctx; 448 int ret; 449 450 drm_modeset_acquire_init(&ctx, 0); 451 452 restart: 453 ret = crtc->funcs->set_config(set, &ctx); 454 455 if (ret == -EDEADLK) { 456 drm_modeset_backoff(&ctx); 457 goto restart; 458 } 459 460 drm_modeset_drop_locks(&ctx); 461 drm_modeset_acquire_fini(&ctx); 462 463 return ret; 464 } 465 466 static int vmw_fb_kms_detach(struct vmw_fb_par *par, 467 bool detach_bo, 468 bool unref_bo) 469 { 470 struct drm_framebuffer *cur_fb = par->set_fb; 471 int ret; 472 473 /* Detach the KMS framebuffer from crtcs */ 474 if (par->set_mode) { 475 struct drm_mode_set set; 476 477 set.crtc = par->crtc; 478 set.x = 0; 479 set.y = 0; 480 set.mode = NULL; 481 set.fb = NULL; 482 set.num_connectors = 0; 483 set.connectors = &par->con; 484 ret = vmwgfx_set_config_internal(&set); 485 if (ret) { 486 DRM_ERROR("Could not unset a mode.\n"); 487 return ret; 488 } 489 drm_mode_destroy(par->vmw_priv->dev, par->set_mode); 490 par->set_mode = NULL; 491 } 492 493 if (cur_fb) { 494 drm_framebuffer_put(cur_fb); 495 par->set_fb = NULL; 496 } 497 498 if (par->vmw_bo && detach_bo && unref_bo) 499 vmw_bo_unreference(&par->vmw_bo); 500 501 return 0; 502 } 503 504 static int vmw_fb_kms_framebuffer(struct fb_info *info) 505 { 506 struct drm_mode_fb_cmd2 mode_cmd; 507 struct vmw_fb_par *par = info->par; 508 struct fb_var_screeninfo *var = &info->var; 509 struct drm_framebuffer *cur_fb; 510 struct vmw_framebuffer *vfb; 511 int ret = 0, depth; 512 size_t new_bo_size; 513 514 ret = vmw_fb_compute_depth(var, &depth); 515 if (ret) 516 return ret; 517 518 mode_cmd.width = var->xres; 519 mode_cmd.height = var->yres; 520 mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width; 521 mode_cmd.pixel_format = 522 drm_mode_legacy_fb_format(var->bits_per_pixel, depth); 523 524 cur_fb = par->set_fb; 525 if (cur_fb && cur_fb->width == mode_cmd.width && 526 cur_fb->height == mode_cmd.height && 527 cur_fb->format->format == mode_cmd.pixel_format && 528 cur_fb->pitches[0] == mode_cmd.pitches[0]) 529 return 0; 530 531 /* Need new buffer object ? */ 532 new_bo_size = (size_t) mode_cmd.pitches[0] * (size_t) mode_cmd.height; 533 ret = vmw_fb_kms_detach(par, 534 par->bo_size < new_bo_size || 535 par->bo_size > 2*new_bo_size, 536 true); 537 if (ret) 538 return ret; 539 540 if (!par->vmw_bo) { 541 ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size, 542 &par->vmw_bo); 543 if (ret) { 544 DRM_ERROR("Failed creating a buffer object for " 545 "fbdev.\n"); 546 return ret; 547 } 548 par->bo_size = new_bo_size; 549 } 550 551 vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL, 552 true, &mode_cmd); 553 if (IS_ERR(vfb)) 554 return PTR_ERR(vfb); 555 556 par->set_fb = &vfb->base; 557 558 return 0; 559 } 560 561 static int vmw_fb_set_par(struct fb_info *info) 562 { 563 struct vmw_fb_par *par = info->par; 564 struct vmw_private *vmw_priv = par->vmw_priv; 565 struct drm_mode_set set; 566 struct fb_var_screeninfo *var = &info->var; 567 struct drm_display_mode new_mode = { DRM_MODE("fb_mode", 568 DRM_MODE_TYPE_DRIVER, 569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 570 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) 571 }; 572 struct drm_display_mode *mode; 573 int ret; 574 575 mode = drm_mode_duplicate(vmw_priv->dev, &new_mode); 576 if (!mode) { 577 DRM_ERROR("Could not create new fb mode.\n"); 578 return -ENOMEM; 579 } 580 581 mode->hdisplay = var->xres; 582 mode->vdisplay = var->yres; 583 vmw_guess_mode_timing(mode); 584 585 if (!vmw_kms_validate_mode_vram(vmw_priv, 586 mode->hdisplay * 587 DIV_ROUND_UP(var->bits_per_pixel, 8), 588 mode->vdisplay)) { 589 drm_mode_destroy(vmw_priv->dev, mode); 590 return -EINVAL; 591 } 592 593 mutex_lock(&par->bo_mutex); 594 ret = vmw_fb_kms_framebuffer(info); 595 if (ret) 596 goto out_unlock; 597 598 par->fb_x = var->xoffset; 599 par->fb_y = var->yoffset; 600 601 set.crtc = par->crtc; 602 set.x = 0; 603 set.y = 0; 604 set.mode = mode; 605 set.fb = par->set_fb; 606 set.num_connectors = 1; 607 set.connectors = &par->con; 608 609 ret = vmwgfx_set_config_internal(&set); 610 if (ret) 611 goto out_unlock; 612 613 vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, 614 par->set_fb->width, par->set_fb->height); 615 616 /* If there already was stuff dirty we wont 617 * schedule a new work, so lets do it now */ 618 619 schedule_delayed_work(&par->local_work, 0); 620 621 out_unlock: 622 if (par->set_mode) 623 drm_mode_destroy(vmw_priv->dev, par->set_mode); 624 par->set_mode = mode; 625 626 mutex_unlock(&par->bo_mutex); 627 628 return ret; 629 } 630 631 632 static const struct fb_ops vmw_fb_ops = { 633 .owner = THIS_MODULE, 634 .fb_check_var = vmw_fb_check_var, 635 .fb_set_par = vmw_fb_set_par, 636 .fb_setcolreg = vmw_fb_setcolreg, 637 .fb_fillrect = vmw_fb_fillrect, 638 .fb_copyarea = vmw_fb_copyarea, 639 .fb_imageblit = vmw_fb_imageblit, 640 .fb_pan_display = vmw_fb_pan_display, 641 .fb_blank = vmw_fb_blank, 642 }; 643 644 int vmw_fb_init(struct vmw_private *vmw_priv) 645 { 646 struct device *device = &vmw_priv->dev->pdev->dev; 647 struct vmw_fb_par *par; 648 struct fb_info *info; 649 unsigned fb_width, fb_height; 650 unsigned int fb_bpp, fb_pitch, fb_size; 651 struct drm_display_mode *init_mode; 652 int ret; 653 654 fb_bpp = 32; 655 656 /* XXX As shouldn't these be as well. */ 657 fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); 658 fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); 659 660 fb_pitch = fb_width * fb_bpp / 8; 661 fb_size = fb_pitch * fb_height; 662 663 info = framebuffer_alloc(sizeof(*par), device); 664 if (!info) 665 return -ENOMEM; 666 667 /* 668 * Par 669 */ 670 vmw_priv->fb_info = info; 671 par = info->par; 672 memset(par, 0, sizeof(*par)); 673 INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush); 674 par->vmw_priv = vmw_priv; 675 par->vmalloc = NULL; 676 par->max_width = fb_width; 677 par->max_height = fb_height; 678 679 ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width, 680 par->max_height, &par->con, 681 &par->crtc, &init_mode); 682 if (ret) 683 goto err_kms; 684 685 info->var.xres = init_mode->hdisplay; 686 info->var.yres = init_mode->vdisplay; 687 688 /* 689 * Create buffers and alloc memory 690 */ 691 par->vmalloc = vzalloc(fb_size); 692 if (unlikely(par->vmalloc == NULL)) { 693 ret = -ENOMEM; 694 goto err_free; 695 } 696 697 /* 698 * Fixed and var 699 */ 700 strcpy(info->fix.id, "svgadrmfb"); 701 info->fix.type = FB_TYPE_PACKED_PIXELS; 702 info->fix.visual = FB_VISUAL_TRUECOLOR; 703 info->fix.type_aux = 0; 704 info->fix.xpanstep = 1; /* doing it in hw */ 705 info->fix.ypanstep = 1; /* doing it in hw */ 706 info->fix.ywrapstep = 0; 707 info->fix.accel = FB_ACCEL_NONE; 708 info->fix.line_length = fb_pitch; 709 710 info->fix.smem_start = 0; 711 info->fix.smem_len = fb_size; 712 713 info->pseudo_palette = par->pseudo_palette; 714 info->screen_base = (char __iomem *)par->vmalloc; 715 info->screen_size = fb_size; 716 717 info->fbops = &vmw_fb_ops; 718 719 /* 24 depth per default */ 720 info->var.red.offset = 16; 721 info->var.green.offset = 8; 722 info->var.blue.offset = 0; 723 info->var.red.length = 8; 724 info->var.green.length = 8; 725 info->var.blue.length = 8; 726 info->var.transp.offset = 0; 727 info->var.transp.length = 0; 728 729 info->var.xres_virtual = fb_width; 730 info->var.yres_virtual = fb_height; 731 info->var.bits_per_pixel = fb_bpp; 732 info->var.xoffset = 0; 733 info->var.yoffset = 0; 734 info->var.activate = FB_ACTIVATE_NOW; 735 info->var.height = -1; 736 info->var.width = -1; 737 738 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ 739 info->apertures = alloc_apertures(1); 740 if (!info->apertures) { 741 ret = -ENOMEM; 742 goto err_aper; 743 } 744 info->apertures->ranges[0].base = vmw_priv->vram_start; 745 info->apertures->ranges[0].size = vmw_priv->vram_size; 746 747 /* 748 * Dirty & Deferred IO 749 */ 750 par->dirty.x1 = par->dirty.x2 = 0; 751 par->dirty.y1 = par->dirty.y2 = 0; 752 par->dirty.active = true; 753 spin_lock_init(&par->dirty.lock); 754 mutex_init(&par->bo_mutex); 755 info->fbdefio = &vmw_defio; 756 fb_deferred_io_init(info); 757 758 ret = register_framebuffer(info); 759 if (unlikely(ret != 0)) 760 goto err_defio; 761 762 vmw_fb_set_par(info); 763 764 return 0; 765 766 err_defio: 767 fb_deferred_io_cleanup(info); 768 err_aper: 769 err_free: 770 vfree(par->vmalloc); 771 err_kms: 772 framebuffer_release(info); 773 vmw_priv->fb_info = NULL; 774 775 return ret; 776 } 777 778 int vmw_fb_close(struct vmw_private *vmw_priv) 779 { 780 struct fb_info *info; 781 struct vmw_fb_par *par; 782 783 if (!vmw_priv->fb_info) 784 return 0; 785 786 info = vmw_priv->fb_info; 787 par = info->par; 788 789 /* ??? order */ 790 fb_deferred_io_cleanup(info); 791 cancel_delayed_work_sync(&par->local_work); 792 unregister_framebuffer(info); 793 794 mutex_lock(&par->bo_mutex); 795 (void) vmw_fb_kms_detach(par, true, true); 796 mutex_unlock(&par->bo_mutex); 797 798 vfree(par->vmalloc); 799 framebuffer_release(info); 800 801 return 0; 802 } 803 804 int vmw_fb_off(struct vmw_private *vmw_priv) 805 { 806 struct fb_info *info; 807 struct vmw_fb_par *par; 808 unsigned long flags; 809 810 if (!vmw_priv->fb_info) 811 return -EINVAL; 812 813 info = vmw_priv->fb_info; 814 par = info->par; 815 816 spin_lock_irqsave(&par->dirty.lock, flags); 817 par->dirty.active = false; 818 spin_unlock_irqrestore(&par->dirty.lock, flags); 819 820 flush_delayed_work(&info->deferred_work); 821 flush_delayed_work(&par->local_work); 822 823 return 0; 824 } 825 826 int vmw_fb_on(struct vmw_private *vmw_priv) 827 { 828 struct fb_info *info; 829 struct vmw_fb_par *par; 830 unsigned long flags; 831 832 if (!vmw_priv->fb_info) 833 return -EINVAL; 834 835 info = vmw_priv->fb_info; 836 par = info->par; 837 838 spin_lock_irqsave(&par->dirty.lock, flags); 839 par->dirty.active = true; 840 spin_unlock_irqrestore(&par->dirty.lock, flags); 841 842 /* 843 * Need to reschedule a dirty update, because otherwise that's 844 * only done in dirty_mark() if the previous coalesced 845 * dirty region was empty. 846 */ 847 schedule_delayed_work(&par->local_work, 0); 848 849 return 0; 850 } 851