Module Name:    src
Committed By:   jmcneill
Date:           Thu Nov 12 00:43:52 UTC 2015

Modified Files:
        src/sys/arch/arm/nvidia: files.tegra tegra_drm.c tegra_drm.h
            tegra_drm_fb.c tegra_drm_mode.c tegra_fb.c
Added Files:
        src/sys/arch/arm/nvidia: tegra_drm_gem.c

Log Message:
Use GEM for memory management. Fixes a couple issues while here:
 - No longer needs to allocate 35MB (!) for framebuffer console.
 - Allows xrandr to switch to modes larger than the framebuffer console.
 - Removes hack that redirected mmap calls to wsdisplay0


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/arm/nvidia/files.tegra
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/nvidia/tegra_drm.c \
    src/sys/arch/arm/nvidia/tegra_drm.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/nvidia/tegra_drm_fb.c \
    src/sys/arch/arm/nvidia/tegra_fb.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/nvidia/tegra_drm_gem.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/nvidia/tegra_drm_mode.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/arch/arm/nvidia/files.tegra
diff -u src/sys/arch/arm/nvidia/files.tegra:1.20 src/sys/arch/arm/nvidia/files.tegra:1.21
--- src/sys/arch/arm/nvidia/files.tegra:1.20	Mon Nov  9 23:05:58 2015
+++ src/sys/arch/arm/nvidia/files.tegra	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-#	$NetBSD: files.tegra,v 1.20 2015/11/09 23:05:58 jmcneill Exp $
+#	$NetBSD: files.tegra,v 1.21 2015/11/12 00:43:52 jmcneill Exp $
 #
 # Configuration info for NVIDIA Tegra ARM Peripherals
 #
@@ -114,6 +114,7 @@ attach	tegradrm at tegraio with tegra_dr
 file	arch/arm/nvidia/tegra_drm.c		tegra_drm
 file	arch/arm/nvidia/tegra_drm_mode.c	tegra_drm
 file	arch/arm/nvidia/tegra_drm_fb.c		tegra_drm
+file	arch/arm/nvidia/tegra_drm_gem.c		tegra_drm
 
 # Framebuffer console
 device	tegrafb: tegrafbbus, drmfb, wsemuldisplaydev

