405 lines · c
1/*2 * Copyright (c) 2006-2009 Red Hat Inc.3 * Copyright (c) 2006-2008 Intel Corporation4 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>5 *6 * DRM framebuffer helper functions7 *8 * Permission to use, copy, modify, distribute, and sell this software and its9 * documentation for any purpose is hereby granted without fee, provided that10 * the above copyright notice appear in all copies and that both that copyright11 * notice and this permission notice appear in supporting documentation, and12 * that the name of the copyright holders not be used in advertising or13 * publicity pertaining to distribution of the software without specific,14 * written prior permission. The copyright holders make no representations15 * about the suitability of this software for any purpose. It is provided "as16 * is" without express or implied warranty.17 *18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE24 * OF THIS SOFTWARE.25 *26 * Authors:27 * Dave Airlie <airlied@linux.ie>28 * Jesse Barnes <jesse.barnes@intel.com>29 */30#ifndef DRM_FB_HELPER_H31#define DRM_FB_HELPER_H32 33struct drm_clip_rect;34struct drm_fb_helper;35 36#include <linux/fb.h>37 38#include <drm/drm_client.h>39 40/**41 * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size42 * @fb_width: fbdev width43 * @fb_height: fbdev height44 * @surface_width: scanout buffer width45 * @surface_height: scanout buffer height46 * @surface_bpp: scanout buffer bpp47 * @surface_depth: scanout buffer depth48 *49 * Note that the scanout surface width/height may be larger than the fbdev50 * width/height. In case of multiple displays, the scanout surface is sized51 * according to the largest width/height (so it is large enough for all CRTCs52 * to scanout). But the fbdev width/height is sized to the minimum width/53 * height of all the displays. This ensures that fbcon fits on the smallest54 * of the attached displays. fb_width/fb_height is used by55 * drm_fb_helper_fill_info() to fill out the &fb_info.var structure.56 */57struct drm_fb_helper_surface_size {58 u32 fb_width;59 u32 fb_height;60 u32 surface_width;61 u32 surface_height;62 u32 surface_bpp;63 u32 surface_depth;64};65 66/**67 * struct drm_fb_helper_funcs - driver callbacks for the fbdev emulation library68 *69 * Driver callbacks used by the fbdev emulation helper library.70 */71struct drm_fb_helper_funcs {72 /**73 * @fb_probe:74 *75 * Driver callback to allocate and initialize the fbdev info structure.76 * Furthermore it also needs to allocate the DRM framebuffer used to77 * back the fbdev.78 *79 * This callback is mandatory.80 *81 * RETURNS:82 *83 * The driver should return 0 on success and a negative error code on84 * failure.85 */86 int (*fb_probe)(struct drm_fb_helper *helper,87 struct drm_fb_helper_surface_size *sizes);88 89 /**90 * @fb_dirty:91 *92 * Driver callback to update the framebuffer memory. If set, fbdev93 * emulation will invoke this callback in regular intervals after94 * the framebuffer has been written.95 *96 * This callback is optional.97 *98 * Returns:99 * 0 on success, or an error code otherwise.100 */101 int (*fb_dirty)(struct drm_fb_helper *helper, struct drm_clip_rect *clip);102};103 104/**105 * struct drm_fb_helper - main structure to emulate fbdev on top of KMS106 * @fb: Scanout framebuffer object107 * @dev: DRM device108 * @funcs: driver callbacks for fb helper109 * @info: emulated fbdev device info struct110 * @pseudo_palette: fake palette of 16 colors111 * @damage_clip: clip rectangle used with deferred_io to accumulate damage to112 * the screen buffer113 * @damage_lock: spinlock protecting @damage_clip114 * @damage_work: worker used to flush the framebuffer115 * @resume_work: worker used during resume if the console lock is already taken116 *117 * This is the main structure used by the fbdev helpers. Drivers supporting118 * fbdev emulation should embedded this into their overall driver structure.119 * Drivers must also fill out a &struct drm_fb_helper_funcs with a few120 * operations.121 */122struct drm_fb_helper {123 /**124 * @client:125 *126 * DRM client used by the generic fbdev emulation.127 */128 struct drm_client_dev client;129 130 /**131 * @buffer:132 *133 * Framebuffer used by the generic fbdev emulation.134 */135 struct drm_client_buffer *buffer;136 137 struct drm_framebuffer *fb;138 struct drm_device *dev;139 const struct drm_fb_helper_funcs *funcs;140 struct fb_info *info;141 u32 pseudo_palette[17];142 struct drm_clip_rect damage_clip;143 spinlock_t damage_lock;144 struct work_struct damage_work;145 struct work_struct resume_work;146 147 /**148 * @lock:149 *150 * Top-level FBDEV helper lock. This protects all internal data151 * structures and lists, such as @connector_info and @crtc_info.152 *153 * FIXME: fbdev emulation locking is a mess and long term we want to154 * protect all helper internal state with this lock as well as reduce155 * core KMS locking as much as possible.156 */157 struct mutex lock;158 159 /**160 * @kernel_fb_list:161 *162 * Entry on the global kernel_fb_helper_list, used for kgdb entry/exit.163 */164 struct list_head kernel_fb_list;165 166 /**167 * @delayed_hotplug:168 *169 * A hotplug was received while fbdev wasn't in control of the DRM170 * device, i.e. another KMS master was active. The output configuration171 * needs to be reprobe when fbdev is in control again.172 */173 bool delayed_hotplug;174 175 /**176 * @deferred_setup:177 *178 * If no outputs are connected (disconnected or unknown) the FB helper179 * code will defer setup until at least one of the outputs shows up.180 * This field keeps track of the status so that setup can be retried181 * at every hotplug event until it succeeds eventually.182 *183 * Protected by @lock.184 */185 bool deferred_setup;186 187 /**188 * @preferred_bpp:189 *190 * Temporary storage for the driver's preferred BPP setting passed to191 * FB helper initialization. This needs to be tracked so that deferred192 * FB helper setup can pass this on.193 *194 * See also: @deferred_setup195 */196 int preferred_bpp;197 198#ifdef CONFIG_FB_DEFERRED_IO199 /**200 * @fbdefio:201 *202 * Temporary storage for the driver's FB deferred I/O handler. If the203 * driver uses the DRM fbdev emulation layer, this is set by the core204 * to a generic deferred I/O handler if a driver is preferring to use205 * a shadow buffer.206 */207 struct fb_deferred_io fbdefio;208#endif209};210 211static inline struct drm_fb_helper *212drm_fb_helper_from_client(struct drm_client_dev *client)213{214 return container_of(client, struct drm_fb_helper, client);215}216 217/**218 * define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers219 *220 * Helper define to register default implementations of drm_fb_helper221 * functions. To be used in struct fb_ops of drm drivers.222 */223#define DRM_FB_HELPER_DEFAULT_OPS \224 .fb_check_var = drm_fb_helper_check_var, \225 .fb_set_par = drm_fb_helper_set_par, \226 .fb_setcmap = drm_fb_helper_setcmap, \227 .fb_blank = drm_fb_helper_blank, \228 .fb_pan_display = drm_fb_helper_pan_display, \229 .fb_debug_enter = drm_fb_helper_debug_enter, \230 .fb_debug_leave = drm_fb_helper_debug_leave, \231 .fb_ioctl = drm_fb_helper_ioctl232 233#ifdef CONFIG_DRM_FBDEV_EMULATION234void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,235 unsigned int preferred_bpp,236 const struct drm_fb_helper_funcs *funcs);237void drm_fb_helper_unprepare(struct drm_fb_helper *fb_helper);238int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *helper);239void drm_fb_helper_fini(struct drm_fb_helper *helper);240int drm_fb_helper_blank(int blank, struct fb_info *info);241int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,242 struct fb_info *info);243int drm_fb_helper_set_par(struct fb_info *info);244int drm_fb_helper_check_var(struct fb_var_screeninfo *var,245 struct fb_info *info);246 247int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper);248 249struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper);250void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper);251void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper);252void drm_fb_helper_fill_info(struct fb_info *info,253 struct drm_fb_helper *fb_helper,254 struct drm_fb_helper_surface_size *sizes);255 256void drm_fb_helper_damage_range(struct fb_info *info, off_t off, size_t len);257void drm_fb_helper_damage_area(struct fb_info *info, u32 x, u32 y, u32 width, u32 height);258 259void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist);260 261void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend);262void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,263 bool suspend);264 265int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);266 267int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,268 unsigned long arg);269 270int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);271int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper);272int drm_fb_helper_debug_enter(struct fb_info *info);273int drm_fb_helper_debug_leave(struct fb_info *info);274void drm_fb_helper_lastclose(struct drm_device *dev);275#else276static inline void drm_fb_helper_prepare(struct drm_device *dev,277 struct drm_fb_helper *helper,278 unsigned int preferred_bpp,279 const struct drm_fb_helper_funcs *funcs)280{281}282 283static inline void drm_fb_helper_unprepare(struct drm_fb_helper *fb_helper)284{285}286 287static inline int drm_fb_helper_init(struct drm_device *dev,288 struct drm_fb_helper *helper)289{290 /* So drivers can use it to free the struct */291 helper->dev = dev;292 dev->fb_helper = helper;293 294 return 0;295}296 297static inline void drm_fb_helper_fini(struct drm_fb_helper *helper)298{299 if (helper && helper->dev)300 helper->dev->fb_helper = NULL;301}302 303static inline int drm_fb_helper_blank(int blank, struct fb_info *info)304{305 return 0;306}307 308static inline int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,309 struct fb_info *info)310{311 return 0;312}313 314static inline int drm_fb_helper_set_par(struct fb_info *info)315{316 return 0;317}318 319static inline int drm_fb_helper_check_var(struct fb_var_screeninfo *var,320 struct fb_info *info)321{322 return 0;323}324 325static inline int326drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)327{328 return 0;329}330 331static inline struct fb_info *332drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)333{334 return NULL;335}336 337static inline void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper)338{339}340 341static inline void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper)342{343}344 345static inline void346drm_fb_helper_fill_info(struct fb_info *info,347 struct drm_fb_helper *fb_helper,348 struct drm_fb_helper_surface_size *sizes)349{350}351 352static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap,353 struct fb_info *info)354{355 return 0;356}357 358static inline int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,359 unsigned long arg)360{361 return 0;362}363 364static inline void drm_fb_helper_deferred_io(struct fb_info *info,365 struct list_head *pagelist)366{367}368 369static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper,370 bool suspend)371{372}373 374static inline void375drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend)376{377}378 379static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)380{381 return 0;382}383 384static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)385{386 return 0;387}388 389static inline int drm_fb_helper_debug_enter(struct fb_info *info)390{391 return 0;392}393 394static inline int drm_fb_helper_debug_leave(struct fb_info *info)395{396 return 0;397}398 399static inline void drm_fb_helper_lastclose(struct drm_device *dev)400{401}402#endif403 404#endif405