1 /*        $NetBSD: drm_fb_helper.h,v 1.14 2021/12/19 10:46:44 riastradh Exp $   */
2 
3 /*
4  * Copyright (c) 2006-2009 Red Hat Inc.
5  * Copyright (c) 2006-2008 Intel Corporation
6  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
7  *
8  * DRM framebuffer helper functions
9  *
10  * Permission to use, copy, modify, distribute, and sell this software and its
11  * documentation for any purpose is hereby granted without fee, provided that
12  * the above copyright notice appear in all copies and that both that copyright
13  * notice and this permission notice appear in supporting documentation, and
14  * that the name of the copyright holders not be used in advertising or
15  * publicity pertaining to distribution of the software without specific,
16  * written prior permission.  The copyright holders make no representations
17  * about the suitability of this software for any purpose.  It is provided "as
18  * is" without express or implied warranty.
19  *
20  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
24  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26  * OF THIS SOFTWARE.
27  *
28  * Authors:
29  *      Dave Airlie <airlied@linux.ie>
30  *      Jesse Barnes <jesse.barnes@intel.com>
31  */
32 #ifndef DRM_FB_HELPER_H
33 #define DRM_FB_HELPER_H
34 
35 struct apertures_struct;
36 struct drm_fb_helper;
37 
38 #include <drm/drm_client.h>
39 #include <drm/drm_crtc.h>
40 #include <drm/drm_device.h>
41 #include <linux/kgdb.h>
42 #include <linux/vgaarb.h>
43 
44 #ifdef __NetBSD__
45 #include <sys/device_if.h>
46 #endif
47 
48 enum mode_set_atomic {
49           LEAVE_ATOMIC_MODE_SET,
50           ENTER_ATOMIC_MODE_SET,
51 };
52 
53 /**
54  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
55  * @fb_width: fbdev width
56  * @fb_height: fbdev height
57  * @surface_width: scanout buffer width
58  * @surface_height: scanout buffer height
59  * @surface_bpp: scanout buffer bpp
60  * @surface_depth: scanout buffer depth
61  *
62  * Note that the scanout surface width/height may be larger than the fbdev
63  * width/height.  In case of multiple displays, the scanout surface is sized
64  * according to the largest width/height (so it is large enough for all CRTCs
65  * to scanout).  But the fbdev width/height is sized to the minimum width/
66  * height of all the displays.  This ensures that fbcon fits on the smallest
67  * of the attached displays. fb_width/fb_height is used by
68  * drm_fb_helper_fill_info() to fill out the &fb_info.var structure.
69  */
70 struct drm_fb_helper_surface_size {
71           u32 fb_width;
72           u32 fb_height;
73           u32 surface_width;
74           u32 surface_height;
75           u32 surface_bpp;
76           u32 surface_depth;
77 };
78 
79 /**
80  * struct drm_fb_helper_funcs - driver callbacks for the fbdev emulation library
81  *
82  * Driver callbacks used by the fbdev emulation helper library.
83  */
84 struct drm_fb_helper_funcs {
85           /**
86            * @fb_probe:
87            *
88            * Driver callback to allocate and initialize the fbdev info structure.
89            * Furthermore it also needs to allocate the DRM framebuffer used to
90            * back the fbdev.
91            *
92            * This callback is mandatory.
93            *
94            * RETURNS:
95            *
96            * The driver should return 0 on success and a negative error code on
97            * failure.
98            */
99           int (*fb_probe)(struct drm_fb_helper *helper,
100                               struct drm_fb_helper_surface_size *sizes);
101 };
102 
103 /**
104  * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
105  * @fb: Scanout framebuffer object
106  * @dev: DRM device
107  * @funcs: driver callbacks for fb helper
108  * @fbdev: emulated fbdev device info struct
109  * @pseudo_palette: fake palette of 16 colors
110  * @dirty_clip: clip rectangle used with deferred_io to accumulate damage to
111  *              the screen buffer
112  * @dirty_lock: spinlock protecting @dirty_clip
113  * @dirty_work: worker used to flush the framebuffer
114  * @resume_work: worker used during resume if the console lock is already taken
115  *
116  * This is the main structure used by the fbdev helpers. Drivers supporting
117  * fbdev emulation should embedded this into their overall driver structure.
118  * Drivers must also fill out a &struct drm_fb_helper_funcs with a few
119  * operations.
120  */
121 struct drm_fb_helper {
122           /**
123            * @client:
124            *
125            * DRM client used by the generic fbdev emulation.
126            */
127           struct drm_client_dev client;
128 
129           /**
130            * @buffer:
131            *
132            * Framebuffer used by the generic fbdev emulation.
133            */
134           struct drm_client_buffer *buffer;
135 
136           struct drm_framebuffer *fb;
137           struct drm_device *dev;
138           const struct drm_fb_helper_funcs *funcs;
139 #ifdef __NetBSD__             /* XXX fb info */
140           device_t fbdev;
141 #else
142           struct fb_info *fbdev;
143 #endif
144           u32 pseudo_palette[17];
145           struct drm_clip_rect dirty_clip;
146           spinlock_t dirty_lock;
147           struct work_struct dirty_work;
148           struct work_struct resume_work;
149 
150           /**
151            * @lock:
152            *
153            * Top-level FBDEV helper lock. This protects all internal data
154            * structures and lists, such as @connector_info and @crtc_info.
155            *
156            * FIXME: fbdev emulation locking is a mess and long term we want to
157            * protect all helper internal state with this lock as well as reduce
158            * core KMS locking as much as possible.
159            */
160           struct mutex lock;
161 
162           /**
163            * @kernel_fb_list:
164            *
165            * Entry on the global kernel_fb_helper_list, used for kgdb entry/exit.
166            */
167           struct list_head kernel_fb_list;
168 
169           /**
170            * @delayed_hotplug:
171            *
172            * A hotplug was received while fbdev wasn't in control of the DRM
173            * device, i.e. another KMS master was active. The output configuration
174            * needs to be reprobe when fbdev is in control again.
175            */
176           bool delayed_hotplug;
177 
178           /**
179            * @deferred_setup:
180            *
181            * If no outputs are connected (disconnected or unknown) the FB helper
182            * code will defer setup until at least one of the outputs shows up.
183            * This field keeps track of the status so that setup can be retried
184            * at every hotplug event until it succeeds eventually.
185            *
186            * Protected by @lock.
187            */
188           bool deferred_setup;
189 
190           /**
191            * @preferred_bpp:
192            *
193            * Temporary storage for the driver's preferred BPP setting passed to
194            * FB helper initialization. This needs to be tracked so that deferred
195            * FB helper setup can pass this on.
196            *
197            * See also: @deferred_setup
198            */
199           int preferred_bpp;
200 };
201 
202 static inline struct drm_fb_helper *
drm_fb_helper_from_client(struct drm_client_dev * client)203 drm_fb_helper_from_client(struct drm_client_dev *client)
204 {
205           return container_of(client, struct drm_fb_helper, client);
206 }
207 
208 /**
209  * define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers
210  *
211  * Helper define to register default implementations of drm_fb_helper
212  * functions. To be used in struct fb_ops of drm drivers.
213  */
214 #define DRM_FB_HELPER_DEFAULT_OPS \
215           .fb_check_var       = drm_fb_helper_check_var, \
216           .fb_set_par         = drm_fb_helper_set_par, \
217           .fb_setcmap         = drm_fb_helper_setcmap, \
218           .fb_blank = drm_fb_helper_blank, \
219           .fb_pan_display     = drm_fb_helper_pan_display, \
220           .fb_debug_enter = drm_fb_helper_debug_enter, \
221           .fb_debug_leave = drm_fb_helper_debug_leave, \
222           .fb_ioctl = drm_fb_helper_ioctl
223 
224 #ifdef CONFIG_DRM_FBDEV_EMULATION
225 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
226                                  const struct drm_fb_helper_funcs *funcs);
227 int drm_fb_helper_init(struct drm_device *dev,
228                            struct drm_fb_helper *helper, int max_conn);
229 void drm_fb_helper_fini(struct drm_fb_helper *helper);
230 #ifndef __NetBSD__            /* XXX fb info */
231 int drm_fb_helper_blank(int blank, struct fb_info *info);
232 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
233                                     struct fb_info *info);
234 int drm_fb_helper_set_par(struct fb_info *info);
235 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
236                                   struct fb_info *info);
237 #endif
238 
239 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper);
240 
241 #ifndef __NetBSD__            /* XXX fb info */
242 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper);
243 #endif
244 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper);
245 #ifndef __NetBSD__            /* XXX fb info */
246 void drm_fb_helper_fill_info(struct fb_info *info,
247                                    struct drm_fb_helper *fb_helper,
248                                    struct drm_fb_helper_surface_size *sizes);
249 
250 void drm_fb_helper_deferred_io(struct fb_info *info,
251                                      struct list_head *pagelist);
252 
253 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
254                                      size_t count, loff_t *ppos);
255 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
256                                         size_t count, loff_t *ppos);
257 
258 void drm_fb_helper_sys_fillrect(struct fb_info *info,
259                                         const struct fb_fillrect *rect);
260 void drm_fb_helper_sys_copyarea(struct fb_info *info,
261                                         const struct fb_copyarea *area);
262 void drm_fb_helper_sys_imageblit(struct fb_info *info,
263                                          const struct fb_image *image);
264 
265 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
266                                         const struct fb_fillrect *rect);
267 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
268                                         const struct fb_copyarea *area);
269 void drm_fb_helper_cfb_imageblit(struct fb_info *info,
270                                          const struct fb_image *image);
271 #endif
272 
273 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend);
274 void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
275                                                   bool suspend);
276 
277 #ifndef __NetBSD__            /* XXX fb cmap */
278 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
279 
280 int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
281                               unsigned long arg);
282 #endif
283 
284 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
285 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
286 int drm_fb_helper_debug_enter_fb(struct drm_fb_helper *);
287 int drm_fb_helper_debug_leave_fb(struct drm_fb_helper *);
288 
289 void drm_fb_helper_lastclose(struct drm_device *dev);
290 void drm_fb_helper_output_poll_changed(struct drm_device *dev);
291 
292 int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp);
293 #else
drm_fb_helper_prepare(struct drm_device * dev,struct drm_fb_helper * helper,const struct drm_fb_helper_funcs * funcs)294 static inline void drm_fb_helper_prepare(struct drm_device *dev,
295                                                   struct drm_fb_helper *helper,
296                                                   const struct drm_fb_helper_funcs *funcs)
297 {
298 }
299 
drm_fb_helper_init(struct drm_device * dev,struct drm_fb_helper * helper,int max_conn)300 static inline int drm_fb_helper_init(struct drm_device *dev,
301                            struct drm_fb_helper *helper,
302                            int max_conn)
303 {
304           /* So drivers can use it to free the struct */
305           helper->dev = dev;
306           dev->fb_helper = helper;
307 
308           return 0;
309 }
310 
drm_fb_helper_fini(struct drm_fb_helper * helper)311 static inline void drm_fb_helper_fini(struct drm_fb_helper *helper)
312 {
313           if (helper && helper->dev)
314                     helper->dev->fb_helper = NULL;
315 }
316 
drm_fb_helper_blank(int blank,struct fb_info * info)317 static inline int drm_fb_helper_blank(int blank, struct fb_info *info)
318 {
319           return 0;
320 }
321 
drm_fb_helper_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)322 static inline int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
323                                                       struct fb_info *info)
324 {
325           return 0;
326 }
327 
drm_fb_helper_set_par(struct fb_info * info)328 static inline int drm_fb_helper_set_par(struct fb_info *info)
329 {
330           return 0;
331 }
332 
drm_fb_helper_check_var(struct fb_var_screeninfo * var,struct fb_info * info)333 static inline int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
334                                                     struct fb_info *info)
335 {
336           return 0;
337 }
338 
339 static inline int
drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper * fb_helper)340 drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
341 {
342           return 0;
343 }
344 
345 static inline struct fb_info *
drm_fb_helper_alloc_fbi(struct drm_fb_helper * fb_helper)346 drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
347 {
348           return NULL;
349 }
350 
drm_fb_helper_unregister_fbi(struct drm_fb_helper * fb_helper)351 static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
352 {
353 }
354 
355 static inline void
drm_fb_helper_fill_info(struct fb_info * info,struct drm_fb_helper * fb_helper,struct drm_fb_helper_surface_size * sizes)356 drm_fb_helper_fill_info(struct fb_info *info,
357                               struct drm_fb_helper *fb_helper,
358                               struct drm_fb_helper_surface_size *sizes)
359 {
360 }
361 
drm_fb_helper_setcmap(struct fb_cmap * cmap,struct fb_info * info)362 static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap,
363                                                   struct fb_info *info)
364 {
365           return 0;
366 }
367 
drm_fb_helper_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)368 static inline int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
369                                               unsigned long arg)
370 {
371           return 0;
372 }
373 
drm_fb_helper_deferred_io(struct fb_info * info,struct list_head * pagelist)374 static inline void drm_fb_helper_deferred_io(struct fb_info *info,
375                                                        struct list_head *pagelist)
376 {
377 }
378 
drm_fb_helper_defio_init(struct drm_fb_helper * fb_helper)379 static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
380 {
381           return -ENODEV;
382 }
383 
drm_fb_helper_sys_read(struct fb_info * info,char __user * buf,size_t count,loff_t * ppos)384 static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
385                                                        char __user *buf, size_t count,
386                                                        loff_t *ppos)
387 {
388           return -ENODEV;
389 }
390 
drm_fb_helper_sys_write(struct fb_info * info,const char __user * buf,size_t count,loff_t * ppos)391 static inline ssize_t drm_fb_helper_sys_write(struct fb_info *info,
392                                                         const char __user *buf,
393                                                         size_t count, loff_t *ppos)
394 {
395           return -ENODEV;
396 }
397 
drm_fb_helper_sys_fillrect(struct fb_info * info,const struct fb_fillrect * rect)398 static inline void drm_fb_helper_sys_fillrect(struct fb_info *info,
399                                                         const struct fb_fillrect *rect)
400 {
401 }
402 
drm_fb_helper_sys_copyarea(struct fb_info * info,const struct fb_copyarea * area)403 static inline void drm_fb_helper_sys_copyarea(struct fb_info *info,
404                                                         const struct fb_copyarea *area)
405 {
406 }
407 
drm_fb_helper_sys_imageblit(struct fb_info * info,const struct fb_image * image)408 static inline void drm_fb_helper_sys_imageblit(struct fb_info *info,
409                                                          const struct fb_image *image)
410 {
411 }
412 
drm_fb_helper_cfb_fillrect(struct fb_info * info,const struct fb_fillrect * rect)413 static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info,
414                                                         const struct fb_fillrect *rect)
415 {
416 }
417 
drm_fb_helper_cfb_copyarea(struct fb_info * info,const struct fb_copyarea * area)418 static inline void drm_fb_helper_cfb_copyarea(struct fb_info *info,
419                                                         const struct fb_copyarea *area)
420 {
421 }
422 
drm_fb_helper_cfb_imageblit(struct fb_info * info,const struct fb_image * image)423 static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info,
424                                                          const struct fb_image *image)
425 {
426 }
427 
drm_fb_helper_set_suspend(struct drm_fb_helper * fb_helper,bool suspend)428 static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper,
429                                                        bool suspend)
430 {
431 }
432 
433 static inline void
drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper * fb_helper,bool suspend)434 drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend)
435 {
436 }
437 
drm_fb_helper_hotplug_event(struct drm_fb_helper * fb_helper)438 static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
439 {
440           return 0;
441 }
442 
drm_fb_helper_initial_config(struct drm_fb_helper * fb_helper,int bpp_sel)443 static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper,
444                                                          int bpp_sel)
445 {
446           return 0;
447 }
448 
drm_fb_helper_debug_enter(struct fb_info * info)449 static inline int drm_fb_helper_debug_enter(struct fb_info *info)
450 {
451           return 0;
452 }
453 
drm_fb_helper_debug_leave(struct fb_info * info)454 static inline int drm_fb_helper_debug_leave(struct fb_info *info)
455 {
456           return 0;
457 }
458 
drm_fb_helper_lastclose(struct drm_device * dev)459 static inline void drm_fb_helper_lastclose(struct drm_device *dev)
460 {
461 }
462 
drm_fb_helper_output_poll_changed(struct drm_device * dev)463 static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev)
464 {
465 }
466 
467 static inline int
drm_fbdev_generic_setup(struct drm_device * dev,unsigned int preferred_bpp)468 drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
469 {
470           return 0;
471 }
472 
473 #endif
474 
475 /* TODO: There's a todo entry to remove these three */
476 static inline int
drm_fb_helper_single_add_all_connectors(struct drm_fb_helper * fb_helper)477 drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
478 {
479           return 0;
480 }
481 
482 static inline int
drm_fb_helper_add_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)483 drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
484                                         struct drm_connector *connector)
485 {
486           return 0;
487 }
488 
489 static inline int
drm_fb_helper_remove_one_connector(struct drm_fb_helper * fb_helper,struct drm_connector * connector)490 drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
491                                            struct drm_connector *connector)
492 {
493           return 0;
494 }
495 
496 /**
497  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
498  * @a: memory range, users of which are to be removed
499  * @name: requesting driver name
500  * @primary: also kick vga16fb if present
501  *
502  * This function removes framebuffer devices (initialized by firmware/bootloader)
503  * which use memory range described by @a. If @a is NULL all such devices are
504  * removed.
505  */
506 static inline int
drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct * a,const char * name,bool primary)507 drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
508                                                         const char *name, bool primary)
509 {
510 #if IS_REACHABLE(CONFIG_FB)
511           return remove_conflicting_framebuffers(a, name, primary);
512 #else
513           return 0;
514 #endif
515 }
516 
517 /**
518  * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
519  * @pdev: PCI device
520  * @name: requesting driver name
521  *
522  * This function removes framebuffer devices (eg. initialized by firmware)
523  * using memory range configured for any of @pdev's memory bars.
524  *
525  * The function assumes that PCI device with shadowed ROM drives a primary
526  * display and so kicks out vga16fb.
527  */
528 static inline int
drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev * pdev,const char * name)529 drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
530                                                               const char *name)
531 {
532           int ret = 0;
533 
534           /*
535            * WARNING: Apparently we must kick fbdev drivers before vgacon,
536            * otherwise the vga fbdev driver falls over.
537            */
538 #if IS_REACHABLE(CONFIG_FB)
539           ret = remove_conflicting_pci_framebuffers(pdev, name);
540 #endif
541           if (ret == 0)
542                     ret = vga_remove_vgacon(pdev);
543           return ret;
544 }
545 
546 #endif
547