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