Merge tag 'for-6.5-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[platform/kernel/linux-starfive.git] / drivers / video / aperture.c
1 // SPDX-License-Identifier: MIT
2
3 #include <linux/aperture.h>
4 #include <linux/device.h>
5 #include <linux/list.h>
6 #include <linux/mutex.h>
7 #include <linux/pci.h>
8 #include <linux/platform_device.h>
9 #include <linux/slab.h>
10 #include <linux/sysfb.h>
11 #include <linux/types.h>
12 #include <linux/vgaarb.h>
13
14 #include <video/vga.h>
15
16 /**
17  * DOC: overview
18  *
19  * A graphics device might be supported by different drivers, but only one
20  * driver can be active at any given time. Many systems load a generic
21  * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
22  * During later boot stages, they replace the generic driver with a dedicated,
23  * hardware-specific driver. To take over the device, the dedicated driver
24  * first has to remove the generic driver. Aperture functions manage
25  * ownership of framebuffer memory and hand-over between drivers.
26  *
27  * Graphics drivers should call aperture_remove_conflicting_devices()
28  * at the top of their probe function. The function removes any generic
29  * driver that is currently associated with the given framebuffer memory.
30  * An example for a graphics device on the platform bus is shown below.
31  *
32  * .. code-block:: c
33  *
34  *      static int example_probe(struct platform_device *pdev)
35  *      {
36  *              struct resource *mem;
37  *              resource_size_t base, size;
38  *              int ret;
39  *
40  *              mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
41  *              if (!mem)
42  *                      return -ENODEV;
43  *              base = mem->start;
44  *              size = resource_size(mem);
45  *
46  *              ret = aperture_remove_conflicting_devices(base, size, "example");
47  *              if (ret)
48  *                      return ret;
49  *
50  *              // Initialize the hardware
51  *              ...
52  *
53  *              return 0;
54  *      }
55  *
56  *      static const struct platform_driver example_driver = {
57  *              .probe = example_probe,
58  *              ...
59  *      };
60  *
61  * The given example reads the platform device's I/O-memory range from the
62  * device instance. An active framebuffer will be located within this range.
63  * The call to aperture_remove_conflicting_devices() releases drivers that
64  * have previously claimed ownership of the range and are currently driving
65  * output on the framebuffer. If successful, the new driver can take over
66  * the device.
67  *
68  * While the given example uses a platform device, the aperture helpers work
69  * with every bus that has an addressable framebuffer. In the case of PCI,
70  * device drivers can also call aperture_remove_conflicting_pci_devices() and
71  * let the function detect the apertures automatically. Device drivers without
72  * knowledge of the framebuffer's location can call
73  * aperture_remove_all_conflicting_devices(), which removes all known devices.
74  *
75  * Drivers that are susceptible to being removed by other drivers, such as
76  * generic EFI or VESA drivers, have to register themselves as owners of their
77  * framebuffer apertures. Ownership of the framebuffer memory is achieved
78  * by calling devm_aperture_acquire_for_platform_device(). If successful, the
79  * driver is the owner of the framebuffer range. The function fails if the
80  * framebuffer is already owned by another driver. See below for an example.
81  *
82  * .. code-block:: c
83  *
84  *      static int generic_probe(struct platform_device *pdev)
85  *      {
86  *              struct resource *mem;
87  *              resource_size_t base, size;
88  *
89  *              mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
90  *              if (!mem)
91  *                      return -ENODEV;
92  *              base = mem->start;
93  *              size = resource_size(mem);
94  *
95  *              ret = devm_aperture_acquire_for_platform_device(pdev, base, size);
96  *              if (ret)
97  *                      return ret;
98  *
99  *              // Initialize the hardware
100  *              ...
101  *
102  *              return 0;
103  *      }
104  *
105  *      static int generic_remove(struct platform_device *)
106  *      {
107  *              // Hot-unplug the device
108  *              ...
109  *
110  *              return 0;
111  *      }
112  *
113  *      static const struct platform_driver generic_driver = {
114  *              .probe = generic_probe,
115  *              .remove = generic_remove,
116  *              ...
117  *      };
118  *
119  * The similar to the previous example, the generic driver claims ownership
120  * of the framebuffer memory from its probe function. This will fail if the
121  * memory range, or parts of it, is already owned by another driver.
122  *
123  * If successful, the generic driver is now subject to forced removal by
124  * another driver. This only works for platform drivers that support hot
125  * unplugging. When a driver calls aperture_remove_conflicting_devices()
126  * et al for the registered framebuffer range, the aperture helpers call
127  * platform_device_unregister() and the generic driver unloads itself. The
128  * generic driver also has to provide a remove function to make this work.
129  * Once hot unplugged from hardware, it may not access the device's
130  * registers, framebuffer memory, ROM, etc afterwards.
131  */
132
133 struct aperture_range {
134         struct device *dev;
135         resource_size_t base;
136         resource_size_t size;
137         struct list_head lh;
138         void (*detach)(struct device *dev);
139 };
140
141 static LIST_HEAD(apertures);
142 static DEFINE_MUTEX(apertures_lock);
143
144 static bool overlap(resource_size_t base1, resource_size_t end1,
145                     resource_size_t base2, resource_size_t end2)
146 {
147         return (base1 < end2) && (end1 > base2);
148 }
149
150 static void devm_aperture_acquire_release(void *data)
151 {
152         struct aperture_range *ap = data;
153         bool detached = !ap->dev;
154
155         if (detached)
156                 return;
157
158         mutex_lock(&apertures_lock);
159         list_del(&ap->lh);
160         mutex_unlock(&apertures_lock);
161 }
162
163 static int devm_aperture_acquire(struct device *dev,
164                                  resource_size_t base, resource_size_t size,
165                                  void (*detach)(struct device *))
166 {
167         size_t end = base + size;
168         struct list_head *pos;
169         struct aperture_range *ap;
170
171         mutex_lock(&apertures_lock);
172
173         list_for_each(pos, &apertures) {
174                 ap = container_of(pos, struct aperture_range, lh);
175                 if (overlap(base, end, ap->base, ap->base + ap->size)) {
176                         mutex_unlock(&apertures_lock);
177                         return -EBUSY;
178                 }
179         }
180
181         ap = devm_kzalloc(dev, sizeof(*ap), GFP_KERNEL);
182         if (!ap) {
183                 mutex_unlock(&apertures_lock);
184                 return -ENOMEM;
185         }
186
187         ap->dev = dev;
188         ap->base = base;
189         ap->size = size;
190         ap->detach = detach;
191         INIT_LIST_HEAD(&ap->lh);
192
193         list_add(&ap->lh, &apertures);
194
195         mutex_unlock(&apertures_lock);
196
197         return devm_add_action_or_reset(dev, devm_aperture_acquire_release, ap);
198 }
199
200 static void aperture_detach_platform_device(struct device *dev)
201 {
202         struct platform_device *pdev = to_platform_device(dev);
203
204         /*
205          * Remove the device from the device hierarchy. This is the right thing
206          * to do for firmware-based fb drivers, such as EFI, VESA or VGA. After
207          * the new driver takes over the hardware, the firmware device's state
208          * will be lost.
209          *
210          * For non-platform devices, a new callback would be required.
211          *
212          * If the aperture helpers ever need to handle native drivers, this call
213          * would only have to unplug the DRM device, so that the hardware device
214          * stays around after detachment.
215          */
216         platform_device_unregister(pdev);
217 }
218
219 /**
220  * devm_aperture_acquire_for_platform_device - Acquires ownership of an aperture
221  *                                             on behalf of a platform device.
222  * @pdev:       the platform device to own the aperture
223  * @base:       the aperture's byte offset in physical memory
224  * @size:       the aperture size in bytes
225  *
226  * Installs the given device as the new owner of the aperture. The function
227  * expects the aperture to be provided by a platform device. If another
228  * driver takes over ownership of the aperture, aperture helpers will then
229  * unregister the platform device automatically. All acquired apertures are
230  * released automatically when the underlying device goes away.
231  *
232  * The function fails if the aperture, or parts of it, is currently
233  * owned by another device. To evict current owners, callers should use
234  * remove_conflicting_devices() et al. before calling this function.
235  *
236  * Returns:
237  * 0 on success, or a negative errno value otherwise.
238  */
239 int devm_aperture_acquire_for_platform_device(struct platform_device *pdev,
240                                               resource_size_t base,
241                                               resource_size_t size)
242 {
243         return devm_aperture_acquire(&pdev->dev, base, size, aperture_detach_platform_device);
244 }
245 EXPORT_SYMBOL(devm_aperture_acquire_for_platform_device);
246
247 static void aperture_detach_devices(resource_size_t base, resource_size_t size)
248 {
249         resource_size_t end = base + size;
250         struct list_head *pos, *n;
251
252         mutex_lock(&apertures_lock);
253
254         list_for_each_safe(pos, n, &apertures) {
255                 struct aperture_range *ap = container_of(pos, struct aperture_range, lh);
256                 struct device *dev = ap->dev;
257
258                 if (WARN_ON_ONCE(!dev))
259                         continue;
260
261                 if (!overlap(base, end, ap->base, ap->base + ap->size))
262                         continue;
263
264                 ap->dev = NULL; /* detach from device */
265                 list_del(&ap->lh);
266
267                 ap->detach(dev);
268         }
269
270         mutex_unlock(&apertures_lock);
271 }
272
273 /**
274  * aperture_remove_conflicting_devices - remove devices in the given range
275  * @base: the aperture's base address in physical memory
276  * @size: aperture size in bytes
277  * @name: a descriptive name of the requesting driver
278  *
279  * This function removes devices that own apertures within @base and @size.
280  *
281  * Returns:
282  * 0 on success, or a negative errno code otherwise
283  */
284 int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size,
285                                         const char *name)
286 {
287         /*
288          * If a driver asked to unregister a platform device registered by
289          * sysfb, then can be assumed that this is a driver for a display
290          * that is set up by the system firmware and has a generic driver.
291          *
292          * Drivers for devices that don't have a generic driver will never
293          * ask for this, so let's assume that a real driver for the display
294          * was already probed and prevent sysfb to register devices later.
295          */
296         sysfb_disable();
297
298         aperture_detach_devices(base, size);
299
300         return 0;
301 }
302 EXPORT_SYMBOL(aperture_remove_conflicting_devices);
303
304 /**
305  * __aperture_remove_legacy_vga_devices - remove legacy VGA devices of a PCI devices
306  * @pdev: PCI device
307  *
308  * This function removes VGA devices provided by @pdev, such as a VGA
309  * framebuffer or a console. This is useful if you have a VGA-compatible
310  * PCI graphics device with framebuffers in non-BAR locations. Drivers
311  * should acquire ownership of those memory areas and afterwards call
312  * this helper to release remaining VGA devices.
313  *
314  * If your hardware has its framebuffers accessible via PCI BARS, use
315  * aperture_remove_conflicting_pci_devices() instead. The function will
316  * release any VGA devices automatically.
317  *
318  * WARNING: Apparently we must remove graphics drivers before calling
319  *          this helper. Otherwise the vga fbdev driver falls over if
320  *          we have vgacon configured.
321  *
322  * Returns:
323  * 0 on success, or a negative errno code otherwise
324  */
325 int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev)
326 {
327         /* VGA framebuffer */
328         aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE);
329
330         /* VGA textmode console */
331         return vga_remove_vgacon(pdev);
332 }
333 EXPORT_SYMBOL(__aperture_remove_legacy_vga_devices);
334
335 /**
336  * aperture_remove_conflicting_pci_devices - remove existing framebuffers for PCI devices
337  * @pdev: PCI device
338  * @name: a descriptive name of the requesting driver
339  *
340  * This function removes devices that own apertures within any of @pdev's
341  * memory bars. The function assumes that PCI device with shadowed ROM
342  * drives a primary display and therefore kicks out vga16fb as well.
343  *
344  * Returns:
345  * 0 on success, or a negative errno code otherwise
346  */
347 int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name)
348 {
349         bool primary = false;
350         resource_size_t base, size;
351         int bar, ret = 0;
352
353         if (pdev == vga_default_device())
354                 primary = true;
355
356         if (primary)
357                 sysfb_disable();
358
359         for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
360                 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
361                         continue;
362
363                 base = pci_resource_start(pdev, bar);
364                 size = pci_resource_len(pdev, bar);
365                 aperture_detach_devices(base, size);
366         }
367
368         /*
369          * If this is the primary adapter, there could be a VGA device
370          * that consumes the VGA framebuffer I/O range. Remove this
371          * device as well.
372          */
373         if (primary)
374                 ret = __aperture_remove_legacy_vga_devices(pdev);
375
376         return ret;
377
378 }
379 EXPORT_SYMBOL(aperture_remove_conflicting_pci_devices);