diff --git a/.gitignore b/.gitignore index 225fd801..9f8eabbf 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ libdrm_nouveau.pc libdrm_radeon.pc libdrm_omap.pc libdrm_exynos.pc +libdrm_freedreno.pc libkms.pc libtool ltmain.sh diff --git a/Makefile.am b/Makefile.am index 94572d01..f7260368 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,11 @@ if HAVE_EXYNOS EXYNOS_SUBDIR = exynos endif -SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) tests include man +if HAVE_FREEDRENO +FREEDRENO_SUBDIR = freedreno +endif + +SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(FREEDRENO_SUBDIR) tests include man libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) diff --git a/configure.ac b/configure.ac index e2e34667..83ffe1b2 100644 --- a/configure.ac +++ b/configure.ac @@ -93,6 +93,11 @@ AC_ARG_ENABLE(exynos-experimental-api, [Enable support for EXYNOS's experimental API (default: disabled)]), [EXYNOS=$enableval], [EXYNOS=no]) +AC_ARG_ENABLE(freedreno-experimental-api, + AS_HELP_STRING([--enable-freedreno-experimental-api], + [Enable support for freedreno's experimental API (default: disabled)]), + [FREEDRENO=$enableval], [FREEDRENO=no]) + dnl =========================================================================== dnl check compiler flags AC_DEFUN([LIBDRM_CC_TRY_FLAG], [ @@ -201,6 +206,11 @@ if test "x$EXYNOS" = xyes; then AC_DEFINE(HAVE_EXYNOS, 1, [Have EXYNOS support]) fi +AM_CONDITIONAL(HAVE_FREEDRENO, [test "x$FREEDRENO" = xyes]) +if test "x$FREEDRENO" = xyes; then + AC_DEFINE(HAVE_FREEDRENO, 1, [Have freedreno support]) +fi + AC_ARG_ENABLE([cairo-tests], [AS_HELP_STRING([--enable-cairo-tests], [Enable support for Cairo rendering in tests (default: auto)])], @@ -247,7 +257,7 @@ else fi AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], [test "x$HAVE_MANPAGES_STYLESHEET" = "xyes"]) -if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$OMAP" != "xno"; then +if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$OMAP" != "xno" -o "x$FREEDRENO" != "xno"; then # Check for atomic intrinsics AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives, [ @@ -358,6 +368,8 @@ AC_CONFIG_FILES([ omap/libdrm_omap.pc exynos/Makefile exynos/libdrm_exynos.pc + freedreno/Makefile + freedreno/libdrm_freedreno.pc tests/Makefile tests/modeprint/Makefile tests/modetest/Makefile @@ -380,4 +392,5 @@ echo " Radeon API $RADEON" echo " Nouveau API $NOUVEAU" echo " OMAP API $OMAP" echo " EXYNOS API $EXYNOS" +echo " Freedreno API $FREEDRENO" echo "" diff --git a/freedreno/Makefile.am b/freedreno/Makefile.am new file mode 100644 index 00000000..f46a7807 --- /dev/null +++ b/freedreno/Makefile.am @@ -0,0 +1,19 @@ +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/freedreno \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/include/drm + +libdrm_freedreno_la_LTLIBRARIES = libdrm_freedreno.la +libdrm_freedreno_ladir = $(libdir) +libdrm_freedreno_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_freedreno_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ + +libdrm_freedreno_la_SOURCES = freedreno_device.c freedreno_pipe.c freedreno_ringbuffer.c freedreno_bo.c + +libdrm_freedrenocommonincludedir = ${includedir}/freedreno +libdrm_freedrenocommoninclude_HEADERS = freedreno_drmif.h freedreno_ringbuffer.h + +pkgconfigdir = @pkgconfigdir@ +pkgconfig_DATA = libdrm_freedreno.pc diff --git a/freedreno/README b/freedreno/README new file mode 100644 index 00000000..ae22e013 --- /dev/null +++ b/freedreno/README @@ -0,0 +1,16 @@ +Note that current msm kernel driver is a bit strange. It provides a +DRM interface for GEM, which is basically sufficient to have DRI2 +working. But it does not provide KMS. And interface to 2d and 3d +cores is via different other devices (/dev/kgsl-*). This is not +quite how I'd write a DRM driver, but at this stage it is useful for +xf86-video-freedreno and fdre (and eventual gallium driver) to be +able to work on existing kernel driver from QCOM, to allow to +capture cmdstream dumps from the binary blob drivers without having +to reboot. So libdrm_freedreno attempts to hide most of the crazy. +The intention is that when there is a proper kernel driver, it will +be mostly just changes in libdrm_freedreno to adapt the gallium +driver and xf86-video-freedreno (ignoring the fbdev->KMS changes). + +So don't look at freedreno as an example of how to write a libdrm +module or a DRM driver.. it is just an attempt to paper over a non- +standard kernel driver architecture. diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c new file mode 100644 index 00000000..4f566e10 --- /dev/null +++ b/freedreno/freedreno_bo.c @@ -0,0 +1,274 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +#include + +static struct fd_bo * bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle) +{ + unsigned i; + struct fd_bo *bo = calloc(1, sizeof(*bo)); + if (!bo) + return NULL; + bo->dev = dev; + bo->size = size; + bo->handle = handle; + atomic_set(&bo->refcnt, 1); + for (i = 0; i < ARRAY_SIZE(bo->list); i++) + list_inithead(&bo->list[i]); + return bo; +} + +static int set_memtype(struct fd_bo *bo, uint32_t flags) +{ + struct drm_kgsl_gem_memtype req = { + .handle = bo->handle, + .type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK, + }; + + return drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SETMEMTYPE, + &req, sizeof(req)); +} + +static int bo_alloc(struct fd_bo *bo) +{ + if (!bo->offset) { + struct drm_kgsl_gem_alloc req = { + .handle = bo->handle, + }; + int ret; + + /* if the buffer is already backed by pages then this + * doesn't actually do anything (other than giving us + * the offset) + */ + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_ALLOC, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("alloc failed: %s", strerror(errno)); + return ret; + } + + bo->offset = req.offset; + } + return 0; +} + +struct fd_bo * fd_bo_new(struct fd_device *dev, + uint32_t size, uint32_t flags) +{ + struct drm_kgsl_gem_create req = { + .size = ALIGN(size, 4096), + }; + struct fd_bo *bo = NULL; + + if (drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE, + &req, sizeof(req))) { + return NULL; + } + + bo = bo_from_handle(dev, size, req.handle); + if (!bo) { + goto fail; + } + + if (set_memtype(bo, flags)) { + goto fail; + } + + return bo; +fail: + if (bo) + fd_bo_del(bo); + return NULL; +} + +/* don't use this... it is just needed to get a bo from the + * framebuffer (pre-dmabuf) + */ +struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, + int fbfd, uint32_t size) +{ + struct drm_kgsl_gem_create_fd req = { + .fd = fbfd, + }; + struct fd_bo *bo; + + if (drmCommandWriteRead(pipe->dev->fd, DRM_KGSL_GEM_CREATE_FD, + &req, sizeof(req))) { + return NULL; + } + + bo = bo_from_handle(pipe->dev, size, req.handle); + + /* this is fugly, but works around a bug in the kernel.. + * priv->memdesc.size never gets set, so getbufinfo ioctl + * thinks the buffer hasn't be allocate and fails + */ + if (bo && !fd_bo_gpuaddr(bo, 0)) { + void *fbmem = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fbfd, 0); + struct kgsl_map_user_mem req = { + .memtype = KGSL_USER_MEM_TYPE_ADDR, + .len = size, + .offset = 0, + .hostptr = (unsigned long)fbmem, + }; + int ret; + ret = ioctl(pipe->fd, IOCTL_KGSL_MAP_USER_MEM, &req); + if (ret) { + ERROR_MSG("mapping user mem failed: %s", + strerror(errno)); + goto fail; + } + bo->gpuaddr = req.gpuaddr; + bo->map = fbmem; + } + + return bo; +fail: + if (bo) + fd_bo_del(bo); + return NULL; +} + +struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name) +{ + struct drm_gem_open req = { + .name = name, + }; + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + return NULL; + } + + return bo_from_handle(dev, req.size, req.handle); +} + +struct fd_bo * fd_bo_ref(struct fd_bo *bo) +{ + atomic_inc(&bo->refcnt); + return bo; +} + +void fd_bo_del(struct fd_bo *bo) +{ + if (!atomic_dec_and_test(&bo->refcnt)) + return; + + if (bo->map) + munmap(bo->map, bo->size); + + if (bo->handle) { + struct drm_gem_close req = { + .handle = bo->handle, + }; + drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + } + + free(bo); +} + +int fd_bo_get_name(struct fd_bo *bo, uint32_t *name) +{ + if (!bo->name) { + struct drm_gem_flink req = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) { + return ret; + } + + bo->name = req.name; + } + + *name = bo->name; + + return 0; +} + +uint32_t fd_bo_handle(struct fd_bo *bo) +{ + return bo->handle; +} + +uint32_t fd_bo_size(struct fd_bo *bo) +{ + return bo->size; +} + +void * fd_bo_map(struct fd_bo *bo) +{ + if (!bo->map) { + int ret; + + ret = bo_alloc(bo); + if (ret) { + return NULL; + } + + bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->dev->fd, bo->offset); + if (bo->map == MAP_FAILED) { + ERROR_MSG("mmap failed: %s", strerror(errno)); + bo->map = NULL; + } + } + return bo->map; +} + +uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset) +{ + if (!bo->gpuaddr) { + struct drm_kgsl_gem_bufinfo req = { + .handle = bo->handle, + }; + int ret; + + ret = bo_alloc(bo); + if (ret) { + return ret; + } + + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("get bufinfo failed: %s", strerror(errno)); + return 0; + } + + bo->gpuaddr = req.gpuaddr[0]; + } + return bo->gpuaddr + offset; +} diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c new file mode 100644 index 00000000..0a9ef9f2 --- /dev/null +++ b/freedreno/freedreno_device.c @@ -0,0 +1,45 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +struct fd_device * fd_device_new(int fd) +{ + struct fd_device *dev = calloc(1, sizeof(*dev)); + if (!dev) + return NULL; + dev->fd = fd; + return dev; +} + +void fd_device_del(struct fd_device *dev) +{ + free(dev); +} + diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h new file mode 100644 index 00000000..775d6995 --- /dev/null +++ b/freedreno/freedreno_drmif.h @@ -0,0 +1,99 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_DRMIF_H_ +#define FREEDRENO_DRMIF_H_ + +#include +#include + +struct fd_bo; +struct fd_pipe; +struct fd_device; + +enum fd_pipe_id { + FD_PIPE_3D = 1, + FD_PIPE_2D = 2, + /* some devices have two 2d blocks.. not really sure how to + * use that yet, so just ignoring the 2nd 2d pipe for now + */ + FD_PIPE_MAX +}; + +enum fd_param_id { + FD_DEVICE_ID, + FD_GMEM_SIZE, +}; + +/* bo flags: */ +#define DRM_FREEDRENO_GEM_TYPE_SMI 0x00000001 +#define DRM_FREEDRENO_GEM_TYPE_KMEM 0x00000002 +#define DRM_FREEDRENO_GEM_TYPE_MEM_MASK 0x0000000f +#define DRM_FREEDRENO_GEM_CACHE_NONE 0x00000000 +#define DRM_FREEDRENO_GEM_CACHE_WCOMBINE 0x00100000 +#define DRM_FREEDRENO_GEM_CACHE_WTHROUGH 0x00200000 +#define DRM_FREEDRENO_GEM_CACHE_WBACK 0x00400000 +#define DRM_FREEDRENO_GEM_CACHE_WBACKWA 0x00800000 +#define DRM_FREEDRENO_GEM_CACHE_MASK 0x00f00000 +#define DRM_FREEDRENO_GEM_GPUREADONLY 0x01000000 + + +/* device functions: + */ + +struct fd_device * fd_device_new(int fd); +void fd_device_del(struct fd_device *dev); + + +/* pipe functions: + */ + +struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id); +void fd_pipe_del(struct fd_pipe *pipe); +int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, + uint64_t *value); +int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp); +int fd_pipe_timestamp(struct fd_pipe *pipe, uint32_t *timestamp); + + +/* buffer-object functions: + */ + +struct fd_bo * fd_bo_new(struct fd_device *dev, + uint32_t size, uint32_t flags); +struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, + int fbfd, uint32_t size); +struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name); +struct fd_bo * fd_bo_ref(struct fd_bo *bo); +void fd_bo_del(struct fd_bo *bo); +int fd_bo_get_name(struct fd_bo *bo, uint32_t *name); +uint32_t fd_bo_handle(struct fd_bo *bo); +uint32_t fd_bo_size(struct fd_bo *bo); +void * fd_bo_map(struct fd_bo *bo); + +#endif /* FREEDRENO_DRMIF_H_ */ diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c new file mode 100644 index 00000000..49949ecc --- /dev/null +++ b/freedreno/freedreno_pipe.c @@ -0,0 +1,227 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + + +static int getprop(int fd, enum kgsl_property_type type, + void *value, int sizebytes) +{ + struct kgsl_device_getproperty req = { + .type = type, + .value = value, + .sizebytes = sizebytes, + }; + return ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &req); +} + +#define GETPROP(fd, prop, x) do { \ + if (getprop((fd), KGSL_PROP_##prop, &(x), sizeof(x))) { \ + ERROR_MSG("failed to get property: " #prop); \ + goto fail; \ + } } while (0) + + +struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id) +{ + static const char *paths[] = { + [FD_PIPE_3D] = "/dev/kgsl-3d0", + [FD_PIPE_2D] = "/dev/kgsl-2d0", + }; + struct kgsl_drawctxt_create req = { + .flags = 0x2000, /* ??? */ + }; + struct fd_pipe *pipe = NULL; + int ret, fd; + + if (id > FD_PIPE_MAX) { + ERROR_MSG("invalid pipe id: %d", id); + goto fail; + } + + fd = open(paths[id], O_RDWR); + if (fd < 0) { + ERROR_MSG("could not open %s device: %d (%s)", + paths[id], fd, strerror(errno)); + goto fail; + } + + ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req); + if (ret) { + ERROR_MSG("failed to allocate context: %d (%s)", + ret, strerror(errno)); + goto fail; + } + + pipe = calloc(1, sizeof(*pipe)); + if (!pipe) { + ERROR_MSG("allocation failed"); + goto fail; + } + + pipe->dev = dev; + pipe->id = id; + pipe->fd = fd; + pipe->drawctxt_id = req.drawctxt_id; + + list_inithead(&pipe->submit_list); + list_inithead(&pipe->pending_list); + + GETPROP(fd, VERSION, pipe->version); + GETPROP(fd, DEVICE_INFO, pipe->devinfo); + + INFO_MSG("Pipe Info:"); + INFO_MSG(" Device: %s", paths[id]); + INFO_MSG(" Chip-id: %d.%d.%d.%d", + (pipe->devinfo.chip_id >> 24) & 0xff, + (pipe->devinfo.chip_id >> 16) & 0xff, + (pipe->devinfo.chip_id >> 8) & 0xff, + (pipe->devinfo.chip_id >> 0) & 0xff); + INFO_MSG(" Device-id: %d", pipe->devinfo.device_id); + INFO_MSG(" GPU-id: %d", pipe->devinfo.gpu_id); + INFO_MSG(" MMU enabled: %d", pipe->devinfo.mmu_enabled); + INFO_MSG(" GMEM Base addr: 0x%08x", pipe->devinfo.gmem_gpubaseaddr); + INFO_MSG(" GMEM size: 0x%08x", pipe->devinfo.gmem_sizebytes); + INFO_MSG(" Driver version: %d.%d", + pipe->version.drv_major, pipe->version.drv_minor); + INFO_MSG(" Device version: %d.%d", + pipe->version.dev_major, pipe->version.dev_minor); + + return pipe; +fail: + if (pipe) + fd_pipe_del(pipe); + return NULL; +} + +void fd_pipe_del(struct fd_pipe *pipe) +{ + struct kgsl_drawctxt_destroy req = { + .drawctxt_id = pipe->drawctxt_id, + }; + + if (pipe->drawctxt_id) + ioctl(pipe->fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req); + + if (pipe->fd) + close(pipe->fd); + + free(pipe); +} + +int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, + uint64_t *value) +{ + switch (param) { + case FD_DEVICE_ID: + *value = pipe->devinfo.device_id; + return 0; + case FD_GMEM_SIZE: + *value = pipe->devinfo.gmem_sizebytes; + return 0; + default: + ERROR_MSG("invalid param id: %d", param); + return -1; + } +} + +int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp) +{ + struct kgsl_device_waittimestamp req = { + .timestamp = timestamp, + .timeout = 5000, + }; + int ret; + + do { + ret = ioctl(pipe->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP, &req); + } while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN))); + if (ret) + ERROR_MSG("waittimestamp failed! %d (%s)", ret, strerror(errno)); + else + fd_pipe_process_pending(pipe, timestamp); + return ret; +} + +int fd_pipe_timestamp(struct fd_pipe *pipe, uint32_t *timestamp) +{ + struct kgsl_cmdstream_readtimestamp req = { + .type = KGSL_TIMESTAMP_RETIRED + }; + int ret = ioctl(pipe->fd, IOCTL_KGSL_CMDSTREAM_READTIMESTAMP, &req); + if (ret) { + ERROR_MSG("readtimestamp failed! %d (%s)", + ret, strerror(errno)); + return ret; + } + *timestamp = req.timestamp; + return 0; +} + +/* add buffer to submit list when it is referenced in cmdstream: */ +void fd_pipe_add_submit(struct fd_pipe *pipe, struct fd_bo *bo) +{ + struct list_head *list = &bo->list[pipe->id]; + if (LIST_IS_EMPTY(list)) { + fd_bo_ref(bo); + } else { + list_del(list); + } + list_addtail(list, &pipe->submit_list); +} + +/* process buffers on submit list after flush: */ +void fd_pipe_process_submit(struct fd_pipe *pipe, uint32_t timestamp) +{ + struct fd_bo *bo, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &pipe->submit_list, list[pipe->id]) { + struct list_head *list = &bo->list[pipe->id]; + list_del(list); + bo->timestamp[pipe->id] = timestamp; + list_addtail(list, &pipe->pending_list); + } + + if (!fd_pipe_timestamp(pipe, ×tamp)) + fd_pipe_process_pending(pipe, timestamp); +} + +void fd_pipe_process_pending(struct fd_pipe *pipe, uint32_t timestamp) +{ + struct fd_bo *bo, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &pipe->pending_list, list[pipe->id]) { + struct list_head *list = &bo->list[pipe->id]; + if (bo->timestamp[pipe->id] > timestamp) + return; + list_delinit(list); + bo->timestamp[pipe->id] = 0; + fd_bo_del(bo); + } +} diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h new file mode 100644 index 00000000..aa71b564 --- /dev/null +++ b/freedreno/freedreno_priv.h @@ -0,0 +1,117 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_PRIV_H_ +#define FREEDRENO_PRIV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86atomic.h" + +#include "list.h" + +#include "freedreno_drmif.h" +#include "msm_kgsl.h" +#include "kgsl_drm.h" + +struct fd_device { + int fd; +}; + +struct fd_pipe { + struct fd_device *dev; + enum fd_pipe_id id; + int fd; + uint32_t drawctxt_id; + + /* device properties: */ + struct kgsl_version version; + struct kgsl_devinfo devinfo; + + /* list of bo's that are referenced in ringbuffer but not + * submitted yet: + */ + struct list_head submit_list; + + /* list of bo's that have been submitted but timestamp has + * not passed yet (so still ref'd in active cmdstream) + */ + struct list_head pending_list; +}; + +void fd_pipe_add_submit(struct fd_pipe *pipe, struct fd_bo *bo); +void fd_pipe_process_submit(struct fd_pipe *pipe, uint32_t timestamp); +void fd_pipe_process_pending(struct fd_pipe *pipe, uint32_t timestamp); + +struct fd_bo { + struct fd_device *dev; + uint32_t size; + uint32_t handle; + uint32_t name; + uint32_t gpuaddr; + void *map; + uint64_t offset; + /* timestamp (per pipe) for bo's in a pipe's pending_list: */ + uint32_t timestamp[FD_PIPE_MAX]; + /* list-node for pipe's submit_list or pending_list */ + struct list_head list[FD_PIPE_MAX]; + atomic_t refcnt; +}; + +/* not exposed publicly, because won't be needed when we have + * a proper kernel driver + */ +uint32_t fd_bo_gpuaddr(struct fd_bo *bo, uint32_t offset); + +#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1)) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define enable_debug 1 /* TODO make dynamic */ + +#define INFO_MSG(fmt, ...) \ + do { drmMsg("[I] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define DEBUG_MSG(fmt, ...) \ + do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define WARN_MSG(fmt, ...) \ + do { drmMsg("[W] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define ERROR_MSG(fmt, ...) \ + do { drmMsg("[E] " fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) + +#endif /* FREEDRENO_PRIV_H_ */ diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c new file mode 100644 index 00000000..822412a9 --- /dev/null +++ b/freedreno/freedreno_ringbuffer.c @@ -0,0 +1,249 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" +#include "freedreno_ringbuffer.h" + + +/* because kgsl tries to validate the gpuaddr on kernel side in ISSUEIBCMDS, + * we can't use normal gem bo's for ringbuffer.. someday the kernel part + * needs to be reworked into a single sane drm driver :-/ + */ +struct fd_rb_bo { + struct fd_pipe *pipe; + void *hostptr; + uint32_t gpuaddr; + uint32_t size; +}; + +struct fd_ringmarker { + struct fd_ringbuffer *ring; + uint32_t *cur; +}; + +static void fd_rb_bo_del(struct fd_rb_bo *bo) +{ + struct kgsl_sharedmem_free req = { + .gpuaddr = bo->gpuaddr, + }; + int ret; + + munmap(bo->hostptr, bo->size); + + ret = ioctl(bo->pipe->fd, IOCTL_KGSL_SHAREDMEM_FREE, &req); + if (ret) { + ERROR_MSG("sharedmem free failed: %s", strerror(errno)); + } + + free(bo); +} + +static struct fd_rb_bo * fd_rb_bo_new(struct fd_pipe *pipe, uint32_t size) +{ + struct fd_rb_bo *bo; + struct kgsl_gpumem_alloc req = { + .size = ALIGN(size, 4096), + .flags = KGSL_MEMFLAGS_GPUREADONLY, + }; + int ret; + + bo = calloc(1, sizeof(*bo)); + if (!bo) { + ERROR_MSG("allocation failed"); + return NULL; + } + ret = ioctl(pipe->fd, IOCTL_KGSL_GPUMEM_ALLOC, &req); + if (ret) { + ERROR_MSG("gpumem allocation failed: %s", strerror(errno)); + goto fail; + } + + bo->pipe = pipe; + bo->gpuaddr = req.gpuaddr; + bo->size = size; + bo->hostptr = mmap(NULL, size, PROT_WRITE|PROT_READ, + MAP_SHARED, pipe->fd, req.gpuaddr); + + return bo; +fail: + if (bo) + fd_rb_bo_del(bo); + return NULL; +} + +struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size) +{ + struct fd_ringbuffer *ring = NULL; + + ring = calloc(1, sizeof(*ring)); + if (!ring) { + ERROR_MSG("allocation failed"); + goto fail; + } + + ring->bo = fd_rb_bo_new(pipe, size); + if (!ring->bo) { + ERROR_MSG("ringbuffer allocation failed"); + goto fail; + } + + ring->size = size; + ring->pipe = pipe; + ring->start = ring->bo->hostptr; + ring->end = &(ring->start[size/4]); + + ring->cur = ring->last_start = ring->start; + + return ring; +fail: + if (ring) + fd_ringbuffer_del(ring); + return NULL; +} + +void fd_ringbuffer_del(struct fd_ringbuffer *ring) +{ + if (ring->bo) + fd_rb_bo_del(ring->bo); + free(ring); +} + +void fd_ringbuffer_reset(struct fd_ringbuffer *ring) +{ + uint32_t *start = ring->start; + if (ring->pipe->id == FD_PIPE_2D) + start = &ring->start[0x140]; + ring->cur = ring->last_start = start; +} + +static int flush_impl(struct fd_ringbuffer *ring, uint32_t *last_start) +{ + uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start; + struct kgsl_ibdesc ibdesc = { + .gpuaddr = ring->bo->gpuaddr + offset, + .hostptr = last_start, + .sizedwords = ring->cur - last_start, + }; + struct kgsl_ringbuffer_issueibcmds req = { + .drawctxt_id = ring->pipe->drawctxt_id, + .ibdesc_addr = (unsigned long)&ibdesc, + .numibs = 1, + .flags = KGSL_CONTEXT_SUBMIT_IB_LIST, + }; + int ret; + + /* z180_cmdstream_issueibcmds() is made of fail: */ + if (ring->pipe->id == FD_PIPE_2D) { + /* fix up size field in last cmd packet */ + uint32_t last_size = (uint32_t)(ring->cur - last_start); + /* 5 is length of first packet, 2 for the two 7f000000's */ + last_start[2] = last_size - (5 + 2); + ibdesc.gpuaddr = ring->bo->gpuaddr; + ibdesc.hostptr = ring->bo->hostptr; + ibdesc.sizedwords = 0x145; + req.timestamp = (uint32_t)ring->bo->hostptr; + } + + do { + ret = ioctl(ring->pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req); + } while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN))); + if (ret) + ERROR_MSG("issueibcmds failed! %d (%s)", ret, strerror(errno)); + + ring->last_timestamp = req.timestamp; + ring->last_start = ring->cur; + + fd_pipe_process_submit(ring->pipe, req.timestamp); + + return ret; +} + +/* maybe get rid of this and use fd_ringmarker_flush() from DDX too? */ +int fd_ringbuffer_flush(struct fd_ringbuffer *ring) +{ + return flush_impl(ring, ring->last_start); +} + +uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring) +{ + return ring->last_timestamp; +} + +void fd_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, + struct fd_bo *bo, uint32_t offset, uint32_t or) +{ + (*ring->cur++) = fd_bo_gpuaddr(bo, offset) | or; + fd_pipe_add_submit(ring->pipe, bo); +} + +void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, + struct fd_ringmarker *target) +{ + (*ring->cur++) = target->ring->bo->gpuaddr + + (uint8_t *)target->cur - (uint8_t *)target->ring->start; +} + +struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring) +{ + struct fd_ringmarker *marker = NULL; + + marker = calloc(1, sizeof(*marker)); + if (!marker) { + ERROR_MSG("allocation failed"); + return NULL; + } + + marker->ring = ring; + + fd_ringmarker_mark(marker); + + return marker; +} + +void fd_ringmarker_del(struct fd_ringmarker *marker) +{ + free(marker); +} + +void fd_ringmarker_mark(struct fd_ringmarker *marker) +{ + marker->cur = marker->ring->cur; +} + +uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start, + struct fd_ringmarker *end) +{ + return end->cur - start->cur; +} + +int fd_ringmarker_flush(struct fd_ringmarker *marker) +{ + return flush_impl(marker->ring, marker->cur); +} diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h new file mode 100644 index 00000000..4fb668f7 --- /dev/null +++ b/freedreno/freedreno_ringbuffer.h @@ -0,0 +1,87 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_RINGBUFFER_H_ +#define FREEDRENO_RINGBUFFER_H_ + +#include + +/* the ringbuffer object is not opaque so that OUT_RING() type stuff + * can be inlined. Note that users should not make assumptions about + * the size of this struct.. more stuff will be added when we eventually + * have a kernel driver that can deal w/ reloc's.. + */ + +struct fd_rb_bo; +struct fd_ringmarker; + +struct fd_ringbuffer { + int size; + uint32_t *cur, *end, *start, *last_start; + struct fd_pipe *pipe; + struct fd_rb_bo *bo; + uint32_t last_timestamp; +}; + +/* ringbuffer flush flags: + * SAVE_GMEM - GMEM contents not preserved to system memory + * in cmds flushed so if there is a context switch after + * this flush and before the next one the kernel must + * save GMEM contents + * SUBMIT_IB_LIST - tbd.. + */ +#define DRM_FREEDRENO_CONTEXT_SAVE_GMEM 1 +#define DRM_FREEDRENO_CONTEXT_SUBMIT_IB_LIST 4 + + +struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size); +void fd_ringbuffer_del(struct fd_ringbuffer *ring); +void fd_ringbuffer_reset(struct fd_ringbuffer *ring); +int fd_ringbuffer_flush(struct fd_ringbuffer *ring); +uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring); + +static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring, + uint32_t data) +{ + (*ring->cur++) = data; +} + +void fd_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, + struct fd_bo *bo, uint32_t offset, uint32_t or); +void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, + struct fd_ringmarker *target); + +struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring); +void fd_ringmarker_del(struct fd_ringmarker *marker); +void fd_ringmarker_mark(struct fd_ringmarker *marker); +uint32_t fd_ringmarker_dwords(struct fd_ringmarker *start, + struct fd_ringmarker *end); +int fd_ringmarker_flush(struct fd_ringmarker *marker); + +#endif /* FREEDRENO_RINGBUFFER_H_ */ diff --git a/freedreno/kgsl_drm.h b/freedreno/kgsl_drm.h new file mode 100644 index 00000000..f1c7f4e2 --- /dev/null +++ b/freedreno/kgsl_drm.h @@ -0,0 +1,192 @@ +#ifndef _KGSL_DRM_H_ +#define _KGSL_DRM_H_ + +#include "drm.h" + +#define DRM_KGSL_GEM_CREATE 0x00 +#define DRM_KGSL_GEM_PREP 0x01 +#define DRM_KGSL_GEM_SETMEMTYPE 0x02 +#define DRM_KGSL_GEM_GETMEMTYPE 0x03 +#define DRM_KGSL_GEM_MMAP 0x04 +#define DRM_KGSL_GEM_ALLOC 0x05 +#define DRM_KGSL_GEM_BIND_GPU 0x06 +#define DRM_KGSL_GEM_UNBIND_GPU 0x07 + +#define DRM_KGSL_GEM_GET_BUFINFO 0x08 +#define DRM_KGSL_GEM_SET_BUFCOUNT 0x09 +#define DRM_KGSL_GEM_SET_ACTIVE 0x0A +#define DRM_KGSL_GEM_LOCK_HANDLE 0x0B +#define DRM_KGSL_GEM_UNLOCK_HANDLE 0x0C +#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D +#define DRM_KGSL_GEM_CREATE_FD 0x0E + +#define DRM_IOCTL_KGSL_GEM_CREATE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create) + +#define DRM_IOCTL_KGSL_GEM_PREP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_PREP, struct drm_kgsl_gem_prep) + +#define DRM_IOCTL_KGSL_GEM_SETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_GETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_MMAP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_MMAP, struct drm_kgsl_gem_mmap) + +#define DRM_IOCTL_KGSL_GEM_ALLOC \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_ALLOC, struct drm_kgsl_gem_alloc) + +#define DRM_IOCTL_KGSL_GEM_BIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_BIND_GPU, struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_UNBIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNBIND_GPU, \ +struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_GET_BUFINFO \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_BUFINFO, \ + struct drm_kgsl_gem_bufinfo) + +#define DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_BUFCOUNT, \ + struct drm_kgsl_gem_bufcount) + +#define DRM_IOCTL_KGSL_GEM_SET_ACTIVE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_ACTIVE, \ + struct drm_kgsl_gem_active) + +#define DRM_IOCTL_KGSL_GEM_LOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_LOCK_HANDLE, \ +struct drm_kgsl_gem_lock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_HANDLE, \ +struct drm_kgsl_gem_unlock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_ON_TS \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_ON_TS, \ +struct drm_kgsl_gem_unlock_on_ts) + +#define DRM_IOCTL_KGSL_GEM_CREATE_FD \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FD, \ +struct drm_kgsl_gem_create_fd) + +/* Maximum number of sub buffers per GEM object */ +#define DRM_KGSL_GEM_MAX_BUFFERS 2 + +/* Memory types - these define the source and caching policies + of the GEM memory chunk */ + +/* Legacy definitions left for compatability */ + +#define DRM_KGSL_GEM_TYPE_EBI 0 +#define DRM_KGSL_GEM_TYPE_SMI 1 +#define DRM_KGSL_GEM_TYPE_KMEM 2 +#define DRM_KGSL_GEM_TYPE_KMEM_NOCACHE 3 +#define DRM_KGSL_GEM_TYPE_MEM_MASK 0xF + +/* Contiguous memory (PMEM) */ +#define DRM_KGSL_GEM_TYPE_PMEM 0x000100 + +/* PMEM memory types */ +#define DRM_KGSL_GEM_PMEM_EBI 0x001000 +#define DRM_KGSL_GEM_PMEM_SMI 0x002000 + +/* Standard paged memory */ +#define DRM_KGSL_GEM_TYPE_MEM 0x010000 + +/* Caching controls */ +#define DRM_KGSL_GEM_CACHE_NONE 0x000000 +#define DRM_KGSL_GEM_CACHE_WCOMBINE 0x100000 +#define DRM_KGSL_GEM_CACHE_WTHROUGH 0x200000 +#define DRM_KGSL_GEM_CACHE_WBACK 0x400000 +#define DRM_KGSL_GEM_CACHE_WBACKWA 0x800000 +#define DRM_KGSL_GEM_CACHE_MASK 0xF00000 + +/* FD based objects */ +#define DRM_KGSL_GEM_TYPE_FD_FBMEM 0x1000000 +#define DRM_KGSL_GEM_TYPE_FD_MASK 0xF000000 + +/* Timestamp types */ +#define DRM_KGSL_GEM_TS_3D 0x00000430 +#define DRM_KGSL_GEM_TS_2D 0x00000180 + + +struct drm_kgsl_gem_create { + uint32_t size; + uint32_t handle; +}; + +struct drm_kgsl_gem_prep { + uint32_t handle; + uint32_t phys; + uint64_t offset; +}; + +struct drm_kgsl_gem_memtype { + uint32_t handle; + uint32_t type; +}; + +struct drm_kgsl_gem_mmap { + uint32_t handle; + uint32_t size; + uint32_t hostptr; + uint64_t offset; +}; + +struct drm_kgsl_gem_alloc { + uint32_t handle; + uint64_t offset; +}; + +struct drm_kgsl_gem_bind_gpu { + uint32_t handle; + uint32_t gpuptr; +}; + +struct drm_kgsl_gem_bufinfo { + uint32_t handle; + uint32_t count; + uint32_t active; + uint32_t offset[DRM_KGSL_GEM_MAX_BUFFERS]; + uint32_t gpuaddr[DRM_KGSL_GEM_MAX_BUFFERS]; +}; + +struct drm_kgsl_gem_bufcount { + uint32_t handle; + uint32_t bufcount; +}; + +struct drm_kgsl_gem_active { + uint32_t handle; + uint32_t active; +}; + +struct drm_kgsl_gem_lock_handles { + uint32_t num_handles; + uint32_t *handle_list; + uint32_t pid; + uint32_t lock_id; /* Returned lock id used for unlocking */ +}; + +struct drm_kgsl_gem_unlock_handles { + uint32_t lock_id; +}; + +struct drm_kgsl_gem_unlock_on_ts { + uint32_t lock_id; + uint32_t timestamp; /* This field is a hw generated ts */ + uint32_t type; /* Which pipe to check for ts generation */ +}; + +struct drm_kgsl_gem_create_fd { + uint32_t fd; + uint32_t handle; +}; + +#endif diff --git a/freedreno/libdrm_freedreno.pc.in b/freedreno/libdrm_freedreno.pc.in new file mode 100644 index 00000000..b736b65a --- /dev/null +++ b/freedreno/libdrm_freedreno.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_freedreno +Description: Userspace interface to freedreno kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_freedreno +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/freedreno +Requires.private: libdrm diff --git a/freedreno/list.h b/freedreno/list.h new file mode 100644 index 00000000..27e0761b --- /dev/null +++ b/freedreno/list.h @@ -0,0 +1,137 @@ +/* + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ +#ifndef _U_DOUBLE_LIST_H_ +#define _U_DOUBLE_LIST_H_ + +#include + +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + +static inline void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +#define LIST_INITHEAD(__item) list_inithead(__item) +#define LIST_ADD(__item, __list) list_add(__item, __list) +#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) +#define LIST_REPLACE(__from, __to) list_replace(__from, __to) +#define LIST_DEL(__item) list_del(__item) +#define LIST_DELINIT(__item) list_delinit(__item) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +#define LIST_IS_EMPTY(__list) \ + ((__list)->next == (__list)) + +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&(sample)->member - (char *)(sample))) +#endif + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#endif /*_U_DOUBLE_LIST_H_*/ diff --git a/freedreno/msm_kgsl.h b/freedreno/msm_kgsl.h new file mode 100644 index 00000000..e67190f0 --- /dev/null +++ b/freedreno/msm_kgsl.h @@ -0,0 +1,519 @@ +#ifndef _MSM_KGSL_H +#define _MSM_KGSL_H + +#define KGSL_VERSION_MAJOR 3 +#define KGSL_VERSION_MINOR 11 + +/*context flags */ +#define KGSL_CONTEXT_SAVE_GMEM 0x00000001 +#define KGSL_CONTEXT_NO_GMEM_ALLOC 0x00000002 +#define KGSL_CONTEXT_SUBMIT_IB_LIST 0x00000004 +#define KGSL_CONTEXT_CTX_SWITCH 0x00000008 +#define KGSL_CONTEXT_PREAMBLE 0x00000010 +#define KGSL_CONTEXT_TRASH_STATE 0x00000020 +#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040 + +#define KGSL_CONTEXT_INVALID 0xffffffff + +/* Memory allocayion flags */ +#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000 + +/* generic flag values */ +#define KGSL_FLAGS_NORMALMODE 0x00000000 +#define KGSL_FLAGS_SAFEMODE 0x00000001 +#define KGSL_FLAGS_INITIALIZED0 0x00000002 +#define KGSL_FLAGS_INITIALIZED 0x00000004 +#define KGSL_FLAGS_STARTED 0x00000008 +#define KGSL_FLAGS_ACTIVE 0x00000010 +#define KGSL_FLAGS_RESERVED0 0x00000020 +#define KGSL_FLAGS_RESERVED1 0x00000040 +#define KGSL_FLAGS_RESERVED2 0x00000080 +#define KGSL_FLAGS_SOFT_RESET 0x00000100 +#define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200 + +/* Clock flags to show which clocks should be controled by a given platform */ +#define KGSL_CLK_SRC 0x00000001 +#define KGSL_CLK_CORE 0x00000002 +#define KGSL_CLK_IFACE 0x00000004 +#define KGSL_CLK_MEM 0x00000008 +#define KGSL_CLK_MEM_IFACE 0x00000010 +#define KGSL_CLK_AXI 0x00000020 + +/* + * Reset status values for context + */ +enum kgsl_ctx_reset_stat { + KGSL_CTX_STAT_NO_ERROR = 0x00000000, + KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001, + KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002, + KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003 +}; + +#define KGSL_MAX_PWRLEVELS 5 + +#define KGSL_CONVERT_TO_MBPS(val) \ + (val*1000*1000U) + +/* device id */ +enum kgsl_deviceid { + KGSL_DEVICE_3D0 = 0x00000000, + KGSL_DEVICE_2D0 = 0x00000001, + KGSL_DEVICE_2D1 = 0x00000002, + KGSL_DEVICE_MAX = 0x00000003 +}; + +enum kgsl_user_mem_type { + KGSL_USER_MEM_TYPE_PMEM = 0x00000000, + KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001, + KGSL_USER_MEM_TYPE_ADDR = 0x00000002, + KGSL_USER_MEM_TYPE_ION = 0x00000003, + KGSL_USER_MEM_TYPE_MAX = 0x00000004, +}; + +struct kgsl_devinfo { + + unsigned int device_id; + /* chip revision id + * coreid:8 majorrev:8 minorrev:8 patch:8 + */ + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned int gmem_gpubaseaddr; + /* + * This field contains the adreno revision + * number 200, 205, 220, etc... + */ + unsigned int gpu_id; + unsigned int gmem_sizebytes; +}; + +/* this structure defines the region of memory that can be mmap()ed from this + driver. The timestamp fields are volatile because they are written by the + GPU +*/ +struct kgsl_devmemstore { + volatile unsigned int soptimestamp; + unsigned int sbz; + volatile unsigned int eoptimestamp; + unsigned int sbz2; + volatile unsigned int ts_cmp_enable; + unsigned int sbz3; + volatile unsigned int ref_wait_ts; + unsigned int sbz4; + unsigned int current_context; + unsigned int sbz5; +}; + +#define KGSL_MEMSTORE_OFFSET(ctxt_id, field) \ + ((ctxt_id)*sizeof(struct kgsl_devmemstore) + \ + offsetof(struct kgsl_devmemstore, field)) + +/* timestamp id*/ +enum kgsl_timestamp_type { + KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */ + KGSL_TIMESTAMP_RETIRED = 0x00000002, /* end-of-pipeline timestamp*/ + KGSL_TIMESTAMP_QUEUED = 0x00000003, +}; + +/* property types - used with kgsl_device_getproperty */ +enum kgsl_property_type { + KGSL_PROP_DEVICE_INFO = 0x00000001, + KGSL_PROP_DEVICE_SHADOW = 0x00000002, + KGSL_PROP_DEVICE_POWER = 0x00000003, + KGSL_PROP_SHMEM = 0x00000004, + KGSL_PROP_SHMEM_APERTURES = 0x00000005, + KGSL_PROP_MMU_ENABLE = 0x00000006, + KGSL_PROP_INTERRUPT_WAITS = 0x00000007, + KGSL_PROP_VERSION = 0x00000008, + KGSL_PROP_GPU_RESET_STAT = 0x00000009, + KGSL_PROP_PWRCTRL = 0x0000000E, +}; + +struct kgsl_shadowprop { + unsigned int gpuaddr; + unsigned int size; + unsigned int flags; /* contains KGSL_FLAGS_ values */ +}; + +struct kgsl_pwrlevel { + unsigned int gpu_freq; + unsigned int bus_freq; + unsigned int io_fraction; +}; + +struct kgsl_version { + unsigned int drv_major; + unsigned int drv_minor; + unsigned int dev_major; + unsigned int dev_minor; +}; + +#ifdef __KERNEL__ + +#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory" +#define KGSL_3D0_IRQ "kgsl_3d0_irq" +#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory" +#define KGSL_2D0_IRQ "kgsl_2d0_irq" +#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory" +#define KGSL_2D1_IRQ "kgsl_2d1_irq" + +enum kgsl_iommu_context_id { + KGSL_IOMMU_CONTEXT_USER = 0, + KGSL_IOMMU_CONTEXT_PRIV = 1, +}; + +struct kgsl_iommu_ctx { + const char *iommu_ctx_name; + enum kgsl_iommu_context_id ctx_id; +}; + +struct kgsl_device_iommu_data { + const struct kgsl_iommu_ctx *iommu_ctxs; + int iommu_ctx_count; + unsigned int physstart; + unsigned int physend; +}; + +struct kgsl_device_platform_data { + struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS]; + int init_level; + int num_levels; + int (*set_grp_async)(void); + unsigned int idle_timeout; + bool strtstp_sleepwake; + unsigned int nap_allowed; + unsigned int clk_map; + unsigned int idle_needed; + struct msm_bus_scale_pdata *bus_scale_table; + struct kgsl_device_iommu_data *iommu_data; + int iommu_count; + struct msm_dcvs_core_info *core_info; +}; + +#endif + +/* structure holds list of ibs */ +struct kgsl_ibdesc { + unsigned int gpuaddr; + void *hostptr; + unsigned int sizedwords; + unsigned int ctrl; +}; + +/* ioctls */ +#define KGSL_IOC_TYPE 0x09 + +/* get misc info about the GPU + type should be a value from enum kgsl_property_type + value points to a structure that varies based on type + sizebytes is sizeof() that structure + for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo + this structure contaings hardware versioning info. + for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop + this is used to find mmap() offset and sizes for mapping + struct kgsl_memstore into userspace. +*/ +struct kgsl_device_getproperty { + unsigned int type; + void *value; + unsigned int sizebytes; +}; + +#define IOCTL_KGSL_DEVICE_GETPROPERTY \ + _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) + +/* IOCTL_KGSL_DEVICE_READ (0x3) - removed 03/2012 + */ + +/* block until the GPU has executed past a given timestamp + * timeout is in milliseconds. + */ +struct kgsl_device_waittimestamp { + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp) + +struct kgsl_device_waittimestamp_ctxtid { + unsigned int context_id; + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid) + +/* issue indirect commands to the GPU. + * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE + * ibaddr and sizedwords must specify a subset of a buffer created + * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM + * flags may be a mask of KGSL_CONTEXT_ values + * timestamp is a returned counter value which can be passed to + * other ioctls to determine when the commands have been executed by + * the GPU. + */ +struct kgsl_ringbuffer_issueibcmds { + unsigned int drawctxt_id; + unsigned int ibdesc_addr; + unsigned int numibs; + unsigned int timestamp; /*output param */ + unsigned int flags; +}; + +#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \ + _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds) + +/* read the most recently executed timestamp value + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_readtimestamp { + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \ + _IOWR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +/* free memory when the GPU reaches a given timestamp. + * gpuaddr specify a memory region created by a + * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_freememontimestamp { + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* Previous versions of this header had incorrectly defined + IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead + of a write only ioctl. To ensure binary compatability, the following + #define will be used to intercept the incorrect ioctl +*/ + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* create a draw context, which is used to preserve GPU state. + * The flags field may contain a mask KGSL_CONTEXT_* values + */ +struct kgsl_drawctxt_create { + unsigned int flags; + unsigned int drawctxt_id; /*output param */ +}; + +#define IOCTL_KGSL_DRAWCTXT_CREATE \ + _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create) + +/* destroy a draw context */ +struct kgsl_drawctxt_destroy { + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_DESTROY \ + _IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy) + +/* add a block of pmem, fb, ashmem or user allocated address + * into the GPU address space */ +struct kgsl_map_user_mem { + int fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; + unsigned int hostptr; /*input param */ + enum kgsl_user_mem_type memtype; + unsigned int reserved; /* May be required to add + params for another mem type */ +}; + +#define IOCTL_KGSL_MAP_USER_MEM \ + _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem) + +struct kgsl_cmdstream_readtimestamp_ctxtid { + unsigned int context_id; + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \ + _IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid) + +struct kgsl_cmdstream_freememontimestamp_ctxtid { + unsigned int context_id; + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x17, \ + struct kgsl_cmdstream_freememontimestamp_ctxtid) + +/* add a block of pmem or fb into the GPU address space */ +struct kgsl_sharedmem_from_pmem { + int pmem_fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \ + _IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem) + +/* remove memory from the GPU's address space */ +struct kgsl_sharedmem_free { + unsigned int gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FREE \ + _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) + +struct kgsl_cff_user_event { + unsigned char cff_opcode; + unsigned int op1; + unsigned int op2; + unsigned int op3; + unsigned int op4; + unsigned int op5; + unsigned int __pad[2]; +}; + +#define IOCTL_KGSL_CFF_USER_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_cff_user_event) + +struct kgsl_gmem_desc { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int pitch; +}; + +struct kgsl_buffer_desc { + void *hostptr; + unsigned int gpuaddr; + int size; + unsigned int format; + unsigned int pitch; + unsigned int enabled; +}; + +struct kgsl_bind_gmem_shadow { + unsigned int drawctxt_id; + struct kgsl_gmem_desc gmem_desc; + unsigned int shadow_x; + unsigned int shadow_y; + struct kgsl_buffer_desc shadow_buffer; + unsigned int buffer_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \ + _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow) + +/* add a block of memory into the GPU address space */ +struct kgsl_sharedmem_from_vmalloc { + unsigned int gpuaddr; /*output param */ + unsigned int hostptr; + unsigned int flags; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc) + +#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \ + _IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free) + +struct kgsl_drawctxt_set_bin_base_offset { + unsigned int drawctxt_id; + unsigned int offset; +}; + +#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \ + _IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset) + +enum kgsl_cmdwindow_type { + KGSL_CMDWINDOW_MIN = 0x00000000, + KGSL_CMDWINDOW_2D = 0x00000000, + KGSL_CMDWINDOW_3D = 0x00000001, /* legacy */ + KGSL_CMDWINDOW_MMU = 0x00000002, + KGSL_CMDWINDOW_ARBITER = 0x000000FF, + KGSL_CMDWINDOW_MAX = 0x000000FF, +}; + +/* write to the command window */ +struct kgsl_cmdwindow_write { + enum kgsl_cmdwindow_type target; + unsigned int addr; + unsigned int data; +}; + +#define IOCTL_KGSL_CMDWINDOW_WRITE \ + _IOW(KGSL_IOC_TYPE, 0x2e, struct kgsl_cmdwindow_write) + +struct kgsl_gpumem_alloc { + unsigned long gpuaddr; + size_t size; + unsigned int flags; +}; + +#define IOCTL_KGSL_GPUMEM_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc) + +struct kgsl_cff_syncmem { + unsigned int gpuaddr; + unsigned int len; + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_CFF_SYNCMEM \ + _IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem) + +/* + * A timestamp event allows the user space to register an action following an + * expired timestamp. + */ + +struct kgsl_timestamp_event { + int type; /* Type of event (see list below) */ + unsigned int timestamp; /* Timestamp to trigger event on */ + unsigned int context_id; /* Context for the timestamp */ + void *priv; /* Pointer to the event specific blob */ + size_t len; /* Size of the event specific blob */ +}; + +#define IOCTL_KGSL_TIMESTAMP_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event) + +/* A genlock timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_GENLOCK 1 + +struct kgsl_timestamp_event_genlock { + int handle; /* Handle of the genlock lock to release */ +}; + +/* + * Set a property within the kernel. Uses the same structure as + * IOCTL_KGSL_GETPROPERTY + */ + +#define IOCTL_KGSL_SETPROPERTY \ + _IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty) + +#ifdef __KERNEL__ +#ifdef CONFIG_MSM_KGSL_DRM +int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start, + unsigned long *len); +#else +#define kgsl_gem_obj_addr(...) 0 +#endif +#endif +#endif /* _MSM_KGSL_H */