2 * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
3 * Copyright (c) 2015 Rimvydas Jasinskas
4 * Copyright (c) 2018 François Tigeot <ftigeot@wolfpond.org>
6 * DRM Dragonfly-specific helper functions
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that copyright
11 * notice and this permission notice appear in supporting documentation, and
12 * that the name of the copyright holders not be used in advertising or
13 * publicity pertaining to distribution of the software without specific,
14 * written prior permission. The copyright holders make no representations
15 * about the suitability of this software for any purpose. It is provided "as
16 * is" without express or implied warranty.
18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
27 #include <sys/libkern.h>
28 #include <sys/ctype.h>
32 * An implementation of fb_get_options()
33 * This can be used to set the video mode used for the syscons fb console,
34 * a la "video=..." in linux.
37 fb_get_options(const char *connector_name
, char **option
)
39 char buf
[128], str
[1024];
42 * Where on linux one would use the command line option
43 * video=LVDS-1:<video-mode>, the corresponding tunable is
44 * drm.video.LVDS-1=<video-mode>.
45 * e.g. drm.video.LVDS-1=1024x768 sets the LVDS-1 connector to
46 * a 1024x768 video mode in the syscons framebuffer console.
47 * See https://wiki.archlinux.org/index.php/Kernel_mode_setting
48 * for an explanation of the video mode command line option.
50 memset(str
, 0, sizeof(str
));
51 ksnprintf(buf
, sizeof(buf
), "drm.video.%s", connector_name
);
52 if (kgetenv_string(buf
, str
, sizeof(str
)-1)) {
53 kprintf("found kenv %s=%s\n", buf
, str
);
54 *option
= kstrdup(str
, M_DRM
);
57 kprintf("tunable %s is not set\n", buf
);
63 * Implement simplified version of kvasnprintf() for drm needs using
64 * M_DRM and kvsnprintf(). Since it is unclear what string size is
65 * optimal thus use of an actual length.
67 char *kvasprintf(int flags
, const char *format
, va_list ap
)
74 size
= kvsnprintf(NULL
, 0, format
, aq
);
77 str
= kmalloc(size
+1, M_DRM
, flags
);
81 kvsnprintf(str
, size
+1, format
, ap
);
86 /* mimic ksnprintf(), return pointer to char* and match drm api */
87 char *kasprintf(int flags
, const char *format
, ...)
93 str
= kvasprintf(flags
, format
, ap
);
100 * XXX pci glue logic helpers
101 * Should be done in drm_pci_init(), pending drm update.
102 * Assumes static runtime data.
103 * Only for usage in *_driver_[un]load()
106 static void drm_fill_pdev(device_t dev
, struct pci_dev
*pdev
)
112 pdev
->dev
.bsddev
= dev
;
113 pdev
->devfn
= PCI_DEVFN(pci_get_slot(dev
), pci_get_function(dev
));
114 pdev
->vendor
= pci_get_vendor(dev
);
115 pdev
->device
= pci_get_device(dev
);
116 pdev
->subsystem_vendor
= pci_get_subvendor(dev
);
117 pdev
->subsystem_device
= pci_get_subdevice(dev
);
119 pdev
->revision
= pci_get_revid(dev
) & 0xff;
121 pdev
->_irq_type
= pci_alloc_1intr(dev
, msi_enable
,
122 &pdev
->_irqrid
, &irq_flags
);
124 pdev
->_irqr
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
125 &pdev
->_irqrid
, irq_flags
);
129 pdev
->irq
= (int)rman_get_start(pdev
->_irqr
);
131 slot
= pci_get_slot(dev
);
132 func
= pci_get_function(dev
);
133 pdev
->devfn
= PCI_DEVFN(slot
, func
);
136 void drm_init_pdev(device_t dev
, struct pci_dev
**pdev
)
138 BUG_ON(*pdev
!= NULL
);
140 *pdev
= kzalloc(sizeof(struct pci_dev
), GFP_KERNEL
);
141 drm_fill_pdev(dev
, *pdev
);
143 (*pdev
)->bus
= kzalloc(sizeof(struct pci_bus
), GFP_KERNEL
);
144 (*pdev
)->bus
->self
= kzalloc(sizeof(struct pci_dev
), GFP_KERNEL
);
146 drm_fill_pdev(device_get_parent(dev
), (*pdev
)->bus
->self
);
147 (*pdev
)->bus
->number
= pci_get_bus(dev
);
150 void drm_fini_pdev(struct pci_dev
**pdev
)
152 kfree((*pdev
)->bus
->self
);
158 void drm_print_pdev(struct pci_dev
*pdev
)
161 DRM_ERROR("pdev is null!\n");
165 DRM_INFO("pdev: vendor=0x%04x device=0x%04x rev=0x%02x\n",
166 pdev
->vendor
, pdev
->device
, pdev
->revision
);
167 DRM_INFO(" svendor=0x%04x sdevice=0x%04x irq=%u\n",
168 pdev
->subsystem_vendor
, pdev
->subsystem_device
, pdev
->irq
);
172 /* Allocation of PCI memory resources (framebuffer, registers, etc.) for
173 * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual
174 * address for accessing them. Cleaned up at unload.
176 static int drm_alloc_resource(struct drm_device
*dev
, int resource
)
178 struct resource
*res
;
181 KKASSERT(lockstatus(&dev
->struct_mutex
, curthread
) != 0);
183 if (resource
>= DRM_MAX_PCI_RESOURCE
) {
184 DRM_ERROR("Resource %d too large\n", resource
);
188 if (dev
->pcir
[resource
] != NULL
) {
193 rid
= PCIR_BAR(resource
);
194 res
= bus_alloc_resource_any(dev
->dev
->bsddev
, SYS_RES_MEMORY
, &rid
,
198 DRM_ERROR("Couldn't find resource 0x%x\n", resource
);
203 if (dev
->pcir
[resource
] == NULL
) {
204 dev
->pcirid
[resource
] = rid
;
205 dev
->pcir
[resource
] = res
;
211 unsigned long drm_get_resource_start(struct drm_device
*dev
,
212 unsigned int resource
)
214 if (drm_alloc_resource(dev
, resource
) != 0)
217 return rman_get_start(dev
->pcir
[resource
]);
220 unsigned long drm_get_resource_len(struct drm_device
*dev
,
221 unsigned int resource
)
223 if (drm_alloc_resource(dev
, resource
) != 0)
226 return rman_get_size(dev
->pcir
[resource
]);
230 /* Former drm_release() in the legacy DragonFly BSD drm codebase */
231 int drm_device_detach(device_t kdev
)
233 struct drm_softc
*softc
= device_get_softc(kdev
);
234 struct drm_device
*dev
= softc
->drm_driver_data
;
236 drm_sysctl_cleanup(dev
);
240 /* Clean up PCI resources allocated by drm_bufs.c. We're not really
241 * worried about resource consumption while the DRM is inactive (between
242 * lastclose and firstopen or unload) because these aren't actually
243 * taking up KVA, just keeping the PCI resource allocated.
245 for (int i
= 0; i
< DRM_MAX_PCI_RESOURCE
; i
++) {
246 if (dev
->pcir
[i
] == NULL
)
248 bus_release_resource(dev
->dev
->bsddev
, SYS_RES_MEMORY
,
249 dev
->pcirid
[i
], dev
->pcir
[i
]);
259 if (dev
->driver
->unload
!= NULL
) {
261 dev
->driver
->unload(dev
);
265 if (pci_disable_busmaster(dev
->dev
->bsddev
))
266 DRM_ERROR("Request to disable bus-master failed.\n");
268 lockuninit(&dev
->vbl_lock
);
269 lockuninit(&dev
->event_lock
);
270 lockuninit(&dev
->struct_mutex
);