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 
2347ce84471SWambui Karuga static void 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 }
240a8c21a54SThe etnaviv authors #endif
241a8c21a54SThe etnaviv authors 
242a8c21a54SThe etnaviv authors /*
243a8c21a54SThe etnaviv authors  * DRM ioctls:
244a8c21a54SThe etnaviv authors  */
245a8c21a54SThe etnaviv authors 
246a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
247a8c21a54SThe etnaviv authors 		struct drm_file *file)
248a8c21a54SThe etnaviv authors {
249a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
250a8c21a54SThe etnaviv authors 	struct drm_etnaviv_param *args = data;
251a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
252a8c21a54SThe etnaviv authors 
253a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
254a8c21a54SThe etnaviv authors 		return -EINVAL;
255a8c21a54SThe etnaviv authors 
256a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
257a8c21a54SThe etnaviv authors 	if (!gpu)
258a8c21a54SThe etnaviv authors 		return -ENXIO;
259a8c21a54SThe etnaviv authors 
260a8c21a54SThe etnaviv authors 	return etnaviv_gpu_get_param(gpu, args->param, &args->value);
261a8c21a54SThe etnaviv authors }
262a8c21a54SThe etnaviv authors 
263a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
264a8c21a54SThe etnaviv authors 		struct drm_file *file)
265a8c21a54SThe etnaviv authors {
266a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_new *args = data;
267a8c21a54SThe etnaviv authors 
268a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED |
269a8c21a54SThe etnaviv authors 			    ETNA_BO_FORCE_MMU))
270a8c21a54SThe etnaviv authors 		return -EINVAL;
271a8c21a54SThe etnaviv authors 
272a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_handle(dev, file, args->size,
273a8c21a54SThe etnaviv authors 			args->flags, &args->handle);
274a8c21a54SThe etnaviv authors }
275a8c21a54SThe etnaviv authors 
276a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
277a8c21a54SThe etnaviv authors 		struct drm_file *file)
278a8c21a54SThe etnaviv authors {
279a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_prep *args = data;
280a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
281a8c21a54SThe etnaviv authors 	int ret;
282a8c21a54SThe etnaviv authors 
283a8c21a54SThe etnaviv authors 	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
284a8c21a54SThe etnaviv authors 		return -EINVAL;
285a8c21a54SThe etnaviv authors 
286a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
287a8c21a54SThe etnaviv authors 	if (!obj)
288a8c21a54SThe etnaviv authors 		return -ENOENT;
289a8c21a54SThe etnaviv authors 
29038c4a4cfSArnd Bergmann 	ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout);
291a8c21a54SThe etnaviv authors 
2926780bf32SEmil Velikov 	drm_gem_object_put(obj);
293a8c21a54SThe etnaviv authors 
294a8c21a54SThe etnaviv authors 	return ret;
295a8c21a54SThe etnaviv authors }
296a8c21a54SThe etnaviv authors 
297a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
298a8c21a54SThe etnaviv authors 		struct drm_file *file)
299a8c21a54SThe etnaviv authors {
300a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_fini *args = data;
301a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
302a8c21a54SThe etnaviv authors 	int ret;
303a8c21a54SThe etnaviv authors 
304a8c21a54SThe etnaviv authors 	if (args->flags)
305a8c21a54SThe etnaviv authors 		return -EINVAL;
306a8c21a54SThe etnaviv authors 
307a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
308a8c21a54SThe etnaviv authors 	if (!obj)
309a8c21a54SThe etnaviv authors 		return -ENOENT;
310a8c21a54SThe etnaviv authors 
311a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_cpu_fini(obj);
312a8c21a54SThe etnaviv authors 
3136780bf32SEmil Velikov 	drm_gem_object_put(obj);
314a8c21a54SThe etnaviv authors 
315a8c21a54SThe etnaviv authors 	return ret;
316a8c21a54SThe etnaviv authors }
317a8c21a54SThe etnaviv authors 
318a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
319a8c21a54SThe etnaviv authors 		struct drm_file *file)
320a8c21a54SThe etnaviv authors {
321a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_info *args = data;
322a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
323a8c21a54SThe etnaviv authors 	int ret;
324a8c21a54SThe etnaviv authors 
325a8c21a54SThe etnaviv authors 	if (args->pad)
326a8c21a54SThe etnaviv authors 		return -EINVAL;
327a8c21a54SThe etnaviv authors 
328a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
329a8c21a54SThe etnaviv authors 	if (!obj)
330a8c21a54SThe etnaviv authors 		return -ENOENT;
331a8c21a54SThe etnaviv authors 
332a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
3336780bf32SEmil Velikov 	drm_gem_object_put(obj);
334a8c21a54SThe etnaviv authors 
335a8c21a54SThe etnaviv authors 	return ret;
336a8c21a54SThe etnaviv authors }
337a8c21a54SThe etnaviv authors 
338a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
339a8c21a54SThe etnaviv authors 		struct drm_file *file)
340a8c21a54SThe etnaviv authors {
341a8c21a54SThe etnaviv authors 	struct drm_etnaviv_wait_fence *args = data;
342a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
34338c4a4cfSArnd Bergmann 	struct drm_etnaviv_timespec *timeout = &args->timeout;
344a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
345a8c21a54SThe etnaviv authors 
346a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
347a8c21a54SThe etnaviv authors 		return -EINVAL;
348a8c21a54SThe etnaviv authors 
349a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
350a8c21a54SThe etnaviv authors 		return -EINVAL;
351a8c21a54SThe etnaviv authors 
352a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
353a8c21a54SThe etnaviv authors 	if (!gpu)
354a8c21a54SThe etnaviv authors 		return -ENXIO;
355a8c21a54SThe etnaviv authors 
356a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
357a8c21a54SThe etnaviv authors 		timeout = NULL;
358a8c21a54SThe etnaviv authors 
359a8c21a54SThe etnaviv authors 	return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
360a8c21a54SThe etnaviv authors 						    timeout);
361a8c21a54SThe etnaviv authors }
362a8c21a54SThe etnaviv authors 
363a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
364a8c21a54SThe etnaviv authors 	struct drm_file *file)
365a8c21a54SThe etnaviv authors {
366a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_userptr *args = data;
367a8c21a54SThe etnaviv authors 
368a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
369a8c21a54SThe etnaviv authors 	    args->flags == 0)
370a8c21a54SThe etnaviv authors 		return -EINVAL;
371a8c21a54SThe etnaviv authors 
372a8c21a54SThe etnaviv authors 	if (offset_in_page(args->user_ptr | args->user_size) ||
373a8c21a54SThe etnaviv authors 	    (uintptr_t)args->user_ptr != args->user_ptr ||
374a8c21a54SThe etnaviv authors 	    (u32)args->user_size != args->user_size ||
375a8c21a54SThe etnaviv authors 	    args->user_ptr & ~PAGE_MASK)
376a8c21a54SThe etnaviv authors 		return -EINVAL;
377a8c21a54SThe etnaviv authors 
37896d4f267SLinus Torvalds 	if (!access_ok((void __user *)(unsigned long)args->user_ptr,
379a8c21a54SThe etnaviv authors 		       args->user_size))
380a8c21a54SThe etnaviv authors 		return -EFAULT;
381a8c21a54SThe etnaviv authors 
382a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
383a8c21a54SThe etnaviv authors 				       args->user_size, args->flags,
384a8c21a54SThe etnaviv authors 				       &args->handle);
385a8c21a54SThe etnaviv authors }
386a8c21a54SThe etnaviv authors 
387a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
388a8c21a54SThe etnaviv authors 	struct drm_file *file)
389a8c21a54SThe etnaviv authors {
390a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
391a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_wait *args = data;
39238c4a4cfSArnd Bergmann 	struct drm_etnaviv_timespec *timeout = &args->timeout;
393a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
394a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
395a8c21a54SThe etnaviv authors 	int ret;
396a8c21a54SThe etnaviv authors 
397a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
398a8c21a54SThe etnaviv authors 		return -EINVAL;
399a8c21a54SThe etnaviv authors 
400a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
401a8c21a54SThe etnaviv authors 		return -EINVAL;
402a8c21a54SThe etnaviv authors 
403a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
404a8c21a54SThe etnaviv authors 	if (!gpu)
405a8c21a54SThe etnaviv authors 		return -ENXIO;
406a8c21a54SThe etnaviv authors 
407a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
408a8c21a54SThe etnaviv authors 	if (!obj)
409a8c21a54SThe etnaviv authors 		return -ENOENT;
410a8c21a54SThe etnaviv authors 
411a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
412a8c21a54SThe etnaviv authors 		timeout = NULL;
413a8c21a54SThe etnaviv authors 
414a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_wait_bo(gpu, obj, timeout);
415a8c21a54SThe etnaviv authors 
4166780bf32SEmil Velikov 	drm_gem_object_put(obj);
417a8c21a54SThe etnaviv authors 
418a8c21a54SThe etnaviv authors 	return ret;
419a8c21a54SThe etnaviv authors }
420a8c21a54SThe etnaviv authors 
4219e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
4229e2c2e27SChristian Gmeiner 	struct drm_file *file)
4239e2c2e27SChristian Gmeiner {
4249e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4259e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_domain *args = data;
4269e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4279e2c2e27SChristian Gmeiner 
4289e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4299e2c2e27SChristian Gmeiner 		return -EINVAL;
4309e2c2e27SChristian Gmeiner 
4319e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4329e2c2e27SChristian Gmeiner 	if (!gpu)
4339e2c2e27SChristian Gmeiner 		return -ENXIO;
4349e2c2e27SChristian Gmeiner 
4359e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_dom(gpu, args);
4369e2c2e27SChristian Gmeiner }
4379e2c2e27SChristian Gmeiner 
4389e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data,
4399e2c2e27SChristian Gmeiner 	struct drm_file *file)
4409e2c2e27SChristian Gmeiner {
4419e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4429e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_signal *args = data;
4439e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4449e2c2e27SChristian Gmeiner 
4459e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4469e2c2e27SChristian Gmeiner 		return -EINVAL;
4479e2c2e27SChristian Gmeiner 
4489e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4499e2c2e27SChristian Gmeiner 	if (!gpu)
4509e2c2e27SChristian Gmeiner 		return -ENXIO;
4519e2c2e27SChristian Gmeiner 
4529e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_sig(gpu, args);
4539e2c2e27SChristian Gmeiner }
4549e2c2e27SChristian Gmeiner 
455a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = {
456a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \
457a8c21a54SThe etnaviv authors 	DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
458b8602f9aSEmil Velikov 	ETNA_IOCTL(GET_PARAM,    get_param,    DRM_RENDER_ALLOW),
459b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_RENDER_ALLOW),
460b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_RENDER_ALLOW),
461b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW),
462b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW),
463b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_RENDER_ALLOW),
464b8602f9aSEmil Velikov 	ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_RENDER_ALLOW),
465b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_RENDER_ALLOW),
466b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_RENDER_ALLOW),
467b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW),
468b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW),
469a8c21a54SThe etnaviv authors };
470a8c21a54SThe etnaviv authors 
47181fd23e2SThomas Zimmermann DEFINE_DRM_GEM_FOPS(fops);
472a8c21a54SThe etnaviv authors 
47370a59dd8SDaniel Vetter static const struct drm_driver etnaviv_drm_driver = {
4740424fdafSDaniel Vetter 	.driver_features    = DRIVER_GEM | DRIVER_RENDER,
475a8c21a54SThe etnaviv authors 	.open               = etnaviv_open,
476fda8fa5bSDaniel Vetter 	.postclose           = etnaviv_postclose,
477a8c21a54SThe etnaviv authors 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
478a8c21a54SThe etnaviv authors 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
479a8c21a54SThe etnaviv authors 	.gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
48081fd23e2SThomas Zimmermann 	.gem_prime_mmap     = drm_gem_prime_mmap,
481a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS
482a8c21a54SThe etnaviv authors 	.debugfs_init       = etnaviv_debugfs_init,
483a8c21a54SThe etnaviv authors #endif
484a8c21a54SThe etnaviv authors 	.ioctls             = etnaviv_ioctls,
485a8c21a54SThe etnaviv authors 	.num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
486a8c21a54SThe etnaviv authors 	.fops               = &fops,
487a8c21a54SThe etnaviv authors 	.name               = "etnaviv",
488a8c21a54SThe etnaviv authors 	.desc               = "etnaviv DRM",
489a8c21a54SThe etnaviv authors 	.date               = "20151214",
490a8c21a54SThe etnaviv authors 	.major              = 1,
491088880ddSLucas Stach 	.minor              = 3,
492a8c21a54SThe etnaviv authors };
493a8c21a54SThe etnaviv authors 
494a8c21a54SThe etnaviv authors /*
495a8c21a54SThe etnaviv authors  * Platform driver:
496a8c21a54SThe etnaviv authors  */
497a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev)
498a8c21a54SThe etnaviv authors {
499a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv;
500a8c21a54SThe etnaviv authors 	struct drm_device *drm;
501a8c21a54SThe etnaviv authors 	int ret;
502a8c21a54SThe etnaviv authors 
503a8c21a54SThe etnaviv authors 	drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
5040f288605STom Gundersen 	if (IS_ERR(drm))
5050f288605STom Gundersen 		return PTR_ERR(drm);
506a8c21a54SThe etnaviv authors 
507a8c21a54SThe etnaviv authors 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
508a8c21a54SThe etnaviv authors 	if (!priv) {
509a8c21a54SThe etnaviv authors 		dev_err(dev, "failed to allocate private data\n");
510a8c21a54SThe etnaviv authors 		ret = -ENOMEM;
51199e29449SThomas Zimmermann 		goto out_put;
512a8c21a54SThe etnaviv authors 	}
513a8c21a54SThe etnaviv authors 	drm->dev_private = priv;
514a8c21a54SThe etnaviv authors 
5151262cc88SRussell King 	dma_set_max_seg_size(dev, SZ_2G);
5161262cc88SRussell King 
517a8c21a54SThe etnaviv authors 	mutex_init(&priv->gem_lock);
518a8c21a54SThe etnaviv authors 	INIT_LIST_HEAD(&priv->gem_list);
519a8c21a54SThe etnaviv authors 	priv->num_gpus = 0;
520b72af445SLucas Stach 	priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
521a8c21a54SThe etnaviv authors 
522bffe5db8SLucas Stach 	priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
523bffe5db8SLucas Stach 	if (IS_ERR(priv->cmdbuf_suballoc)) {
524bffe5db8SLucas Stach 		dev_err(drm->dev, "Failed to create cmdbuf suballocator\n");
525bffe5db8SLucas Stach 		ret = PTR_ERR(priv->cmdbuf_suballoc);
526bffe5db8SLucas Stach 		goto out_free_priv;
527bffe5db8SLucas Stach 	}
528bffe5db8SLucas Stach 
529a8c21a54SThe etnaviv authors 	dev_set_drvdata(dev, drm);
530a8c21a54SThe etnaviv authors 
531a8c21a54SThe etnaviv authors 	ret = component_bind_all(dev, drm);
532a8c21a54SThe etnaviv authors 	if (ret < 0)
533bffe5db8SLucas Stach 		goto out_destroy_suballoc;
534a8c21a54SThe etnaviv authors 
535a8c21a54SThe etnaviv authors 	load_gpu(drm);
536a8c21a54SThe etnaviv authors 
537a8c21a54SThe etnaviv authors 	ret = drm_dev_register(drm, 0);
538a8c21a54SThe etnaviv authors 	if (ret)
539bffe5db8SLucas Stach 		goto out_unbind;
540a8c21a54SThe etnaviv authors 
541a8c21a54SThe etnaviv authors 	return 0;
542a8c21a54SThe etnaviv authors 
543bffe5db8SLucas Stach out_unbind:
544a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
545bffe5db8SLucas Stach out_destroy_suballoc:
546bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
547bffe5db8SLucas Stach out_free_priv:
548a8c21a54SThe etnaviv authors 	kfree(priv);
54999e29449SThomas Zimmermann out_put:
55099e29449SThomas Zimmermann 	drm_dev_put(drm);
551a8c21a54SThe etnaviv authors 
552a8c21a54SThe etnaviv authors 	return ret;
553a8c21a54SThe etnaviv authors }
554a8c21a54SThe etnaviv authors 
555a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev)
556a8c21a54SThe etnaviv authors {
557a8c21a54SThe etnaviv authors 	struct drm_device *drm = dev_get_drvdata(dev);
558a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = drm->dev_private;
559a8c21a54SThe etnaviv authors 
560a8c21a54SThe etnaviv authors 	drm_dev_unregister(drm);
561a8c21a54SThe etnaviv authors 
562a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
563a8c21a54SThe etnaviv authors 
564bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
565bffe5db8SLucas Stach 
566a8c21a54SThe etnaviv authors 	drm->dev_private = NULL;
567a8c21a54SThe etnaviv authors 	kfree(priv);
568a8c21a54SThe etnaviv authors 
56999e29449SThomas Zimmermann 	drm_dev_put(drm);
570a8c21a54SThe etnaviv authors }
571a8c21a54SThe etnaviv authors 
572a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = {
573a8c21a54SThe etnaviv authors 	.bind = etnaviv_bind,
574a8c21a54SThe etnaviv authors 	.unbind = etnaviv_unbind,
575a8c21a54SThe etnaviv authors };
576a8c21a54SThe etnaviv authors 
577a8c21a54SThe etnaviv authors static int compare_of(struct device *dev, void *data)
578a8c21a54SThe etnaviv authors {
579a8c21a54SThe etnaviv authors 	struct device_node *np = data;
580a8c21a54SThe etnaviv authors 
581a8c21a54SThe etnaviv authors 	return dev->of_node == np;
582a8c21a54SThe etnaviv authors }
583a8c21a54SThe etnaviv authors 
584a8c21a54SThe etnaviv authors static int compare_str(struct device *dev, void *data)
585a8c21a54SThe etnaviv authors {
586a8c21a54SThe etnaviv authors 	return !strcmp(dev_name(dev), data);
587a8c21a54SThe etnaviv authors }
588a8c21a54SThe etnaviv authors 
589a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev)
590a8c21a54SThe etnaviv authors {
591a8c21a54SThe etnaviv authors 	struct device *dev = &pdev->dev;
5920ea057a9SMichael Walle 	struct device_node *first_node = NULL;
593a8c21a54SThe etnaviv authors 	struct component_match *match = NULL;
594a8c21a54SThe etnaviv authors 
595246774d1SLucas Stach 	if (!dev->platform_data) {
596a8c21a54SThe etnaviv authors 		struct device_node *core_node;
597a8c21a54SThe etnaviv authors 
598246774d1SLucas Stach 		for_each_compatible_node(core_node, NULL, "vivante,gc") {
599246774d1SLucas Stach 			if (!of_device_is_available(core_node))
600246774d1SLucas Stach 				continue;
601a8c21a54SThe etnaviv authors 
6020ea057a9SMichael Walle 			if (!first_node)
6030ea057a9SMichael Walle 				first_node = core_node;
6040ea057a9SMichael Walle 
60597ac0e47SRussell King 			drm_of_component_match_add(&pdev->dev, &match,
60697ac0e47SRussell King 						   compare_of, core_node);
607a8c21a54SThe etnaviv authors 		}
608246774d1SLucas Stach 	} else {
609a8c21a54SThe etnaviv authors 		char **names = dev->platform_data;
610a8c21a54SThe etnaviv authors 		unsigned i;
611a8c21a54SThe etnaviv authors 
612a8c21a54SThe etnaviv authors 		for (i = 0; names[i]; i++)
613a8c21a54SThe etnaviv authors 			component_match_add(dev, &match, compare_str, names[i]);
614a8c21a54SThe etnaviv authors 	}
615a8c21a54SThe etnaviv authors 
6160ea057a9SMichael Walle 	/*
617*f5be833dSMichael Walle 	 * PTA and MTLB can have 40 bit base addresses, but
618*f5be833dSMichael Walle 	 * unfortunately, an entry in the MTLB can only point to a
619*f5be833dSMichael Walle 	 * 32 bit base address of a STLB. Moreover, to initialize the
620*f5be833dSMichael Walle 	 * MMU we need a command buffer with a 32 bit address because
621*f5be833dSMichael Walle 	 * without an MMU there is only an indentity mapping between
622*f5be833dSMichael Walle 	 * the internal 32 bit addresses and the bus addresses.
623*f5be833dSMichael Walle 	 *
624*f5be833dSMichael Walle 	 * To make things easy, we set the dma_coherent_mask to 32
625*f5be833dSMichael Walle 	 * bit to make sure we are allocating the command buffers and
626*f5be833dSMichael Walle 	 * TLBs in the lower 4 GiB address space.
627*f5be833dSMichael Walle 	 */
628*f5be833dSMichael Walle 	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)) ||
629*f5be833dSMichael Walle 	    dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) {
630*f5be833dSMichael Walle 		dev_dbg(&pdev->dev, "No suitable DMA available\n");
631*f5be833dSMichael Walle 		return -ENODEV;
632*f5be833dSMichael Walle 	}
633*f5be833dSMichael Walle 
634*f5be833dSMichael Walle 	/*
6350ea057a9SMichael Walle 	 * Apply the same DMA configuration to the virtual etnaviv
6360ea057a9SMichael Walle 	 * device as the GPU we found. This assumes that all Vivante
6370ea057a9SMichael Walle 	 * GPUs in the system share the same DMA constraints.
6380ea057a9SMichael Walle 	 */
6390ea057a9SMichael Walle 	if (first_node)
6400ea057a9SMichael Walle 		of_dma_configure(&pdev->dev, first_node, true);
6410ea057a9SMichael Walle 
642a8c21a54SThe etnaviv authors 	return component_master_add_with_match(dev, &etnaviv_master_ops, match);
643a8c21a54SThe etnaviv authors }
644a8c21a54SThe etnaviv authors 
645a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev)
646a8c21a54SThe etnaviv authors {
647a8c21a54SThe etnaviv authors 	component_master_del(&pdev->dev, &etnaviv_master_ops);
648a8c21a54SThe etnaviv authors 
649a8c21a54SThe etnaviv authors 	return 0;
650a8c21a54SThe etnaviv authors }
651a8c21a54SThe etnaviv authors 
652a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = {
653a8c21a54SThe etnaviv authors 	.probe      = etnaviv_pdev_probe,
654a8c21a54SThe etnaviv authors 	.remove     = etnaviv_pdev_remove,
655a8c21a54SThe etnaviv authors 	.driver     = {
656a8c21a54SThe etnaviv authors 		.name   = "etnaviv",
657a8c21a54SThe etnaviv authors 	},
658a8c21a54SThe etnaviv authors };
659a8c21a54SThe etnaviv authors 
66045a0faabSFabio Estevam static struct platform_device *etnaviv_drm;
66145a0faabSFabio Estevam 
662a8c21a54SThe etnaviv authors static int __init etnaviv_init(void)
663a8c21a54SThe etnaviv authors {
66445a0faabSFabio Estevam 	struct platform_device *pdev;
665a8c21a54SThe etnaviv authors 	int ret;
666246774d1SLucas Stach 	struct device_node *np;
667a8c21a54SThe etnaviv authors 
668a8c21a54SThe etnaviv authors 	etnaviv_validate_init();
669a8c21a54SThe etnaviv authors 
670a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_gpu_driver);
671a8c21a54SThe etnaviv authors 	if (ret != 0)
672a8c21a54SThe etnaviv authors 		return ret;
673a8c21a54SThe etnaviv authors 
674a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_platform_driver);
675a8c21a54SThe etnaviv authors 	if (ret != 0)
67645a0faabSFabio Estevam 		goto unregister_gpu_driver;
677a8c21a54SThe etnaviv authors 
678246774d1SLucas Stach 	/*
679246774d1SLucas Stach 	 * If the DT contains at least one available GPU device, instantiate
680246774d1SLucas Stach 	 * the DRM platform device.
681246774d1SLucas Stach 	 */
682246774d1SLucas Stach 	for_each_compatible_node(np, NULL, "vivante,gc") {
683246774d1SLucas Stach 		if (!of_device_is_available(np))
684246774d1SLucas Stach 			continue;
6851a866306SLucas Stach 
6863c7e0cccSMichael Walle 		pdev = platform_device_alloc("etnaviv", PLATFORM_DEVID_NONE);
6871a866306SLucas Stach 		if (!pdev) {
6881a866306SLucas Stach 			ret = -ENOMEM;
68945a0faabSFabio Estevam 			of_node_put(np);
69045a0faabSFabio Estevam 			goto unregister_platform_driver;
69145a0faabSFabio Estevam 		}
6921a866306SLucas Stach 
6931a866306SLucas Stach 		ret = platform_device_add(pdev);
6941a866306SLucas Stach 		if (ret) {
6951a866306SLucas Stach 			platform_device_put(pdev);
6961a866306SLucas Stach 			of_node_put(np);
6971a866306SLucas Stach 			goto unregister_platform_driver;
6981a866306SLucas Stach 		}
6991a866306SLucas Stach 
70045a0faabSFabio Estevam 		etnaviv_drm = pdev;
701246774d1SLucas Stach 		of_node_put(np);
702246774d1SLucas Stach 		break;
703246774d1SLucas Stach 	}
704246774d1SLucas Stach 
70545a0faabSFabio Estevam 	return 0;
70645a0faabSFabio Estevam 
70745a0faabSFabio Estevam unregister_platform_driver:
70845a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_platform_driver);
70945a0faabSFabio Estevam unregister_gpu_driver:
71045a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
711a8c21a54SThe etnaviv authors 	return ret;
712a8c21a54SThe etnaviv authors }
713a8c21a54SThe etnaviv authors module_init(etnaviv_init);
714a8c21a54SThe etnaviv authors 
715a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void)
716a8c21a54SThe etnaviv authors {
717bf6ba3aeSFabio Estevam 	platform_device_unregister(etnaviv_drm);
718a8c21a54SThe etnaviv authors 	platform_driver_unregister(&etnaviv_platform_driver);
719bf6ba3aeSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
720a8c21a54SThe etnaviv authors }
721a8c21a54SThe etnaviv authors module_exit(etnaviv_exit);
722a8c21a54SThe etnaviv authors 
723a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
7244f39467eSRussell King MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
725a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
726a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver");
727a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2");
728a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv");
729