Index: src/sys/arch/arm/nvidia/tegra_drm.c
diff -u src/sys/arch/arm/nvidia/tegra_drm.c:1.2 src/sys/arch/arm/nvidia/tegra_drm.c:1.3
--- src/sys/arch/arm/nvidia/tegra_drm.c:1.2	Tue Nov 10 22:14:05 2015
+++ src/sys/arch/arm/nvidia/tegra_drm.c	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_drm.c,v 1.2 2015/11/10 22:14:05 jmcneill Exp $ */
+/* $NetBSD: tegra_drm.c,v 1.3 2015/11/12 00:43:52 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_drm.c,v 1.2 2015/11/10 22:14:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_drm.c,v 1.3 2015/11/12 00:43:52 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -57,27 +57,30 @@ static int	tegra_drm_set_busid(struct dr
 static int	tegra_drm_load(struct drm_device *, unsigned long);
 static int	tegra_drm_unload(struct drm_device *);
 
-static int	tegra_drm_mmap_object(struct drm_device *, off_t, size_t,
-		    vm_prot_t, struct uvm_object **, voff_t *, struct file *);
-
 static int	tegra_drm_dumb_create(struct drm_file *, struct drm_device *,
 		    struct drm_mode_create_dumb *);
 static int	tegra_drm_dumb_map_offset(struct drm_file *,
 		    struct drm_device *, uint32_t, uint64_t *);
-static int	tegra_drm_dumb_destroy(struct drm_file *, struct drm_device *,
-		    uint32_t);
+
+static const struct uvm_pagerops tegra_drm_gem_uvm_ops = {
+	.pgo_reference = drm_gem_pager_reference,
+	.pgo_detach = drm_gem_pager_detach,
+	.pgo_fault = tegra_drm_gem_fault,
+};
 
 static struct drm_driver tegra_drm_driver = {
-	.driver_features = DRIVER_MODESET,
+	.driver_features = DRIVER_MODESET | DRIVER_GEM,
 	.dev_priv_size = 0,
 	.load = tegra_drm_load,
 	.unload = tegra_drm_unload,
 
-	.mmap_object = tegra_drm_mmap_object,
+	.gem_free_object = tegra_drm_gem_free_object,
+	.mmap_object = drm_gem_or_legacy_mmap_object,
+	.gem_uvm_ops = &tegra_drm_gem_uvm_ops,
 
 	.dumb_create = tegra_drm_dumb_create,
 	.dumb_map_offset = tegra_drm_dumb_map_offset,
-	.dumb_destroy = tegra_drm_dumb_destroy,
+	.dumb_destroy = drm_gem_dumb_destroy,
 
 	.get_vblank_counter = tegra_drm_get_vblank_counter,
 	.enable_vblank = tegra_drm_enable_vblank,
@@ -114,7 +117,7 @@ tegra_drm_attach(device_t parent, device
 	prop_dictionary_t prop = device_properties(self);
 	struct drm_driver * const driver = &tegra_drm_driver;
 	const char *pin, *dev;
-	int error, nsegs;
+	int error;
 
 	sc->sc_dev = self;
 	sc->sc_dmat = tio->tio_dmat;
@@ -145,24 +148,6 @@ tegra_drm_attach(device_t parent, device
 	aprint_naive("\n");
 	aprint_normal("\n");
 
-        sc->sc_dmasize = 4096 * 2160 * 4;
-        error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmasize, PAGE_SIZE, 0,
-            sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
-        if (error)
-                goto failed;
-        error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs,
-	    sc->sc_dmasize, &sc->sc_dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
-        if (error)
-                goto free;
-        error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmasize, 1,
-	    sc->sc_dmasize, 0, BUS_DMA_WAITOK, &sc->sc_dmamap);
-        if (error)
-                goto unmap;
-        error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmap,
-	    sc->sc_dmasize, NULL, BUS_DMA_WAITOK);
-        if (error)
-                goto destroy;
-
 	driver->bus = &tegra_drm_bus;
 
 	sc->sc_ddev = drm_dev_alloc(driver, sc->sc_dev);
@@ -185,16 +170,6 @@ tegra_drm_attach(device_t parent, device
 	    driver->date, sc->sc_ddev->primary->index);
 
 	return;
-
-destroy:
-        bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
-unmap:
-        bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmap, sc->sc_dmasize);
-free:
-        bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, nsegs);
-failed:
-
-	aprint_error_dev(sc->sc_dev, "bus_dma setup failed\n");
 }
 
 static const char *
@@ -256,35 +231,31 @@ tegra_drm_unload(struct drm_device *ddev
 }
 
 static int
-tegra_drm_mmap_object(struct drm_device *ddev, off_t offset, size_t size,
-    vm_prot_t prot, struct uvm_object **uobjp, voff_t *uoffsetp,
-    struct file *file)
-{
-	/* XXX */
-	extern const struct cdevsw wsdisplay_cdevsw;
-	devmajor_t maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
-	dev_t devno = makedev(maj, 0);
-	struct uvm_object *uobj;
-
-	KASSERT(offset == (offset & ~(PAGE_SIZE-1)));
-
-	uobj = udv_attach(devno, prot, offset, size);
-	if (uobj == NULL)
-		return -EINVAL;
-
-	*uobjp = uobj;
-	*uoffsetp = offset;
-	return 0;
-}
-
-static int
 tegra_drm_dumb_create(struct drm_file *file_priv, struct drm_device *ddev,
     struct drm_mode_create_dumb *args)
 {
+	struct tegra_gem_object *obj;
+	uint32_t handle;
+	int error;
+
 	args->pitch = args->width * ((args->bpp + 7) / 8);
 	args->size = args->pitch * args->height;
+	args->size = roundup(args->size, PAGE_SIZE);
 	args->handle = 0;
 
+	obj = tegra_drm_obj_alloc(ddev, args->size);
+	if (obj == NULL)
+		return -ENOMEM;
+
+	error = drm_gem_handle_create(file_priv, &obj->base, &handle);
+	drm_gem_object_unreference_unlocked(&obj->base);
+	if (error) {
+		tegra_drm_obj_free(obj);
+		return error;
+	}
+
+	args->handle = handle;
+
 	return 0;
 }
 
