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>
9426f6e76SRob Herring #include <linux/of.h>
10426f6e76SRob Herring #include <linux/of_device.h>
11426f6e76SRob Herring #include <linux/platform_device.h>
126eae41feSSam Ravnborg #include <linux/uaccess.h>
136eae41feSSam Ravnborg 
146eae41feSSam Ravnborg #include <drm/drm_debugfs.h>
156eae41feSSam Ravnborg #include <drm/drm_drv.h>
166eae41feSSam Ravnborg #include <drm/drm_file.h>
176eae41feSSam Ravnborg #include <drm/drm_ioctl.h>
1897ac0e47SRussell King #include <drm/drm_of.h>
196eae41feSSam Ravnborg #include <drm/drm_prime.h>
20a8c21a54SThe etnaviv authors 
21ea1f5729SLucas Stach #include "etnaviv_cmdbuf.h"
22a8c21a54SThe etnaviv authors #include "etnaviv_drv.h"
23a8c21a54SThe etnaviv authors #include "etnaviv_gpu.h"
24a8c21a54SThe etnaviv authors #include "etnaviv_gem.h"
25a8c21a54SThe etnaviv authors #include "etnaviv_mmu.h"
269e2c2e27SChristian Gmeiner #include "etnaviv_perfmon.h"
27a8c21a54SThe etnaviv authors 
28a8c21a54SThe etnaviv authors /*
29a8c21a54SThe etnaviv authors  * DRM operations:
30a8c21a54SThe etnaviv authors  */
31a8c21a54SThe etnaviv authors 
32a8c21a54SThe etnaviv authors 
load_gpu(struct drm_device * dev)33a8c21a54SThe etnaviv authors static void load_gpu(struct drm_device *dev)
34a8c21a54SThe etnaviv authors {
35a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
36a8c21a54SThe etnaviv authors 	unsigned int i;
37a8c21a54SThe etnaviv authors 
38a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
39a8c21a54SThe etnaviv authors 		struct etnaviv_gpu *g = priv->gpu[i];
40a8c21a54SThe etnaviv authors 
41a8c21a54SThe etnaviv authors 		if (g) {
42a8c21a54SThe etnaviv authors 			int ret;
43a8c21a54SThe etnaviv authors 
44a8c21a54SThe etnaviv authors 			ret = etnaviv_gpu_init(g);
45c1c77b0eSLucas Stach 			if (ret)
46a8c21a54SThe etnaviv authors 				priv->gpu[i] = NULL;
47a8c21a54SThe etnaviv authors 		}
48a8c21a54SThe etnaviv authors 	}
49a8c21a54SThe etnaviv authors }
50a8c21a54SThe etnaviv authors 
etnaviv_open(struct drm_device * dev,struct drm_file * file)51a8c21a54SThe etnaviv authors static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
52a8c21a54SThe etnaviv authors {
53e93b6deeSLucas Stach 	struct etnaviv_drm_private *priv = dev->dev_private;
54a8c21a54SThe etnaviv authors 	struct etnaviv_file_private *ctx;
5517e4660aSLucas Stach 	int ret, i;
56a8c21a54SThe etnaviv authors 
57a8c21a54SThe etnaviv authors 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
58a8c21a54SThe etnaviv authors 	if (!ctx)
59a8c21a54SThe etnaviv authors 		return -ENOMEM;
60a8c21a54SThe etnaviv authors 
61d306788bSLucas Stach 	ret = xa_alloc_cyclic(&priv->active_contexts, &ctx->id, ctx,
62d306788bSLucas Stach 			      xa_limit_32b, &priv->next_context_id, GFP_KERNEL);
63d306788bSLucas Stach 	if (ret < 0)
64d306788bSLucas Stach 		goto out_free;
65d306788bSLucas Stach 
6617e4660aSLucas Stach 	ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global,
6717e4660aSLucas Stach 					      priv->cmdbuf_suballoc);
6817e4660aSLucas Stach 	if (!ctx->mmu) {
6917e4660aSLucas Stach 		ret = -ENOMEM;
7017e4660aSLucas Stach 		goto out_free;
7117e4660aSLucas Stach 	}
7217e4660aSLucas Stach 
73e93b6deeSLucas Stach 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
74e93b6deeSLucas Stach 		struct etnaviv_gpu *gpu = priv->gpu[i];
75b3ac1766SNirmoy Das 		struct drm_gpu_scheduler *sched;
76e93b6deeSLucas Stach 
77e93b6deeSLucas Stach 		if (gpu) {
78b3ac1766SNirmoy Das 			sched = &gpu->sched;
79aa16b6c6SNayan Deshmukh 			drm_sched_entity_init(&ctx->sched_entity[i],
80b3ac1766SNirmoy Das 					      DRM_SCHED_PRIORITY_NORMAL, &sched,
81b3ac1766SNirmoy Das 					      1, NULL);
82e93b6deeSLucas Stach 			}
83e93b6deeSLucas Stach 	}
84e93b6deeSLucas Stach 
85a8c21a54SThe etnaviv authors 	file->driver_priv = ctx;
86a8c21a54SThe etnaviv authors 
87a8c21a54SThe etnaviv authors 	return 0;
8817e4660aSLucas Stach 
8917e4660aSLucas Stach out_free:
9017e4660aSLucas Stach 	kfree(ctx);
9117e4660aSLucas Stach 	return ret;
92a8c21a54SThe etnaviv authors }
93a8c21a54SThe etnaviv authors 
etnaviv_postclose(struct drm_device * dev,struct drm_file * file)94fda8fa5bSDaniel Vetter static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
95a8c21a54SThe etnaviv authors {
96a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
97a8c21a54SThe etnaviv authors 	struct etnaviv_file_private *ctx = file->driver_priv;
98a8c21a54SThe etnaviv authors 	unsigned int i;
99a8c21a54SThe etnaviv authors 
100a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
101a8c21a54SThe etnaviv authors 		struct etnaviv_gpu *gpu = priv->gpu[i];
102a8c21a54SThe etnaviv authors 
103801c7a1eSLucas Stach 		if (gpu)
104cdc50176SNayan Deshmukh 			drm_sched_entity_destroy(&ctx->sched_entity[i]);
105a8c21a54SThe etnaviv authors 	}
106a8c21a54SThe etnaviv authors 
10717e4660aSLucas Stach 	etnaviv_iommu_context_put(ctx->mmu);
10817e4660aSLucas Stach 
109d306788bSLucas Stach 	xa_erase(&priv->active_contexts, ctx->id);
110d306788bSLucas Stach 
111a8c21a54SThe etnaviv authors 	kfree(ctx);
112a8c21a54SThe etnaviv authors }
113a8c21a54SThe etnaviv authors 
114a8c21a54SThe etnaviv authors /*
115a8c21a54SThe etnaviv authors  * DRM debugfs:
116a8c21a54SThe etnaviv authors  */
117a8c21a54SThe etnaviv authors 
118a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS
etnaviv_gem_show(struct drm_device * dev,struct seq_file * m)119a8c21a54SThe etnaviv authors static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
120a8c21a54SThe etnaviv authors {
121a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
122a8c21a54SThe etnaviv authors 
123a8c21a54SThe etnaviv authors 	etnaviv_gem_describe_objects(priv, m);
124a8c21a54SThe etnaviv authors 
125a8c21a54SThe etnaviv authors 	return 0;
126a8c21a54SThe etnaviv authors }
127a8c21a54SThe etnaviv authors 
etnaviv_mm_show(struct drm_device * dev,struct seq_file * m)128a8c21a54SThe etnaviv authors static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
129a8c21a54SThe etnaviv authors {
130b5c3714fSDaniel Vetter 	struct drm_printer p = drm_seq_file_printer(m);
131a8c21a54SThe etnaviv authors 
132a8c21a54SThe etnaviv authors 	read_lock(&dev->vma_offset_manager->vm_lock);
133b5c3714fSDaniel Vetter 	drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
134a8c21a54SThe etnaviv authors 	read_unlock(&dev->vma_offset_manager->vm_lock);
135a8c21a54SThe etnaviv authors 
136b5c3714fSDaniel Vetter 	return 0;
137a8c21a54SThe etnaviv authors }
138a8c21a54SThe etnaviv authors 
etnaviv_mmu_show(struct etnaviv_gpu * gpu,struct seq_file * m)139a8c21a54SThe etnaviv authors static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m)
140a8c21a54SThe etnaviv authors {
141b5c3714fSDaniel Vetter 	struct drm_printer p = drm_seq_file_printer(m);
14217e4660aSLucas Stach 	struct etnaviv_iommu_context *mmu_context;
143b5c3714fSDaniel Vetter 
144a8c21a54SThe etnaviv authors 	seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev));
145a8c21a54SThe etnaviv authors 
14617e4660aSLucas Stach 	/*
14717e4660aSLucas Stach 	 * Lock the GPU to avoid a MMU context switch just now and elevate
14817e4660aSLucas Stach 	 * the refcount of the current context to avoid it disappearing from
14917e4660aSLucas Stach 	 * under our feet.
15017e4660aSLucas Stach 	 */
15117e4660aSLucas Stach 	mutex_lock(&gpu->lock);
15217e4660aSLucas Stach 	mmu_context = gpu->mmu_context;
15317e4660aSLucas Stach 	if (mmu_context)
15417e4660aSLucas Stach 		etnaviv_iommu_context_get(mmu_context);
15517e4660aSLucas Stach 	mutex_unlock(&gpu->lock);
15617e4660aSLucas Stach 
15717e4660aSLucas Stach 	if (!mmu_context)
15817e4660aSLucas Stach 		return 0;
15917e4660aSLucas Stach 
16017e4660aSLucas Stach 	mutex_lock(&mmu_context->lock);
16117e4660aSLucas Stach 	drm_mm_print(&mmu_context->mm, &p);
16217e4660aSLucas Stach 	mutex_unlock(&mmu_context->lock);
16317e4660aSLucas Stach 
16417e4660aSLucas Stach 	etnaviv_iommu_context_put(mmu_context);
165a8c21a54SThe etnaviv authors 
166a8c21a54SThe etnaviv authors 	return 0;
167a8c21a54SThe etnaviv authors }
168a8c21a54SThe etnaviv authors 
etnaviv_buffer_dump(struct etnaviv_gpu * gpu,struct seq_file * m)169a8c21a54SThe etnaviv authors static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
170a8c21a54SThe etnaviv authors {
1712f9225dbSLucas Stach 	struct etnaviv_cmdbuf *buf = &gpu->buffer;
172a8c21a54SThe etnaviv authors 	u32 size = buf->size;
173a8c21a54SThe etnaviv authors 	u32 *ptr = buf->vaddr;
174a8c21a54SThe etnaviv authors 	u32 i;
175a8c21a54SThe etnaviv authors 
176a8c21a54SThe etnaviv authors 	seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
1779912b4dbSLucas Stach 			buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),
1789912b4dbSLucas Stach 			size - buf->user_size);
179a8c21a54SThe etnaviv authors 
180a8c21a54SThe etnaviv authors 	for (i = 0; i < size / 4; i++) {
181a8c21a54SThe etnaviv authors 		if (i && !(i % 4))
182a8c21a54SThe etnaviv authors 			seq_puts(m, "\n");
183a8c21a54SThe etnaviv authors 		if (i % 4 == 0)
184a8c21a54SThe etnaviv authors 			seq_printf(m, "\t0x%p: ", ptr + i);
185a8c21a54SThe etnaviv authors 		seq_printf(m, "%08x ", *(ptr + i));
186a8c21a54SThe etnaviv authors 	}
187a8c21a54SThe etnaviv authors 	seq_puts(m, "\n");
188a8c21a54SThe etnaviv authors }
189a8c21a54SThe etnaviv authors 
etnaviv_ring_show(struct etnaviv_gpu * gpu,struct seq_file * m)190a8c21a54SThe etnaviv authors static int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m)
191a8c21a54SThe etnaviv authors {
192a8c21a54SThe etnaviv authors 	seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev));
193a8c21a54SThe etnaviv authors 
194a8c21a54SThe etnaviv authors 	mutex_lock(&gpu->lock);
195a8c21a54SThe etnaviv authors 	etnaviv_buffer_dump(gpu, m);
196a8c21a54SThe etnaviv authors 	mutex_unlock(&gpu->lock);
197a8c21a54SThe etnaviv authors 
198a8c21a54SThe etnaviv authors 	return 0;
199a8c21a54SThe etnaviv authors }
200a8c21a54SThe etnaviv authors 
show_unlocked(struct seq_file * m,void * arg)201a8c21a54SThe etnaviv authors static int show_unlocked(struct seq_file *m, void *arg)
202a8c21a54SThe etnaviv authors {
203a8c21a54SThe etnaviv authors 	struct drm_info_node *node = (struct drm_info_node *) m->private;
204a8c21a54SThe etnaviv authors 	struct drm_device *dev = node->minor->dev;
205a8c21a54SThe etnaviv authors 	int (*show)(struct drm_device *dev, struct seq_file *m) =
206a8c21a54SThe etnaviv authors 			node->info_ent->data;
207a8c21a54SThe etnaviv authors 
208a8c21a54SThe etnaviv authors 	return show(dev, m);
209a8c21a54SThe etnaviv authors }
210a8c21a54SThe etnaviv authors 
show_each_gpu(struct seq_file * m,void * arg)211a8c21a54SThe etnaviv authors static int show_each_gpu(struct seq_file *m, void *arg)
212a8c21a54SThe etnaviv authors {
213a8c21a54SThe etnaviv authors 	struct drm_info_node *node = (struct drm_info_node *) m->private;
214a8c21a54SThe etnaviv authors 	struct drm_device *dev = node->minor->dev;
215a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
216a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
217a8c21a54SThe etnaviv authors 	int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
218a8c21a54SThe etnaviv authors 			node->info_ent->data;
219a8c21a54SThe etnaviv authors 	unsigned int i;
220a8c21a54SThe etnaviv authors 	int ret = 0;
221a8c21a54SThe etnaviv authors 
222a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
223a8c21a54SThe etnaviv authors 		gpu = priv->gpu[i];
224a8c21a54SThe etnaviv authors 		if (!gpu)
225a8c21a54SThe etnaviv authors 			continue;
226a8c21a54SThe etnaviv authors 
227a8c21a54SThe etnaviv authors 		ret = show(gpu, m);
228a8c21a54SThe etnaviv authors 		if (ret < 0)
229a8c21a54SThe etnaviv authors 			break;
230a8c21a54SThe etnaviv authors 	}
231a8c21a54SThe etnaviv authors 
232a8c21a54SThe etnaviv authors 	return ret;
233a8c21a54SThe etnaviv authors }
234a8c21a54SThe etnaviv authors 
235a8c21a54SThe etnaviv authors static struct drm_info_list etnaviv_debugfs_list[] = {
236a8c21a54SThe etnaviv authors 		{"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
237a8c21a54SThe etnaviv authors 		{"gem", show_unlocked, 0, etnaviv_gem_show},
238a8c21a54SThe etnaviv authors 		{ "mm", show_unlocked, 0, etnaviv_mm_show },
239a8c21a54SThe etnaviv authors 		{"mmu", show_each_gpu, 0, etnaviv_mmu_show},
240a8c21a54SThe etnaviv authors 		{"ring", show_each_gpu, 0, etnaviv_ring_show},
241a8c21a54SThe etnaviv authors };
242a8c21a54SThe etnaviv authors 
etnaviv_debugfs_init(struct drm_minor * minor)2437ce84471SWambui Karuga static void etnaviv_debugfs_init(struct drm_minor *minor)
244a8c21a54SThe etnaviv authors {
24514b46195SWambui Karuga 	drm_debugfs_create_files(etnaviv_debugfs_list,
246a8c21a54SThe etnaviv authors 				 ARRAY_SIZE(etnaviv_debugfs_list),
247a8c21a54SThe etnaviv authors 				 minor->debugfs_root, minor);
248a8c21a54SThe etnaviv authors }
249a8c21a54SThe etnaviv authors #endif
250a8c21a54SThe etnaviv authors 
251a8c21a54SThe etnaviv authors /*
252a8c21a54SThe etnaviv authors  * DRM ioctls:
253a8c21a54SThe etnaviv authors  */
254a8c21a54SThe etnaviv authors 
etnaviv_ioctl_get_param(struct drm_device * dev,void * data,struct drm_file * file)255a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
256a8c21a54SThe etnaviv authors 		struct drm_file *file)
257a8c21a54SThe etnaviv authors {
258a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
259a8c21a54SThe etnaviv authors 	struct drm_etnaviv_param *args = data;
260a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
261a8c21a54SThe etnaviv authors 
262a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
263a8c21a54SThe etnaviv authors 		return -EINVAL;
264a8c21a54SThe etnaviv authors 
265a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
266a8c21a54SThe etnaviv authors 	if (!gpu)
267a8c21a54SThe etnaviv authors 		return -ENXIO;
268a8c21a54SThe etnaviv authors 
269a8c21a54SThe etnaviv authors 	return etnaviv_gpu_get_param(gpu, args->param, &args->value);
270a8c21a54SThe etnaviv authors }
271a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_new(struct drm_device * dev,void * data,struct drm_file * file)272a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
273a8c21a54SThe etnaviv authors 		struct drm_file *file)
274a8c21a54SThe etnaviv authors {
275a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_new *args = data;
276a8c21a54SThe etnaviv authors 
277a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED |
278a8c21a54SThe etnaviv authors 			    ETNA_BO_FORCE_MMU))
279a8c21a54SThe etnaviv authors 		return -EINVAL;
280a8c21a54SThe etnaviv authors 
281a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_handle(dev, file, args->size,
282a8c21a54SThe etnaviv authors 			args->flags, &args->handle);
283a8c21a54SThe etnaviv authors }
284a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_cpu_prep(struct drm_device * dev,void * data,struct drm_file * file)285a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
286a8c21a54SThe etnaviv authors 		struct drm_file *file)
287a8c21a54SThe etnaviv authors {
288a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_prep *args = data;
289a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
290a8c21a54SThe etnaviv authors 	int ret;
291a8c21a54SThe etnaviv authors 
292a8c21a54SThe etnaviv authors 	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
293a8c21a54SThe etnaviv authors 		return -EINVAL;
294a8c21a54SThe etnaviv authors 
295a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
296a8c21a54SThe etnaviv authors 	if (!obj)
297a8c21a54SThe etnaviv authors 		return -ENOENT;
298a8c21a54SThe etnaviv authors 
29938c4a4cfSArnd Bergmann 	ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout);
300a8c21a54SThe etnaviv authors 
3016780bf32SEmil Velikov 	drm_gem_object_put(obj);
302a8c21a54SThe etnaviv authors 
303a8c21a54SThe etnaviv authors 	return ret;
304a8c21a54SThe etnaviv authors }
305a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_cpu_fini(struct drm_device * dev,void * data,struct drm_file * file)306a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
307a8c21a54SThe etnaviv authors 		struct drm_file *file)
308a8c21a54SThe etnaviv authors {
309a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_fini *args = data;
310a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
311a8c21a54SThe etnaviv authors 	int ret;
312a8c21a54SThe etnaviv authors 
313a8c21a54SThe etnaviv authors 	if (args->flags)
314a8c21a54SThe etnaviv authors 		return -EINVAL;
315a8c21a54SThe etnaviv authors 
316a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
317a8c21a54SThe etnaviv authors 	if (!obj)
318a8c21a54SThe etnaviv authors 		return -ENOENT;
319a8c21a54SThe etnaviv authors 
320a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_cpu_fini(obj);
321a8c21a54SThe etnaviv authors 
3226780bf32SEmil Velikov 	drm_gem_object_put(obj);
323a8c21a54SThe etnaviv authors 
324a8c21a54SThe etnaviv authors 	return ret;
325a8c21a54SThe etnaviv authors }
326a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_info(struct drm_device * dev,void * data,struct drm_file * file)327a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
328a8c21a54SThe etnaviv authors 		struct drm_file *file)
329a8c21a54SThe etnaviv authors {
330a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_info *args = data;
331a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
332a8c21a54SThe etnaviv authors 	int ret;
333a8c21a54SThe etnaviv authors 
334a8c21a54SThe etnaviv authors 	if (args->pad)
335a8c21a54SThe etnaviv authors 		return -EINVAL;
336a8c21a54SThe etnaviv authors 
337a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
338a8c21a54SThe etnaviv authors 	if (!obj)
339a8c21a54SThe etnaviv authors 		return -ENOENT;
340a8c21a54SThe etnaviv authors 
341a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
3426780bf32SEmil Velikov 	drm_gem_object_put(obj);
343a8c21a54SThe etnaviv authors 
344a8c21a54SThe etnaviv authors 	return ret;
345a8c21a54SThe etnaviv authors }
346a8c21a54SThe etnaviv authors 
etnaviv_ioctl_wait_fence(struct drm_device * dev,void * data,struct drm_file * file)347a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
348a8c21a54SThe etnaviv authors 		struct drm_file *file)
349a8c21a54SThe etnaviv authors {
350a8c21a54SThe etnaviv authors 	struct drm_etnaviv_wait_fence *args = data;
351a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
35238c4a4cfSArnd Bergmann 	struct drm_etnaviv_timespec *timeout = &args->timeout;
353a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
354a8c21a54SThe etnaviv authors 
355a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
356a8c21a54SThe etnaviv authors 		return -EINVAL;
357a8c21a54SThe etnaviv authors 
358a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
359a8c21a54SThe etnaviv authors 		return -EINVAL;
360a8c21a54SThe etnaviv authors 
361a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
362a8c21a54SThe etnaviv authors 	if (!gpu)
363a8c21a54SThe etnaviv authors 		return -ENXIO;
364a8c21a54SThe etnaviv authors 
365a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
366a8c21a54SThe etnaviv authors 		timeout = NULL;
367a8c21a54SThe etnaviv authors 
368a8c21a54SThe etnaviv authors 	return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
369a8c21a54SThe etnaviv authors 						    timeout);
370a8c21a54SThe etnaviv authors }
371a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_userptr(struct drm_device * dev,void * data,struct drm_file * file)372a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
373a8c21a54SThe etnaviv authors 	struct drm_file *file)
374a8c21a54SThe etnaviv authors {
375a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_userptr *args = data;
376a8c21a54SThe etnaviv authors 
377a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
378a8c21a54SThe etnaviv authors 	    args->flags == 0)
379a8c21a54SThe etnaviv authors 		return -EINVAL;
380a8c21a54SThe etnaviv authors 
381a8c21a54SThe etnaviv authors 	if (offset_in_page(args->user_ptr | args->user_size) ||
382a8c21a54SThe etnaviv authors 	    (uintptr_t)args->user_ptr != args->user_ptr ||
383a8c21a54SThe etnaviv authors 	    (u32)args->user_size != args->user_size ||
384a8c21a54SThe etnaviv authors 	    args->user_ptr & ~PAGE_MASK)
385a8c21a54SThe etnaviv authors 		return -EINVAL;
386a8c21a54SThe etnaviv authors 
38796d4f267SLinus Torvalds 	if (!access_ok((void __user *)(unsigned long)args->user_ptr,
388a8c21a54SThe etnaviv authors 		       args->user_size))
389a8c21a54SThe etnaviv authors 		return -EFAULT;
390a8c21a54SThe etnaviv authors 
391a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
392a8c21a54SThe etnaviv authors 				       args->user_size, args->flags,
393a8c21a54SThe etnaviv authors 				       &args->handle);
394a8c21a54SThe etnaviv authors }
395a8c21a54SThe etnaviv authors 
etnaviv_ioctl_gem_wait(struct drm_device * dev,void * data,struct drm_file * file)396a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
397a8c21a54SThe etnaviv authors 	struct drm_file *file)
398a8c21a54SThe etnaviv authors {
399a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
400a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_wait *args = data;
40138c4a4cfSArnd Bergmann 	struct drm_etnaviv_timespec *timeout = &args->timeout;
402a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
403a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
404a8c21a54SThe etnaviv authors 	int ret;
405a8c21a54SThe etnaviv authors 
406a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
407a8c21a54SThe etnaviv authors 		return -EINVAL;
408a8c21a54SThe etnaviv authors 
409a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
410a8c21a54SThe etnaviv authors 		return -EINVAL;
411a8c21a54SThe etnaviv authors 
412a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
413a8c21a54SThe etnaviv authors 	if (!gpu)
414a8c21a54SThe etnaviv authors 		return -ENXIO;
415a8c21a54SThe etnaviv authors 
416a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
417a8c21a54SThe etnaviv authors 	if (!obj)
418a8c21a54SThe etnaviv authors 		return -ENOENT;
419a8c21a54SThe etnaviv authors 
420a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
421a8c21a54SThe etnaviv authors 		timeout = NULL;
422a8c21a54SThe etnaviv authors 
423a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_wait_bo(gpu, obj, timeout);
424a8c21a54SThe etnaviv authors 
4256780bf32SEmil Velikov 	drm_gem_object_put(obj);
426a8c21a54SThe etnaviv authors 
427a8c21a54SThe etnaviv authors 	return ret;
428a8c21a54SThe etnaviv authors }
429a8c21a54SThe etnaviv authors 
etnaviv_ioctl_pm_query_dom(struct drm_device * dev,void * data,struct drm_file * file)4309e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
4319e2c2e27SChristian Gmeiner 	struct drm_file *file)
4329e2c2e27SChristian Gmeiner {
4339e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4349e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_domain *args = data;
4359e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4369e2c2e27SChristian Gmeiner 
4379e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4389e2c2e27SChristian Gmeiner 		return -EINVAL;
4399e2c2e27SChristian Gmeiner 
4409e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4419e2c2e27SChristian Gmeiner 	if (!gpu)
4429e2c2e27SChristian Gmeiner 		return -ENXIO;
4439e2c2e27SChristian Gmeiner 
4449e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_dom(gpu, args);
4459e2c2e27SChristian Gmeiner }
4469e2c2e27SChristian Gmeiner 
etnaviv_ioctl_pm_query_sig(struct drm_device * dev,void * data,struct drm_file * file)4479e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data,
4489e2c2e27SChristian Gmeiner 	struct drm_file *file)
4499e2c2e27SChristian Gmeiner {
4509e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4519e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_signal *args = data;
4529e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4539e2c2e27SChristian Gmeiner 
4549e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4559e2c2e27SChristian Gmeiner 		return -EINVAL;
4569e2c2e27SChristian Gmeiner 
4579e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4589e2c2e27SChristian Gmeiner 	if (!gpu)
4599e2c2e27SChristian Gmeiner 		return -ENXIO;
4609e2c2e27SChristian Gmeiner 
4619e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_sig(gpu, args);
4629e2c2e27SChristian Gmeiner }
4639e2c2e27SChristian Gmeiner 
464a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = {
465a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \
466a8c21a54SThe etnaviv authors 	DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
467b8602f9aSEmil Velikov 	ETNA_IOCTL(GET_PARAM,    get_param,    DRM_RENDER_ALLOW),
468b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_RENDER_ALLOW),
469b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_RENDER_ALLOW),
470b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW),
471b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW),
472b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_RENDER_ALLOW),
473b8602f9aSEmil Velikov 	ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_RENDER_ALLOW),
474b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_RENDER_ALLOW),
475b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_RENDER_ALLOW),
476b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW),
477b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW),
478a8c21a54SThe etnaviv authors };
479a8c21a54SThe etnaviv authors 
4802658d0d0SLucas Stach DEFINE_DRM_GEM_FOPS(fops);
481a8c21a54SThe etnaviv authors 
48270a59dd8SDaniel Vetter static const struct drm_driver etnaviv_drm_driver = {
4830424fdafSDaniel Vetter 	.driver_features    = DRIVER_GEM | DRIVER_RENDER,
484a8c21a54SThe etnaviv authors 	.open               = etnaviv_open,
485fda8fa5bSDaniel Vetter 	.postclose           = etnaviv_postclose,
486a8c21a54SThe etnaviv authors 	.gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
487a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS
488a8c21a54SThe etnaviv authors 	.debugfs_init       = etnaviv_debugfs_init,
489a8c21a54SThe etnaviv authors #endif
490a8c21a54SThe etnaviv authors 	.ioctls             = etnaviv_ioctls,
491a8c21a54SThe etnaviv authors 	.num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
492a8c21a54SThe etnaviv authors 	.fops               = &fops,
493a8c21a54SThe etnaviv authors 	.name               = "etnaviv",
494a8c21a54SThe etnaviv authors 	.desc               = "etnaviv DRM",
495a8c21a54SThe etnaviv authors 	.date               = "20151214",
496a8c21a54SThe etnaviv authors 	.major              = 1,
497bc8e5fdaSChristian Gmeiner 	.minor              = 4,
498a8c21a54SThe etnaviv authors };
499a8c21a54SThe etnaviv authors 
500a8c21a54SThe etnaviv authors /*
501a8c21a54SThe etnaviv authors  * Platform driver:
502a8c21a54SThe etnaviv authors  */
etnaviv_bind(struct device * dev)503a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev)
504a8c21a54SThe etnaviv authors {
505a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv;
506a8c21a54SThe etnaviv authors 	struct drm_device *drm;
507a8c21a54SThe etnaviv authors 	int ret;
508a8c21a54SThe etnaviv authors 
509a8c21a54SThe etnaviv authors 	drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
5100f288605STom Gundersen 	if (IS_ERR(drm))
5110f288605STom Gundersen 		return PTR_ERR(drm);
512a8c21a54SThe etnaviv authors 
513a8c21a54SThe etnaviv authors 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
514a8c21a54SThe etnaviv authors 	if (!priv) {
515a8c21a54SThe etnaviv authors 		dev_err(dev, "failed to allocate private data\n");
516a8c21a54SThe etnaviv authors 		ret = -ENOMEM;
51799e29449SThomas Zimmermann 		goto out_put;
518a8c21a54SThe etnaviv authors 	}
519a8c21a54SThe etnaviv authors 	drm->dev_private = priv;
520a8c21a54SThe etnaviv authors 
5211262cc88SRussell King 	dma_set_max_seg_size(dev, SZ_2G);
5221262cc88SRussell King 
523d306788bSLucas Stach 	xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
524d306788bSLucas Stach 
525a8c21a54SThe etnaviv authors 	mutex_init(&priv->gem_lock);
526a8c21a54SThe etnaviv authors 	INIT_LIST_HEAD(&priv->gem_list);
527a8c21a54SThe etnaviv authors 	priv->num_gpus = 0;
528b72af445SLucas Stach 	priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
529a8c21a54SThe etnaviv authors 
530bffe5db8SLucas Stach 	priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
531bffe5db8SLucas Stach 	if (IS_ERR(priv->cmdbuf_suballoc)) {
532bffe5db8SLucas Stach 		dev_err(drm->dev, "Failed to create cmdbuf suballocator\n");
533bffe5db8SLucas Stach 		ret = PTR_ERR(priv->cmdbuf_suballoc);
534bffe5db8SLucas Stach 		goto out_free_priv;
535bffe5db8SLucas Stach 	}
536bffe5db8SLucas Stach 
537a8c21a54SThe etnaviv authors 	dev_set_drvdata(dev, drm);
538a8c21a54SThe etnaviv authors 
539a8c21a54SThe etnaviv authors 	ret = component_bind_all(dev, drm);
540a8c21a54SThe etnaviv authors 	if (ret < 0)
541bffe5db8SLucas Stach 		goto out_destroy_suballoc;
542a8c21a54SThe etnaviv authors 
543a8c21a54SThe etnaviv authors 	load_gpu(drm);
544a8c21a54SThe etnaviv authors 
545a8c21a54SThe etnaviv authors 	ret = drm_dev_register(drm, 0);
546a8c21a54SThe etnaviv authors 	if (ret)
547bffe5db8SLucas Stach 		goto out_unbind;
548a8c21a54SThe etnaviv authors 
549a8c21a54SThe etnaviv authors 	return 0;
550a8c21a54SThe etnaviv authors 
551bffe5db8SLucas Stach out_unbind:
552a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
553bffe5db8SLucas Stach out_destroy_suballoc:
554bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
555bffe5db8SLucas Stach out_free_priv:
556a8c21a54SThe etnaviv authors 	kfree(priv);
55799e29449SThomas Zimmermann out_put:
55899e29449SThomas Zimmermann 	drm_dev_put(drm);
559a8c21a54SThe etnaviv authors 
560a8c21a54SThe etnaviv authors 	return ret;
561a8c21a54SThe etnaviv authors }
562a8c21a54SThe etnaviv authors 
etnaviv_unbind(struct device * dev)563a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev)
564a8c21a54SThe etnaviv authors {
565a8c21a54SThe etnaviv authors 	struct drm_device *drm = dev_get_drvdata(dev);
566a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = drm->dev_private;
567a8c21a54SThe etnaviv authors 
568a8c21a54SThe etnaviv authors 	drm_dev_unregister(drm);
569a8c21a54SThe etnaviv authors 
570a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
571a8c21a54SThe etnaviv authors 
572bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
573bffe5db8SLucas Stach 
574d306788bSLucas Stach 	xa_destroy(&priv->active_contexts);
575d306788bSLucas Stach 
576a8c21a54SThe etnaviv authors 	drm->dev_private = NULL;
577a8c21a54SThe etnaviv authors 	kfree(priv);
578a8c21a54SThe etnaviv authors 
57999e29449SThomas Zimmermann 	drm_dev_put(drm);
580a8c21a54SThe etnaviv authors }
581a8c21a54SThe etnaviv authors 
582a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = {
583a8c21a54SThe etnaviv authors 	.bind = etnaviv_bind,
584a8c21a54SThe etnaviv authors 	.unbind = etnaviv_unbind,
585a8c21a54SThe etnaviv authors };
586a8c21a54SThe etnaviv authors 
etnaviv_pdev_probe(struct platform_device * pdev)587a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev)
588a8c21a54SThe etnaviv authors {
589a8c21a54SThe etnaviv authors 	struct device *dev = &pdev->dev;
5900ea057a9SMichael Walle 	struct device_node *first_node = NULL;
591a8c21a54SThe etnaviv authors 	struct component_match *match = NULL;
592a8c21a54SThe etnaviv authors 
593246774d1SLucas Stach 	if (!dev->platform_data) {
594a8c21a54SThe etnaviv authors 		struct device_node *core_node;
595a8c21a54SThe etnaviv authors 
596246774d1SLucas Stach 		for_each_compatible_node(core_node, NULL, "vivante,gc") {
597246774d1SLucas Stach 			if (!of_device_is_available(core_node))
598246774d1SLucas Stach 				continue;
599a8c21a54SThe etnaviv authors 
6000ea057a9SMichael Walle 			if (!first_node)
6010ea057a9SMichael Walle 				first_node = core_node;
6020ea057a9SMichael Walle 
60397ac0e47SRussell King 			drm_of_component_match_add(&pdev->dev, &match,
6040a522394SYong Wu 						   component_compare_of, core_node);
605a8c21a54SThe etnaviv authors 		}
606246774d1SLucas Stach 	} else {
607a8c21a54SThe etnaviv authors 		char **names = dev->platform_data;
608a8c21a54SThe etnaviv authors 		unsigned i;
609a8c21a54SThe etnaviv authors 
610a8c21a54SThe etnaviv authors 		for (i = 0; names[i]; i++)
6110a522394SYong Wu 			component_match_add(dev, &match, component_compare_dev_name, names[i]);
612a8c21a54SThe etnaviv authors 	}
613a8c21a54SThe etnaviv authors 
6140ea057a9SMichael Walle 	/*
615f5be833dSMichael Walle 	 * PTA and MTLB can have 40 bit base addresses, but
616f5be833dSMichael Walle 	 * unfortunately, an entry in the MTLB can only point to a
617f5be833dSMichael Walle 	 * 32 bit base address of a STLB. Moreover, to initialize the
618f5be833dSMichael Walle 	 * MMU we need a command buffer with a 32 bit address because
619f5be833dSMichael Walle 	 * without an MMU there is only an indentity mapping between
620f5be833dSMichael Walle 	 * the internal 32 bit addresses and the bus addresses.
621f5be833dSMichael Walle 	 *
622f5be833dSMichael Walle 	 * To make things easy, we set the dma_coherent_mask to 32
623f5be833dSMichael Walle 	 * bit to make sure we are allocating the command buffers and
624f5be833dSMichael Walle 	 * TLBs in the lower 4 GiB address space.
625f5be833dSMichael Walle 	 */
626f5be833dSMichael Walle 	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)) ||
627f5be833dSMichael Walle 	    dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) {
628f5be833dSMichael Walle 		dev_dbg(&pdev->dev, "No suitable DMA available\n");
629f5be833dSMichael Walle 		return -ENODEV;
630f5be833dSMichael Walle 	}
631f5be833dSMichael Walle 
632f5be833dSMichael Walle 	/*
6330ea057a9SMichael Walle 	 * Apply the same DMA configuration to the virtual etnaviv
6340ea057a9SMichael Walle 	 * device as the GPU we found. This assumes that all Vivante
6350ea057a9SMichael Walle 	 * GPUs in the system share the same DMA constraints.
6360ea057a9SMichael Walle 	 */
6370ea057a9SMichael Walle 	if (first_node)
6380ea057a9SMichael Walle 		of_dma_configure(&pdev->dev, first_node, true);
6390ea057a9SMichael Walle 
640a8c21a54SThe etnaviv authors 	return component_master_add_with_match(dev, &etnaviv_master_ops, match);
641a8c21a54SThe etnaviv authors }
642a8c21a54SThe etnaviv authors 
etnaviv_pdev_remove(struct platform_device * pdev)643a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev)
644a8c21a54SThe etnaviv authors {
645a8c21a54SThe etnaviv authors 	component_master_del(&pdev->dev, &etnaviv_master_ops);
646a8c21a54SThe etnaviv authors 
647a8c21a54SThe etnaviv authors 	return 0;
648a8c21a54SThe etnaviv authors }
649a8c21a54SThe etnaviv authors 
650a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = {
651a8c21a54SThe etnaviv authors 	.probe      = etnaviv_pdev_probe,
652a8c21a54SThe etnaviv authors 	.remove     = etnaviv_pdev_remove,
653a8c21a54SThe etnaviv authors 	.driver     = {
654a8c21a54SThe etnaviv authors 		.name   = "etnaviv",
655a8c21a54SThe etnaviv authors 	},
656a8c21a54SThe etnaviv authors };
657a8c21a54SThe etnaviv authors 
65845a0faabSFabio Estevam static struct platform_device *etnaviv_drm;
65945a0faabSFabio Estevam 
etnaviv_init(void)660a8c21a54SThe etnaviv authors static int __init etnaviv_init(void)
661a8c21a54SThe etnaviv authors {
66245a0faabSFabio Estevam 	struct platform_device *pdev;
663a8c21a54SThe etnaviv authors 	int ret;
664246774d1SLucas Stach 	struct device_node *np;
665a8c21a54SThe etnaviv authors 
666a8c21a54SThe etnaviv authors 	etnaviv_validate_init();
667a8c21a54SThe etnaviv authors 
668a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_gpu_driver);
669a8c21a54SThe etnaviv authors 	if (ret != 0)
670a8c21a54SThe etnaviv authors 		return ret;
671a8c21a54SThe etnaviv authors 
672a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_platform_driver);
673a8c21a54SThe etnaviv authors 	if (ret != 0)
67445a0faabSFabio Estevam 		goto unregister_gpu_driver;
675a8c21a54SThe etnaviv authors 
676246774d1SLucas Stach 	/*
677246774d1SLucas Stach 	 * If the DT contains at least one available GPU device, instantiate
678246774d1SLucas Stach 	 * the DRM platform device.
679246774d1SLucas Stach 	 */
680246774d1SLucas Stach 	for_each_compatible_node(np, NULL, "vivante,gc") {
681246774d1SLucas Stach 		if (!of_device_is_available(np))
682246774d1SLucas Stach 			continue;
6831a866306SLucas Stach 
6843c7e0cccSMichael Walle 		pdev = platform_device_alloc("etnaviv", PLATFORM_DEVID_NONE);
6851a866306SLucas Stach 		if (!pdev) {
6861a866306SLucas Stach 			ret = -ENOMEM;
68745a0faabSFabio Estevam 			of_node_put(np);
68845a0faabSFabio Estevam 			goto unregister_platform_driver;
68945a0faabSFabio Estevam 		}
6901a866306SLucas Stach 
6911a866306SLucas Stach 		ret = platform_device_add(pdev);
6921a866306SLucas Stach 		if (ret) {
6931a866306SLucas Stach 			platform_device_put(pdev);
6941a866306SLucas Stach 			of_node_put(np);
6951a866306SLucas Stach 			goto unregister_platform_driver;
6961a866306SLucas Stach 		}
6971a866306SLucas Stach 
69845a0faabSFabio Estevam 		etnaviv_drm = pdev;
699246774d1SLucas Stach 		of_node_put(np);
700246774d1SLucas Stach 		break;
701246774d1SLucas Stach 	}
702246774d1SLucas Stach 
70345a0faabSFabio Estevam 	return 0;
70445a0faabSFabio Estevam 
70545a0faabSFabio Estevam unregister_platform_driver:
70645a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_platform_driver);
70745a0faabSFabio Estevam unregister_gpu_driver:
70845a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
709a8c21a54SThe etnaviv authors 	return ret;
710a8c21a54SThe etnaviv authors }
711a8c21a54SThe etnaviv authors module_init(etnaviv_init);
712a8c21a54SThe etnaviv authors 
etnaviv_exit(void)713a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void)
714a8c21a54SThe etnaviv authors {
715bf6ba3aeSFabio Estevam 	platform_device_unregister(etnaviv_drm);
716a8c21a54SThe etnaviv authors 	platform_driver_unregister(&etnaviv_platform_driver);
717bf6ba3aeSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
718a8c21a54SThe etnaviv authors }
719a8c21a54SThe etnaviv authors module_exit(etnaviv_exit);
720a8c21a54SThe etnaviv authors 
721a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
7224f39467eSRussell King MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
723a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
724a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver");
725a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2");
726a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv");
727