1 // SPDX-License-Identifier: MIT 2 3 #include <linux/aperture.h> 4 #include <linux/platform_device.h> 5 6 #include <drm/drm_aperture.h> 7 #include <drm/drm_drv.h> 8 #include <drm/drm_print.h> 9 10 /** 11 * DOC: overview 12 * 13 * A graphics device might be supported by different drivers, but only one 14 * driver can be active at any given time. Many systems load a generic 15 * graphics drivers, such as EFI-GOP or VESA, early during the boot process. 16 * During later boot stages, they replace the generic driver with a dedicated, 17 * hardware-specific driver. To take over the device the dedicated driver 18 * first has to remove the generic driver. DRM aperture functions manage 19 * ownership of DRM framebuffer memory and hand-over between drivers. 20 * 21 * DRM drivers should call drm_aperture_remove_conflicting_framebuffers() 22 * at the top of their probe function. The function removes any generic 23 * driver that is currently associated with the given framebuffer memory. 24 * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the 25 * example given below. 26 * 27 * .. code-block:: c 28 * 29 * static const struct drm_driver example_driver = { 30 * ... 31 * }; 32 * 33 * static int remove_conflicting_framebuffers(struct pci_dev *pdev) 34 * { 35 * resource_size_t base, size; 36 * int ret; 37 * 38 * base = pci_resource_start(pdev, 0); 39 * size = pci_resource_len(pdev, 0); 40 * 41 * return drm_aperture_remove_conflicting_framebuffers(base, size, 42 * &example_driver); 43 * } 44 * 45 * static int probe(struct pci_dev *pdev) 46 * { 47 * int ret; 48 * 49 * // Remove any generic drivers... 50 * ret = remove_conflicting_framebuffers(pdev); 51 * if (ret) 52 * return ret; 53 * 54 * // ... and initialize the hardware. 55 * ... 56 * 57 * drm_dev_register(); 58 * 59 * return 0; 60 * } 61 * 62 * PCI device drivers should call 63 * drm_aperture_remove_conflicting_pci_framebuffers() and let it detect the 64 * framebuffer apertures automatically. Device drivers without knowledge of 65 * the framebuffer's location shall call drm_aperture_remove_framebuffers(), 66 * which removes all drivers for known framebuffer. 67 * 68 * Drivers that are susceptible to being removed by other drivers, such as 69 * generic EFI or VESA drivers, have to register themselves as owners of their 70 * given framebuffer memory. Ownership of the framebuffer memory is achieved 71 * by calling devm_aperture_acquire_from_firmware(). On success, the driver 72 * is the owner of the framebuffer range. The function fails if the 73 * framebuffer is already owned by another driver. See below for an example. 74 * 75 * .. code-block:: c 76 * 77 * static int acquire_framebuffers(struct drm_device *dev, struct platform_device *pdev) 78 * { 79 * resource_size_t base, size; 80 * 81 * mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 82 * if (!mem) 83 * return -EINVAL; 84 * base = mem->start; 85 * size = resource_size(mem); 86 * 87 * return devm_acquire_aperture_from_firmware(dev, base, size); 88 * } 89 * 90 * static int probe(struct platform_device *pdev) 91 * { 92 * struct drm_device *dev; 93 * int ret; 94 * 95 * // ... Initialize the device... 96 * dev = devm_drm_dev_alloc(); 97 * ... 98 * 99 * // ... and acquire ownership of the framebuffer. 100 * ret = acquire_framebuffers(dev, pdev); 101 * if (ret) 102 * return ret; 103 * 104 * drm_dev_register(dev, 0); 105 * 106 * return 0; 107 * } 108 * 109 * The generic driver is now subject to forced removal by other drivers. This 110 * only works for platform drivers that support hot unplug. 111 * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al. 112 * for the registered framebuffer range, the aperture helpers call 113 * platform_device_unregister() and the generic driver unloads itself. It 114 * may not access the device's registers, framebuffer memory, ROM, etc 115 * afterwards. 116 */ 117 118 /** 119 * devm_aperture_acquire_from_firmware - Acquires ownership of a firmware framebuffer 120 * on behalf of a DRM driver. 121 * @dev: the DRM device to own the framebuffer memory 122 * @base: the framebuffer's byte offset in physical memory 123 * @size: the framebuffer size in bytes 124 * 125 * Installs the given device as the new owner of the framebuffer. The function 126 * expects the framebuffer to be provided by a platform device that has been 127 * set up by firmware. Firmware can be any generic interface, such as EFI, 128 * VESA, VGA, etc. If the native hardware driver takes over ownership of the 129 * framebuffer range, the firmware state gets lost. Aperture helpers will then 130 * unregister the platform device automatically. Acquired apertures are 131 * released automatically if the underlying device goes away. 132 * 133 * The function fails if the framebuffer range, or parts of it, is currently 134 * owned by another driver. To evict current owners, callers should use 135 * drm_aperture_remove_conflicting_framebuffers() et al. before calling this 136 * function. The function also fails if the given device is not a platform 137 * device. 138 * 139 * Returns: 140 * 0 on success, or a negative errno value otherwise. 141 */ 142 int devm_aperture_acquire_from_firmware(struct drm_device *dev, resource_size_t base, 143 resource_size_t size) 144 { 145 struct platform_device *pdev; 146 147 if (drm_WARN_ON(dev, !dev_is_platform(dev->dev))) 148 return -EINVAL; 149 150 pdev = to_platform_device(dev->dev); 151 152 return devm_aperture_acquire_for_platform_device(pdev, base, size); 153 } 154 EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); 155 156 /** 157 * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range 158 * @base: the aperture's base address in physical memory 159 * @size: aperture size in bytes 160 * @req_driver: requesting DRM driver 161 * 162 * This function removes graphics device drivers which use the memory range described by 163 * @base and @size. 164 * 165 * Returns: 166 * 0 on success, or a negative errno code otherwise 167 */ 168 int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, 169 const struct drm_driver *req_driver) 170 { 171 return aperture_remove_conflicting_devices(base, size, req_driver->name); 172 } 173 EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); 174 175 /** 176 * drm_aperture_remove_conflicting_pci_framebuffers - remove existing framebuffers for PCI devices 177 * @pdev: PCI device 178 * @req_driver: requesting DRM driver 179 * 180 * This function removes graphics device drivers using the memory range configured 181 * for any of @pdev's memory bars. The function assumes that a PCI device with 182 * shadowed ROM drives a primary display and so kicks out vga16fb. 183 * 184 * Returns: 185 * 0 on success, or a negative errno code otherwise 186 */ 187 int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, 188 const struct drm_driver *req_driver) 189 { 190 return aperture_remove_conflicting_pci_devices(pdev, req_driver->name); 191 } 192 EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers); 193