@@ -292,13 +263,26 @@ static int
 tegra_drm_dumb_map_offset(struct drm_file *file_priv,
     struct drm_device *ddev, uint32_t handle, uint64_t *offset)
 {
-	*offset = 0;
-	return 0;
-}
+	struct drm_gem_object *gem_obj;
+	struct tegra_gem_object *obj;
+	int error;
 
-static int
-tegra_drm_dumb_destroy(struct drm_file *file_priv, struct drm_device *ddev,
-    uint32_t handle)
-{
-	return 0;
+	gem_obj = drm_gem_object_lookup(ddev, file_priv, handle);
+	if (gem_obj == NULL)
+		return -ENOENT;
+
+	obj = to_tegra_gem_obj(gem_obj);
+
+	if (drm_vma_node_has_offset(&obj->base.vma_node) == 0) {
+		error = drm_gem_create_mmap_offset(&obj->base);
+		if (error)
+			goto done;
+	}
+
+	*offset = drm_vma_node_offset_addr(&obj->base.vma_node);
+
+done:
+	drm_gem_object_unreference_unlocked(&obj->base);
+
+	return error;
 }
Index: src/sys/arch/arm/nvidia/tegra_drm.h
diff -u src/sys/arch/arm/nvidia/tegra_drm.h:1.2 src/sys/arch/arm/nvidia/tegra_drm.h:1.3
--- src/sys/arch/arm/nvidia/tegra_drm.h:1.2	Tue Nov 10 22:14:05 2015
+++ src/sys/arch/arm/nvidia/tegra_drm.h	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_drm.h,v 1.2 2015/11/10 22:14:05 jmcneill Exp $ */
+/* $NetBSD: tegra_drm.h,v 1.3 2015/11/12 00:43:52 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -48,6 +48,7 @@ struct tegra_drm_softc {
 	struct drm_device	*sc_ddev;
 
 	bus_space_tag_t		sc_bst;
+	bus_dma_tag_t		sc_dmat;
 
 	device_t		sc_ddcdev;
 	struct tegra_gpio_pin	*sc_pin_hpd;
@@ -56,12 +57,6 @@ struct tegra_drm_softc {
 
 	bool			sc_force_dvi;
 
-	bus_dma_tag_t		sc_dmat;
-	bus_dma_segment_t	sc_dmasegs[1];
-	bus_size_t		sc_dmasize;
-	bus_dmamap_t		sc_dmamap;
-	void			*sc_dmap;
-
 	uint32_t		sc_vbl_received[2];
 };
 
@@ -93,14 +88,25 @@ struct tegra_encoder {
 struct tegra_connector {
 	struct drm_connector	base;
 	device_t		ddcdev;
+	struct i2c_adapter	*adapter;
 	struct tegra_gpio_pin	*hpd;
 
 	bool			has_hdmi_sink;
 	bool			has_audio;
 };
 
+struct tegra_gem_object {
+	struct drm_gem_object	base;
+	bus_dma_tag_t		dmat;
+	bus_dma_segment_t	dmasegs[1];
+	bus_size_t		dmasize;
+	bus_dmamap_t		dmamap;
+	void			*dmap;
+};
+
 struct tegra_framebuffer {
 	struct drm_framebuffer	base;
+	struct tegra_gem_object *obj;
 };
 
 struct tegra_fbdev {
@@ -129,11 +135,21 @@ struct tegra_fbdev {
 #define to_tegra_connector(x)	container_of(x, struct tegra_connector, base)
 #define to_tegra_framebuffer(x)	container_of(x, struct tegra_framebuffer, base)
 #define to_tegra_fbdev(x)	container_of(x, struct tegra_fbdev, helper)
+#define to_tegra_gem_obj(x)	container_of(x, struct tegra_gem_object, base)
 
 int	tegra_drm_mode_init(struct drm_device *);
 int	tegra_drm_fb_init(struct drm_device *);
 u32	tegra_drm_get_vblank_counter(struct drm_device *, int);
 int	tegra_drm_enable_vblank(struct drm_device *, int);
 void	tegra_drm_disable_vblank(struct drm_device *, int);
+int	tegra_drm_framebuffer_init(struct drm_device *,
+	    struct tegra_framebuffer *);
+
+struct tegra_gem_object *tegra_drm_obj_alloc(struct drm_device *, size_t);
+void	tegra_drm_obj_free(struct tegra_gem_object *);
+
+int	tegra_drm_gem_fault(struct uvm_faultinfo *, vaddr_t, struct vm_page **,
+	    int, int, vm_prot_t, int);
+void	tegra_drm_gem_free_object(struct drm_gem_object *);
 
 #endif /* _ARM_TEGRA_DRM_H */

