Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.11 641 lines 18 kB view raw
1/* 2 * drm kms/fb cma (contiguous memory allocator) helper functions 3 * 4 * Copyright (C) 2012 Analog Device Inc. 5 * Author: Lars-Peter Clausen <lars@metafoo.de> 6 * 7 * Based on udl_fbdev.c 8 * Copyright (C) 2012 Red Hat 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <drm/drmP.h> 21#include <drm/drm_atomic.h> 22#include <drm/drm_crtc.h> 23#include <drm/drm_fb_helper.h> 24#include <drm/drm_crtc_helper.h> 25#include <drm/drm_gem_cma_helper.h> 26#include <drm/drm_fb_cma_helper.h> 27#include <linux/dma-buf.h> 28#include <linux/dma-mapping.h> 29#include <linux/module.h> 30#include <linux/reservation.h> 31 32#define DEFAULT_FBDEFIO_DELAY_MS 50 33 34struct drm_fb_cma { 35 struct drm_framebuffer fb; 36 struct drm_gem_cma_object *obj[4]; 37}; 38 39struct drm_fbdev_cma { 40 struct drm_fb_helper fb_helper; 41 struct drm_fb_cma *fb; 42 const struct drm_framebuffer_funcs *fb_funcs; 43}; 44 45/** 46 * DOC: framebuffer cma helper functions 47 * 48 * Provides helper functions for creating a cma (contiguous memory allocator) 49 * backed framebuffer. 50 * 51 * drm_fb_cma_create() is used in the &drm_mode_config_funcs.fb_create 52 * callback function to create a cma backed framebuffer. 53 * 54 * An fbdev framebuffer backed by cma is also available by calling 55 * drm_fbdev_cma_init(). drm_fbdev_cma_fini() tears it down. 56 * If the &drm_framebuffer_funcs.dirty callback is set, fb_deferred_io will be 57 * set up automatically. &drm_framebuffer_funcs.dirty is called by 58 * drm_fb_helper_deferred_io() in process context (&struct delayed_work). 59 * 60 * Example fbdev deferred io code:: 61 * 62 * static int driver_fb_dirty(struct drm_framebuffer *fb, 63 * struct drm_file *file_priv, 64 * unsigned flags, unsigned color, 65 * struct drm_clip_rect *clips, 66 * unsigned num_clips) 67 * { 68 * struct drm_gem_cma_object *cma = drm_fb_cma_get_gem_obj(fb, 0); 69 * ... push changes ... 70 * return 0; 71 * } 72 * 73 * static struct drm_framebuffer_funcs driver_fb_funcs = { 74 * .destroy = drm_fb_cma_destroy, 75 * .create_handle = drm_fb_cma_create_handle, 76 * .dirty = driver_fb_dirty, 77 * }; 78 * 79 * Initialize:: 80 * 81 * fbdev = drm_fbdev_cma_init_with_funcs(dev, 16, 82 * dev->mode_config.num_crtc, 83 * dev->mode_config.num_connector, 84 * &driver_fb_funcs); 85 * 86 */ 87 88static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper) 89{ 90 return container_of(helper, struct drm_fbdev_cma, fb_helper); 91} 92 93static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb) 94{ 95 return container_of(fb, struct drm_fb_cma, fb); 96} 97 98void drm_fb_cma_destroy(struct drm_framebuffer *fb) 99{ 100 struct drm_fb_cma *fb_cma = to_fb_cma(fb); 101 int i; 102 103 for (i = 0; i < 4; i++) { 104 if (fb_cma->obj[i]) 105 drm_gem_object_unreference_unlocked(&fb_cma->obj[i]->base); 106 } 107 108 drm_framebuffer_cleanup(fb); 109 kfree(fb_cma); 110} 111EXPORT_SYMBOL(drm_fb_cma_destroy); 112 113int drm_fb_cma_create_handle(struct drm_framebuffer *fb, 114 struct drm_file *file_priv, unsigned int *handle) 115{ 116 struct drm_fb_cma *fb_cma = to_fb_cma(fb); 117 118 return drm_gem_handle_create(file_priv, 119 &fb_cma->obj[0]->base, handle); 120} 121EXPORT_SYMBOL(drm_fb_cma_create_handle); 122 123static struct drm_framebuffer_funcs drm_fb_cma_funcs = { 124 .destroy = drm_fb_cma_destroy, 125 .create_handle = drm_fb_cma_create_handle, 126}; 127 128static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, 129 const struct drm_mode_fb_cmd2 *mode_cmd, 130 struct drm_gem_cma_object **obj, 131 unsigned int num_planes, const struct drm_framebuffer_funcs *funcs) 132{ 133 struct drm_fb_cma *fb_cma; 134 int ret; 135 int i; 136 137 fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL); 138 if (!fb_cma) 139 return ERR_PTR(-ENOMEM); 140 141 drm_helper_mode_fill_fb_struct(dev, &fb_cma->fb, mode_cmd); 142 143 for (i = 0; i < num_planes; i++) 144 fb_cma->obj[i] = obj[i]; 145 146 ret = drm_framebuffer_init(dev, &fb_cma->fb, funcs); 147 if (ret) { 148 dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); 149 kfree(fb_cma); 150 return ERR_PTR(ret); 151 } 152 153 return fb_cma; 154} 155 156/** 157 * drm_fb_cma_create_with_funcs() - helper function for the 158 * &drm_mode_config_funcs.fb_create 159 * callback 160 * @dev: DRM device 161 * @file_priv: drm file for the ioctl call 162 * @mode_cmd: metadata from the userspace fb creation request 163 * @funcs: vtable to be used for the new framebuffer object 164 * 165 * This can be used to set &drm_framebuffer_funcs for drivers that need the 166 * &drm_framebuffer_funcs.dirty callback. Use drm_fb_cma_create() if you don't 167 * need to change &drm_framebuffer_funcs. 168 */ 169struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, 170 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd, 171 const struct drm_framebuffer_funcs *funcs) 172{ 173 const struct drm_format_info *info; 174 struct drm_fb_cma *fb_cma; 175 struct drm_gem_cma_object *objs[4]; 176 struct drm_gem_object *obj; 177 int ret; 178 int i; 179 180 info = drm_format_info(mode_cmd->pixel_format); 181 if (!info) 182 return ERR_PTR(-EINVAL); 183 184 for (i = 0; i < info->num_planes; i++) { 185 unsigned int width = mode_cmd->width / (i ? info->hsub : 1); 186 unsigned int height = mode_cmd->height / (i ? info->vsub : 1); 187 unsigned int min_size; 188 189 obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); 190 if (!obj) { 191 dev_err(dev->dev, "Failed to lookup GEM object\n"); 192 ret = -ENXIO; 193 goto err_gem_object_unreference; 194 } 195 196 min_size = (height - 1) * mode_cmd->pitches[i] 197 + width * info->cpp[i] 198 + mode_cmd->offsets[i]; 199 200 if (obj->size < min_size) { 201 drm_gem_object_unreference_unlocked(obj); 202 ret = -EINVAL; 203 goto err_gem_object_unreference; 204 } 205 objs[i] = to_drm_gem_cma_obj(obj); 206 } 207 208 fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i, funcs); 209 if (IS_ERR(fb_cma)) { 210 ret = PTR_ERR(fb_cma); 211 goto err_gem_object_unreference; 212 } 213 214 return &fb_cma->fb; 215 216err_gem_object_unreference: 217 for (i--; i >= 0; i--) 218 drm_gem_object_unreference_unlocked(&objs[i]->base); 219 return ERR_PTR(ret); 220} 221EXPORT_SYMBOL_GPL(drm_fb_cma_create_with_funcs); 222 223/** 224 * drm_fb_cma_create() - &drm_mode_config_funcs.fb_create callback function 225 * @dev: DRM device 226 * @file_priv: drm file for the ioctl call 227 * @mode_cmd: metadata from the userspace fb creation request 228 * 229 * If your hardware has special alignment or pitch requirements these should be 230 * checked before calling this function. Use drm_fb_cma_create_with_funcs() if 231 * you need to set &drm_framebuffer_funcs.dirty. 232 */ 233struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, 234 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) 235{ 236 return drm_fb_cma_create_with_funcs(dev, file_priv, mode_cmd, 237 &drm_fb_cma_funcs); 238} 239EXPORT_SYMBOL_GPL(drm_fb_cma_create); 240 241/** 242 * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer 243 * @fb: The framebuffer 244 * @plane: Which plane 245 * 246 * Return the CMA GEM object for given framebuffer. 247 * 248 * This function will usually be called from the CRTC callback functions. 249 */ 250struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, 251 unsigned int plane) 252{ 253 struct drm_fb_cma *fb_cma = to_fb_cma(fb); 254 255 if (plane >= 4) 256 return NULL; 257 258 return fb_cma->obj[plane]; 259} 260EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); 261 262/** 263 * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer 264 * @plane: Which plane 265 * @state: Plane state attach fence to 266 * 267 * This should be set as the &struct drm_plane_helper_funcs.prepare_fb hook. 268 * 269 * This function checks if the plane FB has an dma-buf attached, extracts 270 * the exclusive fence and attaches it to plane state for the atomic helper 271 * to wait on. 272 * 273 * There is no need for cleanup_fb for CMA based framebuffer drivers. 274 */ 275int drm_fb_cma_prepare_fb(struct drm_plane *plane, 276 struct drm_plane_state *state) 277{ 278 struct dma_buf *dma_buf; 279 struct dma_fence *fence; 280 281 if ((plane->state->fb == state->fb) || !state->fb) 282 return 0; 283 284 dma_buf = drm_fb_cma_get_gem_obj(state->fb, 0)->base.dma_buf; 285 if (dma_buf) { 286 fence = reservation_object_get_excl_rcu(dma_buf->resv); 287 drm_atomic_set_fence_for_plane(state, fence); 288 } 289 290 return 0; 291} 292EXPORT_SYMBOL_GPL(drm_fb_cma_prepare_fb); 293 294#ifdef CONFIG_DEBUG_FS 295static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m) 296{ 297 struct drm_fb_cma *fb_cma = to_fb_cma(fb); 298 int i; 299 300 seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, 301 (char *)&fb->format->format); 302 303 for (i = 0; i < fb->format->num_planes; i++) { 304 seq_printf(m, " %d: offset=%d pitch=%d, obj: ", 305 i, fb->offsets[i], fb->pitches[i]); 306 drm_gem_cma_describe(fb_cma->obj[i], m); 307 } 308} 309 310/** 311 * drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects 312 * in debugfs. 313 * @m: output file 314 * @arg: private data for the callback 315 */ 316int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) 317{ 318 struct drm_info_node *node = (struct drm_info_node *) m->private; 319 struct drm_device *dev = node->minor->dev; 320 struct drm_framebuffer *fb; 321 322 mutex_lock(&dev->mode_config.fb_lock); 323 drm_for_each_fb(fb, dev) 324 drm_fb_cma_describe(fb, m); 325 mutex_unlock(&dev->mode_config.fb_lock); 326 327 return 0; 328} 329EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show); 330#endif 331 332static int drm_fb_cma_mmap(struct fb_info *info, struct vm_area_struct *vma) 333{ 334 return dma_mmap_writecombine(info->device, vma, info->screen_base, 335 info->fix.smem_start, info->fix.smem_len); 336} 337 338static struct fb_ops drm_fbdev_cma_ops = { 339 .owner = THIS_MODULE, 340 DRM_FB_HELPER_DEFAULT_OPS, 341 .fb_fillrect = drm_fb_helper_sys_fillrect, 342 .fb_copyarea = drm_fb_helper_sys_copyarea, 343 .fb_imageblit = drm_fb_helper_sys_imageblit, 344 .fb_mmap = drm_fb_cma_mmap, 345}; 346 347static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info, 348 struct vm_area_struct *vma) 349{ 350 fb_deferred_io_mmap(info, vma); 351 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 352 353 return 0; 354} 355 356static int drm_fbdev_cma_defio_init(struct fb_info *fbi, 357 struct drm_gem_cma_object *cma_obj) 358{ 359 struct fb_deferred_io *fbdefio; 360 struct fb_ops *fbops; 361 362 /* 363 * Per device structures are needed because: 364 * fbops: fb_deferred_io_cleanup() clears fbops.fb_mmap 365 * fbdefio: individual delays 366 */ 367 fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); 368 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); 369 if (!fbdefio || !fbops) { 370 kfree(fbdefio); 371 kfree(fbops); 372 return -ENOMEM; 373 } 374 375 /* can't be offset from vaddr since dirty() uses cma_obj */ 376 fbi->screen_buffer = cma_obj->vaddr; 377 /* fb_deferred_io_fault() needs a physical address */ 378 fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer)); 379 380 *fbops = *fbi->fbops; 381 fbi->fbops = fbops; 382 383 fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS); 384 fbdefio->deferred_io = drm_fb_helper_deferred_io; 385 fbi->fbdefio = fbdefio; 386 fb_deferred_io_init(fbi); 387 fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap; 388 389 return 0; 390} 391 392static void drm_fbdev_cma_defio_fini(struct fb_info *fbi) 393{ 394 if (!fbi->fbdefio) 395 return; 396 397 fb_deferred_io_cleanup(fbi); 398 kfree(fbi->fbdefio); 399 kfree(fbi->fbops); 400} 401 402static int 403drm_fbdev_cma_create(struct drm_fb_helper *helper, 404 struct drm_fb_helper_surface_size *sizes) 405{ 406 struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper); 407 struct drm_mode_fb_cmd2 mode_cmd = { 0 }; 408 struct drm_device *dev = helper->dev; 409 struct drm_gem_cma_object *obj; 410 struct drm_framebuffer *fb; 411 unsigned int bytes_per_pixel; 412 unsigned long offset; 413 struct fb_info *fbi; 414 size_t size; 415 int ret; 416 417 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", 418 sizes->surface_width, sizes->surface_height, 419 sizes->surface_bpp); 420 421 bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); 422 423 mode_cmd.width = sizes->surface_width; 424 mode_cmd.height = sizes->surface_height; 425 mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; 426 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 427 sizes->surface_depth); 428 429 size = mode_cmd.pitches[0] * mode_cmd.height; 430 obj = drm_gem_cma_create(dev, size); 431 if (IS_ERR(obj)) 432 return -ENOMEM; 433 434 fbi = drm_fb_helper_alloc_fbi(helper); 435 if (IS_ERR(fbi)) { 436 ret = PTR_ERR(fbi); 437 goto err_gem_free_object; 438 } 439 440 fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1, 441 fbdev_cma->fb_funcs); 442 if (IS_ERR(fbdev_cma->fb)) { 443 dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); 444 ret = PTR_ERR(fbdev_cma->fb); 445 goto err_fb_info_destroy; 446 } 447 448 fb = &fbdev_cma->fb->fb; 449 helper->fb = fb; 450 451 fbi->par = helper; 452 fbi->flags = FBINFO_FLAG_DEFAULT; 453 fbi->fbops = &drm_fbdev_cma_ops; 454 455 drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); 456 drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); 457 458 offset = fbi->var.xoffset * bytes_per_pixel; 459 offset += fbi->var.yoffset * fb->pitches[0]; 460 461 dev->mode_config.fb_base = (resource_size_t)obj->paddr; 462 fbi->screen_base = obj->vaddr + offset; 463 fbi->fix.smem_start = (unsigned long)(obj->paddr + offset); 464 fbi->screen_size = size; 465 fbi->fix.smem_len = size; 466 467 if (fbdev_cma->fb_funcs->dirty) { 468 ret = drm_fbdev_cma_defio_init(fbi, obj); 469 if (ret) 470 goto err_cma_destroy; 471 } 472 473 return 0; 474 475err_cma_destroy: 476 drm_framebuffer_remove(&fbdev_cma->fb->fb); 477err_fb_info_destroy: 478 drm_fb_helper_release_fbi(helper); 479err_gem_free_object: 480 drm_gem_object_unreference_unlocked(&obj->base); 481 return ret; 482} 483 484static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { 485 .fb_probe = drm_fbdev_cma_create, 486}; 487 488/** 489 * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct 490 * @dev: DRM device 491 * @preferred_bpp: Preferred bits per pixel for the device 492 * @max_conn_count: Maximum number of connectors 493 * @funcs: fb helper functions, in particular a custom dirty() callback 494 * 495 * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. 496 */ 497struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, 498 unsigned int preferred_bpp, unsigned int max_conn_count, 499 const struct drm_framebuffer_funcs *funcs) 500{ 501 struct drm_fbdev_cma *fbdev_cma; 502 struct drm_fb_helper *helper; 503 int ret; 504 505 fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL); 506 if (!fbdev_cma) { 507 dev_err(dev->dev, "Failed to allocate drm fbdev.\n"); 508 return ERR_PTR(-ENOMEM); 509 } 510 fbdev_cma->fb_funcs = funcs; 511 512 helper = &fbdev_cma->fb_helper; 513 514 drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs); 515 516 ret = drm_fb_helper_init(dev, helper, max_conn_count); 517 if (ret < 0) { 518 dev_err(dev->dev, "Failed to initialize drm fb helper.\n"); 519 goto err_free; 520 } 521 522 ret = drm_fb_helper_single_add_all_connectors(helper); 523 if (ret < 0) { 524 dev_err(dev->dev, "Failed to add connectors.\n"); 525 goto err_drm_fb_helper_fini; 526 527 } 528 529 ret = drm_fb_helper_initial_config(helper, preferred_bpp); 530 if (ret < 0) { 531 dev_err(dev->dev, "Failed to set initial hw configuration.\n"); 532 goto err_drm_fb_helper_fini; 533 } 534 535 return fbdev_cma; 536 537err_drm_fb_helper_fini: 538 drm_fb_helper_fini(helper); 539err_free: 540 kfree(fbdev_cma); 541 542 return ERR_PTR(ret); 543} 544EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs); 545 546/** 547 * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct 548 * @dev: DRM device 549 * @preferred_bpp: Preferred bits per pixel for the device 550 * @num_crtc: Number of CRTCs 551 * @max_conn_count: Maximum number of connectors 552 * 553 * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. 554 */ 555struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, 556 unsigned int preferred_bpp, unsigned int max_conn_count) 557{ 558 return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp, 559 max_conn_count, 560 &drm_fb_cma_funcs); 561} 562EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); 563 564/** 565 * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct 566 * @fbdev_cma: The drm_fbdev_cma struct 567 */ 568void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) 569{ 570 drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); 571 if (fbdev_cma->fb_helper.fbdev) 572 drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); 573 drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); 574 575 if (fbdev_cma->fb) 576 drm_framebuffer_remove(&fbdev_cma->fb->fb); 577 578 drm_fb_helper_fini(&fbdev_cma->fb_helper); 579 kfree(fbdev_cma); 580} 581EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini); 582 583/** 584 * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode 585 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL 586 * 587 * This function is usually called from the &drm_driver.lastclose callback. 588 */ 589void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma) 590{ 591 if (fbdev_cma) 592 drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma->fb_helper); 593} 594EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode); 595 596/** 597 * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events 598 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL 599 * 600 * This function is usually called from the &drm_mode_config.output_poll_changed 601 * callback. 602 */ 603void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma) 604{ 605 if (fbdev_cma) 606 drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper); 607} 608EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); 609 610/** 611 * drm_fbdev_cma_set_suspend - wrapper around drm_fb_helper_set_suspend 612 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL 613 * @state: desired state, zero to resume, non-zero to suspend 614 * 615 * Calls drm_fb_helper_set_suspend, which is a wrapper around 616 * fb_set_suspend implemented by fbdev core. 617 */ 618void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, int state) 619{ 620 if (fbdev_cma) 621 drm_fb_helper_set_suspend(&fbdev_cma->fb_helper, state); 622} 623EXPORT_SYMBOL(drm_fbdev_cma_set_suspend); 624 625/** 626 * drm_fbdev_cma_set_suspend_unlocked - wrapper around 627 * drm_fb_helper_set_suspend_unlocked 628 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL 629 * @state: desired state, zero to resume, non-zero to suspend 630 * 631 * Calls drm_fb_helper_set_suspend, which is a wrapper around 632 * fb_set_suspend implemented by fbdev core. 633 */ 634void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, 635 int state) 636{ 637 if (fbdev_cma) 638 drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper, 639 state); 640} 641EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);