intelfb.c revision 1.6 1 1.6 riastrad /* $NetBSD: intelfb.c,v 1.6 2014/08/05 20:28:56 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation
8 1.1 riastrad * by Taylor R. Campbell.
9 1.1 riastrad *
10 1.1 riastrad * Redistribution and use in source and binary forms, with or without
11 1.1 riastrad * modification, are permitted provided that the following conditions
12 1.1 riastrad * are met:
13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
14 1.1 riastrad * notice, this list of conditions and the following disclaimer.
15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
17 1.1 riastrad * documentation and/or other materials provided with the distribution.
18 1.1 riastrad *
19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
30 1.1 riastrad */
31 1.1 riastrad
32 1.1 riastrad #include <sys/cdefs.h>
33 1.6 riastrad __KERNEL_RCSID(0, "$NetBSD: intelfb.c,v 1.6 2014/08/05 20:28:56 riastradh Exp $");
34 1.1 riastrad
35 1.1 riastrad #ifdef _KERNEL_OPT
36 1.1 riastrad #include "vga.h"
37 1.1 riastrad #endif
38 1.1 riastrad
39 1.1 riastrad #include <sys/types.h>
40 1.1 riastrad #include <sys/bus.h>
41 1.1 riastrad #include <sys/device.h>
42 1.1 riastrad
43 1.1 riastrad #include <dev/pci/pciio.h>
44 1.1 riastrad #include <dev/pci/pcireg.h>
45 1.1 riastrad #include <dev/pci/pcivar.h>
46 1.1 riastrad
47 1.1 riastrad #include <dev/pci/wsdisplay_pci.h>
48 1.1 riastrad #include <dev/wsfb/genfbvar.h>
49 1.1 riastrad
50 1.1 riastrad #if NVGA > 0
51 1.1 riastrad /*
52 1.1 riastrad * XXX All we really need is vga_is_console from vgavar.h, but the
53 1.1 riastrad * header files are missing their own dependencies, so we need to
54 1.1 riastrad * explicitly drag in the other crap.
55 1.1 riastrad */
56 1.1 riastrad #include <dev/ic/mc6845reg.h>
57 1.1 riastrad #include <dev/ic/pcdisplayvar.h>
58 1.1 riastrad #include <dev/ic/vgareg.h>
59 1.1 riastrad #include <dev/ic/vgavar.h>
60 1.1 riastrad #endif
61 1.1 riastrad
62 1.1 riastrad #include <drm/drmP.h>
63 1.1 riastrad #include <drm/drm_fb_helper.h>
64 1.1 riastrad
65 1.1 riastrad #include "i915_drv.h"
66 1.1 riastrad #include "i915_pci.h"
67 1.1 riastrad #include "intelfb.h"
68 1.1 riastrad
69 1.1 riastrad struct intelfb_softc {
70 1.1 riastrad /* XXX genfb requires the genfb_softc to be first. */
71 1.1 riastrad struct genfb_softc sc_genfb;
72 1.1 riastrad device_t sc_dev;
73 1.1 riastrad struct intelfb_attach_args sc_ifa;
74 1.1 riastrad bus_space_handle_t sc_fb_bsh;
75 1.1 riastrad struct i915drmkms_task sc_setconfig_task;
76 1.1 riastrad bool sc_mapped:1;
77 1.1 riastrad bool sc_scheduled:1;
78 1.1 riastrad bool sc_attached:1;
79 1.1 riastrad };
80 1.1 riastrad
81 1.1 riastrad static int intelfb_match(device_t, cfdata_t, void *);
82 1.1 riastrad static void intelfb_attach(device_t, device_t, void *);
83 1.1 riastrad static int intelfb_detach(device_t, int);
84 1.1 riastrad
85 1.1 riastrad static void intelfb_setconfig_task(struct i915drmkms_task *);
86 1.1 riastrad
87 1.1 riastrad static int intelfb_genfb_dpms(struct drm_device *, int);
88 1.1 riastrad static int intelfb_genfb_ioctl(void *, void *, unsigned long, void *,
89 1.1 riastrad int, struct lwp *);
90 1.1 riastrad static paddr_t intelfb_genfb_mmap(void *, void *, off_t, int);
91 1.1 riastrad static int intelfb_genfb_enable_polling(void *);
92 1.1 riastrad static int intelfb_genfb_disable_polling(void *);
93 1.1 riastrad
94 1.1 riastrad CFATTACH_DECL_NEW(intelfb, sizeof(struct intelfb_softc),
95 1.1 riastrad intelfb_match, intelfb_attach, intelfb_detach, NULL);
96 1.1 riastrad
97 1.1 riastrad static int
98 1.1 riastrad intelfb_match(device_t parent, cfdata_t match, void *aux)
99 1.1 riastrad {
100 1.1 riastrad
101 1.1 riastrad return 1;
102 1.1 riastrad }
103 1.1 riastrad
104 1.1 riastrad static void
105 1.1 riastrad intelfb_attach(device_t parent, device_t self, void *aux)
106 1.1 riastrad {
107 1.1 riastrad struct intelfb_softc *const sc = device_private(self);
108 1.1 riastrad const struct intelfb_attach_args *const ifa = aux;
109 1.1 riastrad int error;
110 1.1 riastrad
111 1.1 riastrad sc->sc_dev = self;
112 1.1 riastrad sc->sc_ifa = *ifa;
113 1.1 riastrad sc->sc_mapped = false;
114 1.1 riastrad sc->sc_scheduled = false;
115 1.1 riastrad sc->sc_attached = false;
116 1.1 riastrad
117 1.5 riastrad aprint_naive("\n");
118 1.5 riastrad aprint_normal("\n");
119 1.5 riastrad
120 1.1 riastrad /* XXX Defer this too? */
121 1.1 riastrad error = bus_space_map(ifa->ifa_fb_bst, ifa->ifa_fb_addr,
122 1.1 riastrad ifa->ifa_fb_size,
123 1.1 riastrad (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE),
124 1.1 riastrad &sc->sc_fb_bsh);
125 1.1 riastrad if (error) {
126 1.1 riastrad aprint_error_dev(self, "unable to map framebuffer: %d\n",
127 1.1 riastrad error);
128 1.1 riastrad goto fail0;
129 1.1 riastrad }
130 1.1 riastrad sc->sc_mapped = true;
131 1.1 riastrad
132 1.1 riastrad i915drmkms_task_init(&sc->sc_setconfig_task, &intelfb_setconfig_task);
133 1.1 riastrad error = i915drmkms_task_schedule(parent, &sc->sc_setconfig_task);
134 1.1 riastrad if (error) {
135 1.1 riastrad aprint_error_dev(self, "failed to schedule mode set: %d\n",
136 1.1 riastrad error);
137 1.1 riastrad goto fail1;
138 1.1 riastrad }
139 1.1 riastrad sc->sc_scheduled = true;
140 1.1 riastrad
141 1.1 riastrad /* Success! */
142 1.1 riastrad return;
143 1.1 riastrad
144 1.1 riastrad fail1: bus_space_unmap(ifa->ifa_fb_bst, sc->sc_fb_bsh, ifa->ifa_fb_size);
145 1.1 riastrad sc->sc_mapped = false;
146 1.1 riastrad fail0: return;
147 1.1 riastrad }
148 1.1 riastrad
149 1.1 riastrad static int
150 1.1 riastrad intelfb_detach(device_t self, int flags)
151 1.1 riastrad {
152 1.1 riastrad struct intelfb_softc *const sc = device_private(self);
153 1.1 riastrad
154 1.1 riastrad if (sc->sc_scheduled)
155 1.1 riastrad return EBUSY;
156 1.1 riastrad
157 1.1 riastrad if (sc->sc_attached) {
158 1.1 riastrad /* XXX genfb detach? Help? */
159 1.1 riastrad sc->sc_attached = false;
160 1.1 riastrad }
161 1.1 riastrad
162 1.1 riastrad if (sc->sc_mapped) {
163 1.1 riastrad bus_space_unmap(sc->sc_ifa.ifa_fb_bst, sc->sc_fb_bsh,
164 1.1 riastrad sc->sc_ifa.ifa_fb_size);
165 1.1 riastrad sc->sc_mapped = false;
166 1.1 riastrad }
167 1.1 riastrad
168 1.1 riastrad return 0;
169 1.1 riastrad }
170 1.1 riastrad
171 1.1 riastrad static void
172 1.1 riastrad intelfb_setconfig_task(struct i915drmkms_task *task)
173 1.1 riastrad {
174 1.1 riastrad struct intelfb_softc *const sc = container_of(task,
175 1.1 riastrad struct intelfb_softc, sc_setconfig_task);
176 1.1 riastrad const prop_dictionary_t dict = device_properties(sc->sc_dev);
177 1.1 riastrad const struct intelfb_attach_args *const ifa = &sc->sc_ifa;
178 1.1 riastrad const struct drm_fb_helper_surface_size *const sizes =
179 1.1 riastrad &ifa->ifa_fb_sizes;
180 1.1 riastrad #if NVGA > 0 /* XXX no workie for modules */
181 1.1 riastrad struct drm_device *const dev = sc->sc_ifa.ifa_drm_dev;
182 1.1 riastrad #endif
183 1.1 riastrad enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons;
184 1.1 riastrad static const struct genfb_ops zero_genfb_ops;
185 1.1 riastrad struct genfb_ops genfb_ops = zero_genfb_ops;
186 1.1 riastrad int error;
187 1.1 riastrad
188 1.1 riastrad KASSERT(sc->sc_scheduled);
189 1.1 riastrad
190 1.1 riastrad if (ifa->ifa_fb_zero)
191 1.1 riastrad bus_space_set_region_1(sc->sc_ifa.ifa_fb_bst, sc->sc_fb_bsh, 0,
192 1.1 riastrad 0, sc->sc_ifa.ifa_fb_size);
193 1.1 riastrad
194 1.1 riastrad /* XXX Ugh... Pass these parameters some other way! */
195 1.6 riastrad prop_dictionary_set_uint32(dict, "width", sizes->surface_width);
196 1.6 riastrad prop_dictionary_set_uint32(dict, "height", sizes->surface_height);
197 1.1 riastrad prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp);
198 1.1 riastrad prop_dictionary_set_uint16(dict, "linebytes",
199 1.6 riastrad roundup2((sizes->surface_width * howmany(sizes->surface_bpp, 8)),
200 1.6 riastrad 64));
201 1.1 riastrad prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
202 1.1 riastrad CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
203 1.1 riastrad prop_dictionary_set_uint64(dict, "virtual_address",
204 1.1 riastrad (uint64_t)(uintptr_t)bus_space_vaddr(sc->sc_ifa.ifa_fb_bst,
205 1.1 riastrad sc->sc_fb_bsh));
206 1.1 riastrad
207 1.1 riastrad /* XXX Whattakludge! */
208 1.1 riastrad #if NVGA > 0
209 1.1 riastrad if (vga_is_console(dev->pdev->pd_pa.pa_iot, -1)) {
210 1.1 riastrad what_was_cons = CONS_VGA;
211 1.1 riastrad prop_dictionary_set_bool(dict, "is_console", true);
212 1.1 riastrad i915_disable_vga(dev);
213 1.1 riastrad vga_cndetach();
214 1.1 riastrad } else
215 1.1 riastrad #endif
216 1.1 riastrad if (genfb_is_console() && genfb_is_enabled()) {
217 1.1 riastrad what_was_cons = CONS_GENFB;
218 1.1 riastrad prop_dictionary_set_bool(dict, "is_console", true);
219 1.1 riastrad } else {
220 1.1 riastrad what_was_cons = CONS_NONE;
221 1.1 riastrad prop_dictionary_set_bool(dict, "is_console", false);
222 1.1 riastrad }
223 1.1 riastrad
224 1.1 riastrad sc->sc_genfb.sc_dev = sc->sc_dev;
225 1.1 riastrad genfb_init(&sc->sc_genfb);
226 1.1 riastrad genfb_ops.genfb_ioctl = intelfb_genfb_ioctl;
227 1.1 riastrad genfb_ops.genfb_mmap = intelfb_genfb_mmap;
228 1.1 riastrad genfb_ops.genfb_enable_polling = intelfb_genfb_enable_polling;
229 1.1 riastrad genfb_ops.genfb_disable_polling = intelfb_genfb_disable_polling;
230 1.1 riastrad
231 1.1 riastrad error = genfb_attach(&sc->sc_genfb, &genfb_ops);
232 1.1 riastrad if (error) {
233 1.1 riastrad aprint_error_dev(sc->sc_dev, "failed to attach genfb: %d\n",
234 1.1 riastrad error);
235 1.1 riastrad goto fail0;
236 1.1 riastrad }
237 1.1 riastrad sc->sc_attached = true;
238 1.1 riastrad
239 1.1 riastrad drm_fb_helper_set_config(sc->sc_ifa.ifa_fb_helper);
240 1.1 riastrad
241 1.1 riastrad /* Success! */
242 1.1 riastrad sc->sc_scheduled = false;
243 1.1 riastrad return;
244 1.1 riastrad
245 1.1 riastrad fail0: /* XXX Restore console... */
246 1.1 riastrad switch (what_was_cons) {
247 1.1 riastrad case CONS_VGA:
248 1.1 riastrad break;
249 1.1 riastrad case CONS_GENFB:
250 1.1 riastrad break;
251 1.1 riastrad case CONS_NONE:
252 1.1 riastrad break;
253 1.1 riastrad default:
254 1.1 riastrad break;
255 1.1 riastrad }
256 1.1 riastrad }
257 1.1 riastrad
258 1.1 riastrad static int
259 1.1 riastrad intelfb_genfb_dpms(struct drm_device *dev, int dpms_mode)
260 1.1 riastrad {
261 1.1 riastrad struct drm_i915_private *const dev_priv = dev->dev_private;
262 1.1 riastrad /* XXX What guarantees dev_priv->fbdev stays around? */
263 1.1 riastrad struct drm_fb_helper *const fb_helper = &dev_priv->fbdev->helper;
264 1.1 riastrad unsigned i;
265 1.1 riastrad
266 1.1 riastrad drm_modeset_lock_all(dev);
267 1.1 riastrad for (i = 0; i < fb_helper->connector_count; i++) {
268 1.1 riastrad struct drm_connector *const connector =
269 1.1 riastrad fb_helper->connector_info[i]->connector;
270 1.1 riastrad (*connector->funcs->dpms)(connector, dpms_mode);
271 1.1 riastrad drm_object_property_set_value(&connector->base,
272 1.1 riastrad dev->mode_config.dpms_property, dpms_mode);
273 1.1 riastrad }
274 1.1 riastrad drm_modeset_unlock_all(dev);
275 1.1 riastrad
276 1.1 riastrad return 0;
277 1.1 riastrad }
278 1.1 riastrad
279 1.1 riastrad static int
280 1.1 riastrad intelfb_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
281 1.1 riastrad struct lwp *l)
282 1.1 riastrad {
283 1.1 riastrad struct genfb_softc *const genfb = v;
284 1.1 riastrad struct intelfb_softc *const sc = container_of(genfb,
285 1.1 riastrad struct intelfb_softc, sc_genfb);
286 1.1 riastrad struct drm_device *const dev = sc->sc_ifa.ifa_fb_helper->dev;
287 1.1 riastrad const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
288 1.1 riastrad
289 1.1 riastrad switch (cmd) {
290 1.1 riastrad case WSDISPLAYIO_GTYPE:
291 1.1 riastrad *(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA;
292 1.1 riastrad return 0;
293 1.1 riastrad
294 1.1 riastrad /* PCI config read/write passthrough. */
295 1.1 riastrad case PCI_IOC_CFGREAD:
296 1.1 riastrad case PCI_IOC_CFGWRITE:
297 1.1 riastrad return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l);
298 1.1 riastrad
299 1.1 riastrad case WSDISPLAYIO_GET_BUSID:
300 1.2 riastrad return wsdisplayio_busid_pci(dev->dev, pa->pa_pc, pa->pa_tag,
301 1.2 riastrad data);
302 1.1 riastrad
303 1.1 riastrad /*
304 1.1 riastrad * Screen blanking ioctls. Not to be confused with backlight
305 1.1 riastrad * (can be disabled while stuff is still drawn on the screen),
306 1.1 riastrad * brightness, or contrast (which we don't support). Backlight
307 1.1 riastrad * and brightness are done through WSDISPLAYIO_{GET,SET}PARAM.
308 1.1 riastrad * This toggles between DPMS ON and DPMS OFF; backlight toggles
309 1.1 riastrad * between DPMS ON and DPMS SUSPEND.
310 1.1 riastrad */
311 1.1 riastrad case WSDISPLAYIO_GVIDEO: {
312 1.1 riastrad int *onp = (int *)data;
313 1.1 riastrad
314 1.1 riastrad /* XXX Can't really determine a single answer here. */
315 1.1 riastrad *onp = 1;
316 1.1 riastrad return 0;
317 1.1 riastrad }
318 1.1 riastrad
319 1.1 riastrad case WSDISPLAYIO_SVIDEO: {
320 1.1 riastrad const int on = *(const int *)data;
321 1.1 riastrad
322 1.1 riastrad return intelfb_genfb_dpms(dev,
323 1.1 riastrad on? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF);
324 1.1 riastrad }
325 1.1 riastrad
326 1.1 riastrad default:
327 1.1 riastrad return EPASSTHROUGH;
328 1.1 riastrad }
329 1.1 riastrad }
330 1.1 riastrad
331 1.1 riastrad static paddr_t
332 1.1 riastrad intelfb_genfb_mmap(void *v, void *vs, off_t offset, int prot)
333 1.1 riastrad {
334 1.1 riastrad struct genfb_softc *const genfb = v;
335 1.1 riastrad struct intelfb_softc *const sc = container_of(genfb,
336 1.1 riastrad struct intelfb_softc, sc_genfb);
337 1.1 riastrad struct drm_fb_helper *const helper = sc->sc_ifa.ifa_fb_helper;
338 1.1 riastrad struct intel_fbdev *const fbdev = container_of(helper,
339 1.1 riastrad struct intel_fbdev, helper);
340 1.1 riastrad struct drm_device *const dev = helper->dev;
341 1.1 riastrad struct drm_i915_private *const dev_priv = dev->dev_private;
342 1.1 riastrad const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
343 1.1 riastrad unsigned int i;
344 1.1 riastrad
345 1.1 riastrad if (offset < 0)
346 1.1 riastrad return -1;
347 1.1 riastrad
348 1.1 riastrad /* Treat low memory as the framebuffer itself. */
349 1.1 riastrad if (offset < genfb->sc_fbsize)
350 1.1 riastrad return bus_space_mmap(dev->bst,
351 1.1 riastrad (dev_priv->gtt.mappable_base +
352 1.1 riastrad i915_gem_obj_ggtt_offset(fbdev->fb->obj)),
353 1.1 riastrad offset, prot,
354 1.1 riastrad (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE));
355 1.1 riastrad
356 1.1 riastrad /* XXX Cargo-culted from genfb_pci. */
357 1.1 riastrad if (kauth_authorize_machdep(kauth_cred_get(),
358 1.1 riastrad KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
359 1.1 riastrad aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n",
360 1.1 riastrad (uintmax_t)offset);
361 1.1 riastrad return -1;
362 1.1 riastrad }
363 1.1 riastrad
364 1.1 riastrad for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) {
365 1.1 riastrad pcireg_t type;
366 1.1 riastrad bus_addr_t addr;
367 1.1 riastrad bus_size_t size;
368 1.1 riastrad int flags;
369 1.1 riastrad
370 1.1 riastrad /* Interrogate the BAR. */
371 1.1 riastrad if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i),
372 1.1 riastrad &type))
373 1.1 riastrad continue;
374 1.1 riastrad if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM)
375 1.1 riastrad continue;
376 1.1 riastrad if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type,
377 1.1 riastrad &addr, &size, &flags))
378 1.1 riastrad continue;
379 1.1 riastrad
380 1.1 riastrad /* Try to map it if it's in range. */
381 1.1 riastrad if ((addr <= offset) && (offset < (addr + size)))
382 1.1 riastrad return bus_space_mmap(pa->pa_memt, addr,
383 1.1 riastrad (offset - addr), prot, flags);
384 1.1 riastrad
385 1.1 riastrad /* Skip a slot if this was a 64-bit BAR. */
386 1.1 riastrad if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) &&
387 1.1 riastrad (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT))
388 1.1 riastrad i += 1;
389 1.1 riastrad }
390 1.1 riastrad
391 1.1 riastrad /* Failure! */
392 1.1 riastrad return -1;
393 1.1 riastrad }
394 1.1 riastrad
395 1.1 riastrad static int
396 1.1 riastrad intelfb_genfb_enable_polling(void *cookie)
397 1.1 riastrad {
398 1.1 riastrad struct genfb_softc *const genfb = cookie;
399 1.1 riastrad struct intelfb_softc *const sc = container_of(genfb,
400 1.1 riastrad struct intelfb_softc, sc_genfb);
401 1.1 riastrad
402 1.1 riastrad return drm_fb_helper_debug_enter_fb(sc->sc_ifa.ifa_fb_helper);
403 1.1 riastrad }
404 1.1 riastrad
405 1.1 riastrad static int
406 1.1 riastrad intelfb_genfb_disable_polling(void *cookie)
407 1.1 riastrad {
408 1.1 riastrad struct genfb_softc *const genfb = cookie;
409 1.1 riastrad struct intelfb_softc *const sc = container_of(genfb,
410 1.1 riastrad struct intelfb_softc, sc_genfb);
411 1.1 riastrad
412 1.1 riastrad return drm_fb_helper_debug_leave_fb(sc->sc_ifa.ifa_fb_helper);
413 1.1 riastrad }
414