1e5fe6c2c84e334d7adfcf7d91d289a72e573691
[dragonfly.git] / sys / dev / drm / drm_dragonfly.c
1 /*
2  * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
3  * Copyright (c) 2015 Rimvydas Jasinskas
4  *
5  * DRM Dragonfly-specific helper functions
6  *
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.
16  *
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.
24  */
25
26 #include <sys/libkern.h>
27 #include <sys/ctype.h>
28 #include <drm/drmP.h>
29
30 /*
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.
34  */
35 int
36 fb_get_options(const char *connector_name, char **option)
37 {
38         char buf[128], str[1024];
39         int i;
40
41         /*
42          * This hack allows us to use drm.video.lvds1="<video-mode>"
43          * in loader.conf, where linux would use video=LVDS-1:<video-mode>.
44          * e.g. drm.video.lvds1=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.
48          * (This corresponds to the video= Linux kernel command-line
49          * option)
50          */
51         memset(str, 0, sizeof(str));
52         ksnprintf(buf, sizeof(buf), "drm.video.%s", connector_name);
53         i = 0;
54         while (i < strlen(buf)) {
55                 buf[i] = tolower(buf[i]);
56                 if (buf[i] == '-') {
57                         memmove(&buf[i], &buf[i+1], strlen(buf)-i);
58                 } else {
59                         i++;
60                 }
61         }
62         kprintf("looking up kenv for \"%s\"\n", buf);
63         if (kgetenv_string(buf, str, sizeof(str)-1)) {
64                 kprintf("found kenv %s=%s\n", buf, str);
65                 *option = kstrdup(str, M_DRM);
66                 return (0);
67         } else {
68                 kprintf("didn't find value for kenv %s\n", buf);
69                 return (1);
70         }
71 }
72
73 /*
74  * Implement simplified version of kvasnrprintf() for drm needs using
75  * M_DRM and kvsnprintf(). Since it is unclear what string size is
76  * optimal thus use of an actual length.
77  */
78 char *drm_vasprintf(int flags, const char *format, __va_list ap)
79 {
80         char *str;
81         size_t size;
82         __va_list aq;
83
84         __va_copy(aq, ap);
85         size = kvsnprintf(NULL, 0, format, aq);
86         __va_end(aq);
87
88         str = kmalloc(size+1, M_DRM, flags);
89         if (str == NULL)
90                 return NULL;
91
92         kvsnprintf(str, size+1, format, ap);
93
94         return str;
95 }
96
97 /* mimic ksnrprintf(), return pointer to char* and match drm api */
98 char *drm_asprintf(int flags, const char *format, ...)
99 {
100         char *str;
101         __va_list ap;
102
103         __va_start(ap, format);
104         str = drm_vasprintf(flags, format, ap);
105         __va_end(ap);
106
107         return str;
108 }
109
110 /*
111  * XXX pci glue logic helpers
112  * Should be done in drm_pci_init(), pending drm update.
113  * Assumes static runtime data.
114  * Only for usage in *_driver_[un]load()
115  */
116
117 static void drm_fill_pdev(struct device *dev, struct pci_dev *pdev)
118 {
119         pdev->dev = dev;
120         pdev->vendor = pci_get_vendor(dev);
121         pdev->device = pci_get_device(dev);
122         pdev->subsystem_vendor = pci_get_subvendor(dev);
123         pdev->subsystem_device = pci_get_subdevice(dev);
124 }
125
126 void drm_init_pdev(struct device *dev, struct pci_dev **pdev)
127 {
128         BUG_ON(*pdev != NULL);
129
130         *pdev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
131         drm_fill_pdev(dev, *pdev);
132
133         (*pdev)->bus = kzalloc(sizeof(struct pci_bus), GFP_KERNEL);
134         (*pdev)->bus->self = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
135
136         drm_fill_pdev(device_get_parent(dev), (*pdev)->bus->self);
137         (*pdev)->bus->number = pci_get_bus(dev);
138 }
139
140 void drm_fini_pdev(struct pci_dev **pdev)
141 {
142         kfree((*pdev)->bus->self);
143         kfree((*pdev)->bus);
144
145         kfree(*pdev);
146 }