1f6ffbd4fSLucas Stach // SPDX-License-Identifier: GPL-2.0 2a8c21a54SThe etnaviv authors /* 3f6ffbd4fSLucas Stach * Copyright (C) 2015-2018 Etnaviv Project 4a8c21a54SThe etnaviv authors */ 5a8c21a54SThe etnaviv authors 6a8c21a54SThe etnaviv authors #include <linux/component.h> 76eae41feSSam Ravnborg #include <linux/dma-mapping.h> 82e737e52SLucas Stach #include <linux/module.h> 9a8c21a54SThe etnaviv authors #include <linux/of_platform.h> 106eae41feSSam Ravnborg #include <linux/uaccess.h> 116eae41feSSam Ravnborg 126eae41feSSam Ravnborg #include <drm/drm_debugfs.h> 136eae41feSSam Ravnborg #include <drm/drm_drv.h> 146eae41feSSam Ravnborg #include <drm/drm_file.h> 156eae41feSSam Ravnborg #include <drm/drm_ioctl.h> 1697ac0e47SRussell King #include <drm/drm_of.h> 176eae41feSSam Ravnborg #include <drm/drm_prime.h> 18a8c21a54SThe etnaviv authors 19ea1f5729SLucas Stach #include "etnaviv_cmdbuf.h" 20a8c21a54SThe etnaviv authors #include "etnaviv_drv.h" 21a8c21a54SThe etnaviv authors #include "etnaviv_gpu.h" 22a8c21a54SThe etnaviv authors #include "etnaviv_gem.h" 23a8c21a54SThe etnaviv authors #include "etnaviv_mmu.h" 249e2c2e27SChristian Gmeiner #include "etnaviv_perfmon.h" 25a8c21a54SThe etnaviv authors 26a8c21a54SThe etnaviv authors /* 27a8c21a54SThe etnaviv authors * DRM operations: 28a8c21a54SThe etnaviv authors */ 29a8c21a54SThe etnaviv authors 30a8c21a54SThe etnaviv authors 31a8c21a54SThe etnaviv authors static void load_gpu(struct drm_device *dev) 32a8c21a54SThe etnaviv authors { 33a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 34a8c21a54SThe etnaviv authors unsigned int i; 35a8c21a54SThe etnaviv authors 36a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 37a8c21a54SThe etnaviv authors struct etnaviv_gpu *g = priv->gpu[i]; 38a8c21a54SThe etnaviv authors 39a8c21a54SThe etnaviv authors if (g) { 40a8c21a54SThe etnaviv authors int ret; 41a8c21a54SThe etnaviv authors 42a8c21a54SThe etnaviv authors ret = etnaviv_gpu_init(g); 43c1c77b0eSLucas Stach if (ret) 44a8c21a54SThe etnaviv authors priv->gpu[i] = NULL; 45a8c21a54SThe etnaviv authors } 46a8c21a54SThe etnaviv authors } 47a8c21a54SThe etnaviv authors } 48a8c21a54SThe etnaviv authors 49a8c21a54SThe etnaviv authors static int etnaviv_open(struct drm_device *dev, struct drm_file *file) 50a8c21a54SThe etnaviv authors { 51e93b6deeSLucas Stach struct etnaviv_drm_private *priv = dev->dev_private; 52a8c21a54SThe etnaviv authors struct etnaviv_file_private *ctx; 5317e4660aSLucas Stach int ret, i; 54a8c21a54SThe etnaviv authors 55a8c21a54SThe etnaviv authors ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 56a8c21a54SThe etnaviv authors if (!ctx) 57a8c21a54SThe etnaviv authors return -ENOMEM; 58a8c21a54SThe etnaviv authors 5917e4660aSLucas Stach ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global, 6017e4660aSLucas Stach priv->cmdbuf_suballoc); 6117e4660aSLucas Stach if (!ctx->mmu) { 6217e4660aSLucas Stach ret = -ENOMEM; 6317e4660aSLucas Stach goto out_free; 6417e4660aSLucas Stach } 6517e4660aSLucas Stach 66e93b6deeSLucas Stach for (i = 0; i < ETNA_MAX_PIPES; i++) { 67e93b6deeSLucas Stach struct etnaviv_gpu *gpu = priv->gpu[i]; 68b3ac1766SNirmoy Das struct drm_gpu_scheduler *sched; 69e93b6deeSLucas Stach 70e93b6deeSLucas Stach if (gpu) { 71b3ac1766SNirmoy Das sched = &gpu->sched; 72aa16b6c6SNayan Deshmukh drm_sched_entity_init(&ctx->sched_entity[i], 73b3ac1766SNirmoy Das DRM_SCHED_PRIORITY_NORMAL, &sched, 74b3ac1766SNirmoy Das 1, NULL); 75e93b6deeSLucas Stach } 76e93b6deeSLucas Stach } 77e93b6deeSLucas Stach 78a8c21a54SThe etnaviv authors file->driver_priv = ctx; 79a8c21a54SThe etnaviv authors 80a8c21a54SThe etnaviv authors return 0; 8117e4660aSLucas Stach 8217e4660aSLucas Stach out_free: 8317e4660aSLucas Stach kfree(ctx); 8417e4660aSLucas Stach return ret; 85a8c21a54SThe etnaviv authors } 86a8c21a54SThe etnaviv authors 87fda8fa5bSDaniel Vetter static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) 88a8c21a54SThe etnaviv authors { 89a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 90a8c21a54SThe etnaviv authors struct etnaviv_file_private *ctx = file->driver_priv; 91a8c21a54SThe etnaviv authors unsigned int i; 92a8c21a54SThe etnaviv authors 93a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 94a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu = priv->gpu[i]; 95a8c21a54SThe etnaviv authors 96801c7a1eSLucas Stach if (gpu) 97cdc50176SNayan Deshmukh drm_sched_entity_destroy(&ctx->sched_entity[i]); 98a8c21a54SThe etnaviv authors } 99a8c21a54SThe etnaviv authors 10017e4660aSLucas Stach etnaviv_iommu_context_put(ctx->mmu); 10117e4660aSLucas Stach 102a8c21a54SThe etnaviv authors kfree(ctx); 103a8c21a54SThe etnaviv authors } 104a8c21a54SThe etnaviv authors 105a8c21a54SThe etnaviv authors /* 106a8c21a54SThe etnaviv authors * DRM debugfs: 107a8c21a54SThe etnaviv authors */ 108a8c21a54SThe etnaviv authors 109a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS 110a8c21a54SThe etnaviv authors static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m) 111a8c21a54SThe etnaviv authors { 112a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 113a8c21a54SThe etnaviv authors 114a8c21a54SThe etnaviv authors etnaviv_gem_describe_objects(priv, m); 115a8c21a54SThe etnaviv authors 116a8c21a54SThe etnaviv authors return 0; 117a8c21a54SThe etnaviv authors } 118a8c21a54SThe etnaviv authors 119a8c21a54SThe etnaviv authors static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m) 120a8c21a54SThe etnaviv authors { 121b5c3714fSDaniel Vetter struct drm_printer p = drm_seq_file_printer(m); 122a8c21a54SThe etnaviv authors 123a8c21a54SThe etnaviv authors read_lock(&dev->vma_offset_manager->vm_lock); 124b5c3714fSDaniel Vetter drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); 125a8c21a54SThe etnaviv authors read_unlock(&dev->vma_offset_manager->vm_lock); 126a8c21a54SThe etnaviv authors 127b5c3714fSDaniel Vetter return 0; 128a8c21a54SThe etnaviv authors } 129a8c21a54SThe etnaviv authors 130a8c21a54SThe etnaviv authors static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m) 131a8c21a54SThe etnaviv authors { 132b5c3714fSDaniel Vetter struct drm_printer p = drm_seq_file_printer(m); 13317e4660aSLucas Stach struct etnaviv_iommu_context *mmu_context; 134b5c3714fSDaniel Vetter 135a8c21a54SThe etnaviv authors seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev)); 136a8c21a54SThe etnaviv authors 13717e4660aSLucas Stach /* 13817e4660aSLucas Stach * Lock the GPU to avoid a MMU context switch just now and elevate 13917e4660aSLucas Stach * the refcount of the current context to avoid it disappearing from 14017e4660aSLucas Stach * under our feet. 14117e4660aSLucas Stach */ 14217e4660aSLucas Stach mutex_lock(&gpu->lock); 14317e4660aSLucas Stach mmu_context = gpu->mmu_context; 14417e4660aSLucas Stach if (mmu_context) 14517e4660aSLucas Stach etnaviv_iommu_context_get(mmu_context); 14617e4660aSLucas Stach mutex_unlock(&gpu->lock); 14717e4660aSLucas Stach 14817e4660aSLucas Stach if (!mmu_context) 14917e4660aSLucas Stach return 0; 15017e4660aSLucas Stach 15117e4660aSLucas Stach mutex_lock(&mmu_context->lock); 15217e4660aSLucas Stach drm_mm_print(&mmu_context->mm, &p); 15317e4660aSLucas Stach mutex_unlock(&mmu_context->lock); 15417e4660aSLucas Stach 15517e4660aSLucas Stach etnaviv_iommu_context_put(mmu_context); 156a8c21a54SThe etnaviv authors 157a8c21a54SThe etnaviv authors return 0; 158a8c21a54SThe etnaviv authors } 159a8c21a54SThe etnaviv authors 160a8c21a54SThe etnaviv authors static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m) 161a8c21a54SThe etnaviv authors { 1622f9225dbSLucas Stach struct etnaviv_cmdbuf *buf = &gpu->buffer; 163a8c21a54SThe etnaviv authors u32 size = buf->size; 164a8c21a54SThe etnaviv authors u32 *ptr = buf->vaddr; 165a8c21a54SThe etnaviv authors u32 i; 166a8c21a54SThe etnaviv authors 167a8c21a54SThe etnaviv authors seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", 1689912b4dbSLucas Stach buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf), 1699912b4dbSLucas Stach size - buf->user_size); 170a8c21a54SThe etnaviv authors 171a8c21a54SThe etnaviv authors for (i = 0; i < size / 4; i++) { 172a8c21a54SThe etnaviv authors if (i && !(i % 4)) 173a8c21a54SThe etnaviv authors seq_puts(m, "\n"); 174a8c21a54SThe etnaviv authors if (i % 4 == 0) 175a8c21a54SThe etnaviv authors seq_printf(m, "\t0x%p: ", ptr + i); 176a8c21a54SThe etnaviv authors seq_printf(m, "%08x ", *(ptr + i)); 177a8c21a54SThe etnaviv authors } 178a8c21a54SThe etnaviv authors seq_puts(m, "\n"); 179a8c21a54SThe etnaviv authors } 180a8c21a54SThe etnaviv authors 181a8c21a54SThe etnaviv authors static int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m) 182a8c21a54SThe etnaviv authors { 183a8c21a54SThe etnaviv authors seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev)); 184a8c21a54SThe etnaviv authors 185a8c21a54SThe etnaviv authors mutex_lock(&gpu->lock); 186a8c21a54SThe etnaviv authors etnaviv_buffer_dump(gpu, m); 187a8c21a54SThe etnaviv authors mutex_unlock(&gpu->lock); 188a8c21a54SThe etnaviv authors 189a8c21a54SThe etnaviv authors return 0; 190a8c21a54SThe etnaviv authors } 191a8c21a54SThe etnaviv authors 192a8c21a54SThe etnaviv authors static int show_unlocked(struct seq_file *m, void *arg) 193a8c21a54SThe etnaviv authors { 194a8c21a54SThe etnaviv authors struct drm_info_node *node = (struct drm_info_node *) m->private; 195a8c21a54SThe etnaviv authors struct drm_device *dev = node->minor->dev; 196a8c21a54SThe etnaviv authors int (*show)(struct drm_device *dev, struct seq_file *m) = 197a8c21a54SThe etnaviv authors node->info_ent->data; 198a8c21a54SThe etnaviv authors 199a8c21a54SThe etnaviv authors return show(dev, m); 200a8c21a54SThe etnaviv authors } 201a8c21a54SThe etnaviv authors 202a8c21a54SThe etnaviv authors static int show_each_gpu(struct seq_file *m, void *arg) 203a8c21a54SThe etnaviv authors { 204a8c21a54SThe etnaviv authors struct drm_info_node *node = (struct drm_info_node *) m->private; 205a8c21a54SThe etnaviv authors struct drm_device *dev = node->minor->dev; 206a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 207a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 208a8c21a54SThe etnaviv authors int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) = 209a8c21a54SThe etnaviv authors node->info_ent->data; 210a8c21a54SThe etnaviv authors unsigned int i; 211a8c21a54SThe etnaviv authors int ret = 0; 212a8c21a54SThe etnaviv authors 213a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 214a8c21a54SThe etnaviv authors gpu = priv->gpu[i]; 215a8c21a54SThe etnaviv authors if (!gpu) 216a8c21a54SThe etnaviv authors continue; 217a8c21a54SThe etnaviv authors 218a8c21a54SThe etnaviv authors ret = show(gpu, m); 219a8c21a54SThe etnaviv authors if (ret < 0) 220a8c21a54SThe etnaviv authors break; 221a8c21a54SThe etnaviv authors } 222a8c21a54SThe etnaviv authors 223a8c21a54SThe etnaviv authors return ret; 224a8c21a54SThe etnaviv authors } 225a8c21a54SThe etnaviv authors 226a8c21a54SThe etnaviv authors static struct drm_info_list etnaviv_debugfs_list[] = { 227a8c21a54SThe etnaviv authors {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, 228a8c21a54SThe etnaviv authors {"gem", show_unlocked, 0, etnaviv_gem_show}, 229a8c21a54SThe etnaviv authors { "mm", show_unlocked, 0, etnaviv_mm_show }, 230a8c21a54SThe etnaviv authors {"mmu", show_each_gpu, 0, etnaviv_mmu_show}, 231a8c21a54SThe etnaviv authors {"ring", show_each_gpu, 0, etnaviv_ring_show}, 232a8c21a54SThe etnaviv authors }; 233a8c21a54SThe etnaviv authors 234a8c21a54SThe etnaviv authors static int etnaviv_debugfs_init(struct drm_minor *minor) 235a8c21a54SThe etnaviv authors { 23614b46195SWambui Karuga drm_debugfs_create_files(etnaviv_debugfs_list, 237a8c21a54SThe etnaviv authors ARRAY_SIZE(etnaviv_debugfs_list), 238a8c21a54SThe etnaviv authors minor->debugfs_root, minor); 239a8c21a54SThe etnaviv authors 24014b46195SWambui Karuga return 0; 241a8c21a54SThe etnaviv authors } 242a8c21a54SThe etnaviv authors #endif 243a8c21a54SThe etnaviv authors 244a8c21a54SThe etnaviv authors /* 245a8c21a54SThe etnaviv authors * DRM ioctls: 246a8c21a54SThe etnaviv authors */ 247a8c21a54SThe etnaviv authors 248a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, 249a8c21a54SThe etnaviv authors struct drm_file *file) 250a8c21a54SThe etnaviv authors { 251a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 252a8c21a54SThe etnaviv authors struct drm_etnaviv_param *args = data; 253a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 254a8c21a54SThe etnaviv authors 255a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 256a8c21a54SThe etnaviv authors return -EINVAL; 257a8c21a54SThe etnaviv authors 258a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 259a8c21a54SThe etnaviv authors if (!gpu) 260a8c21a54SThe etnaviv authors return -ENXIO; 261a8c21a54SThe etnaviv authors 262a8c21a54SThe etnaviv authors return etnaviv_gpu_get_param(gpu, args->param, &args->value); 263a8c21a54SThe etnaviv authors } 264a8c21a54SThe etnaviv authors 265a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, 266a8c21a54SThe etnaviv authors struct drm_file *file) 267a8c21a54SThe etnaviv authors { 268a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_new *args = data; 269a8c21a54SThe etnaviv authors 270a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED | 271a8c21a54SThe etnaviv authors ETNA_BO_FORCE_MMU)) 272a8c21a54SThe etnaviv authors return -EINVAL; 273a8c21a54SThe etnaviv authors 274a8c21a54SThe etnaviv authors return etnaviv_gem_new_handle(dev, file, args->size, 275a8c21a54SThe etnaviv authors args->flags, &args->handle); 276a8c21a54SThe etnaviv authors } 277a8c21a54SThe etnaviv authors 278a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, 279a8c21a54SThe etnaviv authors struct drm_file *file) 280a8c21a54SThe etnaviv authors { 281a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_prep *args = data; 282a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 283a8c21a54SThe etnaviv authors int ret; 284a8c21a54SThe etnaviv authors 285a8c21a54SThe etnaviv authors if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC)) 286a8c21a54SThe etnaviv authors return -EINVAL; 287a8c21a54SThe etnaviv authors 288a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 289a8c21a54SThe etnaviv authors if (!obj) 290a8c21a54SThe etnaviv authors return -ENOENT; 291a8c21a54SThe etnaviv authors 29238c4a4cfSArnd Bergmann ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout); 293a8c21a54SThe etnaviv authors 29423d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 295a8c21a54SThe etnaviv authors 296a8c21a54SThe etnaviv authors return ret; 297a8c21a54SThe etnaviv authors } 298a8c21a54SThe etnaviv authors 299a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, 300a8c21a54SThe etnaviv authors struct drm_file *file) 301a8c21a54SThe etnaviv authors { 302a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_fini *args = data; 303a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 304a8c21a54SThe etnaviv authors int ret; 305a8c21a54SThe etnaviv authors 306a8c21a54SThe etnaviv authors if (args->flags) 307a8c21a54SThe etnaviv authors return -EINVAL; 308a8c21a54SThe etnaviv authors 309a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 310a8c21a54SThe etnaviv authors if (!obj) 311a8c21a54SThe etnaviv authors return -ENOENT; 312a8c21a54SThe etnaviv authors 313a8c21a54SThe etnaviv authors ret = etnaviv_gem_cpu_fini(obj); 314a8c21a54SThe etnaviv authors 31523d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 316a8c21a54SThe etnaviv authors 317a8c21a54SThe etnaviv authors return ret; 318a8c21a54SThe etnaviv authors } 319a8c21a54SThe etnaviv authors 320a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data, 321a8c21a54SThe etnaviv authors struct drm_file *file) 322a8c21a54SThe etnaviv authors { 323a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_info *args = data; 324a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 325a8c21a54SThe etnaviv authors int ret; 326a8c21a54SThe etnaviv authors 327a8c21a54SThe etnaviv authors if (args->pad) 328a8c21a54SThe etnaviv authors return -EINVAL; 329a8c21a54SThe etnaviv authors 330a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 331a8c21a54SThe etnaviv authors if (!obj) 332a8c21a54SThe etnaviv authors return -ENOENT; 333a8c21a54SThe etnaviv authors 334a8c21a54SThe etnaviv authors ret = etnaviv_gem_mmap_offset(obj, &args->offset); 33523d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 336a8c21a54SThe etnaviv authors 337a8c21a54SThe etnaviv authors return ret; 338a8c21a54SThe etnaviv authors } 339a8c21a54SThe etnaviv authors 340a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data, 341a8c21a54SThe etnaviv authors struct drm_file *file) 342a8c21a54SThe etnaviv authors { 343a8c21a54SThe etnaviv authors struct drm_etnaviv_wait_fence *args = data; 344a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 34538c4a4cfSArnd Bergmann struct drm_etnaviv_timespec *timeout = &args->timeout; 346a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 347a8c21a54SThe etnaviv authors 348a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 349a8c21a54SThe etnaviv authors return -EINVAL; 350a8c21a54SThe etnaviv authors 351a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 352a8c21a54SThe etnaviv authors return -EINVAL; 353a8c21a54SThe etnaviv authors 354a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 355a8c21a54SThe etnaviv authors if (!gpu) 356a8c21a54SThe etnaviv authors return -ENXIO; 357a8c21a54SThe etnaviv authors 358a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 359a8c21a54SThe etnaviv authors timeout = NULL; 360a8c21a54SThe etnaviv authors 361a8c21a54SThe etnaviv authors return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence, 362a8c21a54SThe etnaviv authors timeout); 363a8c21a54SThe etnaviv authors } 364a8c21a54SThe etnaviv authors 365a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data, 366a8c21a54SThe etnaviv authors struct drm_file *file) 367a8c21a54SThe etnaviv authors { 368a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_userptr *args = data; 369a8c21a54SThe etnaviv authors 370a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || 371a8c21a54SThe etnaviv authors args->flags == 0) 372a8c21a54SThe etnaviv authors return -EINVAL; 373a8c21a54SThe etnaviv authors 374a8c21a54SThe etnaviv authors if (offset_in_page(args->user_ptr | args->user_size) || 375a8c21a54SThe etnaviv authors (uintptr_t)args->user_ptr != args->user_ptr || 376a8c21a54SThe etnaviv authors (u32)args->user_size != args->user_size || 377a8c21a54SThe etnaviv authors args->user_ptr & ~PAGE_MASK) 378a8c21a54SThe etnaviv authors return -EINVAL; 379a8c21a54SThe etnaviv authors 38096d4f267SLinus Torvalds if (!access_ok((void __user *)(unsigned long)args->user_ptr, 381a8c21a54SThe etnaviv authors args->user_size)) 382a8c21a54SThe etnaviv authors return -EFAULT; 383a8c21a54SThe etnaviv authors 384a8c21a54SThe etnaviv authors return etnaviv_gem_new_userptr(dev, file, args->user_ptr, 385a8c21a54SThe etnaviv authors args->user_size, args->flags, 386a8c21a54SThe etnaviv authors &args->handle); 387a8c21a54SThe etnaviv authors } 388a8c21a54SThe etnaviv authors 389a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, 390a8c21a54SThe etnaviv authors struct drm_file *file) 391a8c21a54SThe etnaviv authors { 392a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 393a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_wait *args = data; 39438c4a4cfSArnd Bergmann struct drm_etnaviv_timespec *timeout = &args->timeout; 395a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 396a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 397a8c21a54SThe etnaviv authors int ret; 398a8c21a54SThe etnaviv authors 399a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 400a8c21a54SThe etnaviv authors return -EINVAL; 401a8c21a54SThe etnaviv authors 402a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 403a8c21a54SThe etnaviv authors return -EINVAL; 404a8c21a54SThe etnaviv authors 405a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 406a8c21a54SThe etnaviv authors if (!gpu) 407a8c21a54SThe etnaviv authors return -ENXIO; 408a8c21a54SThe etnaviv authors 409a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 410a8c21a54SThe etnaviv authors if (!obj) 411a8c21a54SThe etnaviv authors return -ENOENT; 412a8c21a54SThe etnaviv authors 413a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 414a8c21a54SThe etnaviv authors timeout = NULL; 415a8c21a54SThe etnaviv authors 416a8c21a54SThe etnaviv authors ret = etnaviv_gem_wait_bo(gpu, obj, timeout); 417a8c21a54SThe etnaviv authors 41823d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 419a8c21a54SThe etnaviv authors 420a8c21a54SThe etnaviv authors return ret; 421a8c21a54SThe etnaviv authors } 422a8c21a54SThe etnaviv authors 4239e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data, 4249e2c2e27SChristian Gmeiner struct drm_file *file) 4259e2c2e27SChristian Gmeiner { 4269e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4279e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_domain *args = data; 4289e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4299e2c2e27SChristian Gmeiner 4309e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4319e2c2e27SChristian Gmeiner return -EINVAL; 4329e2c2e27SChristian Gmeiner 4339e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4349e2c2e27SChristian Gmeiner if (!gpu) 4359e2c2e27SChristian Gmeiner return -ENXIO; 4369e2c2e27SChristian Gmeiner 4379e2c2e27SChristian Gmeiner return etnaviv_pm_query_dom(gpu, args); 4389e2c2e27SChristian Gmeiner } 4399e2c2e27SChristian Gmeiner 4409e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data, 4419e2c2e27SChristian Gmeiner struct drm_file *file) 4429e2c2e27SChristian Gmeiner { 4439e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4449e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_signal *args = data; 4459e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4469e2c2e27SChristian Gmeiner 4479e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4489e2c2e27SChristian Gmeiner return -EINVAL; 4499e2c2e27SChristian Gmeiner 4509e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4519e2c2e27SChristian Gmeiner if (!gpu) 4529e2c2e27SChristian Gmeiner return -ENXIO; 4539e2c2e27SChristian Gmeiner 4549e2c2e27SChristian Gmeiner return etnaviv_pm_query_sig(gpu, args); 4559e2c2e27SChristian Gmeiner } 4569e2c2e27SChristian Gmeiner 457a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = { 458a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \ 459a8c21a54SThe etnaviv authors DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) 460b8602f9aSEmil Velikov ETNA_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), 461b8602f9aSEmil Velikov ETNA_IOCTL(GEM_NEW, gem_new, DRM_RENDER_ALLOW), 462b8602f9aSEmil Velikov ETNA_IOCTL(GEM_INFO, gem_info, DRM_RENDER_ALLOW), 463b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW), 464b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW), 465b8602f9aSEmil Velikov ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_RENDER_ALLOW), 466b8602f9aSEmil Velikov ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_RENDER_ALLOW), 467b8602f9aSEmil Velikov ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_RENDER_ALLOW), 468b8602f9aSEmil Velikov ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), 469b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), 470b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), 471a8c21a54SThe etnaviv authors }; 472a8c21a54SThe etnaviv authors 473a8c21a54SThe etnaviv authors static const struct vm_operations_struct vm_ops = { 474a8c21a54SThe etnaviv authors .fault = etnaviv_gem_fault, 475a8c21a54SThe etnaviv authors .open = drm_gem_vm_open, 476a8c21a54SThe etnaviv authors .close = drm_gem_vm_close, 477a8c21a54SThe etnaviv authors }; 478a8c21a54SThe etnaviv authors 479a8c21a54SThe etnaviv authors static const struct file_operations fops = { 480a8c21a54SThe etnaviv authors .owner = THIS_MODULE, 481a8c21a54SThe etnaviv authors .open = drm_open, 482a8c21a54SThe etnaviv authors .release = drm_release, 483a8c21a54SThe etnaviv authors .unlocked_ioctl = drm_ioctl, 484a8c21a54SThe etnaviv authors .compat_ioctl = drm_compat_ioctl, 485a8c21a54SThe etnaviv authors .poll = drm_poll, 486a8c21a54SThe etnaviv authors .read = drm_read, 487a8c21a54SThe etnaviv authors .llseek = no_llseek, 488a8c21a54SThe etnaviv authors .mmap = etnaviv_gem_mmap, 489a8c21a54SThe etnaviv authors }; 490a8c21a54SThe etnaviv authors 491a8c21a54SThe etnaviv authors static struct drm_driver etnaviv_drm_driver = { 4920424fdafSDaniel Vetter .driver_features = DRIVER_GEM | DRIVER_RENDER, 493a8c21a54SThe etnaviv authors .open = etnaviv_open, 494fda8fa5bSDaniel Vetter .postclose = etnaviv_postclose, 4951d657c58SDaniel Vetter .gem_free_object_unlocked = etnaviv_gem_free_object, 496a8c21a54SThe etnaviv authors .gem_vm_ops = &vm_ops, 497a8c21a54SThe etnaviv authors .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 498a8c21a54SThe etnaviv authors .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 499a8c21a54SThe etnaviv authors .gem_prime_pin = etnaviv_gem_prime_pin, 500a8c21a54SThe etnaviv authors .gem_prime_unpin = etnaviv_gem_prime_unpin, 501a8c21a54SThe etnaviv authors .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table, 502a8c21a54SThe etnaviv authors .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table, 503a8c21a54SThe etnaviv authors .gem_prime_vmap = etnaviv_gem_prime_vmap, 504a8c21a54SThe etnaviv authors .gem_prime_vunmap = etnaviv_gem_prime_vunmap, 5055688e57eSLucas Stach .gem_prime_mmap = etnaviv_gem_prime_mmap, 506a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS 507a8c21a54SThe etnaviv authors .debugfs_init = etnaviv_debugfs_init, 508a8c21a54SThe etnaviv authors #endif 509a8c21a54SThe etnaviv authors .ioctls = etnaviv_ioctls, 510a8c21a54SThe etnaviv authors .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, 511a8c21a54SThe etnaviv authors .fops = &fops, 512a8c21a54SThe etnaviv authors .name = "etnaviv", 513a8c21a54SThe etnaviv authors .desc = "etnaviv DRM", 514a8c21a54SThe etnaviv authors .date = "20151214", 515a8c21a54SThe etnaviv authors .major = 1, 516088880ddSLucas Stach .minor = 3, 517a8c21a54SThe etnaviv authors }; 518a8c21a54SThe etnaviv authors 519a8c21a54SThe etnaviv authors /* 520a8c21a54SThe etnaviv authors * Platform driver: 521a8c21a54SThe etnaviv authors */ 522a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev) 523a8c21a54SThe etnaviv authors { 524a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv; 525a8c21a54SThe etnaviv authors struct drm_device *drm; 526a8c21a54SThe etnaviv authors int ret; 527a8c21a54SThe etnaviv authors 528a8c21a54SThe etnaviv authors drm = drm_dev_alloc(&etnaviv_drm_driver, dev); 5290f288605STom Gundersen if (IS_ERR(drm)) 5300f288605STom Gundersen return PTR_ERR(drm); 531a8c21a54SThe etnaviv authors 532a8c21a54SThe etnaviv authors priv = kzalloc(sizeof(*priv), GFP_KERNEL); 533a8c21a54SThe etnaviv authors if (!priv) { 534a8c21a54SThe etnaviv authors dev_err(dev, "failed to allocate private data\n"); 535a8c21a54SThe etnaviv authors ret = -ENOMEM; 53699e29449SThomas Zimmermann goto out_put; 537a8c21a54SThe etnaviv authors } 538a8c21a54SThe etnaviv authors drm->dev_private = priv; 539a8c21a54SThe etnaviv authors 5401262cc88SRussell King dev->dma_parms = &priv->dma_parms; 5411262cc88SRussell King dma_set_max_seg_size(dev, SZ_2G); 5421262cc88SRussell King 543a8c21a54SThe etnaviv authors mutex_init(&priv->gem_lock); 544a8c21a54SThe etnaviv authors INIT_LIST_HEAD(&priv->gem_list); 545a8c21a54SThe etnaviv authors priv->num_gpus = 0; 546a8c21a54SThe etnaviv authors 547bffe5db8SLucas Stach priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); 548bffe5db8SLucas Stach if (IS_ERR(priv->cmdbuf_suballoc)) { 549bffe5db8SLucas Stach dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); 550bffe5db8SLucas Stach ret = PTR_ERR(priv->cmdbuf_suballoc); 551bffe5db8SLucas Stach goto out_free_priv; 552bffe5db8SLucas Stach } 553bffe5db8SLucas Stach 554a8c21a54SThe etnaviv authors dev_set_drvdata(dev, drm); 555a8c21a54SThe etnaviv authors 556a8c21a54SThe etnaviv authors ret = component_bind_all(dev, drm); 557a8c21a54SThe etnaviv authors if (ret < 0) 558bffe5db8SLucas Stach goto out_destroy_suballoc; 559a8c21a54SThe etnaviv authors 560a8c21a54SThe etnaviv authors load_gpu(drm); 561a8c21a54SThe etnaviv authors 562a8c21a54SThe etnaviv authors ret = drm_dev_register(drm, 0); 563a8c21a54SThe etnaviv authors if (ret) 564bffe5db8SLucas Stach goto out_unbind; 565a8c21a54SThe etnaviv authors 566a8c21a54SThe etnaviv authors return 0; 567a8c21a54SThe etnaviv authors 568bffe5db8SLucas Stach out_unbind: 569a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 570bffe5db8SLucas Stach out_destroy_suballoc: 571bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 572bffe5db8SLucas Stach out_free_priv: 573a8c21a54SThe etnaviv authors kfree(priv); 57499e29449SThomas Zimmermann out_put: 57599e29449SThomas Zimmermann drm_dev_put(drm); 576a8c21a54SThe etnaviv authors 577a8c21a54SThe etnaviv authors return ret; 578a8c21a54SThe etnaviv authors } 579a8c21a54SThe etnaviv authors 580a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev) 581a8c21a54SThe etnaviv authors { 582a8c21a54SThe etnaviv authors struct drm_device *drm = dev_get_drvdata(dev); 583a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = drm->dev_private; 584a8c21a54SThe etnaviv authors 585a8c21a54SThe etnaviv authors drm_dev_unregister(drm); 586a8c21a54SThe etnaviv authors 587a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 588a8c21a54SThe etnaviv authors 5891262cc88SRussell King dev->dma_parms = NULL; 5901262cc88SRussell King 591bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 592bffe5db8SLucas Stach 593a8c21a54SThe etnaviv authors drm->dev_private = NULL; 594a8c21a54SThe etnaviv authors kfree(priv); 595a8c21a54SThe etnaviv authors 59699e29449SThomas Zimmermann drm_dev_put(drm); 597a8c21a54SThe etnaviv authors } 598a8c21a54SThe etnaviv authors 599a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = { 600a8c21a54SThe etnaviv authors .bind = etnaviv_bind, 601a8c21a54SThe etnaviv authors .unbind = etnaviv_unbind, 602a8c21a54SThe etnaviv authors }; 603a8c21a54SThe etnaviv authors 604a8c21a54SThe etnaviv authors static int compare_of(struct device *dev, void *data) 605a8c21a54SThe etnaviv authors { 606a8c21a54SThe etnaviv authors struct device_node *np = data; 607a8c21a54SThe etnaviv authors 608a8c21a54SThe etnaviv authors return dev->of_node == np; 609a8c21a54SThe etnaviv authors } 610a8c21a54SThe etnaviv authors 611a8c21a54SThe etnaviv authors static int compare_str(struct device *dev, void *data) 612a8c21a54SThe etnaviv authors { 613a8c21a54SThe etnaviv authors return !strcmp(dev_name(dev), data); 614a8c21a54SThe etnaviv authors } 615a8c21a54SThe etnaviv authors 616a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev) 617a8c21a54SThe etnaviv authors { 618a8c21a54SThe etnaviv authors struct device *dev = &pdev->dev; 619a8c21a54SThe etnaviv authors struct component_match *match = NULL; 620a8c21a54SThe etnaviv authors 621246774d1SLucas Stach if (!dev->platform_data) { 622a8c21a54SThe etnaviv authors struct device_node *core_node; 623a8c21a54SThe etnaviv authors 624246774d1SLucas Stach for_each_compatible_node(core_node, NULL, "vivante,gc") { 625246774d1SLucas Stach if (!of_device_is_available(core_node)) 626246774d1SLucas Stach continue; 627a8c21a54SThe etnaviv authors 62897ac0e47SRussell King drm_of_component_match_add(&pdev->dev, &match, 62997ac0e47SRussell King compare_of, core_node); 630a8c21a54SThe etnaviv authors } 631246774d1SLucas Stach } else { 632a8c21a54SThe etnaviv authors char **names = dev->platform_data; 633a8c21a54SThe etnaviv authors unsigned i; 634a8c21a54SThe etnaviv authors 635a8c21a54SThe etnaviv authors for (i = 0; names[i]; i++) 636a8c21a54SThe etnaviv authors component_match_add(dev, &match, compare_str, names[i]); 637a8c21a54SThe etnaviv authors } 638a8c21a54SThe etnaviv authors 639a8c21a54SThe etnaviv authors return component_master_add_with_match(dev, &etnaviv_master_ops, match); 640a8c21a54SThe etnaviv authors } 641a8c21a54SThe etnaviv authors 642a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev) 643a8c21a54SThe etnaviv authors { 644a8c21a54SThe etnaviv authors component_master_del(&pdev->dev, &etnaviv_master_ops); 645a8c21a54SThe etnaviv authors 646a8c21a54SThe etnaviv authors return 0; 647a8c21a54SThe etnaviv authors } 648a8c21a54SThe etnaviv authors 649a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = { 650a8c21a54SThe etnaviv authors .probe = etnaviv_pdev_probe, 651a8c21a54SThe etnaviv authors .remove = etnaviv_pdev_remove, 652a8c21a54SThe etnaviv authors .driver = { 653a8c21a54SThe etnaviv authors .name = "etnaviv", 654a8c21a54SThe etnaviv authors }, 655a8c21a54SThe etnaviv authors }; 656a8c21a54SThe etnaviv authors 65745a0faabSFabio Estevam static struct platform_device *etnaviv_drm; 65845a0faabSFabio Estevam 659a8c21a54SThe etnaviv authors static int __init etnaviv_init(void) 660a8c21a54SThe etnaviv authors { 66145a0faabSFabio Estevam struct platform_device *pdev; 662a8c21a54SThe etnaviv authors int ret; 663246774d1SLucas Stach struct device_node *np; 664a8c21a54SThe etnaviv authors 665a8c21a54SThe etnaviv authors etnaviv_validate_init(); 666a8c21a54SThe etnaviv authors 667a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_gpu_driver); 668a8c21a54SThe etnaviv authors if (ret != 0) 669a8c21a54SThe etnaviv authors return ret; 670a8c21a54SThe etnaviv authors 671a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_platform_driver); 672a8c21a54SThe etnaviv authors if (ret != 0) 67345a0faabSFabio Estevam goto unregister_gpu_driver; 674a8c21a54SThe etnaviv authors 675246774d1SLucas Stach /* 676246774d1SLucas Stach * If the DT contains at least one available GPU device, instantiate 677246774d1SLucas Stach * the DRM platform device. 678246774d1SLucas Stach */ 679246774d1SLucas Stach for_each_compatible_node(np, NULL, "vivante,gc") { 680246774d1SLucas Stach if (!of_device_is_available(np)) 681246774d1SLucas Stach continue; 6821a866306SLucas Stach 6831a866306SLucas Stach pdev = platform_device_alloc("etnaviv", -1); 6841a866306SLucas Stach if (!pdev) { 6851a866306SLucas Stach ret = -ENOMEM; 68645a0faabSFabio Estevam of_node_put(np); 68745a0faabSFabio Estevam goto unregister_platform_driver; 68845a0faabSFabio Estevam } 6891a866306SLucas Stach pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40); 6901a866306SLucas Stach pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; 6911a866306SLucas Stach 6921a866306SLucas Stach /* 6931a866306SLucas Stach * Apply the same DMA configuration to the virtual etnaviv 6941a866306SLucas Stach * device as the GPU we found. This assumes that all Vivante 6951a866306SLucas Stach * GPUs in the system share the same DMA constraints. 6961a866306SLucas Stach */ 6971a866306SLucas Stach of_dma_configure(&pdev->dev, np, true); 6981a866306SLucas Stach 6991a866306SLucas Stach ret = platform_device_add(pdev); 7001a866306SLucas Stach if (ret) { 7011a866306SLucas Stach platform_device_put(pdev); 7021a866306SLucas Stach of_node_put(np); 7031a866306SLucas Stach goto unregister_platform_driver; 7041a866306SLucas Stach } 7051a866306SLucas Stach 70645a0faabSFabio Estevam etnaviv_drm = pdev; 707246774d1SLucas Stach of_node_put(np); 708246774d1SLucas Stach break; 709246774d1SLucas Stach } 710246774d1SLucas Stach 71145a0faabSFabio Estevam return 0; 71245a0faabSFabio Estevam 71345a0faabSFabio Estevam unregister_platform_driver: 71445a0faabSFabio Estevam platform_driver_unregister(&etnaviv_platform_driver); 71545a0faabSFabio Estevam unregister_gpu_driver: 71645a0faabSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 717a8c21a54SThe etnaviv authors return ret; 718a8c21a54SThe etnaviv authors } 719a8c21a54SThe etnaviv authors module_init(etnaviv_init); 720a8c21a54SThe etnaviv authors 721a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void) 722a8c21a54SThe etnaviv authors { 723bf6ba3aeSFabio Estevam platform_device_unregister(etnaviv_drm); 724a8c21a54SThe etnaviv authors platform_driver_unregister(&etnaviv_platform_driver); 725bf6ba3aeSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 726a8c21a54SThe etnaviv authors } 727a8c21a54SThe etnaviv authors module_exit(etnaviv_exit); 728a8c21a54SThe etnaviv authors 729a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); 730a8c21a54SThe etnaviv authors MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); 731a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>"); 732a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver"); 733a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2"); 734a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv"); 735