1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Generic System Framebuffers
8 * Simple-Framebuffer support
9 * Create a platform-device for any available boot framebuffer. The
10 * simple-framebuffer platform device is already available on DT systems, so
11 * this module parses the global "screen_info" object and creates a suitable
12 * platform device compatible with the "simple-framebuffer" DT object. If
13 * the framebuffer is incompatible, we instead create a legacy
14 * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
15 * pass the screen_info as platform_data. This allows legacy drivers
16 * to pick these devices up without messing with simple-framebuffer drivers.
17 * The global "screen_info" is still valid at all times.
19 * If CONFIG_SYSFB_SIMPLEFB is not selected, never register "simple-framebuffer"
20 * platform devices, but only use legacy framebuffer devices for
21 * backwards compatibility.
23 * TODO: We set the dev_id field of all platform-devices to 0. This allows
24 * other OF/DT parsers to create such devices, too. However, they must
25 * start at offset 1 for this to work.
28 #include <linux/err.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
32 #include <linux/pci.h>
33 #include <linux/platform_data/simplefb.h>
34 #include <linux/platform_device.h>
35 #include <linux/screen_info.h>
36 #include <linux/sysfb.h>
38 static struct platform_device *pd;
39 static DEFINE_MUTEX(disable_lock);
42 static struct device *sysfb_parent_dev(const struct screen_info *si);
44 static bool sysfb_unregister(void)
46 if (IS_ERR_OR_NULL(pd))
49 platform_device_unregister(pd);
56 * sysfb_disable() - disable the Generic System Framebuffers support
57 * @dev: the device to check if non-NULL
59 * This disables the registration of system framebuffer devices that match the
60 * generic drivers that make use of the system framebuffer set up by firmware.
62 * It also unregisters a device if this was already registered by sysfb_init().
64 * Context: The function can sleep. A @disable_lock mutex is acquired to serialize
65 * against sysfb_init(), that registers a system framebuffer device.
67 void sysfb_disable(struct device *dev)
69 struct screen_info *si = &screen_info;
71 mutex_lock(&disable_lock);
72 if (!dev || dev == sysfb_parent_dev(si)) {
76 mutex_unlock(&disable_lock);
78 EXPORT_SYMBOL_GPL(sysfb_disable);
80 #if defined(CONFIG_PCI)
81 static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
84 * TODO: Try to integrate this code into the PCI subsystem
89 ret = pci_read_config_word(pdev, PCI_COMMAND, &command);
90 if (ret != PCIBIOS_SUCCESSFUL)
92 if (!(command & PCI_COMMAND_MEMORY))
97 static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
103 static struct device *sysfb_parent_dev(const struct screen_info *si)
105 struct pci_dev *pdev;
107 pdev = screen_info_pci_dev(si);
109 return ERR_CAST(pdev);
111 if (!sysfb_pci_dev_is_enabled(pdev)) {
113 return ERR_PTR(-ENODEV);
121 static __init int sysfb_init(void)
123 struct screen_info *si = &screen_info;
124 struct device *parent;
125 struct simplefb_platform_data mode;
130 screen_info_apply_fixups();
132 mutex_lock(&disable_lock);
136 sysfb_apply_efi_quirks();
138 parent = sysfb_parent_dev(si);
139 if (IS_ERR(parent)) {
140 ret = PTR_ERR(parent);
144 /* try to create a simple-framebuffer device */
145 compatible = sysfb_parse_mode(si, &mode);
147 pd = sysfb_create_simplefb(si, &mode, parent);
152 /* if the FB is incompatible, create a legacy framebuffer device */
153 if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
154 name = "efi-framebuffer";
155 else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
156 name = "vesa-framebuffer";
157 else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC)
158 name = "vga-framebuffer";
159 else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC)
160 name = "ega-framebuffer";
162 name = "platform-framebuffer";
164 pd = platform_device_alloc(name, 0);
170 pd->dev.parent = parent;
172 sysfb_set_efifb_fwnode(pd);
174 ret = platform_device_add_data(pd, si, sizeof(*si));
178 ret = platform_device_add(pd);
184 platform_device_put(pd);
188 mutex_unlock(&disable_lock);
192 /* must execute after PCI subsystem for EFI quirks */
193 device_initcall(sysfb_init);