drm/linux: Add sign_extend64()
[dragonfly.git] / sys / dev / drm / drm_dragonfly.c
blob391db92e0ea758c7a5d1ddf39fcd3f9337cff411
1 /*
2 * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
3 * Copyright (c) 2015 Rimvydas Jasinskas
5 * DRM Dragonfly-specific helper functions
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting documentation, and
11 * that the name of the copyright holders not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. The copyright holders make no representations
14 * about the suitability of this software for any purpose. It is provided "as
15 * is" without express or implied warranty.
17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 * OF THIS SOFTWARE.
26 #include <sys/libkern.h>
27 #include <sys/ctype.h>
28 #include <drm/drmP.h>
31 * An implementation of fb_get_options()
32 * This can be used to set the video mode used for the syscons fb console,
33 * a la "video=..." in linux.
35 int
36 fb_get_options(const char *connector_name, char **option)
38 char buf[128], str[1024];
41 * Where on linux one would use the command line option
42 * video=LVDS-1:<video-mode>, the corresponding tunable is
43 * drm.video.LVDS-1=<video-mode>.
44 * e.g. drm.video.LVDS-1=1024x768 sets the LVDS-1 connector to
45 * a 1024x768 video mode in the syscons framebuffer console.
46 * See https://wiki.archlinux.org/index.php/Kernel_mode_setting
47 * for an explanation of the video mode command line option.
49 memset(str, 0, sizeof(str));
50 ksnprintf(buf, sizeof(buf), "drm.video.%s", connector_name);
51 if (kgetenv_string(buf, str, sizeof(str)-1)) {
52 kprintf("found kenv %s=%s\n", buf, str);
53 *option = kstrdup(str, M_DRM);
54 return (0);
55 } else {
56 kprintf("tunable %s is not set\n", buf);
57 return (1);
62 * Implement simplified version of kvasnrprintf() for drm needs using
63 * M_DRM and kvsnprintf(). Since it is unclear what string size is
64 * optimal thus use of an actual length.
66 char *drm_vasprintf(int flags, const char *format, __va_list ap)
68 char *str;
69 size_t size;
70 __va_list aq;
72 __va_copy(aq, ap);
73 size = kvsnprintf(NULL, 0, format, aq);
74 __va_end(aq);
76 str = kmalloc(size+1, M_DRM, flags);
77 if (str == NULL)
78 return NULL;
80 kvsnprintf(str, size+1, format, ap);
82 return str;
85 /* mimic ksnrprintf(), return pointer to char* and match drm api */
86 char *drm_asprintf(int flags, const char *format, ...)
88 char *str;
89 __va_list ap;
91 __va_start(ap, format);
92 str = drm_vasprintf(flags, format, ap);
93 __va_end(ap);
95 return str;
99 * XXX pci glue logic helpers
100 * Should be done in drm_pci_init(), pending drm update.
101 * Assumes static runtime data.
102 * Only for usage in *_driver_[un]load()
105 static void drm_fill_pdev(struct device *dev, struct pci_dev *pdev)
107 pdev->dev = dev;
108 pdev->vendor = pci_get_vendor(dev);
109 pdev->device = pci_get_device(dev);
110 pdev->subsystem_vendor = pci_get_subvendor(dev);
111 pdev->subsystem_device = pci_get_subdevice(dev);
113 pdev->revision = pci_get_revid(dev) & 0xff;
116 void drm_init_pdev(struct device *dev, struct pci_dev **pdev)
118 BUG_ON(*pdev != NULL);
120 *pdev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
121 drm_fill_pdev(dev, *pdev);
123 (*pdev)->bus = kzalloc(sizeof(struct pci_bus), GFP_KERNEL);
124 (*pdev)->bus->self = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
126 drm_fill_pdev(device_get_parent(dev), (*pdev)->bus->self);
127 (*pdev)->bus->number = pci_get_bus(dev);
130 void drm_fini_pdev(struct pci_dev **pdev)
132 kfree((*pdev)->bus->self);
133 kfree((*pdev)->bus);
135 kfree(*pdev);
138 void drm_print_pdev(struct pci_dev *pdev)
140 if (pdev == NULL) {
141 DRM_ERROR("pdev is null!\n");
142 return;
145 DRM_INFO("pdev: vendor=0x%04x device=0x%04x rev=0x%02x\n",
146 pdev->vendor, pdev->device, pdev->revision);
147 DRM_INFO(" svendor=0x%04x sdevice=0x%04x irq=%u\n",
148 pdev->subsystem_vendor, pdev->subsystem_device, pdev->irq);
151 /* Allocation of PCI memory resources (framebuffer, registers, etc.) for
152 * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual
153 * address for accessing them. Cleaned up at unload.
155 static int drm_alloc_resource(struct drm_device *dev, int resource)
157 struct resource *res;
158 int rid;
160 DRM_LOCK_ASSERT(dev);
162 if (resource >= DRM_MAX_PCI_RESOURCE) {
163 DRM_ERROR("Resource %d too large\n", resource);
164 return 1;
167 if (dev->pcir[resource] != NULL) {
168 return 0;
171 DRM_UNLOCK(dev);
172 rid = PCIR_BAR(resource);
173 res = bus_alloc_resource_any(dev->dev, SYS_RES_MEMORY, &rid,
174 RF_SHAREABLE);
175 DRM_LOCK(dev);
176 if (res == NULL) {
177 DRM_ERROR("Couldn't find resource 0x%x\n", resource);
178 return 1;
181 if (dev->pcir[resource] == NULL) {
182 dev->pcirid[resource] = rid;
183 dev->pcir[resource] = res;
186 return 0;
189 unsigned long drm_get_resource_start(struct drm_device *dev,
190 unsigned int resource)
192 if (drm_alloc_resource(dev, resource) != 0)
193 return 0;
195 return rman_get_start(dev->pcir[resource]);
198 unsigned long drm_get_resource_len(struct drm_device *dev,
199 unsigned int resource)
201 if (drm_alloc_resource(dev, resource) != 0)
202 return 0;
204 return rman_get_size(dev->pcir[resource]);