Index: src/sys/arch/arm/nvidia/tegra_drm_fb.c
diff -u src/sys/arch/arm/nvidia/tegra_drm_fb.c:1.1 src/sys/arch/arm/nvidia/tegra_drm_fb.c:1.2
--- src/sys/arch/arm/nvidia/tegra_drm_fb.c:1.1	Mon Nov  9 23:05:58 2015
+++ src/sys/arch/arm/nvidia/tegra_drm_fb.c	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_drm_fb.c,v 1.1 2015/11/09 23:05:58 jmcneill Exp $ */
+/* $NetBSD: tegra_drm_fb.c,v 1.2 2015/11/12 00:43:52 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_drm_fb.c,v 1.1 2015/11/09 23:05:58 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_drm_fb.c,v 1.2 2015/11/12 00:43:52 jmcneill Exp $");
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -36,6 +36,9 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_drm_fb
 
 #include <arm/nvidia/tegra_drm.h>
 
+static int	tegra_fb_init(struct drm_device *, struct drm_framebuffer *,
+		    struct drm_fb_helper_surface_size *);
+
 static int	tegra_fb_probe(struct drm_fb_helper *,
 		    struct drm_fb_helper_surface_size *);
 
@@ -47,8 +50,6 @@ int
 tegra_drm_fb_init(struct drm_device *ddev)
 {
 	struct tegra_fbdev *fbdev;
-	struct drm_framebuffer *fb;
-	struct drm_mode_fb_cmd2 cmd;
 	int error;
 
 	fbdev = kmem_zalloc(sizeof(*fbdev), KM_SLEEP);
@@ -62,18 +63,22 @@ tegra_drm_fb_init(struct drm_device *dde
 		return error;
 	}
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.width = 4096;
-	cmd.height = 2160;
-	cmd.pixel_format = DRM_FORMAT_ARGB8888;
-	cmd.pitches[0] = cmd.width * (32 / 8);
-
-	fb = ddev->mode_config.funcs->fb_create(ddev, NULL, &cmd);
-	if (fb == NULL) {
-		DRM_ERROR("couldn't create framebuffer\n");
-		return -EIO;
+	/*
+	 * This might seem silly, but it saves us from having to allocate
+	 * enough memory for the largest possible framebuffer (around 35MB).
+	 *
+	 * Allocate the fb_helper's framebuffer here but don't initialize
+	 * it yet. The fb helper won't configure a CRTC unless this field is
+	 * set, and we don't know the preferred size at this time.
+	 *
+	 * The fb_probe callback will eventually be called with the preferred
+	 * surface size, so defer allocating the buffer object until then.
+	 */
+	fbdev->helper.fb =
+	    kmem_zalloc(sizeof(struct tegra_framebuffer), KM_SLEEP);
+	if (fbdev->helper.fb == NULL) {
+		DRM_ERROR("failed to create framebuffer\n");
 	}
