radeondrmkmsfb.c revision 1.3.6.2 1 1.3.6.2 tls /* $NetBSD: radeondrmkmsfb.c,v 1.3.6.2 2014/08/20 00:04:22 tls Exp $ */
2 1.3.6.2 tls
3 1.3.6.2 tls /*-
4 1.3.6.2 tls * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 1.3.6.2 tls * All rights reserved.
6 1.3.6.2 tls *
7 1.3.6.2 tls * This code is derived from software contributed to The NetBSD Foundation
8 1.3.6.2 tls * by Taylor R. Campbell.
9 1.3.6.2 tls *
10 1.3.6.2 tls * Redistribution and use in source and binary forms, with or without
11 1.3.6.2 tls * modification, are permitted provided that the following conditions
12 1.3.6.2 tls * are met:
13 1.3.6.2 tls * 1. Redistributions of source code must retain the above copyright
14 1.3.6.2 tls * notice, this list of conditions and the following disclaimer.
15 1.3.6.2 tls * 2. Redistributions in binary form must reproduce the above copyright
16 1.3.6.2 tls * notice, this list of conditions and the following disclaimer in the
17 1.3.6.2 tls * documentation and/or other materials provided with the distribution.
18 1.3.6.2 tls *
19 1.3.6.2 tls * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.3.6.2 tls * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.3.6.2 tls * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.3.6.2 tls * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.3.6.2 tls * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.3.6.2 tls * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.3.6.2 tls * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.3.6.2 tls * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.3.6.2 tls * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.3.6.2 tls * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.3.6.2 tls * POSSIBILITY OF SUCH DAMAGE.
30 1.3.6.2 tls */
31 1.3.6.2 tls
32 1.3.6.2 tls
33 1.3.6.2 tls #include <sys/cdefs.h>
34 1.3.6.2 tls __KERNEL_RCSID(0, "$NetBSD: radeondrmkmsfb.c,v 1.3.6.2 2014/08/20 00:04:22 tls Exp $");
35 1.3.6.2 tls
36 1.3.6.2 tls #ifdef _KERNEL_OPT
37 1.3.6.2 tls #include "vga.h"
38 1.3.6.2 tls #endif
39 1.3.6.2 tls
40 1.3.6.2 tls #include <sys/types.h>
41 1.3.6.2 tls #include <sys/device.h>
42 1.3.6.2 tls
43 1.3.6.2 tls #include <dev/pci/pciio.h>
44 1.3.6.2 tls #include <dev/pci/pcireg.h>
45 1.3.6.2 tls #include <dev/pci/pcivar.h>
46 1.3.6.2 tls
47 1.3.6.2 tls #include <dev/pci/wsdisplay_pci.h>
48 1.3.6.2 tls #include <dev/wsfb/genfbvar.h>
49 1.3.6.2 tls
50 1.3.6.2 tls #if NVGA > 0
51 1.3.6.2 tls /*
52 1.3.6.2 tls * XXX All we really need is vga_is_console from vgavar.h, but the
53 1.3.6.2 tls * header files are missing their own dependencies, so we need to
54 1.3.6.2 tls * explicitly drag in the other crap.
55 1.3.6.2 tls */
56 1.3.6.2 tls #include <dev/ic/mc6845reg.h>
57 1.3.6.2 tls #include <dev/ic/pcdisplayvar.h>
58 1.3.6.2 tls #include <dev/ic/vgareg.h>
59 1.3.6.2 tls #include <dev/ic/vgavar.h>
60 1.3.6.2 tls #endif
61 1.3.6.2 tls
62 1.3.6.2 tls #include <drm/drmP.h>
63 1.3.6.2 tls #include <drm/drm_fb_helper.h>
64 1.3.6.2 tls
65 1.3.6.2 tls #include <radeon.h>
66 1.3.6.2 tls #include "radeon_drv.h"
67 1.3.6.2 tls #include "radeon_task.h"
68 1.3.6.2 tls #include "radeondrmkmsfb.h"
69 1.3.6.2 tls
70 1.3.6.2 tls struct radeonfb_softc {
71 1.3.6.2 tls /* XXX genfb requires the genfb_softc to be first. */
72 1.3.6.2 tls struct genfb_softc sc_genfb;
73 1.3.6.2 tls device_t sc_dev;
74 1.3.6.2 tls struct radeonfb_attach_args sc_rfa;
75 1.3.6.2 tls struct radeon_task sc_setconfig_task;
76 1.3.6.2 tls bool sc_scheduled:1;
77 1.3.6.2 tls bool sc_attached:1;
78 1.3.6.2 tls };
79 1.3.6.2 tls
80 1.3.6.2 tls static int radeonfb_match(device_t, cfdata_t, void *);
81 1.3.6.2 tls static void radeonfb_attach(device_t, device_t, void *);
82 1.3.6.2 tls static int radeonfb_detach(device_t, int);
83 1.3.6.2 tls
84 1.3.6.2 tls static void radeonfb_setconfig_task(struct radeon_task *);
85 1.3.6.2 tls
86 1.3.6.2 tls static int radeonfb_genfb_ioctl(void *, void *, unsigned long, void *,
87 1.3.6.2 tls int, struct lwp *);
88 1.3.6.2 tls static paddr_t radeonfb_genfb_mmap(void *, void *, off_t, int);
89 1.3.6.2 tls static int radeonfb_genfb_enable_polling(void *);
90 1.3.6.2 tls static int radeonfb_genfb_disable_polling(void *);
91 1.3.6.2 tls
92 1.3.6.2 tls CFATTACH_DECL_NEW(radeondrmkmsfb, sizeof(struct radeonfb_softc),
93 1.3.6.2 tls radeonfb_match, radeonfb_attach, radeonfb_detach, NULL);
94 1.3.6.2 tls
95 1.3.6.2 tls static int
96 1.3.6.2 tls radeonfb_match(device_t parent, cfdata_t match, void *aux)
97 1.3.6.2 tls {
98 1.3.6.2 tls
99 1.3.6.2 tls return 1;
100 1.3.6.2 tls }
101 1.3.6.2 tls
102 1.3.6.2 tls static void
103 1.3.6.2 tls radeonfb_attach(device_t parent, device_t self, void *aux)
104 1.3.6.2 tls {
105 1.3.6.2 tls struct radeonfb_softc *const sc = device_private(self);
106 1.3.6.2 tls const struct radeonfb_attach_args *const rfa = aux;
107 1.3.6.2 tls int error;
108 1.3.6.2 tls
109 1.3.6.2 tls sc->sc_dev = self;
110 1.3.6.2 tls sc->sc_rfa = *rfa;
111 1.3.6.2 tls sc->sc_scheduled = false;
112 1.3.6.2 tls sc->sc_attached = false;
113 1.3.6.2 tls
114 1.3.6.2 tls aprint_naive("\n");
115 1.3.6.2 tls aprint_normal("\n");
116 1.3.6.2 tls
117 1.3.6.2 tls radeon_task_init(&sc->sc_setconfig_task, &radeonfb_setconfig_task);
118 1.3.6.2 tls error = radeon_task_schedule(parent, &sc->sc_setconfig_task);
119 1.3.6.2 tls if (error) {
120 1.3.6.2 tls aprint_error_dev(self, "failed to schedule mode set: %d\n",
121 1.3.6.2 tls error);
122 1.3.6.2 tls goto fail0;
123 1.3.6.2 tls }
124 1.3.6.2 tls sc->sc_scheduled = true;
125 1.3.6.2 tls
126 1.3.6.2 tls /* Success! */
127 1.3.6.2 tls return;
128 1.3.6.2 tls
129 1.3.6.2 tls fail0: return;
130 1.3.6.2 tls }
131 1.3.6.2 tls
132 1.3.6.2 tls static int
133 1.3.6.2 tls radeonfb_detach(device_t self, int flags)
134 1.3.6.2 tls {
135 1.3.6.2 tls struct radeonfb_softc *const sc = device_private(self);
136 1.3.6.2 tls
137 1.3.6.2 tls if (sc->sc_scheduled)
138 1.3.6.2 tls return EBUSY;
139 1.3.6.2 tls
140 1.3.6.2 tls if (sc->sc_attached) {
141 1.3.6.2 tls /* XXX genfb detach? Help? */
142 1.3.6.2 tls sc->sc_attached = false;
143 1.3.6.2 tls }
144 1.3.6.2 tls
145 1.3.6.2 tls return 0;
146 1.3.6.2 tls }
147 1.3.6.2 tls
148 1.3.6.2 tls static void
149 1.3.6.2 tls radeonfb_setconfig_task(struct radeon_task *task)
150 1.3.6.2 tls {
151 1.3.6.2 tls struct radeonfb_softc *const sc = container_of(task,
152 1.3.6.2 tls struct radeonfb_softc, sc_setconfig_task);
153 1.3.6.2 tls const prop_dictionary_t dict = device_properties(sc->sc_dev);
154 1.3.6.2 tls const struct radeonfb_attach_args *const rfa = &sc->sc_rfa;
155 1.3.6.2 tls const struct drm_fb_helper_surface_size *const sizes =
156 1.3.6.2 tls &rfa->rfa_fb_sizes;
157 1.3.6.2 tls enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons;
158 1.3.6.2 tls static const struct genfb_ops zero_genfb_ops;
159 1.3.6.2 tls struct genfb_ops genfb_ops = zero_genfb_ops;
160 1.3.6.2 tls int error;
161 1.3.6.2 tls
162 1.3.6.2 tls KASSERT(sc->sc_scheduled);
163 1.3.6.2 tls
164 1.3.6.2 tls /* XXX Ugh... Pass these parameters some other way! */
165 1.3.6.2 tls prop_dictionary_set_uint32(dict, "width", sizes->fb_width);
166 1.3.6.2 tls prop_dictionary_set_uint32(dict, "height", sizes->fb_height);
167 1.3.6.2 tls prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp);
168 1.3.6.2 tls prop_dictionary_set_uint16(dict, "linebytes",
169 1.3.6.2 tls roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64));
170 1.3.6.2 tls prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
171 1.3.6.2 tls CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
172 1.3.6.2 tls prop_dictionary_set_uint64(dict, "virtual_address",
173 1.3.6.2 tls (uint64_t)(uintptr_t)rfa->rfa_fb_ptr);
174 1.3.6.2 tls
175 1.3.6.2 tls /* XXX Whattakludge! */
176 1.3.6.2 tls #if NVGA > 0
177 1.3.6.2 tls if (vga_is_console(rfa->rfa_fb_helper->dev->pdev->pd_pa.pa_iot, -1)) {
178 1.3.6.2 tls what_was_cons = CONS_VGA;
179 1.3.6.2 tls prop_dictionary_set_bool(dict, "is_console", true);
180 1.3.6.2 tls vga_cndetach();
181 1.3.6.2 tls } else
182 1.3.6.2 tls #endif
183 1.3.6.2 tls if (genfb_is_console() && genfb_is_enabled()) {
184 1.3.6.2 tls what_was_cons = CONS_GENFB;
185 1.3.6.2 tls prop_dictionary_set_bool(dict, "is_console", true);
186 1.3.6.2 tls } else {
187 1.3.6.2 tls what_was_cons = CONS_NONE;
188 1.3.6.2 tls prop_dictionary_set_bool(dict, "is_console", false);
189 1.3.6.2 tls }
190 1.3.6.2 tls
191 1.3.6.2 tls sc->sc_genfb.sc_dev = sc->sc_dev;
192 1.3.6.2 tls genfb_init(&sc->sc_genfb);
193 1.3.6.2 tls genfb_ops.genfb_ioctl = radeonfb_genfb_ioctl;
194 1.3.6.2 tls genfb_ops.genfb_mmap = radeonfb_genfb_mmap;
195 1.3.6.2 tls genfb_ops.genfb_enable_polling = radeonfb_genfb_enable_polling;
196 1.3.6.2 tls genfb_ops.genfb_disable_polling = radeonfb_genfb_disable_polling;
197 1.3.6.2 tls
198 1.3.6.2 tls error = genfb_attach(&sc->sc_genfb, &genfb_ops);
199 1.3.6.2 tls if (error) {
200 1.3.6.2 tls aprint_error_dev(sc->sc_dev, "failed to attach genfb: %d\n",
201 1.3.6.2 tls error);
202 1.3.6.2 tls goto fail0;
203 1.3.6.2 tls }
204 1.3.6.2 tls sc->sc_attached = true;
205 1.3.6.2 tls
206 1.3.6.2 tls drm_fb_helper_set_config(sc->sc_rfa.rfa_fb_helper);
207 1.3.6.2 tls
208 1.3.6.2 tls /* Success! */
209 1.3.6.2 tls sc->sc_scheduled = false;
210 1.3.6.2 tls return;
211 1.3.6.2 tls
212 1.3.6.2 tls fail0: /* XXX Restore console... */
213 1.3.6.2 tls switch (what_was_cons) {
214 1.3.6.2 tls case CONS_VGA:
215 1.3.6.2 tls break;
216 1.3.6.2 tls case CONS_GENFB:
217 1.3.6.2 tls break;
218 1.3.6.2 tls case CONS_NONE:
219 1.3.6.2 tls break;
220 1.3.6.2 tls default:
221 1.3.6.2 tls break;
222 1.3.6.2 tls }
223 1.3.6.2 tls }
224 1.3.6.2 tls
225 1.3.6.2 tls static int
226 1.3.6.2 tls radeonfb_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
227 1.3.6.2 tls struct lwp *l)
228 1.3.6.2 tls {
229 1.3.6.2 tls struct genfb_softc *const genfb = v;
230 1.3.6.2 tls struct radeonfb_softc *const sc = container_of(genfb,
231 1.3.6.2 tls struct radeonfb_softc, sc_genfb);
232 1.3.6.2 tls struct drm_device *const dev = sc->sc_rfa.rfa_fb_helper->dev;
233 1.3.6.2 tls const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
234 1.3.6.2 tls
235 1.3.6.2 tls switch (cmd) {
236 1.3.6.2 tls case WSDISPLAYIO_GTYPE:
237 1.3.6.2 tls *(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA;
238 1.3.6.2 tls return 0;
239 1.3.6.2 tls
240 1.3.6.2 tls /* PCI config read/write passthrough. */
241 1.3.6.2 tls case PCI_IOC_CFGREAD:
242 1.3.6.2 tls case PCI_IOC_CFGWRITE:
243 1.3.6.2 tls return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l);
244 1.3.6.2 tls
245 1.3.6.2 tls case WSDISPLAYIO_GET_BUSID:
246 1.3.6.2 tls return wsdisplayio_busid_pci(dev->dev, pa->pa_pc, pa->pa_tag,
247 1.3.6.2 tls data);
248 1.3.6.2 tls
249 1.3.6.2 tls default:
250 1.3.6.2 tls return EPASSTHROUGH;
251 1.3.6.2 tls }
252 1.3.6.2 tls }
253 1.3.6.2 tls
254 1.3.6.2 tls static paddr_t
255 1.3.6.2 tls radeonfb_genfb_mmap(void *v, void *vs, off_t offset, int prot)
256 1.3.6.2 tls {
257 1.3.6.2 tls struct genfb_softc *const genfb = v;
258 1.3.6.2 tls struct radeonfb_softc *const sc = container_of(genfb,
259 1.3.6.2 tls struct radeonfb_softc, sc_genfb);
260 1.3.6.2 tls struct drm_fb_helper *const helper = sc->sc_rfa.rfa_fb_helper;
261 1.3.6.2 tls struct drm_framebuffer *const fb = helper->fb;
262 1.3.6.2 tls struct radeon_framebuffer *const rfb = container_of(fb,
263 1.3.6.2 tls struct radeon_framebuffer, base);
264 1.3.6.2 tls struct drm_gem_object *const gobj = rfb->obj;
265 1.3.6.2 tls struct radeon_bo *const rbo = gem_to_radeon_bo(gobj);
266 1.3.6.2 tls struct drm_device *const dev = helper->dev;
267 1.3.6.2 tls const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
268 1.3.6.2 tls unsigned int i;
269 1.3.6.2 tls
270 1.3.6.2 tls if (offset < 0)
271 1.3.6.2 tls return -1;
272 1.3.6.2 tls
273 1.3.6.2 tls /* Treat low memory as the framebuffer itself. */
274 1.3.6.2 tls if (offset < genfb->sc_fbsize) {
275 1.3.6.2 tls const unsigned num_pages __diagused = rbo->tbo.num_pages;
276 1.3.6.2 tls int flags = 0;
277 1.3.6.2 tls
278 1.3.6.2 tls KASSERT(genfb->sc_fbsize == (num_pages << PAGE_SHIFT));
279 1.3.6.2 tls KASSERT(rbo->tbo.mem.bus.is_iomem);
280 1.3.6.2 tls
281 1.3.6.2 tls if (ISSET(rbo->tbo.mem.placement, TTM_PL_FLAG_WC))
282 1.3.6.2 tls flags |= BUS_SPACE_MAP_PREFETCHABLE;
283 1.3.6.2 tls
284 1.3.6.2 tls return bus_space_mmap(rbo->tbo.bdev->memt,
285 1.3.6.2 tls rbo->tbo.mem.bus.base, rbo->tbo.mem.bus.offset + offset,
286 1.3.6.2 tls prot, flags);
287 1.3.6.2 tls }
288 1.3.6.2 tls
289 1.3.6.2 tls /* XXX Cargo-culted from genfb_pci. */
290 1.3.6.2 tls if (kauth_authorize_machdep(kauth_cred_get(),
291 1.3.6.2 tls KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
292 1.3.6.2 tls aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n",
293 1.3.6.2 tls (uintmax_t)offset);
294 1.3.6.2 tls return -1;
295 1.3.6.2 tls }
296 1.3.6.2 tls
297 1.3.6.2 tls for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) {
298 1.3.6.2 tls pcireg_t type;
299 1.3.6.2 tls bus_addr_t addr;
300 1.3.6.2 tls bus_size_t size;
301 1.3.6.2 tls int flags;
302 1.3.6.2 tls
303 1.3.6.2 tls /* Interrogate the BAR. */
304 1.3.6.2 tls if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i),
305 1.3.6.2 tls &type))
306 1.3.6.2 tls continue;
307 1.3.6.2 tls if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM)
308 1.3.6.2 tls continue;
309 1.3.6.2 tls if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type,
310 1.3.6.2 tls &addr, &size, &flags))
311 1.3.6.2 tls continue;
312 1.3.6.2 tls
313 1.3.6.2 tls /* Try to map it if it's in range. */
314 1.3.6.2 tls if ((addr <= offset) && (offset < (addr + size)))
315 1.3.6.2 tls return bus_space_mmap(pa->pa_memt, addr,
316 1.3.6.2 tls (offset - addr), prot, flags);
317 1.3.6.2 tls
318 1.3.6.2 tls /* Skip a slot if this was a 64-bit BAR. */
319 1.3.6.2 tls if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) &&
320 1.3.6.2 tls (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT))
321 1.3.6.2 tls i += 1;
322 1.3.6.2 tls }
323 1.3.6.2 tls
324 1.3.6.2 tls /* Failure! */
325 1.3.6.2 tls return -1;
326 1.3.6.2 tls }
327 1.3.6.2 tls
328 1.3.6.2 tls static int
329 1.3.6.2 tls radeonfb_genfb_enable_polling(void *cookie)
330 1.3.6.2 tls {
331 1.3.6.2 tls struct genfb_softc *const genfb = cookie;
332 1.3.6.2 tls struct radeonfb_softc *const sc = container_of(genfb,
333 1.3.6.2 tls struct radeonfb_softc, sc_genfb);
334 1.3.6.2 tls
335 1.3.6.2 tls return drm_fb_helper_debug_enter_fb(sc->sc_rfa.rfa_fb_helper);
336 1.3.6.2 tls }
337 1.3.6.2 tls
338 1.3.6.2 tls static int
339 1.3.6.2 tls radeonfb_genfb_disable_polling(void *cookie)
340 1.3.6.2 tls {
341 1.3.6.2 tls struct genfb_softc *const genfb = cookie;
342 1.3.6.2 tls struct radeonfb_softc *const sc = container_of(genfb,
343 1.3.6.2 tls struct radeonfb_softc, sc_genfb);
344 1.3.6.2 tls
345 1.3.6.2 tls return drm_fb_helper_debug_leave_fb(sc->sc_rfa.rfa_fb_helper);
346 1.3.6.2 tls }
347