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 { 236a8c21a54SThe etnaviv authors struct drm_device *dev = minor->dev; 237a8c21a54SThe etnaviv authors int ret; 238a8c21a54SThe etnaviv authors 239a8c21a54SThe etnaviv authors ret = drm_debugfs_create_files(etnaviv_debugfs_list, 240a8c21a54SThe etnaviv authors ARRAY_SIZE(etnaviv_debugfs_list), 241a8c21a54SThe etnaviv authors minor->debugfs_root, minor); 242a8c21a54SThe etnaviv authors 243a8c21a54SThe etnaviv authors if (ret) { 244a8c21a54SThe etnaviv authors dev_err(dev->dev, "could not install etnaviv_debugfs_list\n"); 245a8c21a54SThe etnaviv authors return ret; 246a8c21a54SThe etnaviv authors } 247a8c21a54SThe etnaviv authors 248a8c21a54SThe etnaviv authors return ret; 249a8c21a54SThe etnaviv authors } 250a8c21a54SThe etnaviv authors #endif 251a8c21a54SThe etnaviv authors 252a8c21a54SThe etnaviv authors /* 253a8c21a54SThe etnaviv authors * DRM ioctls: 254a8c21a54SThe etnaviv authors */ 255a8c21a54SThe etnaviv authors 256a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, 257a8c21a54SThe etnaviv authors struct drm_file *file) 258a8c21a54SThe etnaviv authors { 259a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 260a8c21a54SThe etnaviv authors struct drm_etnaviv_param *args = data; 261a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 262a8c21a54SThe etnaviv authors 263a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 264a8c21a54SThe etnaviv authors return -EINVAL; 265a8c21a54SThe etnaviv authors 266a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 267a8c21a54SThe etnaviv authors if (!gpu) 268a8c21a54SThe etnaviv authors return -ENXIO; 269a8c21a54SThe etnaviv authors 270a8c21a54SThe etnaviv authors return etnaviv_gpu_get_param(gpu, args->param, &args->value); 271a8c21a54SThe etnaviv authors } 272a8c21a54SThe etnaviv authors 273a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, 274a8c21a54SThe etnaviv authors struct drm_file *file) 275a8c21a54SThe etnaviv authors { 276a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_new *args = data; 277a8c21a54SThe etnaviv authors 278a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED | 279a8c21a54SThe etnaviv authors ETNA_BO_FORCE_MMU)) 280a8c21a54SThe etnaviv authors return -EINVAL; 281a8c21a54SThe etnaviv authors 282a8c21a54SThe etnaviv authors return etnaviv_gem_new_handle(dev, file, args->size, 283a8c21a54SThe etnaviv authors args->flags, &args->handle); 284a8c21a54SThe etnaviv authors } 285a8c21a54SThe etnaviv authors 286a8c21a54SThe etnaviv authors #define TS(t) ((struct timespec){ \ 287a8c21a54SThe etnaviv authors .tv_sec = (t).tv_sec, \ 288a8c21a54SThe etnaviv authors .tv_nsec = (t).tv_nsec \ 289a8c21a54SThe etnaviv authors }) 290a8c21a54SThe etnaviv authors 291a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, 292a8c21a54SThe etnaviv authors struct drm_file *file) 293a8c21a54SThe etnaviv authors { 294a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_prep *args = data; 295a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 296a8c21a54SThe etnaviv authors int ret; 297a8c21a54SThe etnaviv authors 298a8c21a54SThe etnaviv authors if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC)) 299a8c21a54SThe etnaviv authors return -EINVAL; 300a8c21a54SThe etnaviv authors 301a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 302a8c21a54SThe etnaviv authors if (!obj) 303a8c21a54SThe etnaviv authors return -ENOENT; 304a8c21a54SThe etnaviv authors 305a8c21a54SThe etnaviv authors ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout)); 306a8c21a54SThe etnaviv authors 30723d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 308a8c21a54SThe etnaviv authors 309a8c21a54SThe etnaviv authors return ret; 310a8c21a54SThe etnaviv authors } 311a8c21a54SThe etnaviv authors 312a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, 313a8c21a54SThe etnaviv authors struct drm_file *file) 314a8c21a54SThe etnaviv authors { 315a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_fini *args = data; 316a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 317a8c21a54SThe etnaviv authors int ret; 318a8c21a54SThe etnaviv authors 319a8c21a54SThe etnaviv authors if (args->flags) 320a8c21a54SThe etnaviv authors return -EINVAL; 321a8c21a54SThe etnaviv authors 322a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 323a8c21a54SThe etnaviv authors if (!obj) 324a8c21a54SThe etnaviv authors return -ENOENT; 325a8c21a54SThe etnaviv authors 326a8c21a54SThe etnaviv authors ret = etnaviv_gem_cpu_fini(obj); 327a8c21a54SThe etnaviv authors 32823d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 329a8c21a54SThe etnaviv authors 330a8c21a54SThe etnaviv authors return ret; 331a8c21a54SThe etnaviv authors } 332a8c21a54SThe etnaviv authors 333a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data, 334a8c21a54SThe etnaviv authors struct drm_file *file) 335a8c21a54SThe etnaviv authors { 336a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_info *args = data; 337a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 338a8c21a54SThe etnaviv authors int ret; 339a8c21a54SThe etnaviv authors 340a8c21a54SThe etnaviv authors if (args->pad) 341a8c21a54SThe etnaviv authors return -EINVAL; 342a8c21a54SThe etnaviv authors 343a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 344a8c21a54SThe etnaviv authors if (!obj) 345a8c21a54SThe etnaviv authors return -ENOENT; 346a8c21a54SThe etnaviv authors 347a8c21a54SThe etnaviv authors ret = etnaviv_gem_mmap_offset(obj, &args->offset); 34823d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 349a8c21a54SThe etnaviv authors 350a8c21a54SThe etnaviv authors return ret; 351a8c21a54SThe etnaviv authors } 352a8c21a54SThe etnaviv authors 353a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data, 354a8c21a54SThe etnaviv authors struct drm_file *file) 355a8c21a54SThe etnaviv authors { 356a8c21a54SThe etnaviv authors struct drm_etnaviv_wait_fence *args = data; 357a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 358a8c21a54SThe etnaviv authors struct timespec *timeout = &TS(args->timeout); 359a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 360a8c21a54SThe etnaviv authors 361a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 362a8c21a54SThe etnaviv authors return -EINVAL; 363a8c21a54SThe etnaviv authors 364a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 365a8c21a54SThe etnaviv authors return -EINVAL; 366a8c21a54SThe etnaviv authors 367a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 368a8c21a54SThe etnaviv authors if (!gpu) 369a8c21a54SThe etnaviv authors return -ENXIO; 370a8c21a54SThe etnaviv authors 371a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 372a8c21a54SThe etnaviv authors timeout = NULL; 373a8c21a54SThe etnaviv authors 374a8c21a54SThe etnaviv authors return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence, 375a8c21a54SThe etnaviv authors timeout); 376a8c21a54SThe etnaviv authors } 377a8c21a54SThe etnaviv authors 378a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data, 379a8c21a54SThe etnaviv authors struct drm_file *file) 380a8c21a54SThe etnaviv authors { 381a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_userptr *args = data; 382a8c21a54SThe etnaviv authors 383a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || 384a8c21a54SThe etnaviv authors args->flags == 0) 385a8c21a54SThe etnaviv authors return -EINVAL; 386a8c21a54SThe etnaviv authors 387a8c21a54SThe etnaviv authors if (offset_in_page(args->user_ptr | args->user_size) || 388a8c21a54SThe etnaviv authors (uintptr_t)args->user_ptr != args->user_ptr || 389a8c21a54SThe etnaviv authors (u32)args->user_size != args->user_size || 390a8c21a54SThe etnaviv authors args->user_ptr & ~PAGE_MASK) 391a8c21a54SThe etnaviv authors return -EINVAL; 392a8c21a54SThe etnaviv authors 39396d4f267SLinus Torvalds if (!access_ok((void __user *)(unsigned long)args->user_ptr, 394a8c21a54SThe etnaviv authors args->user_size)) 395a8c21a54SThe etnaviv authors return -EFAULT; 396a8c21a54SThe etnaviv authors 397a8c21a54SThe etnaviv authors return etnaviv_gem_new_userptr(dev, file, args->user_ptr, 398a8c21a54SThe etnaviv authors args->user_size, args->flags, 399a8c21a54SThe etnaviv authors &args->handle); 400a8c21a54SThe etnaviv authors } 401a8c21a54SThe etnaviv authors 402a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, 403a8c21a54SThe etnaviv authors struct drm_file *file) 404a8c21a54SThe etnaviv authors { 405a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 406a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_wait *args = data; 407a8c21a54SThe etnaviv authors struct timespec *timeout = &TS(args->timeout); 408a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 409a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 410a8c21a54SThe etnaviv authors int ret; 411a8c21a54SThe etnaviv authors 412a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 413a8c21a54SThe etnaviv authors return -EINVAL; 414a8c21a54SThe etnaviv authors 415a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 416a8c21a54SThe etnaviv authors return -EINVAL; 417a8c21a54SThe etnaviv authors 418a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 419a8c21a54SThe etnaviv authors if (!gpu) 420a8c21a54SThe etnaviv authors return -ENXIO; 421a8c21a54SThe etnaviv authors 422a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 423a8c21a54SThe etnaviv authors if (!obj) 424a8c21a54SThe etnaviv authors return -ENOENT; 425a8c21a54SThe etnaviv authors 426a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 427a8c21a54SThe etnaviv authors timeout = NULL; 428a8c21a54SThe etnaviv authors 429a8c21a54SThe etnaviv authors ret = etnaviv_gem_wait_bo(gpu, obj, timeout); 430a8c21a54SThe etnaviv authors 43123d1dd03SCihangir Akturk drm_gem_object_put_unlocked(obj); 432a8c21a54SThe etnaviv authors 433a8c21a54SThe etnaviv authors return ret; 434a8c21a54SThe etnaviv authors } 435a8c21a54SThe etnaviv authors 4369e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data, 4379e2c2e27SChristian Gmeiner struct drm_file *file) 4389e2c2e27SChristian Gmeiner { 4399e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4409e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_domain *args = data; 4419e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4429e2c2e27SChristian Gmeiner 4439e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4449e2c2e27SChristian Gmeiner return -EINVAL; 4459e2c2e27SChristian Gmeiner 4469e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4479e2c2e27SChristian Gmeiner if (!gpu) 4489e2c2e27SChristian Gmeiner return -ENXIO; 4499e2c2e27SChristian Gmeiner 4509e2c2e27SChristian Gmeiner return etnaviv_pm_query_dom(gpu, args); 4519e2c2e27SChristian Gmeiner } 4529e2c2e27SChristian Gmeiner 4539e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data, 4549e2c2e27SChristian Gmeiner struct drm_file *file) 4559e2c2e27SChristian Gmeiner { 4569e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4579e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_signal *args = data; 4589e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4599e2c2e27SChristian Gmeiner 4609e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4619e2c2e27SChristian Gmeiner return -EINVAL; 4629e2c2e27SChristian Gmeiner 4639e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4649e2c2e27SChristian Gmeiner if (!gpu) 4659e2c2e27SChristian Gmeiner return -ENXIO; 4669e2c2e27SChristian Gmeiner 4679e2c2e27SChristian Gmeiner return etnaviv_pm_query_sig(gpu, args); 4689e2c2e27SChristian Gmeiner } 4699e2c2e27SChristian Gmeiner 470a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = { 471a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \ 472a8c21a54SThe etnaviv authors DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) 473b8602f9aSEmil Velikov ETNA_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), 474b8602f9aSEmil Velikov ETNA_IOCTL(GEM_NEW, gem_new, DRM_RENDER_ALLOW), 475b8602f9aSEmil Velikov ETNA_IOCTL(GEM_INFO, gem_info, DRM_RENDER_ALLOW), 476b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW), 477b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW), 478b8602f9aSEmil Velikov ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_RENDER_ALLOW), 479b8602f9aSEmil Velikov ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_RENDER_ALLOW), 480b8602f9aSEmil Velikov ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_RENDER_ALLOW), 481b8602f9aSEmil Velikov ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), 482b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), 483b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), 484a8c21a54SThe etnaviv authors }; 485a8c21a54SThe etnaviv authors 486a8c21a54SThe etnaviv authors static const struct vm_operations_struct vm_ops = { 487a8c21a54SThe etnaviv authors .fault = etnaviv_gem_fault, 488a8c21a54SThe etnaviv authors .open = drm_gem_vm_open, 489a8c21a54SThe etnaviv authors .close = drm_gem_vm_close, 490a8c21a54SThe etnaviv authors }; 491a8c21a54SThe etnaviv authors 492a8c21a54SThe etnaviv authors static const struct file_operations fops = { 493a8c21a54SThe etnaviv authors .owner = THIS_MODULE, 494a8c21a54SThe etnaviv authors .open = drm_open, 495a8c21a54SThe etnaviv authors .release = drm_release, 496a8c21a54SThe etnaviv authors .unlocked_ioctl = drm_ioctl, 497a8c21a54SThe etnaviv authors .compat_ioctl = drm_compat_ioctl, 498a8c21a54SThe etnaviv authors .poll = drm_poll, 499a8c21a54SThe etnaviv authors .read = drm_read, 500a8c21a54SThe etnaviv authors .llseek = no_llseek, 501a8c21a54SThe etnaviv authors .mmap = etnaviv_gem_mmap, 502a8c21a54SThe etnaviv authors }; 503a8c21a54SThe etnaviv authors 504a8c21a54SThe etnaviv authors static struct drm_driver etnaviv_drm_driver = { 5050424fdafSDaniel Vetter .driver_features = DRIVER_GEM | DRIVER_RENDER, 506a8c21a54SThe etnaviv authors .open = etnaviv_open, 507fda8fa5bSDaniel Vetter .postclose = etnaviv_postclose, 5081d657c58SDaniel Vetter .gem_free_object_unlocked = etnaviv_gem_free_object, 509a8c21a54SThe etnaviv authors .gem_vm_ops = &vm_ops, 510a8c21a54SThe etnaviv authors .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 511a8c21a54SThe etnaviv authors .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 512a8c21a54SThe etnaviv authors .gem_prime_pin = etnaviv_gem_prime_pin, 513a8c21a54SThe etnaviv authors .gem_prime_unpin = etnaviv_gem_prime_unpin, 514a8c21a54SThe etnaviv authors .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table, 515a8c21a54SThe etnaviv authors .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table, 516a8c21a54SThe etnaviv authors .gem_prime_vmap = etnaviv_gem_prime_vmap, 517a8c21a54SThe etnaviv authors .gem_prime_vunmap = etnaviv_gem_prime_vunmap, 5185688e57eSLucas Stach .gem_prime_mmap = etnaviv_gem_prime_mmap, 519a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS 520a8c21a54SThe etnaviv authors .debugfs_init = etnaviv_debugfs_init, 521a8c21a54SThe etnaviv authors #endif 522a8c21a54SThe etnaviv authors .ioctls = etnaviv_ioctls, 523a8c21a54SThe etnaviv authors .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, 524a8c21a54SThe etnaviv authors .fops = &fops, 525a8c21a54SThe etnaviv authors .name = "etnaviv", 526a8c21a54SThe etnaviv authors .desc = "etnaviv DRM", 527a8c21a54SThe etnaviv authors .date = "20151214", 528a8c21a54SThe etnaviv authors .major = 1, 529088880ddSLucas Stach .minor = 3, 530a8c21a54SThe etnaviv authors }; 531a8c21a54SThe etnaviv authors 532a8c21a54SThe etnaviv authors /* 533a8c21a54SThe etnaviv authors * Platform driver: 534a8c21a54SThe etnaviv authors */ 535a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev) 536a8c21a54SThe etnaviv authors { 537a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv; 538a8c21a54SThe etnaviv authors struct drm_device *drm; 539a8c21a54SThe etnaviv authors int ret; 540a8c21a54SThe etnaviv authors 541a8c21a54SThe etnaviv authors drm = drm_dev_alloc(&etnaviv_drm_driver, dev); 5420f288605STom Gundersen if (IS_ERR(drm)) 5430f288605STom Gundersen return PTR_ERR(drm); 544a8c21a54SThe etnaviv authors 545a8c21a54SThe etnaviv authors priv = kzalloc(sizeof(*priv), GFP_KERNEL); 546a8c21a54SThe etnaviv authors if (!priv) { 547a8c21a54SThe etnaviv authors dev_err(dev, "failed to allocate private data\n"); 548a8c21a54SThe etnaviv authors ret = -ENOMEM; 54999e29449SThomas Zimmermann goto out_put; 550a8c21a54SThe etnaviv authors } 551a8c21a54SThe etnaviv authors drm->dev_private = priv; 552a8c21a54SThe etnaviv authors 5531262cc88SRussell King dev->dma_parms = &priv->dma_parms; 5541262cc88SRussell King dma_set_max_seg_size(dev, SZ_2G); 5551262cc88SRussell King 556a8c21a54SThe etnaviv authors mutex_init(&priv->gem_lock); 557a8c21a54SThe etnaviv authors INIT_LIST_HEAD(&priv->gem_list); 558a8c21a54SThe etnaviv authors priv->num_gpus = 0; 559a8c21a54SThe etnaviv authors 560bffe5db8SLucas Stach priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); 561bffe5db8SLucas Stach if (IS_ERR(priv->cmdbuf_suballoc)) { 562bffe5db8SLucas Stach dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); 563bffe5db8SLucas Stach ret = PTR_ERR(priv->cmdbuf_suballoc); 564bffe5db8SLucas Stach goto out_free_priv; 565bffe5db8SLucas Stach } 566bffe5db8SLucas Stach 567a8c21a54SThe etnaviv authors dev_set_drvdata(dev, drm); 568a8c21a54SThe etnaviv authors 569a8c21a54SThe etnaviv authors ret = component_bind_all(dev, drm); 570a8c21a54SThe etnaviv authors if (ret < 0) 571bffe5db8SLucas Stach goto out_destroy_suballoc; 572a8c21a54SThe etnaviv authors 573a8c21a54SThe etnaviv authors load_gpu(drm); 574a8c21a54SThe etnaviv authors 575a8c21a54SThe etnaviv authors ret = drm_dev_register(drm, 0); 576a8c21a54SThe etnaviv authors if (ret) 577bffe5db8SLucas Stach goto out_unbind; 578a8c21a54SThe etnaviv authors 579a8c21a54SThe etnaviv authors return 0; 580a8c21a54SThe etnaviv authors 581bffe5db8SLucas Stach out_unbind: 582a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 583bffe5db8SLucas Stach out_destroy_suballoc: 584bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 585bffe5db8SLucas Stach out_free_priv: 586a8c21a54SThe etnaviv authors kfree(priv); 58799e29449SThomas Zimmermann out_put: 58899e29449SThomas Zimmermann drm_dev_put(drm); 589a8c21a54SThe etnaviv authors 590a8c21a54SThe etnaviv authors return ret; 591a8c21a54SThe etnaviv authors } 592a8c21a54SThe etnaviv authors 593a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev) 594a8c21a54SThe etnaviv authors { 595a8c21a54SThe etnaviv authors struct drm_device *drm = dev_get_drvdata(dev); 596a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = drm->dev_private; 597a8c21a54SThe etnaviv authors 598a8c21a54SThe etnaviv authors drm_dev_unregister(drm); 599a8c21a54SThe etnaviv authors 600a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 601a8c21a54SThe etnaviv authors 6021262cc88SRussell King dev->dma_parms = NULL; 6031262cc88SRussell King 604bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 605bffe5db8SLucas Stach 606a8c21a54SThe etnaviv authors drm->dev_private = NULL; 607a8c21a54SThe etnaviv authors kfree(priv); 608a8c21a54SThe etnaviv authors 60999e29449SThomas Zimmermann drm_dev_put(drm); 610a8c21a54SThe etnaviv authors } 611a8c21a54SThe etnaviv authors 612a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = { 613a8c21a54SThe etnaviv authors .bind = etnaviv_bind, 614a8c21a54SThe etnaviv authors .unbind = etnaviv_unbind, 615a8c21a54SThe etnaviv authors }; 616a8c21a54SThe etnaviv authors 617a8c21a54SThe etnaviv authors static int compare_of(struct device *dev, void *data) 618a8c21a54SThe etnaviv authors { 619a8c21a54SThe etnaviv authors struct device_node *np = data; 620a8c21a54SThe etnaviv authors 621a8c21a54SThe etnaviv authors return dev->of_node == np; 622a8c21a54SThe etnaviv authors } 623a8c21a54SThe etnaviv authors 624a8c21a54SThe etnaviv authors static int compare_str(struct device *dev, void *data) 625a8c21a54SThe etnaviv authors { 626a8c21a54SThe etnaviv authors return !strcmp(dev_name(dev), data); 627a8c21a54SThe etnaviv authors } 628a8c21a54SThe etnaviv authors 629a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev) 630a8c21a54SThe etnaviv authors { 631a8c21a54SThe etnaviv authors struct device *dev = &pdev->dev; 632a8c21a54SThe etnaviv authors struct component_match *match = NULL; 633a8c21a54SThe etnaviv authors 634246774d1SLucas Stach if (!dev->platform_data) { 635a8c21a54SThe etnaviv authors struct device_node *core_node; 636a8c21a54SThe etnaviv authors 637246774d1SLucas Stach for_each_compatible_node(core_node, NULL, "vivante,gc") { 638246774d1SLucas Stach if (!of_device_is_available(core_node)) 639246774d1SLucas Stach continue; 640a8c21a54SThe etnaviv authors 64197ac0e47SRussell King drm_of_component_match_add(&pdev->dev, &match, 64297ac0e47SRussell King compare_of, core_node); 643a8c21a54SThe etnaviv authors } 644246774d1SLucas Stach } else { 645a8c21a54SThe etnaviv authors char **names = dev->platform_data; 646a8c21a54SThe etnaviv authors unsigned i; 647a8c21a54SThe etnaviv authors 648a8c21a54SThe etnaviv authors for (i = 0; names[i]; i++) 649a8c21a54SThe etnaviv authors component_match_add(dev, &match, compare_str, names[i]); 650a8c21a54SThe etnaviv authors } 651a8c21a54SThe etnaviv authors 652a8c21a54SThe etnaviv authors return component_master_add_with_match(dev, &etnaviv_master_ops, match); 653a8c21a54SThe etnaviv authors } 654a8c21a54SThe etnaviv authors 655a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev) 656a8c21a54SThe etnaviv authors { 657a8c21a54SThe etnaviv authors component_master_del(&pdev->dev, &etnaviv_master_ops); 658a8c21a54SThe etnaviv authors 659a8c21a54SThe etnaviv authors return 0; 660a8c21a54SThe etnaviv authors } 661a8c21a54SThe etnaviv authors 662a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = { 663a8c21a54SThe etnaviv authors .probe = etnaviv_pdev_probe, 664a8c21a54SThe etnaviv authors .remove = etnaviv_pdev_remove, 665a8c21a54SThe etnaviv authors .driver = { 666a8c21a54SThe etnaviv authors .name = "etnaviv", 667a8c21a54SThe etnaviv authors }, 668a8c21a54SThe etnaviv authors }; 669a8c21a54SThe etnaviv authors 67045a0faabSFabio Estevam static struct platform_device *etnaviv_drm; 67145a0faabSFabio Estevam 672a8c21a54SThe etnaviv authors static int __init etnaviv_init(void) 673a8c21a54SThe etnaviv authors { 67445a0faabSFabio Estevam struct platform_device *pdev; 675a8c21a54SThe etnaviv authors int ret; 676246774d1SLucas Stach struct device_node *np; 677a8c21a54SThe etnaviv authors 678a8c21a54SThe etnaviv authors etnaviv_validate_init(); 679a8c21a54SThe etnaviv authors 680a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_gpu_driver); 681a8c21a54SThe etnaviv authors if (ret != 0) 682a8c21a54SThe etnaviv authors return ret; 683a8c21a54SThe etnaviv authors 684a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_platform_driver); 685a8c21a54SThe etnaviv authors if (ret != 0) 68645a0faabSFabio Estevam goto unregister_gpu_driver; 687a8c21a54SThe etnaviv authors 688246774d1SLucas Stach /* 689246774d1SLucas Stach * If the DT contains at least one available GPU device, instantiate 690246774d1SLucas Stach * the DRM platform device. 691246774d1SLucas Stach */ 692246774d1SLucas Stach for_each_compatible_node(np, NULL, "vivante,gc") { 693246774d1SLucas Stach if (!of_device_is_available(np)) 694246774d1SLucas Stach continue; 6951a866306SLucas Stach 6961a866306SLucas Stach pdev = platform_device_alloc("etnaviv", -1); 6971a866306SLucas Stach if (!pdev) { 6981a866306SLucas Stach ret = -ENOMEM; 69945a0faabSFabio Estevam of_node_put(np); 70045a0faabSFabio Estevam goto unregister_platform_driver; 70145a0faabSFabio Estevam } 7021a866306SLucas Stach pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40); 7031a866306SLucas Stach pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; 7041a866306SLucas Stach 7051a866306SLucas Stach /* 7061a866306SLucas Stach * Apply the same DMA configuration to the virtual etnaviv 7071a866306SLucas Stach * device as the GPU we found. This assumes that all Vivante 7081a866306SLucas Stach * GPUs in the system share the same DMA constraints. 7091a866306SLucas Stach */ 7101a866306SLucas Stach of_dma_configure(&pdev->dev, np, true); 7111a866306SLucas Stach 7121a866306SLucas Stach ret = platform_device_add(pdev); 7131a866306SLucas Stach if (ret) { 7141a866306SLucas Stach platform_device_put(pdev); 7151a866306SLucas Stach of_node_put(np); 7161a866306SLucas Stach goto unregister_platform_driver; 7171a866306SLucas Stach } 7181a866306SLucas Stach 71945a0faabSFabio Estevam etnaviv_drm = pdev; 720246774d1SLucas Stach of_node_put(np); 721246774d1SLucas Stach break; 722246774d1SLucas Stach } 723246774d1SLucas Stach 72445a0faabSFabio Estevam return 0; 72545a0faabSFabio Estevam 72645a0faabSFabio Estevam unregister_platform_driver: 72745a0faabSFabio Estevam platform_driver_unregister(&etnaviv_platform_driver); 72845a0faabSFabio Estevam unregister_gpu_driver: 72945a0faabSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 730a8c21a54SThe etnaviv authors return ret; 731a8c21a54SThe etnaviv authors } 732a8c21a54SThe etnaviv authors module_init(etnaviv_init); 733a8c21a54SThe etnaviv authors 734a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void) 735a8c21a54SThe etnaviv authors { 736bf6ba3aeSFabio Estevam platform_device_unregister(etnaviv_drm); 737a8c21a54SThe etnaviv authors platform_driver_unregister(&etnaviv_platform_driver); 738bf6ba3aeSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 739a8c21a54SThe etnaviv authors } 740a8c21a54SThe etnaviv authors module_exit(etnaviv_exit); 741a8c21a54SThe etnaviv authors 742a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); 743a8c21a54SThe etnaviv authors MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>"); 744a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>"); 745a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver"); 746a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2"); 747a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv"); 748