-	fbdev->helper.fb = fb;
 
 	drm_fb_helper_single_add_all_connectors(&fbdev->helper);
 
@@ -92,6 +97,11 @@ tegra_fb_probe(struct drm_fb_helper *hel
 	struct drm_device *ddev = helper->dev;
 	struct tegra_drmfb_attach_args tfa;
 
+	if (tegra_fb_init(ddev, helper->fb, sizes) != 0) {
+		DRM_ERROR("failed to initialize framebuffer\n");
+		return -ENOMEM;
+	}
+
 	memset(&tfa, 0, sizeof(tfa));
 	tfa.tfa_drm_dev = ddev;
 	tfa.tfa_fb_helper = helper;
@@ -107,3 +117,30 @@ tegra_fb_probe(struct drm_fb_helper *hel
 
 	return 0;
 }
+
+static int
+tegra_fb_init(struct drm_device *ddev, struct drm_framebuffer *fb,
+    struct drm_fb_helper_surface_size *sizes)
+{
+	struct tegra_framebuffer *tegra_fb = to_tegra_framebuffer(fb);
+	const u_int width = sizes->surface_width;
+	const u_int height = sizes->surface_height;
+	const u_int pitch = width * (32 / 8);
+
+	const size_t size = roundup(height * pitch, PAGE_SIZE);
+
+	tegra_fb->obj = tegra_drm_obj_alloc(ddev, size);
+	if (tegra_fb->obj == NULL)
+		return -ENOMEM;
+
+        fb->pitches[0] = pitch;
+        fb->offsets[0] = 0;
+        fb->width = width;
+        fb->height = height;
+        fb->pixel_format = DRM_FORMAT_ARGB8888;
+        drm_fb_get_bpp_depth(fb->pixel_format, &fb->depth,
+            &fb->bits_per_pixel);
+	tegra_drm_framebuffer_init(ddev, tegra_fb);
+
+	return 0;
+}
Index: src/sys/arch/arm/nvidia/tegra_fb.c
diff -u src/sys/arch/arm/nvidia/tegra_fb.c:1.1 src/sys/arch/arm/nvidia/tegra_fb.c:1.2
--- src/sys/arch/arm/nvidia/tegra_fb.c:1.1	Mon Nov  9 23:05:58 2015
+++ src/sys/arch/arm/nvidia/tegra_fb.c	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_fb.c,v 1.1 2015/11/09 23:05:58 jmcneill Exp $ */
+/* $NetBSD: tegra_fb.c,v 1.2 2015/11/12 00:43:52 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_fb.c,v 1.1 2015/11/09 23:05:58 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_fb.c,v 1.2 2015/11/12 00:43:52 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -49,6 +49,7 @@ struct tegra_fb_softc {
 	device_t		sc_dev;
 	struct tegra_drm_softc	*sc_drm;
 	struct tegra_drmfb_attach_args sc_tfa;
+	struct tegra_framebuffer *sc_fb;
 };
 
 static paddr_t	tegra_fb_mmapfb(struct drmfb_softc *, off_t, int);
@@ -83,6 +84,7 @@ tegra_fb_attach(device_t parent, device_
 	sc->sc_dev = self;
 	sc->sc_drm = drmsc;
 	sc->sc_tfa = *tfa;
+	sc->sc_fb = to_tegra_framebuffer(tfa->tfa_fb_helper->fb);
 
 	aprint_naive("\n");
 	aprint_normal("\n");
@@ -90,7 +92,7 @@ tegra_fb_attach(device_t parent, device_
 	da.da_dev = self;
 	da.da_fb_helper = tfa->tfa_fb_helper;
 	da.da_fb_sizes = &tfa->tfa_fb_sizes;
-	da.da_fb_vaddr = drmsc->sc_dmap;
+	da.da_fb_vaddr = sc->sc_fb->obj->dmap;
 	da.da_params = &tegrafb_drmfb_params;
 
 	error = drmfb_attach(&sc->sc_drmfb, &da);
@@ -114,12 +116,13 @@ static paddr_t
 tegra_fb_mmapfb(struct drmfb_softc *sc, off_t off, int prot)
 {
 	struct tegra_fb_softc * const tfb_sc = (struct tegra_fb_softc *)sc;
+	struct tegra_gem_object *obj = tfb_sc->sc_fb->obj;
 
 	KASSERT(off >= 0);
-	KASSERT(off < tfb_sc->sc_drm->sc_dmasize);
+	KASSERT(off < obj->dmasize);
 
-	return bus_dmamem_mmap(tfb_sc->sc_drm->sc_dmat,
-	    tfb_sc->sc_drm->sc_dmasegs, 1, off, prot, BUS_DMA_PREFETCHABLE);
+	return bus_dmamem_mmap(obj->dmat, obj->dmasegs, 1, off, prot,
+	    BUS_DMA_PREFETCHABLE);
 }
 
 static int

Index: src/sys/arch/arm/nvidia/tegra_drm_mode.c
diff -u src/sys/arch/arm/nvidia/tegra_drm_mode.c:1.4 src/sys/arch/arm/nvidia/tegra_drm_mode.c:1.5
--- src/sys/arch/arm/nvidia/tegra_drm_mode.c:1.4	Tue Nov 10 22:14:05 2015
+++ src/sys/arch/arm/nvidia/tegra_drm_mode.c	Thu Nov 12 00:43:52 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_drm_mode.c,v 1.4 2015/11/10 22:14:05 jmcneill Exp $ */
+/* $NetBSD: tegra_drm_mode.c,v 1.5 2015/11/12 00:43:52 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_drm_mode.c,v 1.4 2015/11/10 22:14:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_drm_mode.c,v 1.5 2015/11/12 00:43:52 jmcneill Exp $");
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -50,9 +50,12 @@ static const struct drm_mode_config_func
 	.fb_create = tegra_fb_create
 };
 
+static int	tegra_framebuffer_create_handle(struct drm_framebuffer *,
+		    struct drm_file *, unsigned int *);
 static void	tegra_framebuffer_destroy(struct drm_framebuffer *);
 
 static const struct drm_framebuffer_funcs tegra_framebuffer_funcs = {
+	.create_handle = tegra_framebuffer_create_handle,
 	.destroy = tegra_framebuffer_destroy
 };
 
@@ -195,11 +198,19 @@ tegra_drm_mode_init(struct drm_device *d
 	return 0;
 }
 
+int
+tegra_drm_framebuffer_init(struct drm_device *ddev,
+    struct tegra_framebuffer *fb)
+{
+	return drm_framebuffer_init(ddev, &fb->base, &tegra_framebuffer_funcs);
+}
+
 static struct drm_framebuffer *
 tegra_fb_create(struct drm_device *ddev, struct drm_file *file,
     struct drm_mode_fb_cmd2 *cmd)
 {
 	struct tegra_framebuffer *fb;
+	struct drm_gem_object *gem_obj;
 	int error;
 
 	if (cmd->flags)
@@ -209,10 +220,15 @@ tegra_fb_create(struct drm_device *ddev,
 		return NULL;
 	}
 
+	gem_obj = drm_gem_object_lookup(ddev, file, cmd->handles[0]);
+	if (gem_obj == NULL)
+		return NULL;
+
 	fb = kmem_zalloc(sizeof(*fb), KM_SLEEP);
 	if (fb == NULL)
-		return NULL;
+		goto unref;
 
+	fb->obj = to_tegra_gem_obj(gem_obj);
 	fb->base.pitches[0] = cmd->pitches[0];
 	fb->base.offsets[0] = cmd->offsets[0];
 	fb->base.width = cmd->width;
@@ -221,7 +237,7 @@ tegra_fb_create(struct drm_device *ddev,
 	drm_fb_get_bpp_depth(cmd->pixel_format, &fb->base.depth,
 	    &fb->base.bits_per_pixel);
 
-	error = drm_framebuffer_init(ddev, &fb->base, &tegra_framebuffer_funcs);
+	error = tegra_drm_framebuffer_init(ddev, fb);
 	if (error)
 		goto dealloc;
 
@@ -230,15 +246,28 @@ tegra_fb_create(struct drm_device *ddev,
 	drm_framebuffer_cleanup(&fb->base);
 dealloc:
 	kmem_free(fb, sizeof(*fb));
+unref:
+	drm_gem_object_unreference_unlocked(gem_obj);
+
 	return NULL;
 }
 
+static int
+tegra_framebuffer_create_handle(struct drm_framebuffer *fb,
+    struct drm_file *file, unsigned int *handle)
+{
+	struct tegra_framebuffer *tegra_fb = to_tegra_framebuffer(fb);
+
+	return drm_gem_handle_create(file, &tegra_fb->obj->base, handle);
+}
+
 static void
 tegra_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	struct tegra_framebuffer *tegra_fb = to_tegra_framebuffer(fb);
 
 	drm_framebuffer_cleanup(fb);
+	drm_gem_object_unreference_unlocked(&tegra_fb->obj->base);
 	kmem_free(tegra_fb, sizeof(*tegra_fb));
 }
 
@@ -433,17 +462,14 @@ static int
 tegra_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb,
     int x, int y, int atomic)
 {
-	struct tegra_drm_softc * const sc = tegra_drm_private(crtc->dev);
 	struct tegra_crtc *tegra_crtc = to_tegra_crtc(crtc);
-#if 0
 	struct tegra_framebuffer *tegra_fb = atomic ?
 	    to_tegra_framebuffer(fb) :
 	    to_tegra_framebuffer(crtc->primary->fb);
-#endif
 
 	/* Framebuffer start address */
 	DC_WRITE(tegra_crtc, DC_WINBUF_A_START_ADDR_REG,
-	    (uint32_t)sc->sc_dmamap->dm_segs[0].ds_addr);
+	    (uint32_t)tegra_fb->obj->dmamap->dm_segs[0].ds_addr);
 
 	/* Offsets */
 	DC_WRITE(tegra_crtc, DC_WINBUF_A_ADDR_H_OFFSET_REG, x);

