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