Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Generic System Framebuffers
  4 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
  5 */
  6
  7/*
  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.
 18 *
 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.
 22 *
 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.
 26 */
 27
 28#include <linux/err.h>
 29#include <linux/init.h>
 30#include <linux/kernel.h>
 31#include <linux/mm.h>
 
 32#include <linux/platform_data/simplefb.h>
 33#include <linux/platform_device.h>
 34#include <linux/screen_info.h>
 35#include <linux/sysfb.h>
 36
 37static struct platform_device *pd;
 38static DEFINE_MUTEX(disable_lock);
 39static bool disabled;
 40
 
 
 41static bool sysfb_unregister(void)
 42{
 43	if (IS_ERR_OR_NULL(pd))
 44		return false;
 45
 46	platform_device_unregister(pd);
 47	pd = NULL;
 48
 49	return true;
 50}
 51
 52/**
 53 * sysfb_disable() - disable the Generic System Framebuffers support
 
 54 *
 55 * This disables the registration of system framebuffer devices that match the
 56 * generic drivers that make use of the system framebuffer set up by firmware.
 57 *
 58 * It also unregisters a device if this was already registered by sysfb_init().
 59 *
 60 * Context: The function can sleep. A @disable_lock mutex is acquired to serialize
 61 *          against sysfb_init(), that registers a system framebuffer device.
 62 */
 63void sysfb_disable(void)
 64{
 
 
 
 65	mutex_lock(&disable_lock);
 66	sysfb_unregister();
 67	disabled = true;
 
 
 
 68	mutex_unlock(&disable_lock);
 69}
 70EXPORT_SYMBOL_GPL(sysfb_disable);
 71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 72static __init int sysfb_init(void)
 73{
 74	struct screen_info *si = &screen_info;
 
 75	struct simplefb_platform_data mode;
 76	const char *name;
 77	bool compatible;
 78	int ret = 0;
 79
 
 
 80	mutex_lock(&disable_lock);
 81	if (disabled)
 82		goto unlock_mutex;
 83
 84	sysfb_apply_efi_quirks();
 85
 
 
 
 
 
 
 86	/* try to create a simple-framebuffer device */
 87	compatible = sysfb_parse_mode(si, &mode);
 88	if (compatible) {
 89		pd = sysfb_create_simplefb(si, &mode);
 90		if (!IS_ERR(pd))
 91			goto unlock_mutex;
 92	}
 93
 94	/* if the FB is incompatible, create a legacy framebuffer device */
 95	if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
 96		name = "efi-framebuffer";
 97	else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
 98		name = "vesa-framebuffer";
 99	else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC)
100		name = "vga-framebuffer";
101	else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC)
102		name = "ega-framebuffer";
103	else
104		name = "platform-framebuffer";
105
106	pd = platform_device_alloc(name, 0);
107	if (!pd) {
108		ret = -ENOMEM;
109		goto unlock_mutex;
110	}
111
 
 
112	sysfb_set_efifb_fwnode(pd);
113
114	ret = platform_device_add_data(pd, si, sizeof(*si));
115	if (ret)
116		goto err;
117
118	ret = platform_device_add(pd);
119	if (ret)
120		goto err;
121
122	goto unlock_mutex;
123err:
124	platform_device_put(pd);
 
 
125unlock_mutex:
126	mutex_unlock(&disable_lock);
127	return ret;
128}
129
130/* must execute after PCI subsystem for EFI quirks */
131device_initcall(sysfb_init);
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Generic System Framebuffers
  4 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
  5 */
  6
  7/*
  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.
 18 *
 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.
 22 *
 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.
 26 */
 27
 28#include <linux/err.h>
 29#include <linux/init.h>
 30#include <linux/kernel.h>
 31#include <linux/mm.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>
 37
 38static struct platform_device *pd;
 39static DEFINE_MUTEX(disable_lock);
 40static bool disabled;
 41
 42static struct device *sysfb_parent_dev(const struct screen_info *si);
 43
 44static bool sysfb_unregister(void)
 45{
 46	if (IS_ERR_OR_NULL(pd))
 47		return false;
 48
 49	platform_device_unregister(pd);
 50	pd = NULL;
 51
 52	return true;
 53}
 54
 55/**
 56 * sysfb_disable() - disable the Generic System Framebuffers support
 57 * @dev:	the device to check if non-NULL
 58 *
 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.
 61 *
 62 * It also unregisters a device if this was already registered by sysfb_init().
 63 *
 64 * Context: The function can sleep. A @disable_lock mutex is acquired to serialize
 65 *          against sysfb_init(), that registers a system framebuffer device.
 66 */
 67void sysfb_disable(struct device *dev)
 68{
 69	struct screen_info *si = &screen_info;
 70	struct device *parent;
 71
 72	mutex_lock(&disable_lock);
 73	parent = sysfb_parent_dev(si);
 74	if (!dev || !parent || dev == parent) {
 75		sysfb_unregister();
 76		disabled = true;
 77	}
 78	mutex_unlock(&disable_lock);
 79}
 80EXPORT_SYMBOL_GPL(sysfb_disable);
 81
 82/**
 83 * sysfb_handles_screen_info() - reports if sysfb handles the global screen_info
 84 *
 85 * Callers can use sysfb_handles_screen_info() to determine whether the Generic
 86 * System Framebuffers (sysfb) can handle the global screen_info data structure
 87 * or not. Drivers might need this information to know if they have to setup the
 88 * system framebuffer, or if they have to delegate this action to sysfb instead.
 89 *
 90 * Returns:
 91 * True if sysfb handles the global screen_info data structure.
 92 */
 93bool sysfb_handles_screen_info(void)
 94{
 95	const struct screen_info *si = &screen_info;
 96
 97	return !!screen_info_video_type(si);
 98}
 99EXPORT_SYMBOL_GPL(sysfb_handles_screen_info);