Added files:

Index: src/sys/arch/arm/nvidia/tegra_drm_gem.c
diff -u /dev/null src/sys/arch/arm/nvidia/tegra_drm_gem.c:1.1
--- /dev/null	Thu Nov 12 00:43:52 2015
+++ src/sys/arch/arm/nvidia/tegra_drm_gem.c	Thu Nov 12 00:43:52 2015
@@ -0,0 +1,158 @@
+/* $NetBSD: tegra_drm_gem.c,v 1.1 2015/11/12 00:43:52 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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: tegra_drm_gem.c,v 1.1 2015/11/12 00:43:52 jmcneill Exp $");
+
+#include <drm/drmP.h>
+#include <uvm/uvm.h>
+
+#include <arm/nvidia/tegra_drm.h>
+
+struct tegra_gem_object *
+tegra_drm_obj_alloc(struct drm_device *ddev, size_t size)
+{
+	struct tegra_drm_softc * const sc = tegra_drm_private(ddev);
+	struct tegra_gem_object *obj;
+	int error, nsegs;
+
+	obj = kmem_zalloc(sizeof(*obj), KM_SLEEP);
+	if (obj == NULL)
+		return NULL;
+
+	obj->dmat = sc->sc_dmat;
+	obj->dmasize = size;
+
+        error = bus_dmamem_alloc(obj->dmat, obj->dmasize, PAGE_SIZE, 0,
+	    obj->dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
+	if (error)
+		goto failed;
+	error = bus_dmamem_map(obj->dmat, obj->dmasegs, nsegs,
+	    obj->dmasize, &obj->dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
+	if (error)
+		goto free;
+	error = bus_dmamap_create(obj->dmat, obj->dmasize, 1,
+	    obj->dmasize, 0, BUS_DMA_WAITOK, &obj->dmamap);
+	if (error)
+		goto unmap;
+	error = bus_dmamap_load(obj->dmat, obj->dmamap, obj->dmap,
+	    obj->dmasize, NULL, BUS_DMA_WAITOK);
+	if (error)
+		goto destroy;
+
+	drm_gem_private_object_init(ddev, &obj->base, size);
+
+	return obj;
+
+destroy:
+	bus_dmamap_destroy(obj->dmat, obj->dmamap);
+unmap:
+	bus_dmamem_unmap(obj->dmat, obj->dmap, obj->dmasize);
+free:
+	bus_dmamem_free(obj->dmat, obj->dmasegs, nsegs);
+failed:
+	kmem_free(obj, sizeof(*obj));
+
+	return NULL;
+}
+
+void
+tegra_drm_obj_free(struct tegra_gem_object *obj)
+{
+	bus_dmamap_unload(obj->dmat, obj->dmamap);
+	bus_dmamap_destroy(obj->dmat, obj->dmamap);
+	bus_dmamem_unmap(obj->dmat, obj->dmap, obj->dmasize);
+	bus_dmamem_free(obj->dmat, obj->dmasegs, 1);
+	kmem_free(obj, sizeof(*obj));
+}
+
+void
+tegra_drm_gem_free_object(struct drm_gem_object *gem_obj)
+{
+	struct tegra_gem_object *obj = to_tegra_gem_obj(gem_obj);
+
+	drm_gem_free_mmap_offset(gem_obj);
+	drm_gem_object_release(gem_obj);
+	tegra_drm_obj_free(obj);
+}
+
+int
+tegra_drm_gem_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr,
+    struct vm_page **pps, int npages, int centeridx, vm_prot_t access_type,
+    int flags)
+{
+	struct vm_map_entry *entry = ufi->entry;
+	struct uvm_object *uobj = entry->object.uvm_obj;
+	struct drm_gem_object *gem_obj =
+	    container_of(uobj, struct drm_gem_object, gemo_uvmobj);
+	struct tegra_gem_object *obj = to_tegra_gem_obj(gem_obj);
+	off_t curr_offset;
+	vaddr_t curr_va;
+	paddr_t paddr, mdpgno;
+	u_int mmapflags;
+	int lcv, retval;
+	vm_prot_t mapprot;
+
+	if (UVM_ET_ISCOPYONWRITE(entry))
+		return -EIO;
+
+	curr_offset = entry->offset + (vaddr - entry->start);
+	curr_va = vaddr;
+
+	retval = 0;
+	for (lcv = 0; lcv < npages; lcv++, curr_offset += PAGE_SIZE,
+	    curr_va += PAGE_SIZE) {
+		if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx)
+			continue;
+		if (pps[lcv] == PGO_DONTCARE)
+			continue;
+
+		mdpgno = bus_dmamem_mmap(obj->dmat, obj->dmasegs, 1,
+		    curr_offset, access_type, BUS_DMA_PREFETCHABLE);
+		if (mdpgno == -1) {
+			retval = -EIO;
+			break;
+		}
+		paddr = pmap_phys_address(mdpgno);
+		mmapflags = pmap_mmap_flags(mdpgno);
+		mapprot = ufi->entry->protection;
+
+		if (pmap_enter(ufi->orig_map->pmap, curr_va, paddr, mapprot,
+		    PMAP_CANFAIL | mapprot | mmapflags) != 0) {
+			pmap_update(ufi->orig_map->pmap);
+			uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj);
+			uvm_wait("tegra_drm_gem_fault");
+			return -ERESTART;
+		}
+	}
+
+	pmap_update(ufi->orig_map->pmap);
+	uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj);
+
+	return retval;
+}

Reply via email to