xref: /dflybsd-src/sys/dev/drm/drm_dragonfly.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
1ba55f2f5SFrançois Tigeot /*
2ba55f2f5SFrançois Tigeot  * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
3b4efbf42Szrj  * Copyright (c) 2015 Rimvydas Jasinskas
41c45d30aSFrançois Tigeot  * Copyright (c) 2018 François Tigeot <ftigeot@wolfpond.org>
5ba55f2f5SFrançois Tigeot  *
6ba55f2f5SFrançois Tigeot  * DRM Dragonfly-specific helper functions
7ba55f2f5SFrançois Tigeot  *
8ba55f2f5SFrançois Tigeot  * Permission to use, copy, modify, distribute, and sell this software and its
9ba55f2f5SFrançois Tigeot  * documentation for any purpose is hereby granted without fee, provided that
10ba55f2f5SFrançois Tigeot  * the above copyright notice appear in all copies and that both that copyright
11ba55f2f5SFrançois Tigeot  * notice and this permission notice appear in supporting documentation, and
12ba55f2f5SFrançois Tigeot  * that the name of the copyright holders not be used in advertising or
13ba55f2f5SFrançois Tigeot  * publicity pertaining to distribution of the software without specific,
14ba55f2f5SFrançois Tigeot  * written prior permission.  The copyright holders make no representations
15ba55f2f5SFrançois Tigeot  * about the suitability of this software for any purpose.  It is provided "as
16ba55f2f5SFrançois Tigeot  * is" without express or implied warranty.
17ba55f2f5SFrançois Tigeot  *
18ba55f2f5SFrançois Tigeot  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19ba55f2f5SFrançois Tigeot  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20ba55f2f5SFrançois Tigeot  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21ba55f2f5SFrançois Tigeot  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22ba55f2f5SFrançois Tigeot  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23ba55f2f5SFrançois Tigeot  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24ba55f2f5SFrançois Tigeot  * OF THIS SOFTWARE.
25ba55f2f5SFrançois Tigeot  */
26ba55f2f5SFrançois Tigeot 
27ba55f2f5SFrançois Tigeot #include <sys/libkern.h>
28ba55f2f5SFrançois Tigeot #include <sys/ctype.h>
29ba55f2f5SFrançois Tigeot #include <drm/drmP.h>
30ba55f2f5SFrançois Tigeot 
31ba55f2f5SFrançois Tigeot /*
32ba55f2f5SFrançois Tigeot  * An implementation of fb_get_options()
33ba55f2f5SFrançois Tigeot  * This can be used to set the video mode used for the syscons fb console,
34ba55f2f5SFrançois Tigeot  * a la "video=..." in linux.
35ba55f2f5SFrançois Tigeot  */
36ba55f2f5SFrançois Tigeot int
fb_get_options(const char * connector_name,char ** option)37ba55f2f5SFrançois Tigeot fb_get_options(const char *connector_name, char **option)
38ba55f2f5SFrançois Tigeot {
39ba55f2f5SFrançois Tigeot 	char buf[128], str[1024];
40ba55f2f5SFrançois Tigeot 
41ba55f2f5SFrançois Tigeot 	/*
4217707afbSImre Vadasz 	 * Where on linux one would use the command line option
4317707afbSImre Vadasz 	 * video=LVDS-1:<video-mode>, the corresponding tunable is
4417707afbSImre Vadasz 	 * drm.video.LVDS-1=<video-mode>.
4517707afbSImre Vadasz 	 * e.g. drm.video.LVDS-1=1024x768 sets the LVDS-1 connector to
46ba55f2f5SFrançois Tigeot 	 * a 1024x768 video mode in the syscons framebuffer console.
47ba55f2f5SFrançois Tigeot 	 * See https://wiki.archlinux.org/index.php/Kernel_mode_setting
48ba55f2f5SFrançois Tigeot 	 * for an explanation of the video mode command line option.
49ba55f2f5SFrançois Tigeot 	 */
50ba55f2f5SFrançois Tigeot 	memset(str, 0, sizeof(str));
51ba55f2f5SFrançois Tigeot 	ksnprintf(buf, sizeof(buf), "drm.video.%s", connector_name);
52ba55f2f5SFrançois Tigeot 	if (kgetenv_string(buf, str, sizeof(str)-1)) {
53ba55f2f5SFrançois Tigeot 		kprintf("found kenv %s=%s\n", buf, str);
54ba55f2f5SFrançois Tigeot 		*option = kstrdup(str, M_DRM);
55ba55f2f5SFrançois Tigeot 		return (0);
56ba55f2f5SFrançois Tigeot 	} else {
5717707afbSImre Vadasz 		kprintf("tunable %s is not set\n", buf);
58ba55f2f5SFrançois Tigeot 		return (1);
59ba55f2f5SFrançois Tigeot 	}
60ba55f2f5SFrançois Tigeot }
61ba55f2f5SFrançois Tigeot 
62b4efbf42Szrj /*
63ae71ac09Szrj  * Implement simplified version of kvasnprintf() for drm needs using
64b4efbf42Szrj  * M_DRM and kvsnprintf(). Since it is unclear what string size is
65b4efbf42Szrj  * optimal thus use of an actual length.
66b4efbf42Szrj  */
kvasprintf(int flags,const char * format,va_list ap)671dedbd3bSFrançois Tigeot char *kvasprintf(int flags, const char *format, va_list ap)
68b4efbf42Szrj {
69b4efbf42Szrj 	char *str;
70b4efbf42Szrj 	size_t size;
719286b91eSSascha Wildner 	va_list aq;
72b4efbf42Szrj 
739286b91eSSascha Wildner 	va_copy(aq, ap);
74b4efbf42Szrj 	size = kvsnprintf(NULL, 0, format, aq);
759286b91eSSascha Wildner 	va_end(aq);
76b4efbf42Szrj 
77b4efbf42Szrj 	str = kmalloc(size+1, M_DRM, flags);
78b4efbf42Szrj 	if (str == NULL)
79b4efbf42Szrj 		return NULL;
80b4efbf42Szrj 
81b4efbf42Szrj 	kvsnprintf(str, size+1, format, ap);
82b4efbf42Szrj 
83b4efbf42Szrj 	return str;
84b4efbf42Szrj }
85b4efbf42Szrj 
86ae71ac09Szrj /* mimic ksnprintf(), return pointer to char* and match drm api */
kasprintf(int flags,const char * format,...)871dedbd3bSFrançois Tigeot char *kasprintf(int flags, const char *format, ...)
88b4efbf42Szrj {
89b4efbf42Szrj 	char *str;
909286b91eSSascha Wildner 	va_list ap;
91b4efbf42Szrj 
929286b91eSSascha Wildner 	va_start(ap, format);
931dedbd3bSFrançois Tigeot 	str = kvasprintf(flags, format, ap);
949286b91eSSascha Wildner 	va_end(ap);
95b4efbf42Szrj 
96b4efbf42Szrj 	return str;
97b4efbf42Szrj }
983e7afdc3Szrj 
993e7afdc3Szrj /*
1003e7afdc3Szrj  * XXX pci glue logic helpers
1013e7afdc3Szrj  * Should be done in drm_pci_init(), pending drm update.
1023e7afdc3Szrj  * Assumes static runtime data.
1033e7afdc3Szrj  * Only for usage in *_driver_[un]load()
1043e7afdc3Szrj  */
1053e7afdc3Szrj 
drm_fill_pdev(device_t dev,struct pci_dev * pdev)1065d302545SFrançois Tigeot static void drm_fill_pdev(device_t dev, struct pci_dev *pdev)
1073e7afdc3Szrj {
108183e2373SFrançois Tigeot 	int msi_enable = 1;
109183e2373SFrançois Tigeot 	u_int irq_flags;
1108a697a22SFrançois Tigeot 	int slot, func;
111183e2373SFrançois Tigeot 
112fb572d17SFrançois Tigeot 	pdev->dev.bsddev = dev;
1131c45d30aSFrançois Tigeot 	pdev->devfn = PCI_DEVFN(pci_get_slot(dev), pci_get_function(dev));
1143e7afdc3Szrj 	pdev->vendor = pci_get_vendor(dev);
1153e7afdc3Szrj 	pdev->device = pci_get_device(dev);
1163e7afdc3Szrj 	pdev->subsystem_vendor = pci_get_subvendor(dev);
1173e7afdc3Szrj 	pdev->subsystem_device = pci_get_subdevice(dev);
118fc53575bSzrj 
119fc53575bSzrj 	pdev->revision = pci_get_revid(dev) & 0xff;
120183e2373SFrançois Tigeot 
121183e2373SFrançois Tigeot 	pdev->_irq_type = pci_alloc_1intr(dev, msi_enable,
122183e2373SFrançois Tigeot 	    &pdev->_irqrid, &irq_flags);
123183e2373SFrançois Tigeot 
124183e2373SFrançois Tigeot 	pdev->_irqr = bus_alloc_resource_any(dev, SYS_RES_IRQ,
125183e2373SFrançois Tigeot 	    &pdev->_irqrid, irq_flags);
126183e2373SFrançois Tigeot 	if (!pdev->_irqr)
127183e2373SFrançois Tigeot 		return;
128183e2373SFrançois Tigeot 
12911949c65SFrançois Tigeot 	pdev->irq = (int)rman_get_start(pdev->_irqr);
1308a697a22SFrançois Tigeot 
1318a697a22SFrançois Tigeot 	slot = pci_get_slot(dev);
1328a697a22SFrançois Tigeot 	func = pci_get_function(dev);
1338a697a22SFrançois Tigeot 	pdev->devfn = PCI_DEVFN(slot, func);
1343e7afdc3Szrj }
1353e7afdc3Szrj 
drm_init_pdev(device_t dev,struct pci_dev ** pdev)1365d302545SFrançois Tigeot void drm_init_pdev(device_t dev, struct pci_dev **pdev)
1373e7afdc3Szrj {
1383e7afdc3Szrj 	BUG_ON(*pdev != NULL);
1393e7afdc3Szrj 
1403e7afdc3Szrj 	*pdev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
1413e7afdc3Szrj 	drm_fill_pdev(dev, *pdev);
1426f06a24cSzrj 
1436f06a24cSzrj 	(*pdev)->bus = kzalloc(sizeof(struct pci_bus), GFP_KERNEL);
1446f06a24cSzrj 	(*pdev)->bus->self = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
1456f06a24cSzrj 
1466f06a24cSzrj 	drm_fill_pdev(device_get_parent(dev), (*pdev)->bus->self);
1476f06a24cSzrj 	(*pdev)->bus->number = pci_get_bus(dev);
1483e7afdc3Szrj }
1493e7afdc3Szrj 
drm_fini_pdev(struct pci_dev ** pdev)1503e7afdc3Szrj void drm_fini_pdev(struct pci_dev **pdev)
1513e7afdc3Szrj {
1526f06a24cSzrj 	kfree((*pdev)->bus->self);
1536f06a24cSzrj 	kfree((*pdev)->bus);
1546f06a24cSzrj 
1553e7afdc3Szrj 	kfree(*pdev);
1563e7afdc3Szrj }
1571b13d190SFrançois Tigeot 
drm_print_pdev(struct pci_dev * pdev)158fc53575bSzrj void drm_print_pdev(struct pci_dev *pdev)
159fc53575bSzrj {
160fc53575bSzrj 	if (pdev == NULL) {
161fc53575bSzrj 		DRM_ERROR("pdev is null!\n");
162fc53575bSzrj 		return;
163fc53575bSzrj 	}
164fc53575bSzrj 
165fc53575bSzrj 	DRM_INFO("pdev:  vendor=0x%04x  device=0x%04x rev=0x%02x\n",
166fc53575bSzrj 		 pdev->vendor, pdev->device, pdev->revision);
167fc53575bSzrj 	DRM_INFO("      svendor=0x%04x sdevice=0x%04x irq=%u\n",
168fc53575bSzrj 		 pdev->subsystem_vendor, pdev->subsystem_device, pdev->irq);
169fc53575bSzrj }
170fc53575bSzrj 
1713f2dd94aSFrançois Tigeot #if 0
1721b13d190SFrançois Tigeot /* Allocation of PCI memory resources (framebuffer, registers, etc.) for
1731b13d190SFrançois Tigeot  * drm_get_resource_*.  Note that they are not RF_ACTIVE, so there's no virtual
1741b13d190SFrançois Tigeot  * address for accessing them.  Cleaned up at unload.
1751b13d190SFrançois Tigeot  */
1761b13d190SFrançois Tigeot static int drm_alloc_resource(struct drm_device *dev, int resource)
1771b13d190SFrançois Tigeot {
1781b13d190SFrançois Tigeot 	struct resource *res;
1791b13d190SFrançois Tigeot 	int rid;
1801b13d190SFrançois Tigeot 
1811dedbd3bSFrançois Tigeot 	KKASSERT(lockstatus(&dev->struct_mutex, curthread) != 0);
1821b13d190SFrançois Tigeot 
1831b13d190SFrançois Tigeot 	if (resource >= DRM_MAX_PCI_RESOURCE) {
1841b13d190SFrançois Tigeot 		DRM_ERROR("Resource %d too large\n", resource);
1851b13d190SFrançois Tigeot 		return 1;
1861b13d190SFrançois Tigeot 	}
1871b13d190SFrançois Tigeot 
1881b13d190SFrançois Tigeot 	if (dev->pcir[resource] != NULL) {
1891b13d190SFrançois Tigeot 		return 0;
1901b13d190SFrançois Tigeot 	}
1911b13d190SFrançois Tigeot 
1921b13d190SFrançois Tigeot 	DRM_UNLOCK(dev);
1931b13d190SFrançois Tigeot 	rid = PCIR_BAR(resource);
194fb572d17SFrançois Tigeot 	res = bus_alloc_resource_any(dev->dev->bsddev, SYS_RES_MEMORY, &rid,
1951b13d190SFrançois Tigeot 	    RF_SHAREABLE);
1961b13d190SFrançois Tigeot 	DRM_LOCK(dev);
1971b13d190SFrançois Tigeot 	if (res == NULL) {
1981b13d190SFrançois Tigeot 		DRM_ERROR("Couldn't find resource 0x%x\n", resource);
199*78973132SSergey Zigachev 		DRM_UNLOCK(dev);
2001b13d190SFrançois Tigeot 		return 1;
2011b13d190SFrançois Tigeot 	}
2021b13d190SFrançois Tigeot 
2031b13d190SFrançois Tigeot 	if (dev->pcir[resource] == NULL) {
2041b13d190SFrançois Tigeot 		dev->pcirid[resource] = rid;
2051b13d190SFrançois Tigeot 		dev->pcir[resource] = res;
2061b13d190SFrançois Tigeot 	}
2071b13d190SFrançois Tigeot 
2081b13d190SFrançois Tigeot 	return 0;
2091b13d190SFrançois Tigeot }
2101b13d190SFrançois Tigeot 
2111b13d190SFrançois Tigeot unsigned long drm_get_resource_start(struct drm_device *dev,
2121b13d190SFrançois Tigeot 				     unsigned int resource)
2131b13d190SFrançois Tigeot {
2141b13d190SFrançois Tigeot 	if (drm_alloc_resource(dev, resource) != 0)
2151b13d190SFrançois Tigeot 		return 0;
2161b13d190SFrançois Tigeot 
2171b13d190SFrançois Tigeot 	return rman_get_start(dev->pcir[resource]);
2181b13d190SFrançois Tigeot }
2191b13d190SFrançois Tigeot 
2201b13d190SFrançois Tigeot unsigned long drm_get_resource_len(struct drm_device *dev,
2211b13d190SFrançois Tigeot 				   unsigned int resource)
2221b13d190SFrançois Tigeot {
2231b13d190SFrançois Tigeot 	if (drm_alloc_resource(dev, resource) != 0)
2241b13d190SFrançois Tigeot 		return 0;
2251b13d190SFrançois Tigeot 
2261b13d190SFrançois Tigeot 	return rman_get_size(dev->pcir[resource]);
2271b13d190SFrançois Tigeot }
2283f2dd94aSFrançois Tigeot #endif
2291dedbd3bSFrançois Tigeot 
2301dedbd3bSFrançois Tigeot /* Former drm_release() in the legacy DragonFly BSD drm codebase */
drm_device_detach(device_t kdev)2311dedbd3bSFrançois Tigeot int drm_device_detach(device_t kdev)
2321dedbd3bSFrançois Tigeot {
233bb916eedSFrançois Tigeot 	struct drm_softc *softc = device_get_softc(kdev);
234bb916eedSFrançois Tigeot 	struct drm_device *dev = softc->drm_driver_data;
2351dedbd3bSFrançois Tigeot 
2361dedbd3bSFrançois Tigeot 	drm_sysctl_cleanup(dev);
2371dedbd3bSFrançois Tigeot 
2381dedbd3bSFrançois Tigeot #ifdef __DragonFly__
2393f2dd94aSFrançois Tigeot #if 0
2401dedbd3bSFrançois Tigeot 	/* Clean up PCI resources allocated by drm_bufs.c.  We're not really
2411dedbd3bSFrançois Tigeot 	 * worried about resource consumption while the DRM is inactive (between
2421dedbd3bSFrançois Tigeot 	 * lastclose and firstopen or unload) because these aren't actually
2431dedbd3bSFrançois Tigeot 	 * taking up KVA, just keeping the PCI resource allocated.
2441dedbd3bSFrançois Tigeot 	 */
2451dedbd3bSFrançois Tigeot 	for (int i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
2461dedbd3bSFrançois Tigeot 		if (dev->pcir[i] == NULL)
2471dedbd3bSFrançois Tigeot 			continue;
2481dedbd3bSFrançois Tigeot 		bus_release_resource(dev->dev->bsddev, SYS_RES_MEMORY,
2491dedbd3bSFrançois Tigeot 		    dev->pcirid[i], dev->pcir[i]);
2501dedbd3bSFrançois Tigeot 		dev->pcir[i] = NULL;
2511dedbd3bSFrançois Tigeot 	}
2523f2dd94aSFrançois Tigeot #endif
2531dedbd3bSFrançois Tigeot 
2541dedbd3bSFrançois Tigeot 	if (dev->agp) {
2551dedbd3bSFrançois Tigeot 		kfree(dev->agp);
2561dedbd3bSFrançois Tigeot 		dev->agp = NULL;
2571dedbd3bSFrançois Tigeot 	}
2581dedbd3bSFrançois Tigeot 
2591dedbd3bSFrançois Tigeot 	if (dev->driver->unload != NULL) {
2601dedbd3bSFrançois Tigeot 		DRM_LOCK(dev);
2611dedbd3bSFrançois Tigeot 		dev->driver->unload(dev);
2621dedbd3bSFrançois Tigeot 		DRM_UNLOCK(dev);
2631dedbd3bSFrançois Tigeot 	}
2641dedbd3bSFrançois Tigeot 
2651dedbd3bSFrançois Tigeot 	if (pci_disable_busmaster(dev->dev->bsddev))
2661dedbd3bSFrançois Tigeot 		DRM_ERROR("Request to disable bus-master failed.\n");
2671dedbd3bSFrançois Tigeot 
2681dedbd3bSFrançois Tigeot 	lockuninit(&dev->vbl_lock);
2691dedbd3bSFrançois Tigeot 	lockuninit(&dev->event_lock);
2701dedbd3bSFrançois Tigeot 	lockuninit(&dev->struct_mutex);
2711dedbd3bSFrançois Tigeot #endif
2721dedbd3bSFrançois Tigeot 
2731dedbd3bSFrançois Tigeot 	return 0;
2741dedbd3bSFrançois Tigeot }
275