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