100
101#if defined(CONFIG_PCI)
102static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
103{
104	/*
105	 * TODO: Try to integrate this code into the PCI subsystem
106	 */
107	int ret;
108	u16 command;
109
110	ret = pci_read_config_word(pdev, PCI_COMMAND, &command);
111	if (ret != PCIBIOS_SUCCESSFUL)
112		return false;
113	if (!(command & PCI_COMMAND_MEMORY))
114		return false;
115	return true;
116}
117#else
118static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev)
119{
120	return false;
121}
122#endif
123
124static struct device *sysfb_parent_dev(const struct screen_info *si)
125{
126	struct pci_dev *pdev;
127
128	pdev = screen_info_pci_dev(si);
129	if (IS_ERR(pdev)) {
130		return ERR_CAST(pdev);
131	} else if (pdev) {
132		if (!sysfb_pci_dev_is_enabled(pdev)) {
133			pci_dev_put(pdev);
134			return ERR_PTR(-ENODEV);
135		}
136		return &pdev->dev;
137	}
138
139	return NULL;
140}
141
142static __init int sysfb_init(void)
143{
144	struct screen_info *si = &screen_info;
145	struct device *parent;
146	struct simplefb_platform_data mode;
147	const char *name;
148	bool compatible;
149	int ret = 0;
150
151	screen_info_apply_fixups();
152
153	mutex_lock(&disable_lock);
154	if (disabled)
155		goto unlock_mutex;
156
157	sysfb_apply_efi_quirks();
158
159	parent = sysfb_parent_dev(si);
160	if (IS_ERR(parent)) {
161		ret = PTR_ERR(parent);
162		goto unlock_mutex;
163	}
164
165	/* try to create a simple-framebuffer device */
166	compatible = sysfb_parse_mode(si, &mode);
167	if (compatible) {
168		pd = sysfb_create_simplefb(si, &mode, parent);
169		if (!IS_ERR(pd))
170			goto put_device;
171	}
172
173	/* if the FB is incompatible, create a legacy framebuffer device */
174	if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
175		name = "efi-framebuffer";
176	else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
177		name = "vesa-framebuffer";
178	else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC)
179		name = "vga-framebuffer";
180	else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC)
181		name = "ega-framebuffer";
182	else
183		name = "platform-framebuffer";
184
185	pd = platform_device_alloc(name, 0);
186	if (!pd) {
187		ret = -ENOMEM;
188		goto put_device;
189	}
190
191	pd->dev.parent = parent;
192
193	sysfb_set_efifb_fwnode(pd);
194
195	ret = platform_device_add_data(pd, si, sizeof(*si));
196	if (ret)
197		goto err;
198
199	ret = platform_device_add(pd);
200	if (ret)
201		goto err;
202
203	goto put_device;
204err:
205	platform_device_put(pd);
206put_device:
207	put_device(parent);
208unlock_mutex:
209	mutex_unlock(&disable_lock);
210	return ret;
211}
212
213/* must execute after PCI subsystem for EFI quirks */
214device_initcall(sysfb_init);