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