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