Module Name:    src
Committed By:   riastradh
Date:           Sun Sep  8 16:41:07 UTC 2013

Modified Files:
        src/sys/external/bsd/drm2/i915drm [riastradh-drm2]: i915_pci.c

Log Message:
First draft of genfb attachment for i915.


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/sys/external/bsd/drm2/i915drm/i915_pci.c

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

Modified files:

Index: src/sys/external/bsd/drm2/i915drm/i915_pci.c
diff -u src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.1.2.3 src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.1.2.4
--- src/sys/external/bsd/drm2/i915drm/i915_pci.c:1.1.2.3	Wed Jul 24 03:54:43 2013
+++ src/sys/external/bsd/drm2/i915drm/i915_pci.c	Sun Sep  8 16:41:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: i915_pci.c,v 1.1.2.3 2013/07/24 03:54:43 riastradh Exp $	*/
+/*	$NetBSD: i915_pci.c,v 1.1.2.4 2013/09/08 16:41:07 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,27 +30,51 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i915_pci.c,v 1.1.2.3 2013/07/24 03:54:43 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i915_pci.c,v 1.1.2.4 2013/09/08 16:41:07 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/systm.h>
 
+#include <dev/pci/pciio.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
+#if 0				/* XXX genfb */
+#include <dev/pci/wsdisplay_pci.h>
+#include <dev/wsfb/genfbvar.h>
+#endif
+
 #include <drm/drmP.h>
 
 #include "i915_drv.h"
 
 struct i915drm_softc {
-	struct drm_device	sc_drm_dev;
-	struct pci_dev		sc_pci_dev;
+	device_t			sc_dev;
+	struct drm_device		sc_drm_dev;
+	struct pci_dev			sc_pci_dev;
+	struct drm_i915_gem_object	*sc_fb_obj;
+	bus_space_handle_t		sc_fb_bsh;
+#if 0				/* XXX genfb */
+	struct genfb_softc		sc_genfb;
+#endif
 };
 
 static int	i915drm_match(device_t, cfdata_t, void *);
 static void	i915drm_attach(device_t, device_t, void *);
 static int	i915drm_detach(device_t, int);
 
+static void	i915drm_attach_framebuffer(device_t);
+static int	i915drm_detach_framebuffer(device_t, int);
+
+static int	i915drm_fb_probe(struct drm_fb_helper *,
+		    struct drm_fb_helper_surface_size *);
+
+#if 0				/* XXX genfb */
+static int	i915drm_genfb_ioctl(void *, void *, unsigned long, void *,
+		    int, struct lwp *);
+static paddr_t	i915drm_genfb_mmap(void *, void *, off_t, int);
+#endif
+
 CFATTACH_DECL_NEW(i915drm, sizeof(struct i915drm_softc),
     i915drm_match, i915drm_attach, i915drm_detach, NULL);
 
@@ -115,10 +139,9 @@ i915drm_attach(device_t parent, device_t
 
 	KASSERT(info != NULL);
 
-	/* XXX Show more information...  */
-	aprint_naive("\n");
-	aprint_normal(": vendor 0x%04x, device 0x%04x, gen %u\n",
-	    PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id), info->gen);
+	sc->sc_dev = self;
+
+	pci_aprint_devinfo(pa, NULL);
 
 	/* XXX Whattakludge!  */
 	if (info->gen != 3) {
@@ -132,6 +155,8 @@ i915drm_attach(device_t parent, device_t
 
 	/* Attach the drm driver.  */
 	drm_config_found(self, i915_drm_driver, flags, &sc->sc_drm_dev);
+
+	i915drm_attach_framebuffer(self);
 }
 
 static int
@@ -145,6 +170,10 @@ i915drm_detach(device_t self, int flags)
 	if (error)
 		return error;
 
+	error = i915drm_detach_framebuffer(self, flags);
+	if (error)
+		return error;
+
 	/* drm driver is gone.  We can safely drop drm pci driver state.  */
 	error = drm_pci_detach(&sc->sc_drm_dev, flags);
 	if (error)
@@ -152,3 +181,331 @@ i915drm_detach(device_t self, int flags)
 
 	return 0;
 }
