.. | .. |
---|
36 | 36 | #include <drm/drm_crtc.h> |
---|
37 | 37 | #include <drm/drm_device.h> |
---|
38 | 38 | #include <linux/kgdb.h> |
---|
| 39 | +#include <linux/vgaarb.h> |
---|
39 | 40 | |
---|
40 | 41 | enum mode_set_atomic { |
---|
41 | 42 | LEAVE_ATOMIC_MODE_SET, |
---|
42 | 43 | ENTER_ATOMIC_MODE_SET, |
---|
43 | | -}; |
---|
44 | | - |
---|
45 | | -struct drm_fb_offset { |
---|
46 | | - int x, y; |
---|
47 | | -}; |
---|
48 | | - |
---|
49 | | -struct drm_fb_helper_crtc { |
---|
50 | | - struct drm_mode_set mode_set; |
---|
51 | | - struct drm_display_mode *desired_mode; |
---|
52 | | - int x, y; |
---|
53 | | - int rotation; |
---|
54 | 44 | }; |
---|
55 | 45 | |
---|
56 | 46 | /** |
---|
.. | .. |
---|
67 | 57 | * according to the largest width/height (so it is large enough for all CRTCs |
---|
68 | 58 | * to scanout). But the fbdev width/height is sized to the minimum width/ |
---|
69 | 59 | * height of all the displays. This ensures that fbcon fits on the smallest |
---|
70 | | - * of the attached displays. |
---|
71 | | - * |
---|
72 | | - * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height, |
---|
73 | | - * rather than the surface size. |
---|
| 60 | + * of the attached displays. fb_width/fb_height is used by |
---|
| 61 | + * drm_fb_helper_fill_info() to fill out the &fb_info.var structure. |
---|
74 | 62 | */ |
---|
75 | 63 | struct drm_fb_helper_surface_size { |
---|
76 | 64 | u32 fb_width; |
---|
.. | .. |
---|
103 | 91 | */ |
---|
104 | 92 | int (*fb_probe)(struct drm_fb_helper *helper, |
---|
105 | 93 | struct drm_fb_helper_surface_size *sizes); |
---|
106 | | - |
---|
107 | | - /** |
---|
108 | | - * @initial_config: |
---|
109 | | - * |
---|
110 | | - * Driver callback to setup an initial fbdev display configuration. |
---|
111 | | - * Drivers can use this callback to tell the fbdev emulation what the |
---|
112 | | - * preferred initial configuration is. This is useful to implement |
---|
113 | | - * smooth booting where the fbdev (and subsequently all userspace) never |
---|
114 | | - * changes the mode, but always inherits the existing configuration. |
---|
115 | | - * |
---|
116 | | - * This callback is optional. |
---|
117 | | - * |
---|
118 | | - * RETURNS: |
---|
119 | | - * |
---|
120 | | - * The driver should return true if a suitable initial configuration has |
---|
121 | | - * been filled out and false when the fbdev helper should fall back to |
---|
122 | | - * the default probing logic. |
---|
123 | | - */ |
---|
124 | | - bool (*initial_config)(struct drm_fb_helper *fb_helper, |
---|
125 | | - struct drm_fb_helper_crtc **crtcs, |
---|
126 | | - struct drm_display_mode **modes, |
---|
127 | | - struct drm_fb_offset *offsets, |
---|
128 | | - bool *enabled, int width, int height); |
---|
129 | | -}; |
---|
130 | | - |
---|
131 | | -struct drm_fb_helper_connector { |
---|
132 | | - struct drm_connector *connector; |
---|
133 | 94 | }; |
---|
134 | 95 | |
---|
135 | 96 | /** |
---|
136 | 97 | * struct drm_fb_helper - main structure to emulate fbdev on top of KMS |
---|
137 | 98 | * @fb: Scanout framebuffer object |
---|
138 | 99 | * @dev: DRM device |
---|
139 | | - * @crtc_count: number of possible CRTCs |
---|
140 | | - * @crtc_info: per-CRTC helper state (mode, x/y offset, etc) |
---|
141 | | - * @connector_count: number of connected connectors |
---|
142 | | - * @connector_info_alloc_count: size of connector_info |
---|
143 | 100 | * @funcs: driver callbacks for fb helper |
---|
144 | 101 | * @fbdev: emulated fbdev device info struct |
---|
145 | 102 | * @pseudo_palette: fake palette of 16 colors |
---|
.. | .. |
---|
171 | 128 | |
---|
172 | 129 | struct drm_framebuffer *fb; |
---|
173 | 130 | struct drm_device *dev; |
---|
174 | | - int crtc_count; |
---|
175 | | - struct drm_fb_helper_crtc *crtc_info; |
---|
176 | | - int connector_count; |
---|
177 | | - int connector_info_alloc_count; |
---|
178 | | - /** |
---|
179 | | - * @sw_rotations: |
---|
180 | | - * Bitmask of all rotations requested for panel-orientation which |
---|
181 | | - * could not be handled in hardware. If only one bit is set |
---|
182 | | - * fbdev->fbcon_rotate_hint gets set to the requested rotation. |
---|
183 | | - */ |
---|
184 | | - int sw_rotations; |
---|
185 | | - /** |
---|
186 | | - * @connector_info: |
---|
187 | | - * |
---|
188 | | - * Array of per-connector information. Do not iterate directly, but use |
---|
189 | | - * drm_fb_helper_for_each_connector. |
---|
190 | | - */ |
---|
191 | | - struct drm_fb_helper_connector **connector_info; |
---|
192 | 131 | const struct drm_fb_helper_funcs *funcs; |
---|
193 | 132 | struct fb_info *fbdev; |
---|
194 | 133 | u32 pseudo_palette[17]; |
---|
.. | .. |
---|
274 | 213 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
---|
275 | 214 | void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, |
---|
276 | 215 | const struct drm_fb_helper_funcs *funcs); |
---|
277 | | -int drm_fb_helper_init(struct drm_device *dev, |
---|
278 | | - struct drm_fb_helper *helper, int max_conn); |
---|
| 216 | +int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *helper); |
---|
279 | 217 | void drm_fb_helper_fini(struct drm_fb_helper *helper); |
---|
280 | 218 | int drm_fb_helper_blank(int blank, struct fb_info *info); |
---|
281 | 219 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
---|
.. | .. |
---|
288 | 226 | |
---|
289 | 227 | struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper); |
---|
290 | 228 | void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper); |
---|
291 | | -void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, |
---|
292 | | - uint32_t fb_width, uint32_t fb_height); |
---|
293 | | -void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
---|
294 | | - uint32_t depth); |
---|
295 | | - |
---|
296 | | -void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); |
---|
| 229 | +void drm_fb_helper_fill_info(struct fb_info *info, |
---|
| 230 | + struct drm_fb_helper *fb_helper, |
---|
| 231 | + struct drm_fb_helper_surface_size *sizes); |
---|
297 | 232 | |
---|
298 | 233 | void drm_fb_helper_deferred_io(struct fb_info *info, |
---|
299 | 234 | struct list_head *pagelist); |
---|
300 | | -int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper); |
---|
301 | 235 | |
---|
302 | 236 | ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, |
---|
303 | 237 | size_t count, loff_t *ppos); |
---|
.. | .. |
---|
329 | 263 | |
---|
330 | 264 | int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); |
---|
331 | 265 | int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); |
---|
332 | | -int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); |
---|
333 | 266 | int drm_fb_helper_debug_enter(struct fb_info *info); |
---|
334 | 267 | int drm_fb_helper_debug_leave(struct fb_info *info); |
---|
335 | | -struct drm_display_mode * |
---|
336 | | -drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, |
---|
337 | | - int width, int height); |
---|
338 | | -struct drm_display_mode * |
---|
339 | | -drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn); |
---|
340 | | - |
---|
341 | | -int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); |
---|
342 | | -int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, |
---|
343 | | - struct drm_connector *connector); |
---|
344 | | - |
---|
345 | | -int drm_fb_helper_fbdev_setup(struct drm_device *dev, |
---|
346 | | - struct drm_fb_helper *fb_helper, |
---|
347 | | - const struct drm_fb_helper_funcs *funcs, |
---|
348 | | - unsigned int preferred_bpp, |
---|
349 | | - unsigned int max_conn_count); |
---|
350 | | -void drm_fb_helper_fbdev_teardown(struct drm_device *dev); |
---|
351 | 268 | |
---|
352 | 269 | void drm_fb_helper_lastclose(struct drm_device *dev); |
---|
353 | 270 | void drm_fb_helper_output_poll_changed(struct drm_device *dev); |
---|
354 | 271 | |
---|
355 | | -int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, |
---|
356 | | - struct drm_fb_helper_surface_size *sizes); |
---|
357 | | -int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp); |
---|
| 272 | +void drm_fbdev_generic_setup(struct drm_device *dev, |
---|
| 273 | + unsigned int preferred_bpp); |
---|
358 | 274 | #else |
---|
359 | 275 | static inline void drm_fb_helper_prepare(struct drm_device *dev, |
---|
360 | 276 | struct drm_fb_helper *helper, |
---|
.. | .. |
---|
363 | 279 | } |
---|
364 | 280 | |
---|
365 | 281 | static inline int drm_fb_helper_init(struct drm_device *dev, |
---|
366 | | - struct drm_fb_helper *helper, |
---|
367 | | - int max_conn) |
---|
| 282 | + struct drm_fb_helper *helper) |
---|
368 | 283 | { |
---|
369 | 284 | /* So drivers can use it to free the struct */ |
---|
370 | 285 | helper->dev = dev; |
---|
.. | .. |
---|
417 | 332 | { |
---|
418 | 333 | } |
---|
419 | 334 | |
---|
420 | | -static inline void drm_fb_helper_fill_var(struct fb_info *info, |
---|
421 | | - struct drm_fb_helper *fb_helper, |
---|
422 | | - uint32_t fb_width, uint32_t fb_height) |
---|
423 | | -{ |
---|
424 | | -} |
---|
425 | | - |
---|
426 | | -static inline void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
---|
427 | | - uint32_t depth) |
---|
| 335 | +static inline void |
---|
| 336 | +drm_fb_helper_fill_info(struct fb_info *info, |
---|
| 337 | + struct drm_fb_helper *fb_helper, |
---|
| 338 | + struct drm_fb_helper_surface_size *sizes) |
---|
428 | 339 | { |
---|
429 | 340 | } |
---|
430 | 341 | |
---|
.. | .. |
---|
438 | 349 | unsigned long arg) |
---|
439 | 350 | { |
---|
440 | 351 | return 0; |
---|
441 | | -} |
---|
442 | | - |
---|
443 | | -static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) |
---|
444 | | -{ |
---|
445 | 352 | } |
---|
446 | 353 | |
---|
447 | 354 | static inline void drm_fb_helper_deferred_io(struct fb_info *info, |
---|
.. | .. |
---|
519 | 426 | return 0; |
---|
520 | 427 | } |
---|
521 | 428 | |
---|
522 | | -static inline int |
---|
523 | | -drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
---|
524 | | -{ |
---|
525 | | - return 0; |
---|
526 | | -} |
---|
527 | | - |
---|
528 | 429 | static inline int drm_fb_helper_debug_enter(struct fb_info *info) |
---|
529 | 430 | { |
---|
530 | 431 | return 0; |
---|
.. | .. |
---|
535 | 436 | return 0; |
---|
536 | 437 | } |
---|
537 | 438 | |
---|
538 | | -static inline struct drm_display_mode * |
---|
539 | | -drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, |
---|
540 | | - int width, int height) |
---|
541 | | -{ |
---|
542 | | - return NULL; |
---|
543 | | -} |
---|
544 | | - |
---|
545 | | -static inline struct drm_display_mode * |
---|
546 | | -drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
---|
547 | | - int width, int height) |
---|
548 | | -{ |
---|
549 | | - return NULL; |
---|
550 | | -} |
---|
551 | | - |
---|
552 | | -static inline int |
---|
553 | | -drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, |
---|
554 | | - struct drm_connector *connector) |
---|
555 | | -{ |
---|
556 | | - return 0; |
---|
557 | | -} |
---|
558 | | - |
---|
559 | | -static inline int |
---|
560 | | -drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, |
---|
561 | | - struct drm_connector *connector) |
---|
562 | | -{ |
---|
563 | | - return 0; |
---|
564 | | -} |
---|
565 | | - |
---|
566 | | -static inline int |
---|
567 | | -drm_fb_helper_fbdev_setup(struct drm_device *dev, |
---|
568 | | - struct drm_fb_helper *fb_helper, |
---|
569 | | - const struct drm_fb_helper_funcs *funcs, |
---|
570 | | - unsigned int preferred_bpp, |
---|
571 | | - unsigned int max_conn_count) |
---|
572 | | -{ |
---|
573 | | - /* So drivers can use it to free the struct */ |
---|
574 | | - dev->fb_helper = fb_helper; |
---|
575 | | - |
---|
576 | | - return 0; |
---|
577 | | -} |
---|
578 | | - |
---|
579 | | -static inline void drm_fb_helper_fbdev_teardown(struct drm_device *dev) |
---|
580 | | -{ |
---|
581 | | - dev->fb_helper = NULL; |
---|
582 | | -} |
---|
583 | | - |
---|
584 | 439 | static inline void drm_fb_helper_lastclose(struct drm_device *dev) |
---|
585 | 440 | { |
---|
586 | 441 | } |
---|
.. | .. |
---|
589 | 444 | { |
---|
590 | 445 | } |
---|
591 | 446 | |
---|
592 | | -static inline int |
---|
593 | | -drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, |
---|
594 | | - struct drm_fb_helper_surface_size *sizes) |
---|
595 | | -{ |
---|
596 | | - return 0; |
---|
597 | | -} |
---|
598 | | - |
---|
599 | | -static inline int |
---|
| 447 | +static inline void |
---|
600 | 448 | drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) |
---|
601 | 449 | { |
---|
602 | | - return 0; |
---|
603 | 450 | } |
---|
604 | 451 | |
---|
605 | 452 | #endif |
---|
606 | 453 | |
---|
| 454 | +/** |
---|
| 455 | + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers |
---|
| 456 | + * @a: memory range, users of which are to be removed |
---|
| 457 | + * @name: requesting driver name |
---|
| 458 | + * @primary: also kick vga16fb if present |
---|
| 459 | + * |
---|
| 460 | + * This function removes framebuffer devices (initialized by firmware/bootloader) |
---|
| 461 | + * which use memory range described by @a. If @a is NULL all such devices are |
---|
| 462 | + * removed. |
---|
| 463 | + */ |
---|
607 | 464 | static inline int |
---|
608 | 465 | drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, |
---|
609 | 466 | const char *name, bool primary) |
---|
.. | .. |
---|
615 | 472 | #endif |
---|
616 | 473 | } |
---|
617 | 474 | |
---|
| 475 | +/** |
---|
| 476 | + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices |
---|
| 477 | + * @pdev: PCI device |
---|
| 478 | + * @name: requesting driver name |
---|
| 479 | + * |
---|
| 480 | + * This function removes framebuffer devices (eg. initialized by firmware) |
---|
| 481 | + * using memory range configured for any of @pdev's memory bars. |
---|
| 482 | + * |
---|
| 483 | + * The function assumes that PCI device with shadowed ROM drives a primary |
---|
| 484 | + * display and so kicks out vga16fb. |
---|
| 485 | + */ |
---|
| 486 | +static inline int |
---|
| 487 | +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, |
---|
| 488 | + const char *name) |
---|
| 489 | +{ |
---|
| 490 | + int ret = 0; |
---|
| 491 | + |
---|
| 492 | + /* |
---|
| 493 | + * WARNING: Apparently we must kick fbdev drivers before vgacon, |
---|
| 494 | + * otherwise the vga fbdev driver falls over. |
---|
| 495 | + */ |
---|
| 496 | +#if IS_REACHABLE(CONFIG_FB) |
---|
| 497 | + ret = remove_conflicting_pci_framebuffers(pdev, name); |
---|
| 498 | +#endif |
---|
| 499 | + if (ret == 0) |
---|
| 500 | + ret = vga_remove_vgacon(pdev); |
---|
| 501 | + return ret; |
---|
| 502 | +} |
---|
| 503 | + |
---|
618 | 504 | #endif |
---|