summaryrefslogtreecommitdiff
path: root/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c')
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c813
1 files changed, 813 insertions, 0 deletions
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
new file mode 100644
index 000000000000..b4846cb65bb8
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
@@ -0,0 +1,813 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* 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 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#if gcdENABLE_DRM
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <linux/dma-buf.h>
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_drm.h"
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/******************************************************************************\
+******************************* gckKERNEL DRM Code ******************************
+\******************************************************************************/
+
+struct viv_gem_object {
+ struct drm_gem_object base;
+
+ uint32_t node_handle;
+ gckVIDMEM_NODE node_object;
+};
+
+struct dma_buf *viv_gem_prime_export(struct drm_device *drm,
+ struct drm_gem_object *gem_obj,
+ int flags)
+{
+ struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ struct dma_buf *dmabuf = gcvNULL;
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ if (gal_dev)
+ {
+ gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Export(kernel, viv_obj->node_handle, flags,
+ (gctPOINTER*)&dmabuf, gcvNULL));
+ }
+
+ return dmabuf;
+}
+
+struct drm_gem_object *viv_gem_prime_import(struct drm_device *drm,
+ struct dma_buf *dmabuf)
+{
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev;
+ gckKERNEL kernel;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObject;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_WRAP_USER_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.WrapUserMemory.desc.flag = gcvALLOC_FLAG_DMABUF;
+ iface.u.WrapUserMemory.desc.handle = -1;
+ iface.u.WrapUserMemory.desc.dmabuf = gcmPTR_TO_UINT64(dmabuf);
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.WrapUserMemory.node, &nodeObject));
+
+ /* ioctl output */
+ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+ drm_gem_private_object_init(drm, gem_obj, dmabuf->size);
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ viv_obj->node_handle = iface.u.WrapUserMemory.node;
+ viv_obj->node_object = nodeObject;
+
+OnError:
+ return gem_obj;
+}
+
+void viv_gem_free_object(struct drm_gem_object *gem_obj)
+{
+ struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ struct drm_device *drm = gem_obj->dev;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_RELEASE_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.ReleaseVideoMemory.node = viv_obj->node_handle;
+ gcmkVERIFY_OK(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ drm_gem_object_release(gem_obj);
+ kfree(gem_obj);
+}
+
+static int viv_ioctl_gem_create(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ int ret = 0;
+ struct drm_viv_gem_create *args = (struct drm_viv_gem_create*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev;
+ gckKERNEL kernel;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObject;
+ gctUINT32 flags = gcvALLOC_FLAG_DMABUF_EXPORTABLE;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (args->flags & DRM_VIV_GEM_CONTIGUOUS)
+ {
+ flags |= gcvALLOC_FLAG_CONTIGUOUS;
+ }
+ if (args->flags & DRM_VIV_GEM_CACHED)
+ {
+ flags |= gcvALLOC_FLAG_CACHEABLE;
+ }
+ if (args->flags & DRM_VIV_GEM_SECURE)
+ {
+ flags |= gcvALLOC_FLAG_SECURITY;
+ }
+ if (args->flags & DRM_VIV_GEM_CMA_LIMIT)
+ {
+ flags |= gcvALLOC_FLAG_CMA_LIMIT;
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.AllocateLinearVideoMemory.bytes = PAGE_ALIGN(args->size);
+ iface.u.AllocateLinearVideoMemory.alignment = 256;
+ iface.u.AllocateLinearVideoMemory.type = gcvSURF_RENDER_TARGET; /* should be general */
+ iface.u.AllocateLinearVideoMemory.flag = flags;
+ iface.u.AllocateLinearVideoMemory.pool = gcvPOOL_DEFAULT;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.AllocateLinearVideoMemory.node, &nodeObject));
+
+ /* ioctl output */
+ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+ drm_gem_private_object_init(drm, gem_obj, iface.u.AllocateLinearVideoMemory.bytes);
+ ret = drm_gem_handle_create(file, gem_obj, &args->handle);
+
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ viv_obj->node_handle = iface.u.AllocateLinearVideoMemory.node;
+ viv_obj->node_object = nodeObject;
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+OnError:
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_lock(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_lock *args = (struct drm_viv_gem_lock*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_LOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.LockVideoMemory.node = viv_obj->node_handle;
+ iface.u.LockVideoMemory.cacheable = args->cacheable;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ args->logical = iface.u.LockVideoMemory.memory;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_unlock(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_unlock *args = (struct drm_viv_gem_unlock*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ memset(&iface, 0, sizeof(iface));
+ iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.UnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+ iface.u.UnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ memset(&iface, 0, sizeof(iface));
+ iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+ iface.u.BottomHalfUnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_cache(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_cache *args = (struct drm_viv_gem_cache*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gceCACHEOPERATION cache_op = 0;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ switch (args->op)
+ {
+ case DRM_VIV_GEM_CLEAN_CACHE:
+ cache_op = gcvCACHE_CLEAN;
+ break;
+ case DRM_VIV_GEM_INVALIDATE_CACHE:
+ cache_op = gcvCACHE_INVALIDATE;
+ break;
+ case DRM_VIV_GEM_FLUSH_CACHE:
+ cache_op = gcvCACHE_FLUSH;
+ break;
+ case DRM_VIV_GEM_MEMORY_BARRIER:
+ cache_op = gcvCACHE_MEMORY_BARRIER;
+ break;
+ default:
+ break;
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_CACHE;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.Cache.node = viv_obj->node_handle;
+ iface.u.Cache.operation = cache_op;
+ iface.u.Cache.logical = args->logical;
+ iface.u.Cache.bytes = args->bytes;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_query(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_query *args = (struct drm_viv_gem_query*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ switch (args->param)
+ {
+ case DRM_VIV_GEM_PARAM_POOL:
+ args->value = (__u64)viv_obj->node_object->pool;
+ break;
+ case DRM_VIV_GEM_PARAM_SIZE:
+ args->value = (__u64)gem_obj->size;
+ break;
+ default:
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_timestamp(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_timestamp *args = (struct drm_viv_gem_timestamp *)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ viv_obj->node_object->timeStamp += args->inc;
+ args->timestamp = viv_obj->node_object->timeStamp;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_set_tiling(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_set_tiling *args = (struct drm_viv_gem_set_tiling*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ viv_obj->node_object->tilingMode = args->tiling_mode;
+ viv_obj->node_object->tsMode = args->ts_mode;
+ viv_obj->node_object->clearValue = args->clear_value;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_get_tiling(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_get_tiling *args = (struct drm_viv_gem_get_tiling*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ args->tiling_mode = viv_obj->node_object->tilingMode;
+ args->ts_mode = viv_obj->node_object->tsMode;
+ args->clear_value = viv_obj->node_object->clearValue;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_attach_aux(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_attach_aux *args = (struct drm_viv_gem_attach_aux*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+ struct drm_gem_object *gem_ts_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gckVIDMEM_NODE nodeObj = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ nodeObj = viv_obj->node_object;
+
+ /* do not support re-attach */
+ if (nodeObj->tsNode)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ if (args->ts_handle)
+ {
+ struct viv_gem_object *viv_ts_obj;
+ gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+
+ gem_ts_obj = drm_gem_object_lookup(file, args->ts_handle);
+ if (!gem_ts_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_ts_obj = container_of(gem_ts_obj, struct viv_gem_object, base);
+
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, viv_ts_obj->node_object));
+ nodeObj->tsNode = viv_ts_obj->node_object;
+ }
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ if (gem_ts_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_ts_obj);
+ }
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_ref_node(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_ref_node *args = (struct drm_viv_gem_ref_node*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gckKERNEL kernel = gcvNULL;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObj;
+ gctUINT32 nodeHandle = 0, tsNodeHandle = 0;
+ gctBOOL refered = gcvFALSE;
+ int ret = 0;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ nodeObj = viv_obj->node_object;
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj, &nodeHandle));
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(kernel,
+ processID, gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(nodeHandle),
+ gcvNULL,
+ 0));
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj));
+ refered = gcvTRUE;
+
+ if (nodeObj->tsNode)
+ {
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj->tsNode, &tsNodeHandle));
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(kernel,
+ processID, gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(tsNodeHandle),
+ gcvNULL,
+ 0));
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj->tsNode));
+ }
+ args->node = nodeHandle;
+ args->ts_node = tsNodeHandle;
+
+OnError:
+ if (gcmIS_ERROR(status) && kernel)
+ {
+ gctUINT32 processID;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
+
+ if (tsNodeHandle)
+ {
+ gckVIDMEM_HANDLE_Dereference(kernel, processID, tsNodeHandle);
+ }
+
+ if (nodeHandle)
+ {
+ gckVIDMEM_HANDLE_Dereference(kernel, processID, nodeHandle);
+ }
+
+ if (refered)
+ {
+ gcmkONERROR(gckVIDMEM_NODE_Dereference(kernel, nodeObj));
+ }
+
+ args->node = 0;
+ args->ts_node = 0;
+
+ ret = -ENOTTY;
+ }
+
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+
+ return ret;
+}
+
+static const struct drm_ioctl_desc viv_ioctls[] =
+{
+ DRM_IOCTL_DEF_DRV(VIV_GEM_CREATE, viv_ioctl_gem_create, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_LOCK, viv_ioctl_gem_lock, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_UNLOCK, viv_ioctl_gem_unlock, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_CACHE, viv_ioctl_gem_cache, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_QUERY, viv_ioctl_gem_query, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_TIMESTAMP, viv_ioctl_gem_timestamp, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_SET_TILING, viv_ioctl_gem_set_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_GET_TILING, viv_ioctl_gem_get_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_ATTACH_AUX, viv_ioctl_gem_attach_aux, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_REF_NODE, viv_ioctl_gem_ref_node, DRM_AUTH | DRM_RENDER_ALLOW),
+};
+
+int viv_drm_open(struct drm_device *drm, struct drm_file *file)
+{
+ gctINT i;
+ gctUINT32 pid = _GetProcessID();
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+ {
+ if (gal_dev->kernels[i])
+ {
+ gcmkONERROR(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvTRUE, pid));
+ }
+ }
+ file->driver_priv = gcmINT2PTR(pid);
+
+OnError:
+ return gcmIS_ERROR(status) ? -ENODEV : 0;
+}
+
+void viv_drm_postclose(struct drm_device *drm, struct drm_file *file)
+{
+ gctINT i;
+ gctUINT32 pid = gcmPTR2INT(file->driver_priv);
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+ {
+ if (gal_dev->kernels[i])
+ {
+ gcmkVERIFY_OK(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvFALSE, pid));
+ }
+ }
+}
+
+static const struct file_operations viv_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+};
+
+static struct drm_driver viv_drm_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER,
+ .open = viv_drm_open,
+ .postclose = viv_drm_postclose,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
+ .gem_free_object_unlocked = viv_gem_free_object,
+#else
+ .gem_free_object = viv_gem_free_object,
+#endif
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = viv_gem_prime_export,
+ .gem_prime_import = viv_gem_prime_import,
+ .ioctls = viv_ioctls,
+ .num_ioctls = DRM_VIV_NUM_IOCTLS,
+ .fops = &viv_drm_fops,
+ .name = "vivante",
+ .desc = "vivante DRM",
+ .date = "20170808",
+ .major = 1,
+ .minor = 0,
+};
+
+int viv_drm_probe(struct device *dev)
+{
+ int ret = 0;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ struct drm_device *drm = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+ if (!gal_dev)
+ {
+ ret = -ENODEV;
+ gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+ }
+
+ drm = drm_dev_alloc(&viv_drm_driver, dev);
+ if (IS_ERR(drm))
+ {
+ ret = PTR_ERR(drm);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ drm->dev_private = (void*)gal_dev;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ gal_dev->drm = (void*)drm;
+
+OnError:
+ if (gcmIS_ERROR(status))
+ {
+ if (drm)
+ {
+ drm_dev_unref(drm);
+ }
+ printk(KERN_ERR "galcore: Failed to setup drm device.\n");
+ }
+ return ret;
+}
+
+int viv_drm_remove(struct device *dev)
+{
+ gckGALDEVICE gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+
+ if (gal_dev)
+ {
+ struct drm_device *drm = (struct drm_device*)gal_dev->drm;
+
+ drm_dev_unregister(drm);
+ drm_dev_unref(drm);
+ }
+
+ return 0;
+}
+
+#endif