+
+static struct drm_fb_helper_funcs i915drm_fb_helper_funcs = {
+	.gamma_set = &intel_crtc_fb_gamma_set,
+	.gamma_get = &intel_crtc_fb_gamma_get,
+	.fb_probe = &i915drm_fb_probe,
+};
+
+static void
+i915drm_attach_framebuffer(device_t self)
+{
+	struct i915drm_softc *const sc = device_private(self);
+	struct drm_device *const dev = &sc->sc_drm_dev;
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	int ret;
+
+	aprint_debug_dev(self, "attach framebuffer\n");
+	dev_priv->fbdev = kmem_zalloc(sizeof(*dev_priv->fbdev), KM_SLEEP);
+
+	struct drm_fb_helper *const fb_helper = &dev_priv->fbdev->helper;
+
+	aprint_debug_dev(self, "drm_fb_helper_init\n");
+	fb_helper->funcs = &i915drm_fb_helper_funcs;
+	ret = drm_fb_helper_init(dev, fb_helper, dev_priv->num_pipe,
+	    INTELFB_CONN_LIMIT);
+	if (ret) {
+		aprint_error_dev(self, "unable to init drm fb helper: %d\n",
+		    ret);
+		goto fail0;
+	}
+
+	aprint_debug_dev(self, "drm_fb_helper_single_add_all_connectors\n");
+	drm_fb_helper_single_add_all_connectors(fb_helper);
+	aprint_debug_dev(self, "drm_fb_helper_initial_config\n");
+	drm_fb_helper_initial_config(fb_helper, 32 /* XXX ? */);
+
+	/* Success!  */
+	return;
+
+fail0:	kmem_free(dev_priv->fbdev, sizeof(*dev_priv->fbdev));
+	dev_priv->fbdev = NULL;
+}
+
+static int
+i915drm_detach_framebuffer(device_t self, int flags)
+{
+	struct i915drm_softc *const sc = device_private(self);
+	struct drm_device *const dev = &sc->sc_drm_dev;
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct intel_fbdev *const fbdev = dev_priv->fbdev;
+
+	if (fbdev != NULL) {
+		struct drm_fb_helper *const fb_helper = &fbdev->helper;
+
+		if (fb_helper->fb != NULL) {
+			struct drm_i915_gem_object *const obj = sc->sc_fb_obj;
+
+			/*
+			 * genfb children have already been detached,
+			 * so all we need do is unmap the space and
+			 * clean up the drm structures.
+			 */
+			bus_space_unmap(dev->bst, sc->sc_fb_bsh,
+			    obj->base.size);
+			drm_framebuffer_unreference(fb_helper->fb);
+			fb_helper->fb = NULL;
+			drm_gem_object_unreference_unlocked(&obj->base);
+			sc->sc_fb_obj = NULL;
+		}
+
+		KASSERT(sc->sc_fb_obj == NULL);
+		drm_fb_helper_fini(fb_helper);
+		kmem_free(fbdev, sizeof(*fbdev));
+		dev_priv->fbdev = NULL;
+	}
+
+	return 0;
+}
+
+static int
+i915drm_fb_probe(struct drm_fb_helper *fb_helper,
+    struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_device *const dev = fb_helper->dev;
+	struct drm_i915_private *const dev_priv = dev->dev_private;
+	struct i915drm_softc *const sc = container_of(dev,
+	    struct i915drm_softc, sc_drm_dev);
+#if 0				/* XXX genfb */
+	const prop_dictionary_t dict = device_properties(sc->sc_dev);
+	static const struct genfb_ops zero_genfb_ops;
+	struct genfb_ops genfb_ops = zero_genfb_ops;
+#endif
+	static const struct drm_mode_fb_cmd2 zero_mode_cmd;
+	struct drm_mode_fb_cmd2 mode_cmd = zero_mode_cmd;
+	bus_size_t size;
+	int ret;
+
+	aprint_debug_dev(sc->sc_dev, "probe framebuffer"
+	    ": %"PRIu32" by %"PRIu32"\n",
+	    sizes->surface_width,
+	    sizes->surface_height);
+
+	if (fb_helper->fb != NULL) {
+		aprint_debug_dev(sc->sc_dev, "already have a framebuffer"
+		    ": %p\n", fb_helper->fb);
+		return 0;
+	}
+
+	/*
+	 * XXX Cargo-culted from Linux.  Using sizes as an input/output
+	 * parameter seems sketchy...
+	 */
+	if (sizes->surface_bpp == 24)
+		sizes->surface_bpp = 32;
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	KASSERT(sizes->surface_bpp <= (UINT32_MAX - 7));
+	KASSERT(mode_cmd.width <=
+	    ((UINT32_MAX / howmany(sizes->surface_bpp, 8)) - 63));
+	mode_cmd.pitches[0] = round_up((mode_cmd.width *
+		howmany(sizes->surface_bpp, 8)), 64);
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+	    sizes->surface_depth);
+
+	KASSERT(mode_cmd.pitches[0] <=
+	    ((__type_max(bus_size_t) / mode_cmd.height) - 63));
+	size = round_up((mode_cmd.pitches[0] * mode_cmd.height), PAGE_SIZE);
+
+	sc->sc_fb_obj = i915_gem_alloc_object(dev, size);
+	if (sc->sc_fb_obj == NULL) {
+		aprint_error_dev(sc->sc_dev, "unable to create framebuffer\n");
+		ret = -ENODEV; /* XXX ? */
+		goto fail0;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+	ret = intel_pin_and_fence_fb_obj(dev, sc->sc_fb_obj, NULL);
+	if (ret) {
+		aprint_error_dev(sc->sc_dev, "unable to pin fb: %d\n", ret);
+		goto fail1;
+	}
+
+	ret = intel_framebuffer_init(dev, &dev_priv->fbdev->ifb, &mode_cmd,
+	    sc->sc_fb_obj);
+	if (ret) {
+		aprint_error_dev(sc->sc_dev, "unable to init framebuffer"
+		    ": %d\n", ret);
+		goto fail2;
+	}
+
+	/*
+	 * XXX Kludge: The intel_framebuffer abstraction `steals' a
+	 * reference to the object.  intel_framebuffer_init doesn't add
+	 * a reference, but when the drm_framebuffer inside is
+	 * destroyed, it will drop a reference.
+	 */
+	drm_gem_object_reference(&sc->sc_fb_obj->base);
+
+	fb_helper->fb = &dev_priv->fbdev->ifb.base;
+	mutex_unlock(&dev->struct_mutex);
+
+	aprint_error_dev(sc->sc_dev, "GTT base 0x%"PRIxMAX
+	    ", GTT offset 0x%"PRIxMAX"\n",
+	    (uintmax_t)dev_priv->mm.gtt_base_addr,
+	    (uintmax_t)sc->sc_fb_obj->gtt_offset);
+	/* XXX errno NetBSD->Linux */
+	ret = -bus_space_map(dev->bst,
+	    (dev_priv->mm.gtt_base_addr + sc->sc_fb_obj->gtt_offset),
+	    size,
+	    (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE),
+	    &sc->sc_fb_bsh);
+	if (ret) {
+		aprint_error_dev(sc->sc_dev, "unable to map framebuffer: %d\n",
+		    ret);
+		goto fail3;
+	}
+
+	if (0)
+		goto fail4;
+
+	aprint_error_dev(sc->sc_dev, "write crap to the framebuffer\n");
+    {
+	bus_size_t i;
+
+	for (i = 0; i < size; i++)
+		bus_space_write_1(dev->bst, sc->sc_fb_bsh, i,
+		    ((i % 4) == 0? 0x53 :
+		     (i % 4) == 1? 0x00 :
+		     (i % 4) == 2? 0x35 :
+			0xff));
+    }
+#if 0
+	(void)memset(bus_space_vaddr(dev->bst, sc->sc_fb_bsh), 0x53, size/4);
+	(void)kpause("drmfbxxx", false, hz, NULL);
+	(void)memset((char *)bus_space_vaddr(dev->bst, sc->sc_fb_bsh) + size/4,
+	    0x00, size/4);
+	(void)kpause("drmfbxxx", false, hz, NULL);
+	(void)memset((char *)bus_space_vaddr(dev->bst, sc->sc_fb_bsh) + size/2,
+	    0x35, size/4);
+	(void)kpause("drmfbxxx", false, hz, NULL);
+	(void)memset((char *)bus_space_vaddr(dev->bst, sc->sc_fb_bsh) + size/2
+	    + size/4, 0xff, size/4);
+#endif
+
+#if 0				/* XXX genfb */
+	prop_dictionary_set_uint32(dict, "is_console", 1); /* XXX */
+	prop_dictionary_set_uint32(dict, "width", mode_cmd.width);
+	prop_dictionary_set_uint32(dict, "height", mode_cmd.height);
+	prop_dictionary_set_uint8(dict, "depth", sizes->surface_depth);
+#if 0				/* XXX fb stride/linebytes? */
+	prop_dictionary_set_uint16(dict, "linebytes", ...);
+#endif
+	prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
+	prop_dictionary_set_uint64(dict, "virtual_address",
+	    (uint64_t)bus_space_vaddr(dev->bst, sc->sc_fb_bsh));
+	sc->sc_genfb.sc_dev = sc->sc_dev;
+	genfb_init(&sc->sc_genfb);
+
+	genfb_ops.genfb_ioctl = i915drm_genfb_ioctl;
+	genfb_ops.genfb_mmap = i915drm_genfb_mmap;
+
+	/* XXX errno NetBSD->Linux */
+	ret = -genfb_attach(&sc->sc_genfb, &genfb_ops);
+	if (ret) {
+		aprint_error_dev(sc->sc_dev, "unable to attach genfb: %d\n",
+		    ret);
+		goto fail4;
+	}
+#endif
+
+	/* Success!  */
+	return 1;
+
+fail4:	bus_space_unmap(dev->bst, sc->sc_fb_bsh, size);
+	fb_helper->fb = NULL;
+fail3:	drm_framebuffer_unreference(&dev_priv->fbdev->ifb.base);
+fail2:	i915_gem_object_unpin(sc->sc_fb_obj);
+fail1:	drm_gem_object_unreference_unlocked(&sc->sc_fb_obj->base);
+	mutex_unlock(&dev->struct_mutex);
+fail0:	KASSERT(ret < 0);
+	return ret;
+}
+
+#if 0				/* XXX genfb */
+static int
+i915drm_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
+    struct lwp *l)
+{
+	struct genfb_softc *const genfb = v;
+	struct i915drm_softc *const sc = container_of(genfb,
+	    struct i915drm_softc, sc_genfb);
+	const struct pci_attach_args *const pa = &sc->sc_pci_dev.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);
+
+	default:
+		return EPASSTHROUGH;
+	}
+}
+
+static paddr_t
+i915drm_genfb_mmap(void *v, void *vs, off_t offset, int prot)
+{
+	struct genfb_softc *const genfb = v;
+	struct i915drm_softc *const sc = container_of(genfb,
+	    struct i915drm_softc, sc_genfb);
+	const struct pci_attach_args *const pa = &sc->sc_drm_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(pa->pa_memt, genfb->sc_fboffset, 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(sc->sc_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, offset, 0, 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;
+}
+#endif

Reply via email to