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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
+ * 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;
+}