xref: /netbsd-src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h (revision 89e579d568290de2cff7a3c9870cd6df58d65dd1)
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