1f6ffbd4fSLucas Stach // SPDX-License-Identifier: GPL-2.0
2a8c21a54SThe etnaviv authors /*
3f6ffbd4fSLucas Stach  * Copyright (C) 2015-2018 Etnaviv Project
4a8c21a54SThe etnaviv authors  */
5a8c21a54SThe etnaviv authors 
6a8c21a54SThe etnaviv authors #include <linux/component.h>
76eae41feSSam Ravnborg #include <linux/dma-mapping.h>
82e737e52SLucas Stach #include <linux/module.h>
9a8c21a54SThe etnaviv authors #include <linux/of_platform.h>
106eae41feSSam Ravnborg #include <linux/uaccess.h>
116eae41feSSam Ravnborg 
126eae41feSSam Ravnborg #include <drm/drm_debugfs.h>
136eae41feSSam Ravnborg #include <drm/drm_drv.h>
146eae41feSSam Ravnborg #include <drm/drm_file.h>
156eae41feSSam Ravnborg #include <drm/drm_ioctl.h>
1697ac0e47SRussell King #include <drm/drm_of.h>
176eae41feSSam Ravnborg #include <drm/drm_prime.h>
18a8c21a54SThe etnaviv authors 
19ea1f5729SLucas Stach #include "etnaviv_cmdbuf.h"
20a8c21a54SThe etnaviv authors #include "etnaviv_drv.h"
21a8c21a54SThe etnaviv authors #include "etnaviv_gpu.h"
22a8c21a54SThe etnaviv authors #include "etnaviv_gem.h"
23a8c21a54SThe etnaviv authors #include "etnaviv_mmu.h"
249e2c2e27SChristian Gmeiner #include "etnaviv_perfmon.h"
25a8c21a54SThe etnaviv authors 
26a8c21a54SThe etnaviv authors /*
27a8c21a54SThe etnaviv authors  * DRM operations:
28a8c21a54SThe etnaviv authors  */
29a8c21a54SThe etnaviv authors 
30a8c21a54SThe etnaviv authors 
31a8c21a54SThe etnaviv authors static void load_gpu(struct drm_device *dev)
32a8c21a54SThe etnaviv authors {
33a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
34a8c21a54SThe etnaviv authors 	unsigned int i;
35a8c21a54SThe etnaviv authors 
36a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
37a8c21a54SThe etnaviv authors 		struct etnaviv_gpu *g = priv->gpu[i];
38a8c21a54SThe etnaviv authors 
39a8c21a54SThe etnaviv authors 		if (g) {
40a8c21a54SThe etnaviv authors 			int ret;
41a8c21a54SThe etnaviv authors 
42a8c21a54SThe etnaviv authors 			ret = etnaviv_gpu_init(g);
43c1c77b0eSLucas Stach 			if (ret)
44a8c21a54SThe etnaviv authors 				priv->gpu[i] = NULL;
45a8c21a54SThe etnaviv authors 		}
46a8c21a54SThe etnaviv authors 	}
47a8c21a54SThe etnaviv authors }
48a8c21a54SThe etnaviv authors 
49a8c21a54SThe etnaviv authors static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
50a8c21a54SThe etnaviv authors {
51e93b6deeSLucas Stach 	struct etnaviv_drm_private *priv = dev->dev_private;
52a8c21a54SThe etnaviv authors 	struct etnaviv_file_private *ctx;
5317e4660aSLucas Stach 	int ret, i;
54a8c21a54SThe etnaviv authors 
55a8c21a54SThe etnaviv authors 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
56a8c21a54SThe etnaviv authors 	if (!ctx)
57a8c21a54SThe etnaviv authors 		return -ENOMEM;
58a8c21a54SThe etnaviv authors 
5917e4660aSLucas Stach 	ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global,
6017e4660aSLucas Stach 					      priv->cmdbuf_suballoc);
6117e4660aSLucas Stach 	if (!ctx->mmu) {
6217e4660aSLucas Stach 		ret = -ENOMEM;
6317e4660aSLucas Stach 		goto out_free;
6417e4660aSLucas Stach 	}
6517e4660aSLucas Stach 
66e93b6deeSLucas Stach 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
67e93b6deeSLucas Stach 		struct etnaviv_gpu *gpu = priv->gpu[i];
68b3ac1766SNirmoy Das 		struct drm_gpu_scheduler *sched;
69e93b6deeSLucas Stach 
70e93b6deeSLucas Stach 		if (gpu) {
71b3ac1766SNirmoy Das 			sched = &gpu->sched;
72aa16b6c6SNayan Deshmukh 			drm_sched_entity_init(&ctx->sched_entity[i],
73b3ac1766SNirmoy Das 					      DRM_SCHED_PRIORITY_NORMAL, &sched,
74b3ac1766SNirmoy Das 					      1, NULL);
75e93b6deeSLucas Stach 			}
76e93b6deeSLucas Stach 	}
77e93b6deeSLucas Stach 
78a8c21a54SThe etnaviv authors 	file->driver_priv = ctx;
79a8c21a54SThe etnaviv authors 
80a8c21a54SThe etnaviv authors 	return 0;
8117e4660aSLucas Stach 
8217e4660aSLucas Stach out_free:
8317e4660aSLucas Stach 	kfree(ctx);
8417e4660aSLucas Stach 	return ret;
85a8c21a54SThe etnaviv authors }
86a8c21a54SThe etnaviv authors 
87fda8fa5bSDaniel Vetter static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
88a8c21a54SThe etnaviv authors {
89a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
90a8c21a54SThe etnaviv authors 	struct etnaviv_file_private *ctx = file->driver_priv;
91a8c21a54SThe etnaviv authors 	unsigned int i;
92a8c21a54SThe etnaviv authors 
93a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
94a8c21a54SThe etnaviv authors 		struct etnaviv_gpu *gpu = priv->gpu[i];
95a8c21a54SThe etnaviv authors 
96801c7a1eSLucas Stach 		if (gpu)
97cdc50176SNayan Deshmukh 			drm_sched_entity_destroy(&ctx->sched_entity[i]);
98a8c21a54SThe etnaviv authors 	}
99a8c21a54SThe etnaviv authors 
10017e4660aSLucas Stach 	etnaviv_iommu_context_put(ctx->mmu);
10117e4660aSLucas Stach 
102a8c21a54SThe etnaviv authors 	kfree(ctx);
103a8c21a54SThe etnaviv authors }
104a8c21a54SThe etnaviv authors 
105a8c21a54SThe etnaviv authors /*
106a8c21a54SThe etnaviv authors  * DRM debugfs:
107a8c21a54SThe etnaviv authors  */
108a8c21a54SThe etnaviv authors 
109a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS
110a8c21a54SThe etnaviv authors static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
111a8c21a54SThe etnaviv authors {
112a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
113a8c21a54SThe etnaviv authors 
114a8c21a54SThe etnaviv authors 	etnaviv_gem_describe_objects(priv, m);
115a8c21a54SThe etnaviv authors 
116a8c21a54SThe etnaviv authors 	return 0;
117a8c21a54SThe etnaviv authors }
118a8c21a54SThe etnaviv authors 
119a8c21a54SThe etnaviv authors static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m)
120a8c21a54SThe etnaviv authors {
121b5c3714fSDaniel Vetter 	struct drm_printer p = drm_seq_file_printer(m);
122a8c21a54SThe etnaviv authors 
123a8c21a54SThe etnaviv authors 	read_lock(&dev->vma_offset_manager->vm_lock);
124b5c3714fSDaniel Vetter 	drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p);
125a8c21a54SThe etnaviv authors 	read_unlock(&dev->vma_offset_manager->vm_lock);
126a8c21a54SThe etnaviv authors 
127b5c3714fSDaniel Vetter 	return 0;
128a8c21a54SThe etnaviv authors }
129a8c21a54SThe etnaviv authors 
130a8c21a54SThe etnaviv authors static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m)
131a8c21a54SThe etnaviv authors {
132b5c3714fSDaniel Vetter 	struct drm_printer p = drm_seq_file_printer(m);
13317e4660aSLucas Stach 	struct etnaviv_iommu_context *mmu_context;
134b5c3714fSDaniel Vetter 
135a8c21a54SThe etnaviv authors 	seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev));
136a8c21a54SThe etnaviv authors 
13717e4660aSLucas Stach 	/*
13817e4660aSLucas Stach 	 * Lock the GPU to avoid a MMU context switch just now and elevate
13917e4660aSLucas Stach 	 * the refcount of the current context to avoid it disappearing from
14017e4660aSLucas Stach 	 * under our feet.
14117e4660aSLucas Stach 	 */
14217e4660aSLucas Stach 	mutex_lock(&gpu->lock);
14317e4660aSLucas Stach 	mmu_context = gpu->mmu_context;
14417e4660aSLucas Stach 	if (mmu_context)
14517e4660aSLucas Stach 		etnaviv_iommu_context_get(mmu_context);
14617e4660aSLucas Stach 	mutex_unlock(&gpu->lock);
14717e4660aSLucas Stach 
14817e4660aSLucas Stach 	if (!mmu_context)
14917e4660aSLucas Stach 		return 0;
15017e4660aSLucas Stach 
15117e4660aSLucas Stach 	mutex_lock(&mmu_context->lock);
15217e4660aSLucas Stach 	drm_mm_print(&mmu_context->mm, &p);
15317e4660aSLucas Stach 	mutex_unlock(&mmu_context->lock);
15417e4660aSLucas Stach 
15517e4660aSLucas Stach 	etnaviv_iommu_context_put(mmu_context);
156a8c21a54SThe etnaviv authors 
157a8c21a54SThe etnaviv authors 	return 0;
158a8c21a54SThe etnaviv authors }
159a8c21a54SThe etnaviv authors 
160a8c21a54SThe etnaviv authors static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
161a8c21a54SThe etnaviv authors {
1622f9225dbSLucas Stach 	struct etnaviv_cmdbuf *buf = &gpu->buffer;
163a8c21a54SThe etnaviv authors 	u32 size = buf->size;
164a8c21a54SThe etnaviv authors 	u32 *ptr = buf->vaddr;
165a8c21a54SThe etnaviv authors 	u32 i;
166a8c21a54SThe etnaviv authors 
167a8c21a54SThe etnaviv authors 	seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
1689912b4dbSLucas Stach 			buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),
1699912b4dbSLucas Stach 			size - buf->user_size);
170a8c21a54SThe etnaviv authors 
171a8c21a54SThe etnaviv authors 	for (i = 0; i < size / 4; i++) {
172a8c21a54SThe etnaviv authors 		if (i && !(i % 4))
173a8c21a54SThe etnaviv authors 			seq_puts(m, "\n");
174a8c21a54SThe etnaviv authors 		if (i % 4 == 0)
175a8c21a54SThe etnaviv authors 			seq_printf(m, "\t0x%p: ", ptr + i);
176a8c21a54SThe etnaviv authors 		seq_printf(m, "%08x ", *(ptr + i));
177a8c21a54SThe etnaviv authors 	}
178a8c21a54SThe etnaviv authors 	seq_puts(m, "\n");
179a8c21a54SThe etnaviv authors }
180a8c21a54SThe etnaviv authors 
181a8c21a54SThe etnaviv authors static int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m)
182a8c21a54SThe etnaviv authors {
183a8c21a54SThe etnaviv authors 	seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev));
184a8c21a54SThe etnaviv authors 
185a8c21a54SThe etnaviv authors 	mutex_lock(&gpu->lock);
186a8c21a54SThe etnaviv authors 	etnaviv_buffer_dump(gpu, m);
187a8c21a54SThe etnaviv authors 	mutex_unlock(&gpu->lock);
188a8c21a54SThe etnaviv authors 
189a8c21a54SThe etnaviv authors 	return 0;
190a8c21a54SThe etnaviv authors }
191a8c21a54SThe etnaviv authors 
192a8c21a54SThe etnaviv authors static int show_unlocked(struct seq_file *m, void *arg)
193a8c21a54SThe etnaviv authors {
194a8c21a54SThe etnaviv authors 	struct drm_info_node *node = (struct drm_info_node *) m->private;
195a8c21a54SThe etnaviv authors 	struct drm_device *dev = node->minor->dev;
196a8c21a54SThe etnaviv authors 	int (*show)(struct drm_device *dev, struct seq_file *m) =
197a8c21a54SThe etnaviv authors 			node->info_ent->data;
198a8c21a54SThe etnaviv authors 
199a8c21a54SThe etnaviv authors 	return show(dev, m);
200a8c21a54SThe etnaviv authors }
201a8c21a54SThe etnaviv authors 
202a8c21a54SThe etnaviv authors static int show_each_gpu(struct seq_file *m, void *arg)
203a8c21a54SThe etnaviv authors {
204a8c21a54SThe etnaviv authors 	struct drm_info_node *node = (struct drm_info_node *) m->private;
205a8c21a54SThe etnaviv authors 	struct drm_device *dev = node->minor->dev;
206a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
207a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
208a8c21a54SThe etnaviv authors 	int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
209a8c21a54SThe etnaviv authors 			node->info_ent->data;
210a8c21a54SThe etnaviv authors 	unsigned int i;
211a8c21a54SThe etnaviv authors 	int ret = 0;
212a8c21a54SThe etnaviv authors 
213a8c21a54SThe etnaviv authors 	for (i = 0; i < ETNA_MAX_PIPES; i++) {
214a8c21a54SThe etnaviv authors 		gpu = priv->gpu[i];
215a8c21a54SThe etnaviv authors 		if (!gpu)
216a8c21a54SThe etnaviv authors 			continue;
217a8c21a54SThe etnaviv authors 
218a8c21a54SThe etnaviv authors 		ret = show(gpu, m);
219a8c21a54SThe etnaviv authors 		if (ret < 0)
220a8c21a54SThe etnaviv authors 			break;
221a8c21a54SThe etnaviv authors 	}
222a8c21a54SThe etnaviv authors 
223a8c21a54SThe etnaviv authors 	return ret;
224a8c21a54SThe etnaviv authors }
225a8c21a54SThe etnaviv authors 
226a8c21a54SThe etnaviv authors static struct drm_info_list etnaviv_debugfs_list[] = {
227a8c21a54SThe etnaviv authors 		{"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs},
228a8c21a54SThe etnaviv authors 		{"gem", show_unlocked, 0, etnaviv_gem_show},
229a8c21a54SThe etnaviv authors 		{ "mm", show_unlocked, 0, etnaviv_mm_show },
230a8c21a54SThe etnaviv authors 		{"mmu", show_each_gpu, 0, etnaviv_mmu_show},
231a8c21a54SThe etnaviv authors 		{"ring", show_each_gpu, 0, etnaviv_ring_show},
232a8c21a54SThe etnaviv authors };
233a8c21a54SThe etnaviv authors 
234a8c21a54SThe etnaviv authors static int etnaviv_debugfs_init(struct drm_minor *minor)
235a8c21a54SThe etnaviv authors {
236a8c21a54SThe etnaviv authors 	struct drm_device *dev = minor->dev;
237a8c21a54SThe etnaviv authors 	int ret;
238a8c21a54SThe etnaviv authors 
239a8c21a54SThe etnaviv authors 	ret = drm_debugfs_create_files(etnaviv_debugfs_list,
240a8c21a54SThe etnaviv authors 			ARRAY_SIZE(etnaviv_debugfs_list),
241a8c21a54SThe etnaviv authors 			minor->debugfs_root, minor);
242a8c21a54SThe etnaviv authors 
243a8c21a54SThe etnaviv authors 	if (ret) {
244a8c21a54SThe etnaviv authors 		dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
245a8c21a54SThe etnaviv authors 		return ret;
246a8c21a54SThe etnaviv authors 	}
247a8c21a54SThe etnaviv authors 
248a8c21a54SThe etnaviv authors 	return ret;
249a8c21a54SThe etnaviv authors }
250a8c21a54SThe etnaviv authors #endif
251a8c21a54SThe etnaviv authors 
252a8c21a54SThe etnaviv authors /*
253a8c21a54SThe etnaviv authors  * DRM ioctls:
254a8c21a54SThe etnaviv authors  */
255a8c21a54SThe etnaviv authors 
256a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
257a8c21a54SThe etnaviv authors 		struct drm_file *file)
258a8c21a54SThe etnaviv authors {
259a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
260a8c21a54SThe etnaviv authors 	struct drm_etnaviv_param *args = data;
261a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
262a8c21a54SThe etnaviv authors 
263a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
264a8c21a54SThe etnaviv authors 		return -EINVAL;
265a8c21a54SThe etnaviv authors 
266a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
267a8c21a54SThe etnaviv authors 	if (!gpu)
268a8c21a54SThe etnaviv authors 		return -ENXIO;
269a8c21a54SThe etnaviv authors 
270a8c21a54SThe etnaviv authors 	return etnaviv_gpu_get_param(gpu, args->param, &args->value);
271a8c21a54SThe etnaviv authors }
272a8c21a54SThe etnaviv authors 
273a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
274a8c21a54SThe etnaviv authors 		struct drm_file *file)
275a8c21a54SThe etnaviv authors {
276a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_new *args = data;
277a8c21a54SThe etnaviv authors 
278a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED |
279a8c21a54SThe etnaviv authors 			    ETNA_BO_FORCE_MMU))
280a8c21a54SThe etnaviv authors 		return -EINVAL;
281a8c21a54SThe etnaviv authors 
282a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_handle(dev, file, args->size,
283a8c21a54SThe etnaviv authors 			args->flags, &args->handle);
284a8c21a54SThe etnaviv authors }
285a8c21a54SThe etnaviv authors 
286a8c21a54SThe etnaviv authors #define TS(t) ((struct timespec){ \
287a8c21a54SThe etnaviv authors 	.tv_sec = (t).tv_sec, \
288a8c21a54SThe etnaviv authors 	.tv_nsec = (t).tv_nsec \
289a8c21a54SThe etnaviv authors })
290a8c21a54SThe etnaviv authors 
291a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
292a8c21a54SThe etnaviv authors 		struct drm_file *file)
293a8c21a54SThe etnaviv authors {
294a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_prep *args = data;
295a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
296a8c21a54SThe etnaviv authors 	int ret;
297a8c21a54SThe etnaviv authors 
298a8c21a54SThe etnaviv authors 	if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC))
299a8c21a54SThe etnaviv authors 		return -EINVAL;
300a8c21a54SThe etnaviv authors 
301a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
302a8c21a54SThe etnaviv authors 	if (!obj)
303a8c21a54SThe etnaviv authors 		return -ENOENT;
304a8c21a54SThe etnaviv authors 
305a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout));
306a8c21a54SThe etnaviv authors 
30723d1dd03SCihangir Akturk 	drm_gem_object_put_unlocked(obj);
308a8c21a54SThe etnaviv authors 
309a8c21a54SThe etnaviv authors 	return ret;
310a8c21a54SThe etnaviv authors }
311a8c21a54SThe etnaviv authors 
312a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
313a8c21a54SThe etnaviv authors 		struct drm_file *file)
314a8c21a54SThe etnaviv authors {
315a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_cpu_fini *args = data;
316a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
317a8c21a54SThe etnaviv authors 	int ret;
318a8c21a54SThe etnaviv authors 
319a8c21a54SThe etnaviv authors 	if (args->flags)
320a8c21a54SThe etnaviv authors 		return -EINVAL;
321a8c21a54SThe etnaviv authors 
322a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
323a8c21a54SThe etnaviv authors 	if (!obj)
324a8c21a54SThe etnaviv authors 		return -ENOENT;
325a8c21a54SThe etnaviv authors 
326a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_cpu_fini(obj);
327a8c21a54SThe etnaviv authors 
32823d1dd03SCihangir Akturk 	drm_gem_object_put_unlocked(obj);
329a8c21a54SThe etnaviv authors 
330a8c21a54SThe etnaviv authors 	return ret;
331a8c21a54SThe etnaviv authors }
332a8c21a54SThe etnaviv authors 
333a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
334a8c21a54SThe etnaviv authors 		struct drm_file *file)
335a8c21a54SThe etnaviv authors {
336a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_info *args = data;
337a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
338a8c21a54SThe etnaviv authors 	int ret;
339a8c21a54SThe etnaviv authors 
340a8c21a54SThe etnaviv authors 	if (args->pad)
341a8c21a54SThe etnaviv authors 		return -EINVAL;
342a8c21a54SThe etnaviv authors 
343a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
344a8c21a54SThe etnaviv authors 	if (!obj)
345a8c21a54SThe etnaviv authors 		return -ENOENT;
346a8c21a54SThe etnaviv authors 
347a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
34823d1dd03SCihangir Akturk 	drm_gem_object_put_unlocked(obj);
349a8c21a54SThe etnaviv authors 
350a8c21a54SThe etnaviv authors 	return ret;
351a8c21a54SThe etnaviv authors }
352a8c21a54SThe etnaviv authors 
353a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
354a8c21a54SThe etnaviv authors 		struct drm_file *file)
355a8c21a54SThe etnaviv authors {
356a8c21a54SThe etnaviv authors 	struct drm_etnaviv_wait_fence *args = data;
357a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
358a8c21a54SThe etnaviv authors 	struct timespec *timeout = &TS(args->timeout);
359a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
360a8c21a54SThe etnaviv authors 
361a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
362a8c21a54SThe etnaviv authors 		return -EINVAL;
363a8c21a54SThe etnaviv authors 
364a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
365a8c21a54SThe etnaviv authors 		return -EINVAL;
366a8c21a54SThe etnaviv authors 
367a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
368a8c21a54SThe etnaviv authors 	if (!gpu)
369a8c21a54SThe etnaviv authors 		return -ENXIO;
370a8c21a54SThe etnaviv authors 
371a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
372a8c21a54SThe etnaviv authors 		timeout = NULL;
373a8c21a54SThe etnaviv authors 
374a8c21a54SThe etnaviv authors 	return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence,
375a8c21a54SThe etnaviv authors 						    timeout);
376a8c21a54SThe etnaviv authors }
377a8c21a54SThe etnaviv authors 
378a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
379a8c21a54SThe etnaviv authors 	struct drm_file *file)
380a8c21a54SThe etnaviv authors {
381a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_userptr *args = data;
382a8c21a54SThe etnaviv authors 
383a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) ||
384a8c21a54SThe etnaviv authors 	    args->flags == 0)
385a8c21a54SThe etnaviv authors 		return -EINVAL;
386a8c21a54SThe etnaviv authors 
387a8c21a54SThe etnaviv authors 	if (offset_in_page(args->user_ptr | args->user_size) ||
388a8c21a54SThe etnaviv authors 	    (uintptr_t)args->user_ptr != args->user_ptr ||
389a8c21a54SThe etnaviv authors 	    (u32)args->user_size != args->user_size ||
390a8c21a54SThe etnaviv authors 	    args->user_ptr & ~PAGE_MASK)
391a8c21a54SThe etnaviv authors 		return -EINVAL;
392a8c21a54SThe etnaviv authors 
39396d4f267SLinus Torvalds 	if (!access_ok((void __user *)(unsigned long)args->user_ptr,
394a8c21a54SThe etnaviv authors 		       args->user_size))
395a8c21a54SThe etnaviv authors 		return -EFAULT;
396a8c21a54SThe etnaviv authors 
397a8c21a54SThe etnaviv authors 	return etnaviv_gem_new_userptr(dev, file, args->user_ptr,
398a8c21a54SThe etnaviv authors 				       args->user_size, args->flags,
399a8c21a54SThe etnaviv authors 				       &args->handle);
400a8c21a54SThe etnaviv authors }
401a8c21a54SThe etnaviv authors 
402a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
403a8c21a54SThe etnaviv authors 	struct drm_file *file)
404a8c21a54SThe etnaviv authors {
405a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = dev->dev_private;
406a8c21a54SThe etnaviv authors 	struct drm_etnaviv_gem_wait *args = data;
407a8c21a54SThe etnaviv authors 	struct timespec *timeout = &TS(args->timeout);
408a8c21a54SThe etnaviv authors 	struct drm_gem_object *obj;
409a8c21a54SThe etnaviv authors 	struct etnaviv_gpu *gpu;
410a8c21a54SThe etnaviv authors 	int ret;
411a8c21a54SThe etnaviv authors 
412a8c21a54SThe etnaviv authors 	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
413a8c21a54SThe etnaviv authors 		return -EINVAL;
414a8c21a54SThe etnaviv authors 
415a8c21a54SThe etnaviv authors 	if (args->pipe >= ETNA_MAX_PIPES)
416a8c21a54SThe etnaviv authors 		return -EINVAL;
417a8c21a54SThe etnaviv authors 
418a8c21a54SThe etnaviv authors 	gpu = priv->gpu[args->pipe];
419a8c21a54SThe etnaviv authors 	if (!gpu)
420a8c21a54SThe etnaviv authors 		return -ENXIO;
421a8c21a54SThe etnaviv authors 
422a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file, args->handle);
423a8c21a54SThe etnaviv authors 	if (!obj)
424a8c21a54SThe etnaviv authors 		return -ENOENT;
425a8c21a54SThe etnaviv authors 
426a8c21a54SThe etnaviv authors 	if (args->flags & ETNA_WAIT_NONBLOCK)
427a8c21a54SThe etnaviv authors 		timeout = NULL;
428a8c21a54SThe etnaviv authors 
429a8c21a54SThe etnaviv authors 	ret = etnaviv_gem_wait_bo(gpu, obj, timeout);
430a8c21a54SThe etnaviv authors 
43123d1dd03SCihangir Akturk 	drm_gem_object_put_unlocked(obj);
432a8c21a54SThe etnaviv authors 
433a8c21a54SThe etnaviv authors 	return ret;
434a8c21a54SThe etnaviv authors }
435a8c21a54SThe etnaviv authors 
4369e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
4379e2c2e27SChristian Gmeiner 	struct drm_file *file)
4389e2c2e27SChristian Gmeiner {
4399e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4409e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_domain *args = data;
4419e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4429e2c2e27SChristian Gmeiner 
4439e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4449e2c2e27SChristian Gmeiner 		return -EINVAL;
4459e2c2e27SChristian Gmeiner 
4469e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4479e2c2e27SChristian Gmeiner 	if (!gpu)
4489e2c2e27SChristian Gmeiner 		return -ENXIO;
4499e2c2e27SChristian Gmeiner 
4509e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_dom(gpu, args);
4519e2c2e27SChristian Gmeiner }
4529e2c2e27SChristian Gmeiner 
4539e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data,
4549e2c2e27SChristian Gmeiner 	struct drm_file *file)
4559e2c2e27SChristian Gmeiner {
4569e2c2e27SChristian Gmeiner 	struct etnaviv_drm_private *priv = dev->dev_private;
4579e2c2e27SChristian Gmeiner 	struct drm_etnaviv_pm_signal *args = data;
4589e2c2e27SChristian Gmeiner 	struct etnaviv_gpu *gpu;
4599e2c2e27SChristian Gmeiner 
4609e2c2e27SChristian Gmeiner 	if (args->pipe >= ETNA_MAX_PIPES)
4619e2c2e27SChristian Gmeiner 		return -EINVAL;
4629e2c2e27SChristian Gmeiner 
4639e2c2e27SChristian Gmeiner 	gpu = priv->gpu[args->pipe];
4649e2c2e27SChristian Gmeiner 	if (!gpu)
4659e2c2e27SChristian Gmeiner 		return -ENXIO;
4669e2c2e27SChristian Gmeiner 
4679e2c2e27SChristian Gmeiner 	return etnaviv_pm_query_sig(gpu, args);
4689e2c2e27SChristian Gmeiner }
4699e2c2e27SChristian Gmeiner 
470a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = {
471a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \
472a8c21a54SThe etnaviv authors 	DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags)
473b8602f9aSEmil Velikov 	ETNA_IOCTL(GET_PARAM,    get_param,    DRM_RENDER_ALLOW),
474b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_NEW,      gem_new,      DRM_RENDER_ALLOW),
475b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_INFO,     gem_info,     DRM_RENDER_ALLOW),
476b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW),
477b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW),
478b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_SUBMIT,   gem_submit,   DRM_RENDER_ALLOW),
479b8602f9aSEmil Velikov 	ETNA_IOCTL(WAIT_FENCE,   wait_fence,   DRM_RENDER_ALLOW),
480b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_USERPTR,  gem_userptr,  DRM_RENDER_ALLOW),
481b8602f9aSEmil Velikov 	ETNA_IOCTL(GEM_WAIT,     gem_wait,     DRM_RENDER_ALLOW),
482b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW),
483b8602f9aSEmil Velikov 	ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW),
484a8c21a54SThe etnaviv authors };
485a8c21a54SThe etnaviv authors 
486a8c21a54SThe etnaviv authors static const struct vm_operations_struct vm_ops = {
487a8c21a54SThe etnaviv authors 	.fault = etnaviv_gem_fault,
488a8c21a54SThe etnaviv authors 	.open = drm_gem_vm_open,
489a8c21a54SThe etnaviv authors 	.close = drm_gem_vm_close,
490a8c21a54SThe etnaviv authors };
491a8c21a54SThe etnaviv authors 
492a8c21a54SThe etnaviv authors static const struct file_operations fops = {
493a8c21a54SThe etnaviv authors 	.owner              = THIS_MODULE,
494a8c21a54SThe etnaviv authors 	.open               = drm_open,
495a8c21a54SThe etnaviv authors 	.release            = drm_release,
496a8c21a54SThe etnaviv authors 	.unlocked_ioctl     = drm_ioctl,
497a8c21a54SThe etnaviv authors 	.compat_ioctl       = drm_compat_ioctl,
498a8c21a54SThe etnaviv authors 	.poll               = drm_poll,
499a8c21a54SThe etnaviv authors 	.read               = drm_read,
500a8c21a54SThe etnaviv authors 	.llseek             = no_llseek,
501a8c21a54SThe etnaviv authors 	.mmap               = etnaviv_gem_mmap,
502a8c21a54SThe etnaviv authors };
503a8c21a54SThe etnaviv authors 
504a8c21a54SThe etnaviv authors static struct drm_driver etnaviv_drm_driver = {
5050424fdafSDaniel Vetter 	.driver_features    = DRIVER_GEM | DRIVER_RENDER,
506a8c21a54SThe etnaviv authors 	.open               = etnaviv_open,
507fda8fa5bSDaniel Vetter 	.postclose           = etnaviv_postclose,
5081d657c58SDaniel Vetter 	.gem_free_object_unlocked = etnaviv_gem_free_object,
509a8c21a54SThe etnaviv authors 	.gem_vm_ops         = &vm_ops,
510a8c21a54SThe etnaviv authors 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
511a8c21a54SThe etnaviv authors 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
512a8c21a54SThe etnaviv authors 	.gem_prime_pin      = etnaviv_gem_prime_pin,
513a8c21a54SThe etnaviv authors 	.gem_prime_unpin    = etnaviv_gem_prime_unpin,
514a8c21a54SThe etnaviv authors 	.gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table,
515a8c21a54SThe etnaviv authors 	.gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table,
516a8c21a54SThe etnaviv authors 	.gem_prime_vmap     = etnaviv_gem_prime_vmap,
517a8c21a54SThe etnaviv authors 	.gem_prime_vunmap   = etnaviv_gem_prime_vunmap,
5185688e57eSLucas Stach 	.gem_prime_mmap     = etnaviv_gem_prime_mmap,
519a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS
520a8c21a54SThe etnaviv authors 	.debugfs_init       = etnaviv_debugfs_init,
521a8c21a54SThe etnaviv authors #endif
522a8c21a54SThe etnaviv authors 	.ioctls             = etnaviv_ioctls,
523a8c21a54SThe etnaviv authors 	.num_ioctls         = DRM_ETNAVIV_NUM_IOCTLS,
524a8c21a54SThe etnaviv authors 	.fops               = &fops,
525a8c21a54SThe etnaviv authors 	.name               = "etnaviv",
526a8c21a54SThe etnaviv authors 	.desc               = "etnaviv DRM",
527a8c21a54SThe etnaviv authors 	.date               = "20151214",
528a8c21a54SThe etnaviv authors 	.major              = 1,
529088880ddSLucas Stach 	.minor              = 3,
530a8c21a54SThe etnaviv authors };
531a8c21a54SThe etnaviv authors 
532a8c21a54SThe etnaviv authors /*
533a8c21a54SThe etnaviv authors  * Platform driver:
534a8c21a54SThe etnaviv authors  */
535a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev)
536a8c21a54SThe etnaviv authors {
537a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv;
538a8c21a54SThe etnaviv authors 	struct drm_device *drm;
539a8c21a54SThe etnaviv authors 	int ret;
540a8c21a54SThe etnaviv authors 
541a8c21a54SThe etnaviv authors 	drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
5420f288605STom Gundersen 	if (IS_ERR(drm))
5430f288605STom Gundersen 		return PTR_ERR(drm);
544a8c21a54SThe etnaviv authors 
545a8c21a54SThe etnaviv authors 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
546a8c21a54SThe etnaviv authors 	if (!priv) {
547a8c21a54SThe etnaviv authors 		dev_err(dev, "failed to allocate private data\n");
548a8c21a54SThe etnaviv authors 		ret = -ENOMEM;
54999e29449SThomas Zimmermann 		goto out_put;
550a8c21a54SThe etnaviv authors 	}
551a8c21a54SThe etnaviv authors 	drm->dev_private = priv;
552a8c21a54SThe etnaviv authors 
5531262cc88SRussell King 	dev->dma_parms = &priv->dma_parms;
5541262cc88SRussell King 	dma_set_max_seg_size(dev, SZ_2G);
5551262cc88SRussell King 
556a8c21a54SThe etnaviv authors 	mutex_init(&priv->gem_lock);
557a8c21a54SThe etnaviv authors 	INIT_LIST_HEAD(&priv->gem_list);
558a8c21a54SThe etnaviv authors 	priv->num_gpus = 0;
559a8c21a54SThe etnaviv authors 
560bffe5db8SLucas Stach 	priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
561bffe5db8SLucas Stach 	if (IS_ERR(priv->cmdbuf_suballoc)) {
562bffe5db8SLucas Stach 		dev_err(drm->dev, "Failed to create cmdbuf suballocator\n");
563bffe5db8SLucas Stach 		ret = PTR_ERR(priv->cmdbuf_suballoc);
564bffe5db8SLucas Stach 		goto out_free_priv;
565bffe5db8SLucas Stach 	}
566bffe5db8SLucas Stach 
567a8c21a54SThe etnaviv authors 	dev_set_drvdata(dev, drm);
568a8c21a54SThe etnaviv authors 
569a8c21a54SThe etnaviv authors 	ret = component_bind_all(dev, drm);
570a8c21a54SThe etnaviv authors 	if (ret < 0)
571bffe5db8SLucas Stach 		goto out_destroy_suballoc;
572a8c21a54SThe etnaviv authors 
573a8c21a54SThe etnaviv authors 	load_gpu(drm);
574a8c21a54SThe etnaviv authors 
575a8c21a54SThe etnaviv authors 	ret = drm_dev_register(drm, 0);
576a8c21a54SThe etnaviv authors 	if (ret)
577bffe5db8SLucas Stach 		goto out_unbind;
578a8c21a54SThe etnaviv authors 
579a8c21a54SThe etnaviv authors 	return 0;
580a8c21a54SThe etnaviv authors 
581bffe5db8SLucas Stach out_unbind:
582a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
583bffe5db8SLucas Stach out_destroy_suballoc:
584bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
585bffe5db8SLucas Stach out_free_priv:
586a8c21a54SThe etnaviv authors 	kfree(priv);
58799e29449SThomas Zimmermann out_put:
58899e29449SThomas Zimmermann 	drm_dev_put(drm);
589a8c21a54SThe etnaviv authors 
590a8c21a54SThe etnaviv authors 	return ret;
591a8c21a54SThe etnaviv authors }
592a8c21a54SThe etnaviv authors 
593a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev)
594a8c21a54SThe etnaviv authors {
595a8c21a54SThe etnaviv authors 	struct drm_device *drm = dev_get_drvdata(dev);
596a8c21a54SThe etnaviv authors 	struct etnaviv_drm_private *priv = drm->dev_private;
597a8c21a54SThe etnaviv authors 
598a8c21a54SThe etnaviv authors 	drm_dev_unregister(drm);
599a8c21a54SThe etnaviv authors 
600a8c21a54SThe etnaviv authors 	component_unbind_all(dev, drm);
601a8c21a54SThe etnaviv authors 
6021262cc88SRussell King 	dev->dma_parms = NULL;
6031262cc88SRussell King 
604bffe5db8SLucas Stach 	etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
605bffe5db8SLucas Stach 
606a8c21a54SThe etnaviv authors 	drm->dev_private = NULL;
607a8c21a54SThe etnaviv authors 	kfree(priv);
608a8c21a54SThe etnaviv authors 
60999e29449SThomas Zimmermann 	drm_dev_put(drm);
610a8c21a54SThe etnaviv authors }
611a8c21a54SThe etnaviv authors 
612a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = {
613a8c21a54SThe etnaviv authors 	.bind = etnaviv_bind,
614a8c21a54SThe etnaviv authors 	.unbind = etnaviv_unbind,
615a8c21a54SThe etnaviv authors };
616a8c21a54SThe etnaviv authors 
617a8c21a54SThe etnaviv authors static int compare_of(struct device *dev, void *data)
618a8c21a54SThe etnaviv authors {
619a8c21a54SThe etnaviv authors 	struct device_node *np = data;
620a8c21a54SThe etnaviv authors 
621a8c21a54SThe etnaviv authors 	return dev->of_node == np;
622a8c21a54SThe etnaviv authors }
623a8c21a54SThe etnaviv authors 
624a8c21a54SThe etnaviv authors static int compare_str(struct device *dev, void *data)
625a8c21a54SThe etnaviv authors {
626a8c21a54SThe etnaviv authors 	return !strcmp(dev_name(dev), data);
627a8c21a54SThe etnaviv authors }
628a8c21a54SThe etnaviv authors 
629a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev)
630a8c21a54SThe etnaviv authors {
631a8c21a54SThe etnaviv authors 	struct device *dev = &pdev->dev;
632a8c21a54SThe etnaviv authors 	struct component_match *match = NULL;
633a8c21a54SThe etnaviv authors 
634246774d1SLucas Stach 	if (!dev->platform_data) {
635a8c21a54SThe etnaviv authors 		struct device_node *core_node;
636a8c21a54SThe etnaviv authors 
637246774d1SLucas Stach 		for_each_compatible_node(core_node, NULL, "vivante,gc") {
638246774d1SLucas Stach 			if (!of_device_is_available(core_node))
639246774d1SLucas Stach 				continue;
640a8c21a54SThe etnaviv authors 
64197ac0e47SRussell King 			drm_of_component_match_add(&pdev->dev, &match,
64297ac0e47SRussell King 						   compare_of, core_node);
643a8c21a54SThe etnaviv authors 		}
644246774d1SLucas Stach 	} else {
645a8c21a54SThe etnaviv authors 		char **names = dev->platform_data;
646a8c21a54SThe etnaviv authors 		unsigned i;
647a8c21a54SThe etnaviv authors 
648a8c21a54SThe etnaviv authors 		for (i = 0; names[i]; i++)
649a8c21a54SThe etnaviv authors 			component_match_add(dev, &match, compare_str, names[i]);
650a8c21a54SThe etnaviv authors 	}
651a8c21a54SThe etnaviv authors 
652a8c21a54SThe etnaviv authors 	return component_master_add_with_match(dev, &etnaviv_master_ops, match);
653a8c21a54SThe etnaviv authors }
654a8c21a54SThe etnaviv authors 
655a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev)
656a8c21a54SThe etnaviv authors {
657a8c21a54SThe etnaviv authors 	component_master_del(&pdev->dev, &etnaviv_master_ops);
658a8c21a54SThe etnaviv authors 
659a8c21a54SThe etnaviv authors 	return 0;
660a8c21a54SThe etnaviv authors }
661a8c21a54SThe etnaviv authors 
662a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = {
663a8c21a54SThe etnaviv authors 	.probe      = etnaviv_pdev_probe,
664a8c21a54SThe etnaviv authors 	.remove     = etnaviv_pdev_remove,
665a8c21a54SThe etnaviv authors 	.driver     = {
666a8c21a54SThe etnaviv authors 		.name   = "etnaviv",
667a8c21a54SThe etnaviv authors 	},
668a8c21a54SThe etnaviv authors };
669a8c21a54SThe etnaviv authors 
67045a0faabSFabio Estevam static struct platform_device *etnaviv_drm;
67145a0faabSFabio Estevam 
672a8c21a54SThe etnaviv authors static int __init etnaviv_init(void)
673a8c21a54SThe etnaviv authors {
67445a0faabSFabio Estevam 	struct platform_device *pdev;
675a8c21a54SThe etnaviv authors 	int ret;
676246774d1SLucas Stach 	struct device_node *np;
677a8c21a54SThe etnaviv authors 
678a8c21a54SThe etnaviv authors 	etnaviv_validate_init();
679a8c21a54SThe etnaviv authors 
680a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_gpu_driver);
681a8c21a54SThe etnaviv authors 	if (ret != 0)
682a8c21a54SThe etnaviv authors 		return ret;
683a8c21a54SThe etnaviv authors 
684a8c21a54SThe etnaviv authors 	ret = platform_driver_register(&etnaviv_platform_driver);
685a8c21a54SThe etnaviv authors 	if (ret != 0)
68645a0faabSFabio Estevam 		goto unregister_gpu_driver;
687a8c21a54SThe etnaviv authors 
688246774d1SLucas Stach 	/*
689246774d1SLucas Stach 	 * If the DT contains at least one available GPU device, instantiate
690246774d1SLucas Stach 	 * the DRM platform device.
691246774d1SLucas Stach 	 */
692246774d1SLucas Stach 	for_each_compatible_node(np, NULL, "vivante,gc") {
693246774d1SLucas Stach 		if (!of_device_is_available(np))
694246774d1SLucas Stach 			continue;
6951a866306SLucas Stach 
6961a866306SLucas Stach 		pdev = platform_device_alloc("etnaviv", -1);
6971a866306SLucas Stach 		if (!pdev) {
6981a866306SLucas Stach 			ret = -ENOMEM;
69945a0faabSFabio Estevam 			of_node_put(np);
70045a0faabSFabio Estevam 			goto unregister_platform_driver;
70145a0faabSFabio Estevam 		}
7021a866306SLucas Stach 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40);
7031a866306SLucas Stach 		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
7041a866306SLucas Stach 
7051a866306SLucas Stach 		/*
7061a866306SLucas Stach 		 * Apply the same DMA configuration to the virtual etnaviv
7071a866306SLucas Stach 		 * device as the GPU we found. This assumes that all Vivante
7081a866306SLucas Stach 		 * GPUs in the system share the same DMA constraints.
7091a866306SLucas Stach 		 */
7101a866306SLucas Stach 		of_dma_configure(&pdev->dev, np, true);
7111a866306SLucas Stach 
7121a866306SLucas Stach 		ret = platform_device_add(pdev);
7131a866306SLucas Stach 		if (ret) {
7141a866306SLucas Stach 			platform_device_put(pdev);
7151a866306SLucas Stach 			of_node_put(np);
7161a866306SLucas Stach 			goto unregister_platform_driver;
7171a866306SLucas Stach 		}
7181a866306SLucas Stach 
71945a0faabSFabio Estevam 		etnaviv_drm = pdev;
720246774d1SLucas Stach 		of_node_put(np);
721246774d1SLucas Stach 		break;
722246774d1SLucas Stach 	}
723246774d1SLucas Stach 
72445a0faabSFabio Estevam 	return 0;
72545a0faabSFabio Estevam 
72645a0faabSFabio Estevam unregister_platform_driver:
72745a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_platform_driver);
72845a0faabSFabio Estevam unregister_gpu_driver:
72945a0faabSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
730a8c21a54SThe etnaviv authors 	return ret;
731a8c21a54SThe etnaviv authors }
732a8c21a54SThe etnaviv authors module_init(etnaviv_init);
733a8c21a54SThe etnaviv authors 
734a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void)
735a8c21a54SThe etnaviv authors {
736bf6ba3aeSFabio Estevam 	platform_device_unregister(etnaviv_drm);
737a8c21a54SThe etnaviv authors 	platform_driver_unregister(&etnaviv_platform_driver);
738bf6ba3aeSFabio Estevam 	platform_driver_unregister(&etnaviv_gpu_driver);
739a8c21a54SThe etnaviv authors }
740a8c21a54SThe etnaviv authors module_exit(etnaviv_exit);
741a8c21a54SThe etnaviv authors 
742a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
743a8c21a54SThe etnaviv authors MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
744a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>");
745a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver");
746a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2");
747a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv");
748