From 41fc2cc8a98a8d02ea7d3635d3103f7dd371de10 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sun, 7 Oct 2012 18:57:31 -0500 Subject: freedreno: add freedreno DRM The libdrm_freedreno helper layer for use by xf86-video-freedreno, fdre (freedreno r/e library and tests for driving gpu), and eventual gallium driver for the Adreno GPU. This uses the msm gpu driver from QCOM's android kernel tree. 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. v1: original v2: hold ref's to pending bo's (because qcom's kernel driver doesn't), various bug fixes, add ringbuffer markers so we can emit IB's to portion of ringbuffer (so that gallium driver can use a single ringbuffer for both tile cmds and draw cmds. Signed-off-by: Rob Clark --- freedreno/Makefile.am | 19 ++ freedreno/README | 16 ++ freedreno/freedreno_bo.c | 274 +++++++++++++++++++++ freedreno/freedreno_device.c | 45 ++++ freedreno/freedreno_drmif.h | 99 ++++++++ freedreno/freedreno_pipe.c | 227 +++++++++++++++++ freedreno/freedreno_priv.h | 117 +++++++++ freedreno/freedreno_ringbuffer.c | 249 +++++++++++++++++++ freedreno/freedreno_ringbuffer.h | 87 +++++++ freedreno/kgsl_drm.h | 192 +++++++++++++++ freedreno/libdrm_freedreno.pc.in | 11 + freedreno/list.h | 137 +++++++++++ freedreno/msm_kgsl.h | 519 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 1992 insertions(+) create mode 100644 freedreno/Makefile.am create mode 100644 freedreno/README create mode 100644 freedreno/freedreno_bo.c create mode 100644 freedreno/freedreno_device.c create mode 100644 freedreno/freedreno_drmif.h create mode 100644 freedreno/freedreno_pipe.c create mode 100644 freedreno/freedreno_priv.h create mode 100644 freedreno/freedreno_ringbuffer.c create mode 100644 freedreno/freedreno_ringbuffer.h create mode 100644 freedreno/kgsl_drm.h create mode 100644 freedreno/libdrm_freedreno.pc.in create mode 100644 freedreno/list.h create mode 100644 freedreno/msm_kgsl.h (limited to 'freedreno') 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 */ -- cgit v1.2.3