Module Name:    src
Committed By:   riastradh
Date:           Thu Jul 24 21:18:40 UTC 2014

Modified Files:
        src/sys/arch/amd64/conf: DRMKMS
        src/sys/external/bsd/drm2/dist/drm/i915: i915_drv.h intel_display.c
            intel_fbdev.c
        src/sys/external/bsd/drm2/dist/include/drm: drm_fb_helper.h
        src/sys/external/bsd/drm2/i915drm: files.i915drmkms i915_pci.c
        src/sys/modules/i915drmkms: Makefile i915drmkms.ioconf
Added Files:
        src/sys/external/bsd/drm2/i915drm: i915_pci.h intelfb.c intelfb.h

Log Message:
Rework Intel framebuffer attachment.

Turns out genfb_softc must be at the start of its own device_private,
so we can't have it in the middle of a structure, and certainly can't
have potentially multiple genfbs per graphics device.  Failing to do
this is why entering ddb didn't work with an i915drmkms console.

Instead of putting a genfb_softc into each drm_fb_helper, put a
device_t into each drm_fb_helper and create a new intelfb(4) device
for each Intel framebuffer.  This will be more flexible, too, in case
we want accelerated framebuffers later on.  (XXX Need to adapt the
radeon code, which I'm disabling until that happens to avoid breaking
the build.)

While here, defer disabling VGA, vga_cndetach, and genfb_attach until
we're actually ready to do them all together along with the mode
switch.  This should reduce the amount of time during which the
screen is blanked, in case it hangs.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/amd64/conf/DRMKMS
cvs rdiff -u -r1.6 -r1.7 src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h
cvs rdiff -u -r1.9 -r1.10 \
    src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c
cvs rdiff -u -r1.2 -r1.3 \
    src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c
cvs rdiff -u -r1.4 -r1.5 \
    src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/i915drm/files.i915drmkms
cvs rdiff -u -r1.13 -r1.14 src/sys/external/bsd/drm2/i915drm/i915_pci.c
cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/i915drm/i915_pci.h \
    src/sys/external/bsd/drm2/i915drm/intelfb.c \
    src/sys/external/bsd/drm2/i915drm/intelfb.h
cvs rdiff -u -r1.3 -r1.4 src/sys/modules/i915drmkms/Makefile
cvs rdiff -u -r1.2 -r1.3 src/sys/modules/i915drmkms/i915drmkms.ioconf

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/conf/DRMKMS
diff -u src/sys/arch/amd64/conf/DRMKMS:1.4 src/sys/arch/amd64/conf/DRMKMS:1.5
--- src/sys/arch/amd64/conf/DRMKMS:1.4	Wed Jul 16 20:59:57 2014
+++ src/sys/arch/amd64/conf/DRMKMS	Thu Jul 24 21:18:40 2014
@@ -1,7 +1,9 @@
 include "arch/amd64/conf/NO_DRM"
 
 i915drmkms* 	at pci? dev ? function ?
-radeondrmkms*	at pci? dev ? function ?
+intelfb*	at intelfbbus?
+#nouveau*	at pci? dev ? function ?
+#radeondrmkms*	at pci? dev ? function ?
 
 no options 	DIAGNOSTIC
 options 	DIAGNOSTIC	# expensive kernel consistency check

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.6 src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.7
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h:1.6	Wed Jul 16 23:25:18 2014
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_drv.h	Thu Jul 24 21:18:40 2014
@@ -2756,6 +2756,7 @@ static inline void intel_unregister_dsm_
 #endif /* CONFIG_ACPI */
 
 /* modesetting */
+extern void i915_disable_vga(struct drm_device *dev);
 extern void intel_modeset_init_hw(struct drm_device *dev);
 extern void intel_modeset_suspend_hw(struct drm_device *dev);
 extern void intel_modeset_init(struct drm_device *dev);

Index: src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c:1.9 src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c:1.10
--- src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c:1.9	Wed Jul 16 21:28:50 2014
+++ src/sys/external/bsd/drm2/dist/drm/i915/intel_display.c	Thu Jul 24 21:18:40 2014
@@ -11318,7 +11318,7 @@ static void intel_init_quirks(struct drm
 }
 
 /* Disable the VGA plane that we never use */
