Home | History | Annotate | Line # | Download | only in drm
      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 (at) 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 (at) linux.ie>
     30  *      Jesse Barnes <jesse.barnes (at) 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 *
    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
    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 
    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 
    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 
    317 static inline int drm_fb_helper_blank(int blank, struct fb_info *info)
    318 {
    319 	return 0;
    320 }
    321 
    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 
    328 static inline int drm_fb_helper_set_par(struct fb_info *info)
    329 {
    330 	return 0;
    331 }
    332 
    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
    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 *
    346 drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
    347 {
    348 	return NULL;
    349 }
    350 
    351 static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
    352 {
    353 }
    354 
    355 static inline void
    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 
    362 static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap,
    363 					struct fb_info *info)
    364 {
    365 	return 0;
    366 }
    367 
    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 
    374 static inline void drm_fb_helper_deferred_io(struct fb_info *info,
    375 					     struct list_head *pagelist)
    376 {
    377 }
    378 
    379 static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
    380 {
    381 	return -ENODEV;
    382 }
    383 
    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 
    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 
    398 static inline void drm_fb_helper_sys_fillrect(struct fb_info *info,
    399 					      const struct fb_fillrect *rect)
    400 {
    401 }
    402 
    403 static inline void drm_fb_helper_sys_copyarea(struct fb_info *info,
    404 					      const struct fb_copyarea *area)
    405 {
    406 }
    407 
    408 static inline void drm_fb_helper_sys_imageblit(struct fb_info *info,
    409 					       const struct fb_image *image)
    410 {
    411 }
    412 
    413 static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info,
    414 					      const struct fb_fillrect *rect)
    415 {
    416 }
    417 
    418 static inline void drm_fb_helper_cfb_copyarea(struct fb_info *info,
    419 					      const struct fb_copyarea *area)
    420 {
    421 }
    422 
    423 static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info,
    424 					       const struct fb_image *image)
    425 {
    426 }
    427 
    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
    434 drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend)
    435 {
    436 }
    437 
    438 static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
    439 {
    440 	return 0;
    441 }
    442 
    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 
    449 static inline int drm_fb_helper_debug_enter(struct fb_info *info)
    450 {
    451 	return 0;
    452 }
    453 
    454 static inline int drm_fb_helper_debug_leave(struct fb_info *info)
    455 {
    456 	return 0;
    457 }
    458 
    459 static inline void drm_fb_helper_lastclose(struct drm_device *dev)
    460 {
    461 }
    462 
    463 static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev)
    464 {
    465 }
    466 
    467 static inline int
    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
    477 drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
    478 {
    479 	return 0;
    480 }
    481 
    482 static inline int
    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
    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
    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
    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