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 * bool primary = false; 36 * resource_size_t base, size; 37 * int ret; 38 * 39 * base = pci_resource_start(pdev, 0); 40 * size = pci_resource_len(pdev, 0); 41 * #ifdef CONFIG_X86 42 * primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; 43 * #endif 44 * 45 * return drm_aperture_remove_conflicting_framebuffers(base, size, primary, 46 * &example_driver); 47 * } 48 * 49 * static int probe(struct pci_dev *pdev) 50 * { 51 * int ret; 52 * 53 * // Remove any generic drivers... 54 * ret = remove_conflicting_framebuffers(pdev); 55 * if (ret) 56 * return ret; 57 * 58 * // ... and initialize the hardware. 59 * ... 60 * 61 * drm_dev_register(); 62 * 63 * return 0; 64 * } 65 * 66 * PCI device drivers should call 67 * drm_aperture_remove_conflicting_pci_framebuffers() and let it detect the 68 * framebuffer apertures automatically. Device drivers without knowledge of 69 * the framebuffer's location shall call drm_aperture_remove_framebuffers(), 70 * which removes all drivers for known framebuffer. 71 * 72 * Drivers that are susceptible to being removed by other drivers, such as 73 * generic EFI or VESA drivers, have to register themselves as owners of their 74 * given framebuffer memory. Ownership of the framebuffer memory is achieved 75 * by calling devm_aperture_acquire_from_firmware(). On success, the driver 76 * is the owner of the framebuffer range. The function fails if the 77 * framebuffer is already by another driver. See below for an example. 78 * 79 * .. code-block:: c 80 * 81 * static int acquire_framebuffers(struct drm_device *dev, struct platform_device *pdev) 82 * { 83 * resource_size_t base, size; 84 * 85 * mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 86 * if (!mem) 87 * return -EINVAL; 88 * base = mem->start; 89 * size = resource_size(mem); 90 * 91 * return devm_acquire_aperture_from_firmware(dev, base, size); 92 * } 93 * 94 * static int probe(struct platform_device *pdev) 95 * { 96 * struct drm_device *dev; 97 * int ret; 98 * 99 * // ... Initialize the device... 100 * dev = devm_drm_dev_alloc(); 101 * ... 102 * 103 * // ... and acquire ownership of the framebuffer. 104 * ret = acquire_framebuffers(dev, pdev); 105 * if (ret) 106 * return ret; 107 * 108 * drm_dev_register(dev, 0); 109 * 110 * return 0; 111 * } 112 * 113 * The generic driver is now subject to forced removal by other drivers. This 114 * only works for platform drivers that support hot unplug. 115 * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al 116 * for the registered framebuffer range, the aperture helpers call 117 * platform_device_unregister() and the generic driver unloads itself. It 118 * may not access the device's registers, framebuffer memory, ROM, etc 119 * afterwards. 120 */ 121 122 /** 123 * devm_aperture_acquire_from_firmware - Acquires ownership of a firmware framebuffer 124 * on behalf of a DRM driver. 125 * @dev: the DRM device to own the framebuffer memory 126 * @base: the framebuffer's byte offset in physical memory 127 * @size: the framebuffer size in bytes 128 * 129 * Installs the given device as the new owner of the framebuffer. The function 130 * expects the framebuffer to be provided by a platform device that has been 131 * set up by firmware. Firmware can be any generic interface, such as EFI, 132 * VESA, VGA, etc. If the native hardware driver takes over ownership of the 133 * framebuffer range, the firmware state gets lost. Aperture helpers will then 134 * unregister the platform device automatically. Acquired apertures are 135 * released automatically if the underlying device goes away. 136 * 137 * The function fails if the framebuffer range, or parts of it, is currently 138 * owned by another driver. To evict current owners, callers should use 139 * drm_aperture_remove_conflicting_framebuffers() et al. before calling this 140 * function. The function also fails if the given device is not a platform 141 * device. 142 * 143 * Returns: 144 * 0 on success, or a negative errno value otherwise. 145 */ 146 int devm_aperture_acquire_from_firmware(struct drm_device *dev, resource_size_t base, 147 resource_size_t size) 148 { 149 struct platform_device *pdev; 150 151 if (drm_WARN_ON(dev, !dev_is_platform(dev->dev))) 152 return -EINVAL; 153 154 pdev = to_platform_device(dev->dev); 155 156 return devm_aperture_acquire_for_platform_device(pdev, base, size); 157 } 158 EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); 159 160 /** 161 * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range 162 * @base: the aperture's base address in physical memory 163 * @size: aperture size in bytes 164 * @primary: also kick vga16fb if present 165 * @req_driver: requesting DRM driver 166 * 167 * This function removes graphics device drivers which use memory range described by 168 * @base and @size. 169 * 170 * Returns: 171 * 0 on success, or a negative errno code otherwise 172 */ 173 int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, 174 bool primary, const struct drm_driver *req_driver) 175 { 176 return aperture_remove_conflicting_devices(base, size, primary, req_driver->name); 177 } 178 EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); 179 180 /** 181 * drm_aperture_remove_conflicting_pci_framebuffers - remove existing framebuffers for PCI devices 182 * @pdev: PCI device 183 * @req_driver: requesting DRM driver 184 * 185 * This function removes graphics device drivers using memory range configured 186 * for any of @pdev's memory bars. The function assumes that PCI device with 187 * shadowed ROM drives a primary display and so kicks out vga16fb. 188 * 189 * Returns: 190 * 0 on success, or a negative errno code otherwise 191 */ 192 int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, 193 const struct drm_driver *req_driver) 194 { 195 return aperture_remove_conflicting_pci_devices(pdev, req_driver->name); 196 } 197 EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers); 198