-static void i915_disable_vga(struct drm_device *dev)
+void i915_disable_vga(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u8 sr1;
@@ -11326,7 +11326,7 @@ static void i915_disable_vga(struct drm_
 
 #ifdef __NetBSD__
     {
-	const bus_size_t vgabase = 0x3c0;
+	const bus_addr_t vgabase = 0x3c0;
 	const bus_space_tag_t iot = dev->pdev->pd_pa.pa_iot;
 	bus_space_handle_t ioh;
 	int error;
@@ -11435,8 +11435,10 @@ void intel_modeset_init(struct drm_devic
 	intel_cpu_pll_init(dev);
 	intel_shared_dpll_init(dev);
 
+#ifndef __NetBSD__		/* XXX We wait until intelfb is ready.  */
 	/* Just disable it once at startup */
 	i915_disable_vga(dev);
+#endif
 	intel_setup_outputs(dev);
 
 	/* Just in case the BIOS is doing something questionable. */

Index: src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c:1.2 src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c:1.3
--- src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c:1.2	Wed Jul 16 20:56:25 2014
+++ src/sys/external/bsd/drm2/dist/drm/i915/intel_fbdev.c	Thu Jul 24 21:18:40 2014
@@ -44,6 +44,8 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
+#include "intelfb.h"
+
 #ifndef __NetBSD__
 static struct fb_ops intelfb_ops = {
 	.owner = THIS_MODULE,
@@ -174,30 +176,31 @@ static int intelfb_create(struct drm_fb_
 	size = obj->base.size;
 
 #ifdef __NetBSD__
-	/* XXX errno NetBSD->Linux */
-	helper->fb_bst = dev->pdev->pd_pa.pa_memt;
-	ret = -bus_space_map(helper->fb_bst,
-	    (dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj)),
-	    size, (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE),
-	    &helper->fb_bsh);
-	if (ret) {
-		DRM_ERROR("unable to map framebuffer: %d\n", ret);
-		goto out_unpin;
-	}
+    {
+	static const struct intelfb_attach_args zero_ifa;
+	struct intelfb_attach_args ifa = zero_ifa;
+
+	ifa.ifa_drm_dev = dev;
+	ifa.ifa_fb_helper = helper;
+	ifa.ifa_fb_sizes = *sizes;
+	ifa.ifa_fb_bst = dev->pdev->pd_pa.pa_memt;
+	ifa.ifa_fb_addr = (dev_priv->gtt.mappable_base +
+	    i915_gem_obj_ggtt_offset(obj));
+	ifa.ifa_fb_size = size;
+	ifa.ifa_fb_zero = (ifbdev->fb->obj->stolen && !prealloc);
 
-	ret = intel_genfb_attach(dev, helper, sizes);
-	if (ret) {
-		DRM_ERROR("unable to attach genfb: %d\n", ret);
-		bus_space_unmap(helper->fb_bst, helper->fb_bsh, size);
+	/*
+	 * XXX Should do this asynchronously, since we hold
+	 * dev->struct_mutex.
+	 */
+	helper->fbdev = config_found_ia(dev->dev, "intelfbbus", &ifa, NULL);
+	if (helper->fbdev == NULL) {
+		DRM_ERROR("unable to attach intelfb\n");
 		goto out_unpin;
 	}
-	helper->genfb_attached = true;
 	fb = &ifbdev->fb->base;
 	ifbdev->helper.fb = fb;
-
-	if (ifbdev->fb->obj->stolen && !prealloc)
-		bus_space_set_region_1(helper->fb_bst, helper->fb_bsh, 0, 0,
-		    size);
+    }
 #else
 	info = framebuffer_alloc(0, &dev->pdev->dev);
 	if (!info) {
@@ -503,13 +506,15 @@ static void intel_fbdev_destroy(struct d
 				struct intel_fbdev *ifbdev)
 {
 #ifdef __NetBSD__
-	if (ifbdev->helper.genfb_attached) {
-		/* XXX genfb doesn't give us a child device_t!  */
-		(void)config_detach_children(dev->dev, DETACH_FORCE);
-		bus_space_unmap(ifbdev->helper.fb_bst, ifbdev->helper.fb_bsh,
-		    ifbdev->fb->obj->base.size);
-		ifbdev->helper.genfb_attached = false;
-	}
+	int ret;
+#endif
+
+#ifdef __NetBSD__
+	/* XXX errno NetBSD->Linux */
+	ret = -config_detach(ifbdev->helper.fbdev, DETACH_FORCE);
+	if (ret)
+		DRM_ERROR("failed to detach intelfb: %d\n", ret);
+	ifbdev->helper.fbdev = NULL;
 #else
 	if (ifbdev->helper.fbdev) {
 		struct fb_info *info = ifbdev->helper.fbdev;

Index: src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h:1.4 src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h:1.5
--- src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h:1.4	Wed Jul 16 20:56:25 2014
+++ src/sys/external/bsd/drm2/dist/include/drm/drm_fb_helper.h	Thu Jul 24 21:18:40 2014
@@ -35,7 +35,7 @@ struct drm_fb_helper;
 #include <linux/kgdb.h>
 
 #ifdef __NetBSD__
-#include <dev/wsfb/genfbvar.h>
+#include <sys/device_if.h>
 #endif
 
 struct drm_fb_helper_crtc {
@@ -93,14 +93,7 @@ struct drm_fb_helper {
 	struct drm_fb_helper_connector **connector_info;
 	struct drm_fb_helper_funcs *funcs;
 #ifdef __NetBSD__		/* XXX fb info */
-	bus_space_tag_t fb_bst;
-	bus_space_handle_t fb_bsh;
-	/*
-	 * XXX Should be a child, not genfb, but genfb doesn't have its
-	 * own independent device_t concept.
-	 */
-	struct genfb_softc genfb;
-	bool genfb_attached:1;
+	device_t fbdev;
 #else
 	struct fb_info *fbdev;
 #endif

Index: src/sys/external/bsd/drm2/i915drm/files.i915drmkms
diff -u src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.3 src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.4
--- src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.3	Wed Jul 16 20:56:25 2014
+++ src/sys/external/bsd/drm2/i915drm/files.i915drmkms	Thu Jul 24 21:18:40 2014
@@ -1,9 +1,14 @@
-#	$NetBSD: files.i915drmkms,v 1.3 2014/07/16 20:56:25 riastradh Exp $
+#	$NetBSD: files.i915drmkms,v 1.4 2014/07/24 21:18:40 riastradh Exp $
 
-device	i915drmkms: drmkms, drmkms_pci, genfb, wsemuldisplaydev
+define	intelfbbus	{ }
+device	i915drmkms: drmkms, drmkms_pci, intelfbbus
 attach	i915drmkms at pci
 
+device	intelfb: intelfbbus, genfb, wsemuldisplaydev
+attach	intelfb at intelfbbus
+
 makeoptions	i915drmkms	CPPFLAGS+="-I$S/external/bsd/drm2/dist/drm/i915"
+makeoptions	i915drmkms	CPPFLAGS+="-I$S/external/bsd/drm2/i915drm"
 
 makeoptions 	i915drmkms 	"CWARNFLAGS.i915_drv.c"+="-Wno-override-init"
 makeoptions 	i915drmkms 	"CWARNFLAGS.intel_display.c"+="-Wno-shadow"
@@ -71,3 +76,5 @@ file	external/bsd/drm2/dist/drm/i915/int
 file	external/bsd/drm2/i915drm/i915_module.c		i915drmkms
 file	external/bsd/drm2/i915drm/i915_pci.c		i915drmkms
 file	external/bsd/drm2/i915drm/intel_gtt.c		i915drmkms
+
+file	external/bsd/drm2/i915drm/intelfb.c		intelfb

Index: src/sys/external/bsd/drm2/i915drm/i915_pci.c
diff -u src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.13 src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.14
--- src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.13	Wed Jul 23 18:05:44 2014
+++ src/sys/external/bsd/drm2/i915drm/i915_pci.c	Thu Jul 24 21:18:40 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: i915_pci.c,v 1.13 2014/07/23 18:05:44 riastradh Exp $	*/
+/*	$NetBSD: i915_pci.c,v 1.14 2014/07/24 21:18:40 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,61 +30,33 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i915_pci.c,v 1.13 2014/07/23 18:05:44 riastradh Exp $");
-
-#ifdef _KERNEL_OPT
-#include "vga.h"
-#endif
+__KERNEL_RCSID(0, "$NetBSD: i915_pci.c,v 1.14 2014/07/24 21:18:40 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
+#include <sys/queue.h>
 #include <sys/workqueue.h>
 
-#include <dev/pci/pciio.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-
-#include <dev/pci/wsdisplay_pci.h>
-#include <dev/wsfb/genfbvar.h>
-
-#if NVGA > 0
-/*
- * XXX All we really need is vga_is_console from vgavar.h, but the
- * header files are missing their own dependencies, so we need to
- * explicitly drag in the other crap.
- */
-#include <dev/ic/mc6845reg.h>
-#include <dev/ic/pcdisplayvar.h>
-#include <dev/ic/vgareg.h>
-#include <dev/ic/vgavar.h>
-#endif
-
 #include <drm/drmP.h>
 
 #include "i915_drv.h"
+#include "i915_pci.h"
 
-struct intel_genfb_work;
-SIMPLEQ_HEAD(intel_genfb_work_head, intel_genfb_work);
+SIMPLEQ_HEAD(i915drmkms_task_head, i915drmkms_task);
 
 struct i915drmkms_softc {
 	device_t			sc_dev;
-	struct workqueue		*sc_genfb_wq;
-	struct intel_genfb_work_head	sc_genfb_work;
+	enum {
+		I915DRMKMS_TASK_ATTACH,
+		I915DRMKMS_TASK_WORKQUEUE,
+	}				sc_task_state;
+	union {
+		struct workqueue		*workqueue;
+		struct i915drmkms_task_head	attach;
+	}				sc_task_u;
 	struct drm_device		*sc_drm_dev;
 	struct pci_dev			sc_pci_dev;
-#if 0				/* XXX backlight/brightness */
-	struct genfb_parameter_callback	sc_genfb_backlight_callback;
-	struct genfb_parameter_callback	sc_genfb_brightness_callback;
-#endif
-};
-
-struct intel_genfb_work {
-	struct drm_fb_helper	*igw_fb_helper;
-	union {
-		SIMPLEQ_ENTRY(intel_genfb_work)	queue;
-		struct work			work;
-	}			igw_u;
 };
 
 static const struct intel_device_info *
@@ -97,22 +69,7 @@ static int	i915drmkms_detach(device_t, i
 static bool	i915drmkms_suspend(device_t, const pmf_qual_t *);
 static bool	i915drmkms_resume(device_t, const pmf_qual_t *);
 
-static void	intel_genfb_defer_set_config(struct drm_fb_helper *);
-static void	intel_genfb_set_config_work(struct work *, void *);
-static void	intel_genfb_set_config(struct intel_genfb_work *);
-static int	intel_genfb_dpms(struct drm_device *, int);
-static int	intel_genfb_ioctl(void *, void *, unsigned long, void *,
-		    int, struct lwp *);
-static paddr_t	intel_genfb_mmap(void *, void *, off_t, int);
-
-#if 0				/* XXX backlight/brightness */
-static int	intel_genfb_get_backlight(void *, int *);
-static int	intel_genfb_set_backlight(void *, int);
-static int	intel_genfb_upd_backlight(void *, int);
-static int	intel_genfb_get_brightness(void *, int *);
-static int	intel_genfb_set_brightness(void *, int);
-static int	intel_genfb_upd_brightness(void *, int);
-#endif
+static void	i915drmkms_task_work(struct work *, void *);
 
 CFATTACH_DECL_NEW(i915drmkms, sizeof(struct i915drmkms_softc),
     i915drmkms_match, i915drmkms_attach, i915drmkms_detach, NULL);
@@ -197,7 +154,8 @@ i915drmkms_attach(device_t parent, devic
 		&i915drmkms_resume))
 		aprint_error_dev(self, "unable to establish power handler\n");
 
-	SIMPLEQ_INIT(&sc->sc_genfb_work);
+	sc->sc_task_state = I915DRMKMS_TASK_ATTACH;
+	SIMPLEQ_INIT(&sc->sc_task_u.attach);
 
 	/* XXX errno Linux->NetBSD */
 	error = -drm_pci_attach(self, pa, &sc->sc_pci_dev, i915_drm_driver,
@@ -207,19 +165,21 @@ i915drmkms_attach(device_t parent, devic
 		return;
 	}
 
-	while (!SIMPLEQ_EMPTY(&sc->sc_genfb_work)) {
-		struct intel_genfb_work *const work =
-		    SIMPLEQ_FIRST(&sc->sc_genfb_work);
+	while (!SIMPLEQ_EMPTY(&sc->sc_task_u.attach)) {
+		struct i915drmkms_task *const task =
+		    SIMPLEQ_FIRST(&sc->sc_task_u.attach);
 
-		SIMPLEQ_REMOVE_HEAD(&sc->sc_genfb_work, igw_u.queue);
-		intel_genfb_set_config(work);
+		SIMPLEQ_REMOVE_HEAD(&sc->sc_task_u.attach, ift_u.queue);
+		(*task->ift_fn)(task);
 	}
 
-	error = workqueue_create(&sc->sc_genfb_wq, "intelfb",
-	    &intel_genfb_set_config_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE);
+	sc->sc_task_state = I915DRMKMS_TASK_WORKQUEUE;
+	error = workqueue_create(&sc->sc_task_u.workqueue, "intelfb",
+	    &i915drmkms_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE);
 	if (error) {
 		aprint_error_dev(self, "unable to create workqueue: %d\n",
 		    error);
+		sc->sc_task_u.workqueue = NULL;
 		return;
 	}
 }
@@ -235,9 +195,10 @@ i915drmkms_detach(device_t self, int fla
 	if (error)
 		return error;
 
-	if (sc->sc_genfb_wq == NULL)
+	KASSERT(sc->sc_task_state == I915DRMKMS_TASK_WORKQUEUE);
+	if (sc->sc_task_u.workqueue == NULL)
 		goto out;
-	workqueue_destroy(sc->sc_genfb_wq);
+	workqueue_destroy(sc->sc_task_u.workqueue);
 
 	if (sc->sc_drm_dev == NULL)
 		goto out;
@@ -288,324 +249,34 @@ i915drmkms_resume(device_t self, const p
 	return true;
 }
 
-int
-intel_genfb_attach(struct drm_device *dev, struct drm_fb_helper *helper,
-    const struct drm_fb_helper_surface_size *sizes)
-{
-	struct i915drmkms_softc *const sc = container_of(dev->pdev,
-	    struct i915drmkms_softc, sc_pci_dev);
-	static const struct genfb_ops zero_genfb_ops;
-	struct genfb_ops genfb_ops = zero_genfb_ops;
-	const prop_dictionary_t dict = device_properties(sc->sc_dev);
-	enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons;
-	int ret;
-
-#if NVGA > 0
-	if (vga_is_console(dev->pdev->pd_pa.pa_iot, -1)) {
-		what_was_cons = CONS_VGA;
-		prop_dictionary_set_bool(dict, "is_console", true);
-		/*
-		 * There is a window from here until genfb attaches in
-		 * which kernel messages will go into a black hole,
-		 * until genfb replays the console.  Whattakludge.
-		 */
-		vga_cndetach();
-	} else
-#endif
-	if (genfb_is_console() && genfb_is_enabled()) {
-		what_was_cons = CONS_GENFB;
-		prop_dictionary_set_bool(dict, "is_console", true);
-	} else {
-		what_was_cons = CONS_NONE;
-		prop_dictionary_set_bool(dict, "is_console", false);
-	}
-
-	/* XXX Ugh...  Pass these parameters some other way!  */
-	prop_dictionary_set_uint32(dict, "width", sizes->fb_width);
-	prop_dictionary_set_uint32(dict, "height", sizes->fb_height);
-	prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp);
-	prop_dictionary_set_uint16(dict, "linebytes",
-	    roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64));
-	prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
-	CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
-	prop_dictionary_set_uint64(dict, "virtual_address",
-	    (uint64_t)(uintptr_t)bus_space_vaddr(helper->fb_bst,
-		helper->fb_bsh));
-
-#if 0				/* XXX backlight/brightness */
-	/* XXX What happens with multi-head, multi-fb displays?  */
-	sc->sc_genfb_backlight_callback = (struct genfb_parameter_callback) {
-		.gpc_cookie = dev,
-		.gpc_get_parameter = &intel_genfb_get_backlight,
-		.gpc_set_parameter = &intel_genfb_set_backlight,
-		.gpc_upd_parameter = &intel_genfb_upd_backlight,
-	};
-	prop_dictionary_set_uint64(dict, "backlight_callback",
-	    (uint64_t)(uintptr_t)&sc->sc_genfb_backlight_callback);
-
-	sc->sc_genfb_brightness_callback = (struct genfb_parameter_callback) {
-		.gpc_cookie = dev,
-		.gpc_get_parameter = &intel_genfb_get_brightness,
-		.gpc_set_parameter = &intel_genfb_set_brightness,
-		.gpc_upd_parameter = &intel_genfb_upd_brightness,
-	};
-	prop_dictionary_set_uint64(dict, "brightness_callback",
-	    (uint64_t)(uintptr_t)&sc->sc_genfb_brightness_callback);
-#endif
-
-	helper->genfb.sc_dev = sc->sc_dev;
-	genfb_init(&helper->genfb);
-	genfb_ops.genfb_ioctl = intel_genfb_ioctl;
-	genfb_ops.genfb_mmap = intel_genfb_mmap;
-
-	/* XXX errno NetBSD->Linux */
-	ret = -genfb_attach(&helper->genfb, &genfb_ops);
-	if (ret) {
-		DRM_ERROR("failed to attach genfb: %d\n", ret);
-		switch (what_was_cons) { /* XXX Restore console...  */
-		case CONS_VGA: break;
-		case CONS_GENFB: break;
-		case CONS_NONE: break;
-		default: break;
-		}
-		return ret;
-	}
-
-	intel_genfb_defer_set_config(helper);
-
-	return 0;
-}
-
-static void
-intel_genfb_defer_set_config(struct drm_fb_helper *helper)
-{
-	struct drm_device *const dev = helper->dev;
-	struct i915drmkms_softc *const sc = container_of(dev->pdev,
-	    struct i915drmkms_softc, sc_pci_dev);
-	struct intel_genfb_work *work;
-
-	/* Really shouldn't sleep here...  */
-	work = kmem_alloc(sizeof(*work), KM_SLEEP);
-	work->igw_fb_helper = helper;
-
-	if (sc->sc_genfb_wq == NULL) /* during attachment */
-		SIMPLEQ_INSERT_TAIL(&sc->sc_genfb_work, work, igw_u.queue);
-	else
-		workqueue_enqueue(sc->sc_genfb_wq, &work->igw_u.work, NULL);
-}
-
-static void
-intel_genfb_set_config_work(struct work *work, void *cookie __unused)
-{
-
-	intel_genfb_set_config(container_of(work, struct intel_genfb_work,
-		igw_u.work));
-}
-
 static void
-intel_genfb_set_config(struct intel_genfb_work *work)
+i915drmkms_task_work(struct work *work, void *cookie __unused)
 {
+	struct i915drmkms_task *const task = container_of(work,
+	    struct i915drmkms_task, ift_u.work);
 
-	drm_fb_helper_set_config(work->igw_fb_helper);
-	kmem_free(work, sizeof(*work));
+	(*task->ift_fn)(task);
 }
 
-static int
-intel_genfb_dpms(struct drm_device *dev, int dpms_mode)
+int
+i915drmkms_task_schedule(device_t self, struct i915drmkms_task *task)
 {
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-	/* XXX What guarantees dev_priv->fbdev stays around?  */
-	struct drm_fb_helper *const fb_helper = &dev_priv->fbdev->helper;
-	unsigned i;
-
-	drm_modeset_lock_all(dev);
-	for (i = 0; i < fb_helper->connector_count; i++) {
-		struct drm_connector *const connector =
-		    fb_helper->connector_info[i]->connector;
-		(*connector->funcs->dpms)(connector, dpms_mode);
-		drm_object_property_set_value(&connector->base,
-		    dev->mode_config.dpms_property, dpms_mode);
-	}
-	drm_modeset_unlock_all(dev);
-
-	return 0;
-}
+	struct i915drmkms_softc *const sc = device_private(self);
 
-static int
-intel_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
-    struct lwp *l)
-{
-	struct genfb_softc *const genfb = v;
-	struct drm_fb_helper *const helper = container_of(genfb,
-	    struct drm_fb_helper, genfb);
-	struct drm_device *const dev = helper->dev;
-	const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
-
-	switch (cmd) {
-	case WSDISPLAYIO_GTYPE:
-		*(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA;
+	switch (sc->sc_task_state) {
+	case I915DRMKMS_TASK_ATTACH:
+		SIMPLEQ_INSERT_TAIL(&sc->sc_task_u.attach, task, ift_u.queue);
 		return 0;
-
-	/* PCI config read/write passthrough.  */
-	case PCI_IOC_CFGREAD:
-	case PCI_IOC_CFGWRITE:
-		return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l);
-
-	case WSDISPLAYIO_GET_BUSID:
-		return wsdisplayio_busid_pci(genfb->sc_dev,
-		    pa->pa_pc, pa->pa_tag, data);
-
-	/*
-	 * Screen blanking ioctls.  Not to be confused with backlight
-	 * (can be disabled while stuff is still drawn on the screen),
-	 * brightness, or contrast (which we don't support).  Backlight
-	 * and brightness are done through WSDISPLAYIO_{GET,SET}PARAM.
-	 * This toggles between DPMS ON and DPMS OFF; backlight toggles
-	 * between DPMS ON and DPMS SUSPEND.
-	 */
-	case WSDISPLAYIO_GVIDEO: {
-		int *onp = (int *)data;
-
-		/* XXX Can't really determine a single answer here.  */
-		*onp = 1;
+	case I915DRMKMS_TASK_WORKQUEUE:
+		if (sc->sc_task_u.workqueue == NULL) {
+			aprint_error_dev(self, "unable to schedule task\n");
+			return EIO;
+		}
+		workqueue_enqueue(sc->sc_task_u.workqueue, &task->ift_u.work,
+		    NULL);
 		return 0;
-	}
-
-	case WSDISPLAYIO_SVIDEO: {
-		const int on = *(const int *)data;
-
-		return intel_genfb_dpms(dev,
-		    on? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF);
-	}
-
 	default:
-		return EPASSTHROUGH;
-	}
-}
-
-static paddr_t
-intel_genfb_mmap(void *v, void *vs, off_t offset, int prot)
-{
-	struct genfb_softc *const genfb = v;
-	struct drm_fb_helper *const helper = container_of(genfb,
-	    struct drm_fb_helper, genfb);
-	struct intel_fbdev *const fbdev = container_of(helper,
-	    struct intel_fbdev, helper);
-	struct drm_device *const dev = helper->dev;
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-	const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
-	unsigned int i;
-
-	if (offset < 0)
-		return -1;
-
-	/* Treat low memory as the framebuffer itself.  */
-	if (offset < genfb->sc_fbsize)
-		return bus_space_mmap(dev->bst,
-		    (dev_priv->gtt.mappable_base +
-			i915_gem_obj_ggtt_offset(fbdev->fb->obj)),
-		    offset, prot,
-		    (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE));
-
-	/* XXX Cargo-culted from genfb_pci.  */
-	if (kauth_authorize_machdep(kauth_cred_get(),
-		KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
-		aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n",
-		    (uintmax_t)offset);
-		return -1;
-	}
-
-	for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) {
-		pcireg_t type;
-		bus_addr_t addr;
-		bus_size_t size;
-		int flags;
-
-		/* Interrogate the BAR.  */
-		if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i),
-			&type))
-			continue;
-		if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM)
-			continue;
-		if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type,
-			&addr, &size, &flags))
-			continue;
-
-		/* Try to map it if it's in range.  */
-		if ((addr <= offset) && (offset < (addr + size)))
-			return bus_space_mmap(pa->pa_memt, addr,
-			    (offset - addr), prot, flags);
-
-		/* Skip a slot if this was a 64-bit BAR.  */
-		if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) &&
-		    (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT))
-			i += 1;
+		panic("i915drmkms in invalid task state: %d\n",
+		    (int)sc->sc_task_state);
 	}
-
-	/* Failure!  */
-	return -1;
-}
-
-#if 0				/* XXX backlight/brightness */
-static int
-intel_genfb_get_backlight(void *cookie, int *enablep)
-{
-	struct drm_device *const dev = cookie;
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-
-	*enablep = dev_priv->backlight.present;
-
-	return 0;
-}
-
-static int
-intel_genfb_set_backlight(void *cookie, int enable)
-{
-	struct drm_device *const dev = cookie;
-
-	return intel_genfb_dpms(dev,
-	    enable? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_SUSPEND);
-}
-
-static int
-intel_genfb_upd_backlight(void *cookie __unused, int step __unused)
-{
-
-	panic("can't update i915drm backlight");
-}
-
-static int
-intel_genfb_get_brightness(void *cookie, int *brightnessp)
-{
-	struct drm_device *const dev = cookie;
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-
-	*brightnessp = dev_priv->backlight_level;
-
-	return 0;
-}
-
-static int
-intel_genfb_set_brightness(void *cookie, int brightness)
-{
-	struct drm_device *const dev = cookie;
-
-	intel_panel_set_backlight(dev,
-	    MIN(brightness, intel_panel_get_max_backlight(dev)));
-
-	return 0;
-}
-
-static int
-intel_genfb_upd_brightness(void *cookie, int delta)
-{
-	struct drm_device *const dev = cookie;
-	struct drm_i915_private *const dev_priv = dev->dev_private;
-
-	intel_panel_set_backlight(dev,
-	    MIN(dev_priv->backlight_level + delta,
-		intel_panel_get_max_backlight(dev)));
-
-	return 0;
 }
-#endif

Index: src/sys/modules/i915drmkms/Makefile
diff -u src/sys/modules/i915drmkms/Makefile:1.3 src/sys/modules/i915drmkms/Makefile:1.4
--- src/sys/modules/i915drmkms/Makefile:1.3	Wed Jul 16 20:56:26 2014
+++ src/sys/modules/i915drmkms/Makefile	Thu Jul 24 21:18:40 2014
@@ -1,9 +1,10 @@
-# $NetBSD: Makefile,v 1.3 2014/07/16 20:56:26 riastradh Exp $
+# $NetBSD: Makefile,v 1.4 2014/07/24 21:18:40 riastradh Exp $
 
 .include "../Makefile.inc"
 .include "../drmkms/Makefile.inc"
 
 CPPFLAGS+=	-I${S}/external/bsd/drm2/dist/drm/i915
+CPPFLAGS+=	-I${S}/external/bsd/drm2/i915drm
 
 .PATH:	${S}/external/bsd/drm2/i915drm
 .PATH:	${S}/external/bsd/drm2/dist/drm/i915
@@ -66,6 +67,7 @@ SRCS+=	intel_uncore.c
 SRCS+=	i915_module.c
 SRCS+=	i915_pci.c
 SRCS+=	intel_gtt.c
+SRCS+=	intelfb.c
 
 COPTS.i915_drv.c+=	-Wno-override-init
 COPTS.intel_display.c+=	-Wno-shadow

Index: src/sys/modules/i915drmkms/i915drmkms.ioconf
diff -u src/sys/modules/i915drmkms/i915drmkms.ioconf:1.2 src/sys/modules/i915drmkms/i915drmkms.ioconf:1.3
--- src/sys/modules/i915drmkms/i915drmkms.ioconf:1.2	Tue Mar 18 18:20:43 2014
+++ src/sys/modules/i915drmkms/i915drmkms.ioconf	Thu Jul 24 21:18:40 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: i915drmkms.ioconf,v 1.2 2014/03/18 18:20:43 riastradh Exp $
+#	$NetBSD: i915drmkms.ioconf,v 1.3 2014/07/24 21:18:40 riastradh Exp $
 
 ioconf i915drmkms
 
@@ -6,5 +6,7 @@ include "conf/files"
 include "dev/pci/files.pci"
 
 pseudo-root	pci*
+pseudo-root	intelfbbus*
 
 i915drmkms* 	at pci? dev ? function ?
+intelfb* 	at intelfbbus?

Added files:

Index: src/sys/external/bsd/drm2/i915drm/i915_pci.h
diff -u /dev/null src/sys/external/bsd/drm2/i915drm/i915_pci.h:1.1
--- /dev/null	Thu Jul 24 21:18:40 2014
+++ src/sys/external/bsd/drm2/i915drm/i915_pci.h	Thu Jul 24 21:18:40 2014
@@ -0,0 +1,56 @@
+/*	$NetBSD: i915_pci.h,v 1.1 2014/07/24 21:18:40 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_I915DRM_I915_PCI_H_
+#define	_I915DRM_I915_PCI_H_
+
+#include <sys/queue.h>
+#include <sys/workqueue.h>
+
+struct i915drmkms_task {
+	union {
+		SIMPLEQ_ENTRY(i915drmkms_task)	queue;
+		struct work			work;
+	}			ift_u;
+	void			(*ift_fn)(struct i915drmkms_task *);
+};
+
+static inline void
+i915drmkms_task_init(struct i915drmkms_task *task,
+    void (*fn)(struct i915drmkms_task *))
+{
+
+	task->ift_fn = fn;
+}
+
+int	i915drmkms_task_schedule(device_t, struct i915drmkms_task *);
+
+#endif	/* _I915DRM_I915_PCI_H_ */
Index: src/sys/external/bsd/drm2/i915drm/intelfb.c
diff -u /dev/null src/sys/external/bsd/drm2/i915drm/intelfb.c:1.1
--- /dev/null	Thu Jul 24 21:18:40 2014
+++ src/sys/external/bsd/drm2/i915drm/intelfb.c	Thu Jul 24 21:18:40 2014
@@ -0,0 +1,434 @@
+/*	$NetBSD: intelfb.c,v 1.1 2014/07/24 21:18:40 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: intelfb.c,v 1.1 2014/07/24 21:18:40 riastradh Exp $");
+
+#ifdef _KERNEL_OPT
+#include "vga.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+
+#include <dev/pci/pciio.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/pci/wsdisplay_pci.h>
+#include <dev/wsfb/genfbvar.h>
+
+#if NVGA > 0
+/*
+ * XXX All we really need is vga_is_console from vgavar.h, but the
+ * header files are missing their own dependencies, so we need to
+ * explicitly drag in the other crap.
+ */
+#include <dev/ic/mc6845reg.h>
+#include <dev/ic/pcdisplayvar.h>
+#include <dev/ic/vgareg.h>
+#include <dev/ic/vgavar.h>
+#endif
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+
+#include "i915_drv.h"
+#include "i915_pci.h"
+#include "intelfb.h"
+
+extern void	comcnputc(dev_t, int);
+static void __printflike(1,2) __unused
+comprintf(const char *fmt, ...)
+{
+	char buf[1024], *p;
+	va_list va;
+
+	va_start(va, fmt);
+	vsnprintf(buf, sizeof buf, fmt, va);
+	va_end(va);
+
+	buf[sizeof buf - 1] = '\0';
+	for (p = buf; *p != '\0'; p++) {
+		comcnputc(NODEV, *p);
+		if (*p == '\n')
+			comcnputc(NODEV, '\r');
+	}
+}
+
+struct intelfb_softc {
+	/* XXX genfb requires the genfb_softc to be first.  */
+	struct genfb_softc		sc_genfb;
+	device_t			sc_dev;
+	struct intelfb_attach_args	sc_ifa;
+	bus_space_handle_t		sc_fb_bsh;
+	struct i915drmkms_task		sc_setconfig_task;
+	bool				sc_mapped:1;
+	bool				sc_scheduled:1;
+	bool				sc_attached:1;
+};
+
+static int	intelfb_match(device_t, cfdata_t, void *);
+static void	intelfb_attach(device_t, device_t, void *);
+static int	intelfb_detach(device_t, int);
+
+static void	intelfb_setconfig_task(struct i915drmkms_task *);
+
+static int	intelfb_genfb_dpms(struct drm_device *, int);
+static int	intelfb_genfb_ioctl(void *, void *, unsigned long, void *,
+		    int, struct lwp *);
+static paddr_t	intelfb_genfb_mmap(void *, void *, off_t, int);
+#if notyet			/* XXX */
+static int	intelfb_genfb_enable_polling(void *);
+static int	intelfb_genfb_disable_polling(void *);
+#endif
+
+CFATTACH_DECL_NEW(intelfb, sizeof(struct intelfb_softc),
+    intelfb_match, intelfb_attach, intelfb_detach, NULL);
+
+static int
+intelfb_match(device_t parent, cfdata_t match, void *aux)
+{
+
+	return 1;
+}
+
+static void
+intelfb_attach(device_t parent, device_t self, void *aux)
+{
+	struct intelfb_softc *const sc = device_private(self);
+	const struct intelfb_attach_args *const ifa = aux;
+	int error;
+
+	sc->sc_dev = self;
+	sc->sc_ifa = *ifa;
+	sc->sc_mapped = false;
+	sc->sc_scheduled = false;
+	sc->sc_attached = false;
+
+	/* XXX Defer this too?  */
+	error = bus_space_map(ifa->ifa_fb_bst, ifa->ifa_fb_addr,
+	    ifa->ifa_fb_size,
+	    (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE),
+	    &sc->sc_fb_bsh);
+	if (error) {
+		aprint_error_dev(self, "unable to map framebuffer: %d\n",
+		    error);
+		goto fail0;
+	}
+	sc->sc_mapped = true;
+
+	i915drmkms_task_init(&sc->sc_setconfig_task, &intelfb_setconfig_task);
+	error = i915drmkms_task_schedule(parent, &sc->sc_setconfig_task);
+	if (error) {
+		aprint_error_dev(self, "failed to schedule mode set: %d\n",
+		    error);
+		goto fail1;
+	}
+	sc->sc_scheduled = true;
+
+	/* Success!  */
+	return;
+
+fail1:	bus_space_unmap(ifa->ifa_fb_bst, sc->sc_fb_bsh, ifa->ifa_fb_size);
+	sc->sc_mapped = false;
+fail0:	return;
+}
+
+static int
+intelfb_detach(device_t self, int flags)
+{
+	struct intelfb_softc *const sc = device_private(self);
+
+	if (sc->sc_scheduled)
+		return EBUSY;
+
+	if (sc->sc_attached) {
+		/* XXX genfb detach?  Help?  */
+		sc->sc_attached = false;
+	}
+
+	if (sc->sc_mapped) {
+		bus_space_unmap(sc->sc_ifa.ifa_fb_bst, sc->sc_fb_bsh,
+		    sc->sc_ifa.ifa_fb_size);
+		sc->sc_mapped = false;
+	}
+
+	return 0;
+}
+
+static void
+intelfb_setconfig_task(struct i915drmkms_task *task)
+{
+	struct intelfb_softc *const sc = container_of(task,
+	    struct intelfb_softc, sc_setconfig_task);
+	const prop_dictionary_t dict = device_properties(sc->sc_dev);
+	const struct intelfb_attach_args *const ifa = &sc->sc_ifa;
+	const struct drm_fb_helper_surface_size *const sizes =
+	    &ifa->ifa_fb_sizes;
+#if NVGA > 0			/* XXX no workie for modules */
+	struct drm_device *const dev = sc->sc_ifa.ifa_drm_dev;
+#endif
+	enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons;
+	static const struct genfb_ops zero_genfb_ops;
+	struct genfb_ops genfb_ops = zero_genfb_ops;
+	int error;
+
+	KASSERT(sc->sc_scheduled);
+
+	if (ifa->ifa_fb_zero)
+		bus_space_set_region_1(sc->sc_ifa.ifa_fb_bst, sc->sc_fb_bsh, 0,
+		    0, sc->sc_ifa.ifa_fb_size);
+
+	/* XXX Ugh...  Pass these parameters some other way!  */
+	prop_dictionary_set_uint32(dict, "width", sizes->fb_width);
+	prop_dictionary_set_uint32(dict, "height", sizes->fb_height);
+	prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp);
+	prop_dictionary_set_uint16(dict, "linebytes",
+	    roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64));
+	prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
+	CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
+	prop_dictionary_set_uint64(dict, "virtual_address",
+	    (uint64_t)(uintptr_t)bus_space_vaddr(sc->sc_ifa.ifa_fb_bst,
+		sc->sc_fb_bsh));
+
+	/* XXX Whattakludge!  */
+#if NVGA > 0
+	if (vga_is_console(dev->pdev->pd_pa.pa_iot, -1)) {
+		what_was_cons = CONS_VGA;
+		prop_dictionary_set_bool(dict, "is_console", true);
+		i915_disable_vga(dev);
+		vga_cndetach();
+	} else
+#endif
+	if (genfb_is_console() && genfb_is_enabled()) {
+		what_was_cons = CONS_GENFB;
+		prop_dictionary_set_bool(dict, "is_console", true);
+	} else {
+		what_was_cons = CONS_NONE;
+		prop_dictionary_set_bool(dict, "is_console", false);
+	}
+
+	sc->sc_genfb.sc_dev = sc->sc_dev;
+	genfb_init(&sc->sc_genfb);
+	genfb_ops.genfb_ioctl = intelfb_genfb_ioctl;
+	genfb_ops.genfb_mmap = intelfb_genfb_mmap;
+#if notyet			/* XXX */
+	genfb_ops.genfb_enable_polling = intelfb_genfb_enable_polling;
+	genfb_ops.genfb_disable_polling = intelfb_genfb_disable_polling;
+#endif
+
+	error = genfb_attach(&sc->sc_genfb, &genfb_ops);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "failed to attach genfb: %d\n",
+		    error);
+		goto fail0;
+	}
+	sc->sc_attached = true;
+
+	drm_fb_helper_set_config(sc->sc_ifa.ifa_fb_helper);
+
+	/* Success!  */
+	sc->sc_scheduled = false;
+	return;
+
+fail0:	/* XXX Restore console...  */
+	switch (what_was_cons) {
+	case CONS_VGA:
+		break;
+	case CONS_GENFB:
+		break;
+	case CONS_NONE:
+		break;
+	default:
+		break;
+	}
+}
+
+static int
+intelfb_genfb_dpms(struct drm_device *dev, int dpms_mode)
+{
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	/* XXX What guarantees dev_priv->fbdev stays around?  */
+	struct drm_fb_helper *const fb_helper = &dev_priv->fbdev->helper;
+	unsigned i;
+
+	drm_modeset_lock_all(dev);
+	for (i = 0; i < fb_helper->connector_count; i++) {
+		struct drm_connector *const connector =
+		    fb_helper->connector_info[i]->connector;
+		(*connector->funcs->dpms)(connector, dpms_mode);
+		drm_object_property_set_value(&connector->base,
+		    dev->mode_config.dpms_property, dpms_mode);
+	}
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
+static int
+intelfb_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
+    struct lwp *l)
+{
+	struct genfb_softc *const genfb = v;
+	struct intelfb_softc *const sc = container_of(genfb,
+	    struct intelfb_softc, sc_genfb);
+	struct drm_device *const dev = sc->sc_ifa.ifa_fb_helper->dev;
+	const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
+
+	switch (cmd) {
+	case WSDISPLAYIO_GTYPE:
+		*(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA;
+		return 0;
+
+	/* PCI config read/write passthrough.  */
+	case PCI_IOC_CFGREAD:
+	case PCI_IOC_CFGWRITE:
+		return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l);
+
+	case WSDISPLAYIO_GET_BUSID:
+		return wsdisplayio_busid_pci(genfb->sc_dev,
+		    pa->pa_pc, pa->pa_tag, data);
+
+	/*
+	 * Screen blanking ioctls.  Not to be confused with backlight
+	 * (can be disabled while stuff is still drawn on the screen),
+	 * brightness, or contrast (which we don't support).  Backlight
+	 * and brightness are done through WSDISPLAYIO_{GET,SET}PARAM.
+	 * This toggles between DPMS ON and DPMS OFF; backlight toggles
+	 * between DPMS ON and DPMS SUSPEND.
+	 */
+	case WSDISPLAYIO_GVIDEO: {
+		int *onp = (int *)data;
+
+		/* XXX Can't really determine a single answer here.  */
+		*onp = 1;
+		return 0;
+	}
+
+	case WSDISPLAYIO_SVIDEO: {
+		const int on = *(const int *)data;
+
+		return intelfb_genfb_dpms(dev,
+		    on? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF);
+	}
+
+	default:
+		return EPASSTHROUGH;
+	}
+}
+
+static paddr_t
+intelfb_genfb_mmap(void *v, void *vs, off_t offset, int prot)
+{
+	struct genfb_softc *const genfb = v;
+	struct intelfb_softc *const sc = container_of(genfb,
+	    struct intelfb_softc, sc_genfb);
+	struct drm_fb_helper *const helper = sc->sc_ifa.ifa_fb_helper;
+	struct intel_fbdev *const fbdev = container_of(helper,
+	    struct intel_fbdev, helper);
+	struct drm_device *const dev = helper->dev;
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
+	unsigned int i;
+
+	if (offset < 0)
+		return -1;
+
+	/* Treat low memory as the framebuffer itself.  */
+	if (offset < genfb->sc_fbsize)
+		return bus_space_mmap(dev->bst,
+		    (dev_priv->gtt.mappable_base +
+			i915_gem_obj_ggtt_offset(fbdev->fb->obj)),
+		    offset, prot,
+		    (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE));
+
+	/* XXX Cargo-culted from genfb_pci.  */
+	if (kauth_authorize_machdep(kauth_cred_get(),
+		KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
+		aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n",
+		    (uintmax_t)offset);
+		return -1;
+	}
+
+	for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) {
+		pcireg_t type;
+		bus_addr_t addr;
+		bus_size_t size;
+		int flags;
+
+		/* Interrogate the BAR.  */
+		if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i),
+			&type))
+			continue;
+		if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM)
+			continue;
+		if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type,
+			&addr, &size, &flags))
+			continue;
+
+		/* Try to map it if it's in range.  */
+		if ((addr <= offset) && (offset < (addr + size)))
+			return bus_space_mmap(pa->pa_memt, addr,
+			    (offset - addr), prot, flags);
+
+		/* Skip a slot if this was a 64-bit BAR.  */
+		if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) &&
+		    (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT))
+			i += 1;
+	}
+
+	/* Failure!  */
+	return -1;
+}
+
+#if notyet			/* XXX */
+static int
+intelfb_genfb_enable_polling(void *cookie)
+{
+	struct genfb_softc *const genfb = cookie;
+	struct intelfb_softc *const sc = container_of(genfb,
+	    struct intelfb_softc, sc_genfb);
+
+	return drm_fb_helper_debug_enter_fb(sc->sc_ifa.ifa_fb_helper);
+}
+
+static int
+intelfb_genfb_disable_polling(void *cookie)
+{
+	struct genfb_softc *const genfb = cookie;
+	struct intelfb_softc *const sc = container_of(genfb,
+	    struct intelfb_softc, sc_genfb);
+
+	return drm_fb_helper_debug_leave_fb(sc->sc_ifa.ifa_fb_helper);
+}
+#endif
Index: src/sys/external/bsd/drm2/i915drm/intelfb.h
diff -u /dev/null src/sys/external/bsd/drm2/i915drm/intelfb.h:1.1
--- /dev/null	Thu Jul 24 21:18:40 2014
+++ src/sys/external/bsd/drm2/i915drm/intelfb.h	Thu Jul 24 21:18:40 2014
@@ -0,0 +1,50 @@
+/*	$NetBSD: intelfb.h,v 1.1 2014/07/24 21:18:40 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_I915DRM_INTELFB_H_
+#define	_I915DRM_INTELFB_H_
+
+#include <sys/bus.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+
+struct intelfb_attach_args {
+	struct drm_device			*ifa_drm_dev;
+	struct drm_fb_helper			*ifa_fb_helper;
+	struct drm_fb_helper_surface_size	ifa_fb_sizes;
+	bus_space_tag_t				ifa_fb_bst;
+	bus_addr_t				ifa_fb_addr;
+	bus_size_t				ifa_fb_size;
+	bool					ifa_fb_zero;
+};
+
+#endif	/* _I915DRM_INTELFB_H_ */

Reply via email to