18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Etnaviv Project 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/component.h> 78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 108c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_ioctl.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_of.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_prime.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "etnaviv_cmdbuf.h" 208c2ecf20Sopenharmony_ci#include "etnaviv_drv.h" 218c2ecf20Sopenharmony_ci#include "etnaviv_gpu.h" 228c2ecf20Sopenharmony_ci#include "etnaviv_gem.h" 238c2ecf20Sopenharmony_ci#include "etnaviv_mmu.h" 248c2ecf20Sopenharmony_ci#include "etnaviv_perfmon.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * DRM operations: 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void load_gpu(struct drm_device *dev) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 348c2ecf20Sopenharmony_ci unsigned int i; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci for (i = 0; i < ETNA_MAX_PIPES; i++) { 378c2ecf20Sopenharmony_ci struct etnaviv_gpu *g = priv->gpu[i]; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (g) { 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci ret = etnaviv_gpu_init(g); 438c2ecf20Sopenharmony_ci if (ret) 448c2ecf20Sopenharmony_ci priv->gpu[i] = NULL; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int etnaviv_open(struct drm_device *dev, struct drm_file *file) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 528c2ecf20Sopenharmony_ci struct etnaviv_file_private *ctx; 538c2ecf20Sopenharmony_ci int ret, i; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 568c2ecf20Sopenharmony_ci if (!ctx) 578c2ecf20Sopenharmony_ci return -ENOMEM; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global, 608c2ecf20Sopenharmony_ci priv->cmdbuf_suballoc); 618c2ecf20Sopenharmony_ci if (!ctx->mmu) { 628c2ecf20Sopenharmony_ci ret = -ENOMEM; 638c2ecf20Sopenharmony_ci goto out_free; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for (i = 0; i < ETNA_MAX_PIPES; i++) { 678c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = priv->gpu[i]; 688c2ecf20Sopenharmony_ci struct drm_gpu_scheduler *sched; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (gpu) { 718c2ecf20Sopenharmony_ci sched = &gpu->sched; 728c2ecf20Sopenharmony_ci drm_sched_entity_init(&ctx->sched_entity[i], 738c2ecf20Sopenharmony_ci DRM_SCHED_PRIORITY_NORMAL, &sched, 748c2ecf20Sopenharmony_ci 1, NULL); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci file->driver_priv = ctx; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciout_free: 838c2ecf20Sopenharmony_ci kfree(ctx); 848c2ecf20Sopenharmony_ci return ret; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 908c2ecf20Sopenharmony_ci struct etnaviv_file_private *ctx = file->driver_priv; 918c2ecf20Sopenharmony_ci unsigned int i; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (i = 0; i < ETNA_MAX_PIPES; i++) { 948c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = priv->gpu[i]; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (gpu) 978c2ecf20Sopenharmony_ci drm_sched_entity_destroy(&ctx->sched_entity[i]); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci etnaviv_iommu_context_put(ctx->mmu); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci kfree(ctx); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * DRM debugfs: 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 1108c2ecf20Sopenharmony_cistatic int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci etnaviv_gem_describe_objects(priv, m); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct drm_printer p = drm_seq_file_printer(m); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci read_lock(&dev->vma_offset_manager->vm_lock); 1248c2ecf20Sopenharmony_ci drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); 1258c2ecf20Sopenharmony_ci read_unlock(&dev->vma_offset_manager->vm_lock); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct drm_printer p = drm_seq_file_printer(m); 1338c2ecf20Sopenharmony_ci struct etnaviv_iommu_context *mmu_context; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev)); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * Lock the GPU to avoid a MMU context switch just now and elevate 1398c2ecf20Sopenharmony_ci * the refcount of the current context to avoid it disappearing from 1408c2ecf20Sopenharmony_ci * under our feet. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 1438c2ecf20Sopenharmony_ci mmu_context = gpu->mmu_context; 1448c2ecf20Sopenharmony_ci if (mmu_context) 1458c2ecf20Sopenharmony_ci etnaviv_iommu_context_get(mmu_context); 1468c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!mmu_context) 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mutex_lock(&mmu_context->lock); 1528c2ecf20Sopenharmony_ci drm_mm_print(&mmu_context->mm, &p); 1538c2ecf20Sopenharmony_ci mutex_unlock(&mmu_context->lock); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci etnaviv_iommu_context_put(mmu_context); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct etnaviv_cmdbuf *buf = &gpu->buffer; 1638c2ecf20Sopenharmony_ci u32 size = buf->size; 1648c2ecf20Sopenharmony_ci u32 *ptr = buf->vaddr; 1658c2ecf20Sopenharmony_ci u32 i; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", 1688c2ecf20Sopenharmony_ci buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf), 1698c2ecf20Sopenharmony_ci size - buf->user_size); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci for (i = 0; i < size / 4; i++) { 1728c2ecf20Sopenharmony_ci if (i && !(i % 4)) 1738c2ecf20Sopenharmony_ci seq_puts(m, "\n"); 1748c2ecf20Sopenharmony_ci if (i % 4 == 0) 1758c2ecf20Sopenharmony_ci seq_printf(m, "\t0x%p: ", ptr + i); 1768c2ecf20Sopenharmony_ci seq_printf(m, "%08x ", *(ptr + i)); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci seq_puts(m, "\n"); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev)); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 1868c2ecf20Sopenharmony_ci etnaviv_buffer_dump(gpu, m); 1878c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int show_unlocked(struct seq_file *m, void *arg) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 1958c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 1968c2ecf20Sopenharmony_ci int (*show)(struct drm_device *dev, struct seq_file *m) = 1978c2ecf20Sopenharmony_ci node->info_ent->data; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return show(dev, m); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int show_each_gpu(struct seq_file *m, void *arg) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *) m->private; 2058c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 2068c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 2078c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 2088c2ecf20Sopenharmony_ci int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) = 2098c2ecf20Sopenharmony_ci node->info_ent->data; 2108c2ecf20Sopenharmony_ci unsigned int i; 2118c2ecf20Sopenharmony_ci int ret = 0; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci for (i = 0; i < ETNA_MAX_PIPES; i++) { 2148c2ecf20Sopenharmony_ci gpu = priv->gpu[i]; 2158c2ecf20Sopenharmony_ci if (!gpu) 2168c2ecf20Sopenharmony_ci continue; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = show(gpu, m); 2198c2ecf20Sopenharmony_ci if (ret < 0) 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic struct drm_info_list etnaviv_debugfs_list[] = { 2278c2ecf20Sopenharmony_ci {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, 2288c2ecf20Sopenharmony_ci {"gem", show_unlocked, 0, etnaviv_gem_show}, 2298c2ecf20Sopenharmony_ci { "mm", show_unlocked, 0, etnaviv_mm_show }, 2308c2ecf20Sopenharmony_ci {"mmu", show_each_gpu, 0, etnaviv_mmu_show}, 2318c2ecf20Sopenharmony_ci {"ring", show_each_gpu, 0, etnaviv_ring_show}, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void etnaviv_debugfs_init(struct drm_minor *minor) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci drm_debugfs_create_files(etnaviv_debugfs_list, 2378c2ecf20Sopenharmony_ci ARRAY_SIZE(etnaviv_debugfs_list), 2388c2ecf20Sopenharmony_ci minor->debugfs_root, minor); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci#endif 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 2438c2ecf20Sopenharmony_ci * DRM ioctls: 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, 2478c2ecf20Sopenharmony_ci struct drm_file *file) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 2508c2ecf20Sopenharmony_ci struct drm_etnaviv_param *args = data; 2518c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (args->pipe >= ETNA_MAX_PIPES) 2548c2ecf20Sopenharmony_ci return -EINVAL; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci gpu = priv->gpu[args->pipe]; 2578c2ecf20Sopenharmony_ci if (!gpu) 2588c2ecf20Sopenharmony_ci return -ENXIO; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return etnaviv_gpu_get_param(gpu, args->param, &args->value); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, 2648c2ecf20Sopenharmony_ci struct drm_file *file) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_new *args = data; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED | 2698c2ecf20Sopenharmony_ci ETNA_BO_FORCE_MMU)) 2708c2ecf20Sopenharmony_ci return -EINVAL; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return etnaviv_gem_new_handle(dev, file, args->size, 2738c2ecf20Sopenharmony_ci args->flags, &args->handle); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, 2778c2ecf20Sopenharmony_ci struct drm_file *file) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_cpu_prep *args = data; 2808c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC)) 2848c2ecf20Sopenharmony_ci return -EINVAL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci obj = drm_gem_object_lookup(file, args->handle); 2878c2ecf20Sopenharmony_ci if (!obj) 2888c2ecf20Sopenharmony_ci return -ENOENT; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, 2988c2ecf20Sopenharmony_ci struct drm_file *file) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_cpu_fini *args = data; 3018c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 3028c2ecf20Sopenharmony_ci int ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (args->flags) 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci obj = drm_gem_object_lookup(file, args->handle); 3088c2ecf20Sopenharmony_ci if (!obj) 3098c2ecf20Sopenharmony_ci return -ENOENT; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ret = etnaviv_gem_cpu_fini(obj); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data, 3198c2ecf20Sopenharmony_ci struct drm_file *file) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_info *args = data; 3228c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (args->pad) 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci obj = drm_gem_object_lookup(file, args->handle); 3298c2ecf20Sopenharmony_ci if (!obj) 3308c2ecf20Sopenharmony_ci return -ENOENT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = etnaviv_gem_mmap_offset(obj, &args->offset); 3338c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return ret; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data, 3398c2ecf20Sopenharmony_ci struct drm_file *file) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct drm_etnaviv_wait_fence *args = data; 3428c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 3438c2ecf20Sopenharmony_ci struct drm_etnaviv_timespec *timeout = &args->timeout; 3448c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (args->pipe >= ETNA_MAX_PIPES) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci gpu = priv->gpu[args->pipe]; 3538c2ecf20Sopenharmony_ci if (!gpu) 3548c2ecf20Sopenharmony_ci return -ENXIO; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (args->flags & ETNA_WAIT_NONBLOCK) 3578c2ecf20Sopenharmony_ci timeout = NULL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence, 3608c2ecf20Sopenharmony_ci timeout); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data, 3648c2ecf20Sopenharmony_ci struct drm_file *file) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_userptr *args = data; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || 3698c2ecf20Sopenharmony_ci args->flags == 0) 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (offset_in_page(args->user_ptr | args->user_size) || 3738c2ecf20Sopenharmony_ci (uintptr_t)args->user_ptr != args->user_ptr || 3748c2ecf20Sopenharmony_ci (u32)args->user_size != args->user_size || 3758c2ecf20Sopenharmony_ci args->user_ptr & ~PAGE_MASK) 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!access_ok((void __user *)(unsigned long)args->user_ptr, 3798c2ecf20Sopenharmony_ci args->user_size)) 3808c2ecf20Sopenharmony_ci return -EFAULT; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return etnaviv_gem_new_userptr(dev, file, args->user_ptr, 3838c2ecf20Sopenharmony_ci args->user_size, args->flags, 3848c2ecf20Sopenharmony_ci &args->handle); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, 3888c2ecf20Sopenharmony_ci struct drm_file *file) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 3918c2ecf20Sopenharmony_ci struct drm_etnaviv_gem_wait *args = data; 3928c2ecf20Sopenharmony_ci struct drm_etnaviv_timespec *timeout = &args->timeout; 3938c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 3948c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 3958c2ecf20Sopenharmony_ci int ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (args->pipe >= ETNA_MAX_PIPES) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci gpu = priv->gpu[args->pipe]; 4048c2ecf20Sopenharmony_ci if (!gpu) 4058c2ecf20Sopenharmony_ci return -ENXIO; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci obj = drm_gem_object_lookup(file, args->handle); 4088c2ecf20Sopenharmony_ci if (!obj) 4098c2ecf20Sopenharmony_ci return -ENOENT; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (args->flags & ETNA_WAIT_NONBLOCK) 4128c2ecf20Sopenharmony_ci timeout = NULL; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = etnaviv_gem_wait_bo(gpu, obj, timeout); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data, 4228c2ecf20Sopenharmony_ci struct drm_file *file) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 4258c2ecf20Sopenharmony_ci struct drm_etnaviv_pm_domain *args = data; 4268c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (args->pipe >= ETNA_MAX_PIPES) 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci gpu = priv->gpu[args->pipe]; 4328c2ecf20Sopenharmony_ci if (!gpu) 4338c2ecf20Sopenharmony_ci return -ENXIO; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return etnaviv_pm_query_dom(gpu, args); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data, 4398c2ecf20Sopenharmony_ci struct drm_file *file) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = dev->dev_private; 4428c2ecf20Sopenharmony_ci struct drm_etnaviv_pm_signal *args = data; 4438c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (args->pipe >= ETNA_MAX_PIPES) 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci gpu = priv->gpu[args->pipe]; 4498c2ecf20Sopenharmony_ci if (!gpu) 4508c2ecf20Sopenharmony_ci return -ENXIO; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return etnaviv_pm_query_sig(gpu, args); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic const struct drm_ioctl_desc etnaviv_ioctls[] = { 4568c2ecf20Sopenharmony_ci#define ETNA_IOCTL(n, func, flags) \ 4578c2ecf20Sopenharmony_ci DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) 4588c2ecf20Sopenharmony_ci ETNA_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), 4598c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_NEW, gem_new, DRM_RENDER_ALLOW), 4608c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_INFO, gem_info, DRM_RENDER_ALLOW), 4618c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW), 4628c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW), 4638c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_RENDER_ALLOW), 4648c2ecf20Sopenharmony_ci ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_RENDER_ALLOW), 4658c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_RENDER_ALLOW), 4668c2ecf20Sopenharmony_ci ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), 4678c2ecf20Sopenharmony_ci ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), 4688c2ecf20Sopenharmony_ci ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic const struct vm_operations_struct vm_ops = { 4728c2ecf20Sopenharmony_ci .fault = etnaviv_gem_fault, 4738c2ecf20Sopenharmony_ci .open = drm_gem_vm_open, 4748c2ecf20Sopenharmony_ci .close = drm_gem_vm_close, 4758c2ecf20Sopenharmony_ci}; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic const struct file_operations fops = { 4788c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4798c2ecf20Sopenharmony_ci .open = drm_open, 4808c2ecf20Sopenharmony_ci .release = drm_release, 4818c2ecf20Sopenharmony_ci .unlocked_ioctl = drm_ioctl, 4828c2ecf20Sopenharmony_ci .compat_ioctl = drm_compat_ioctl, 4838c2ecf20Sopenharmony_ci .poll = drm_poll, 4848c2ecf20Sopenharmony_ci .read = drm_read, 4858c2ecf20Sopenharmony_ci .llseek = no_llseek, 4868c2ecf20Sopenharmony_ci .mmap = etnaviv_gem_mmap, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic struct drm_driver etnaviv_drm_driver = { 4908c2ecf20Sopenharmony_ci .driver_features = DRIVER_GEM | DRIVER_RENDER, 4918c2ecf20Sopenharmony_ci .open = etnaviv_open, 4928c2ecf20Sopenharmony_ci .postclose = etnaviv_postclose, 4938c2ecf20Sopenharmony_ci .gem_free_object_unlocked = etnaviv_gem_free_object, 4948c2ecf20Sopenharmony_ci .gem_vm_ops = &vm_ops, 4958c2ecf20Sopenharmony_ci .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 4968c2ecf20Sopenharmony_ci .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 4978c2ecf20Sopenharmony_ci .gem_prime_pin = etnaviv_gem_prime_pin, 4988c2ecf20Sopenharmony_ci .gem_prime_unpin = etnaviv_gem_prime_unpin, 4998c2ecf20Sopenharmony_ci .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table, 5008c2ecf20Sopenharmony_ci .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table, 5018c2ecf20Sopenharmony_ci .gem_prime_vmap = etnaviv_gem_prime_vmap, 5028c2ecf20Sopenharmony_ci .gem_prime_vunmap = etnaviv_gem_prime_vunmap, 5038c2ecf20Sopenharmony_ci .gem_prime_mmap = etnaviv_gem_prime_mmap, 5048c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 5058c2ecf20Sopenharmony_ci .debugfs_init = etnaviv_debugfs_init, 5068c2ecf20Sopenharmony_ci#endif 5078c2ecf20Sopenharmony_ci .ioctls = etnaviv_ioctls, 5088c2ecf20Sopenharmony_ci .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, 5098c2ecf20Sopenharmony_ci .fops = &fops, 5108c2ecf20Sopenharmony_ci .name = "etnaviv", 5118c2ecf20Sopenharmony_ci .desc = "etnaviv DRM", 5128c2ecf20Sopenharmony_ci .date = "20151214", 5138c2ecf20Sopenharmony_ci .major = 1, 5148c2ecf20Sopenharmony_ci .minor = 3, 5158c2ecf20Sopenharmony_ci}; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * Platform driver: 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_cistatic int etnaviv_bind(struct device *dev) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv; 5238c2ecf20Sopenharmony_ci struct drm_device *drm; 5248c2ecf20Sopenharmony_ci int ret; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci drm = drm_dev_alloc(&etnaviv_drm_driver, dev); 5278c2ecf20Sopenharmony_ci if (IS_ERR(drm)) 5288c2ecf20Sopenharmony_ci return PTR_ERR(drm); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 5318c2ecf20Sopenharmony_ci if (!priv) { 5328c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate private data\n"); 5338c2ecf20Sopenharmony_ci ret = -ENOMEM; 5348c2ecf20Sopenharmony_ci goto out_put; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci drm->dev_private = priv; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dev->dma_parms = &priv->dma_parms; 5398c2ecf20Sopenharmony_ci dma_set_max_seg_size(dev, SZ_2G); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci mutex_init(&priv->gem_lock); 5428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->gem_list); 5438c2ecf20Sopenharmony_ci priv->num_gpus = 0; 5448c2ecf20Sopenharmony_ci priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); 5478c2ecf20Sopenharmony_ci if (IS_ERR(priv->cmdbuf_suballoc)) { 5488c2ecf20Sopenharmony_ci dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); 5498c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->cmdbuf_suballoc); 5508c2ecf20Sopenharmony_ci goto out_free_priv; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci dev_set_drvdata(dev, drm); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ret = component_bind_all(dev, drm); 5568c2ecf20Sopenharmony_ci if (ret < 0) 5578c2ecf20Sopenharmony_ci goto out_destroy_suballoc; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci load_gpu(drm); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ret = drm_dev_register(drm, 0); 5628c2ecf20Sopenharmony_ci if (ret) 5638c2ecf20Sopenharmony_ci goto out_unbind; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ciout_unbind: 5688c2ecf20Sopenharmony_ci component_unbind_all(dev, drm); 5698c2ecf20Sopenharmony_ciout_destroy_suballoc: 5708c2ecf20Sopenharmony_ci etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 5718c2ecf20Sopenharmony_ciout_free_priv: 5728c2ecf20Sopenharmony_ci kfree(priv); 5738c2ecf20Sopenharmony_ciout_put: 5748c2ecf20Sopenharmony_ci drm_dev_put(drm); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return ret; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void etnaviv_unbind(struct device *dev) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct drm_device *drm = dev_get_drvdata(dev); 5828c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = drm->dev_private; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci drm_dev_unregister(drm); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci component_unbind_all(dev, drm); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dev->dma_parms = NULL; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci drm->dev_private = NULL; 5938c2ecf20Sopenharmony_ci kfree(priv); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci drm_dev_put(drm); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic const struct component_master_ops etnaviv_master_ops = { 5998c2ecf20Sopenharmony_ci .bind = etnaviv_bind, 6008c2ecf20Sopenharmony_ci .unbind = etnaviv_unbind, 6018c2ecf20Sopenharmony_ci}; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int compare_of(struct device *dev, void *data) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct device_node *np = data; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return dev->of_node == np; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int compare_str(struct device *dev, void *data) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci return !strcmp(dev_name(dev), data); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int etnaviv_pdev_probe(struct platform_device *pdev) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6188c2ecf20Sopenharmony_ci struct component_match *match = NULL; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (!dev->platform_data) { 6218c2ecf20Sopenharmony_ci struct device_node *core_node; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci for_each_compatible_node(core_node, NULL, "vivante,gc") { 6248c2ecf20Sopenharmony_ci if (!of_device_is_available(core_node)) 6258c2ecf20Sopenharmony_ci continue; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci drm_of_component_match_add(&pdev->dev, &match, 6288c2ecf20Sopenharmony_ci compare_of, core_node); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci char **names = dev->platform_data; 6328c2ecf20Sopenharmony_ci unsigned i; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci for (i = 0; names[i]; i++) 6358c2ecf20Sopenharmony_ci component_match_add(dev, &match, compare_str, names[i]); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return component_master_add_with_match(dev, &etnaviv_master_ops, match); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int etnaviv_pdev_remove(struct platform_device *pdev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci component_master_del(&pdev->dev, &etnaviv_master_ops); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic struct platform_driver etnaviv_platform_driver = { 6498c2ecf20Sopenharmony_ci .probe = etnaviv_pdev_probe, 6508c2ecf20Sopenharmony_ci .remove = etnaviv_pdev_remove, 6518c2ecf20Sopenharmony_ci .driver = { 6528c2ecf20Sopenharmony_ci .name = "etnaviv", 6538c2ecf20Sopenharmony_ci }, 6548c2ecf20Sopenharmony_ci}; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic struct platform_device *etnaviv_drm; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int __init etnaviv_init(void) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct platform_device *pdev; 6618c2ecf20Sopenharmony_ci int ret; 6628c2ecf20Sopenharmony_ci struct device_node *np; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci etnaviv_validate_init(); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci ret = platform_driver_register(&etnaviv_gpu_driver); 6678c2ecf20Sopenharmony_ci if (ret != 0) 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci ret = platform_driver_register(&etnaviv_platform_driver); 6718c2ecf20Sopenharmony_ci if (ret != 0) 6728c2ecf20Sopenharmony_ci goto unregister_gpu_driver; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * If the DT contains at least one available GPU device, instantiate 6768c2ecf20Sopenharmony_ci * the DRM platform device. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "vivante,gc") { 6798c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) 6808c2ecf20Sopenharmony_ci continue; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci pdev = platform_device_alloc("etnaviv", -1); 6838c2ecf20Sopenharmony_ci if (!pdev) { 6848c2ecf20Sopenharmony_ci ret = -ENOMEM; 6858c2ecf20Sopenharmony_ci of_node_put(np); 6868c2ecf20Sopenharmony_ci goto unregister_platform_driver; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40); 6898c2ecf20Sopenharmony_ci pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* 6928c2ecf20Sopenharmony_ci * Apply the same DMA configuration to the virtual etnaviv 6938c2ecf20Sopenharmony_ci * device as the GPU we found. This assumes that all Vivante 6948c2ecf20Sopenharmony_ci * GPUs in the system share the same DMA constraints. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ci of_dma_configure(&pdev->dev, np, true); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ret = platform_device_add(pdev); 6998c2ecf20Sopenharmony_ci if (ret) { 7008c2ecf20Sopenharmony_ci platform_device_put(pdev); 7018c2ecf20Sopenharmony_ci of_node_put(np); 7028c2ecf20Sopenharmony_ci goto unregister_platform_driver; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci etnaviv_drm = pdev; 7068c2ecf20Sopenharmony_ci of_node_put(np); 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ciunregister_platform_driver: 7138c2ecf20Sopenharmony_ci platform_driver_unregister(&etnaviv_platform_driver); 7148c2ecf20Sopenharmony_ciunregister_gpu_driver: 7158c2ecf20Sopenharmony_ci platform_driver_unregister(&etnaviv_gpu_driver); 7168c2ecf20Sopenharmony_ci return ret; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_cimodule_init(etnaviv_init); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic void __exit etnaviv_exit(void) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci platform_device_unregister(etnaviv_drm); 7238c2ecf20Sopenharmony_ci platform_driver_unregister(&etnaviv_platform_driver); 7248c2ecf20Sopenharmony_ci platform_driver_unregister(&etnaviv_gpu_driver); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_cimodule_exit(etnaviv_exit); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); 7298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>"); 7308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>"); 7318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("etnaviv DRM Driver"); 7328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 7338c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:etnaviv"); 734