1f3ba9122SRob Herring // SPDX-License-Identifier: GPL-2.0
2f3ba9122SRob Herring /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
3f3ba9122SRob Herring /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
4f3ba9122SRob Herring /* Copyright 2019 Collabora ltd. */
5f3ba9122SRob Herring
6f3ba9122SRob Herring #include <linux/module.h>
7722d4f06SRob Herring #include <linux/of.h>
8f3ba9122SRob Herring #include <linux/pagemap.h>
9722d4f06SRob Herring #include <linux/platform_device.h>
10f3ba9122SRob Herring #include <linux/pm_runtime.h>
11f3ba9122SRob Herring #include <drm/panfrost_drm.h>
12f3ba9122SRob Herring #include <drm/drm_drv.h>
13f3ba9122SRob Herring #include <drm/drm_ioctl.h>
14f3ba9122SRob Herring #include <drm/drm_syncobj.h>
15f3ba9122SRob Herring #include <drm/drm_utils.h>
16f3ba9122SRob Herring
17f3ba9122SRob Herring #include "panfrost_device.h"
18f3ba9122SRob Herring #include "panfrost_gem.h"
19f3ba9122SRob Herring #include "panfrost_mmu.h"
20f3ba9122SRob Herring #include "panfrost_job.h"
21f3ba9122SRob Herring #include "panfrost_gpu.h"
227786fd10SBoris Brezillon #include "panfrost_perfcnt.h"
23f3ba9122SRob Herring
2492f0ad0bSBoris Brezillon static bool unstable_ioctls;
2592f0ad0bSBoris Brezillon module_param_unsafe(unstable_ioctls, bool, 0600);
2692f0ad0bSBoris Brezillon
panfrost_ioctl_get_param(struct drm_device * ddev,void * data,struct drm_file * file)27f3ba9122SRob Herring static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file)
28f3ba9122SRob Herring {
29f3ba9122SRob Herring struct drm_panfrost_get_param *param = data;
30f3ba9122SRob Herring struct panfrost_device *pfdev = ddev->dev_private;
31f3ba9122SRob Herring
32f3ba9122SRob Herring if (param->pad != 0)
33f3ba9122SRob Herring return -EINVAL;
34f3ba9122SRob Herring
354bced8beSSteven Price #define PANFROST_FEATURE(name, member) \
364bced8beSSteven Price case DRM_PANFROST_PARAM_ ## name: \
374bced8beSSteven Price param->value = pfdev->features.member; \
384bced8beSSteven Price break
394bced8beSSteven Price #define PANFROST_FEATURE_ARRAY(name, member, max) \
404bced8beSSteven Price case DRM_PANFROST_PARAM_ ## name ## 0 ... \
414bced8beSSteven Price DRM_PANFROST_PARAM_ ## name ## max: \
424bced8beSSteven Price param->value = pfdev->features.member[param->param - \
434bced8beSSteven Price DRM_PANFROST_PARAM_ ## name ## 0]; \
444bced8beSSteven Price break
454bced8beSSteven Price
46f3ba9122SRob Herring switch (param->param) {
474bced8beSSteven Price PANFROST_FEATURE(GPU_PROD_ID, id);
484bced8beSSteven Price PANFROST_FEATURE(GPU_REVISION, revision);
494bced8beSSteven Price PANFROST_FEATURE(SHADER_PRESENT, shader_present);
504bced8beSSteven Price PANFROST_FEATURE(TILER_PRESENT, tiler_present);
514bced8beSSteven Price PANFROST_FEATURE(L2_PRESENT, l2_present);
524bced8beSSteven Price PANFROST_FEATURE(STACK_PRESENT, stack_present);
534bced8beSSteven Price PANFROST_FEATURE(AS_PRESENT, as_present);
544bced8beSSteven Price PANFROST_FEATURE(JS_PRESENT, js_present);
554bced8beSSteven Price PANFROST_FEATURE(L2_FEATURES, l2_features);
564bced8beSSteven Price PANFROST_FEATURE(CORE_FEATURES, core_features);
574bced8beSSteven Price PANFROST_FEATURE(TILER_FEATURES, tiler_features);
584bced8beSSteven Price PANFROST_FEATURE(MEM_FEATURES, mem_features);
594bced8beSSteven Price PANFROST_FEATURE(MMU_FEATURES, mmu_features);
604bced8beSSteven Price PANFROST_FEATURE(THREAD_FEATURES, thread_features);
614bced8beSSteven Price PANFROST_FEATURE(MAX_THREADS, max_threads);
624bced8beSSteven Price PANFROST_FEATURE(THREAD_MAX_WORKGROUP_SZ,
634bced8beSSteven Price thread_max_workgroup_sz);
644bced8beSSteven Price PANFROST_FEATURE(THREAD_MAX_BARRIER_SZ,
654bced8beSSteven Price thread_max_barrier_sz);
664bced8beSSteven Price PANFROST_FEATURE(COHERENCY_FEATURES, coherency_features);
673e2926f8SAlyssa Rosenzweig PANFROST_FEATURE(AFBC_FEATURES, afbc_features);
684bced8beSSteven Price PANFROST_FEATURE_ARRAY(TEXTURE_FEATURES, texture_features, 3);
694bced8beSSteven Price PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15);
704bced8beSSteven Price PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups);
714bced8beSSteven Price PANFROST_FEATURE(THREAD_TLS_ALLOC, thread_tls_alloc);
72f3ba9122SRob Herring default:
73f3ba9122SRob Herring return -EINVAL;
74f3ba9122SRob Herring }
75f3ba9122SRob Herring
76f3ba9122SRob Herring return 0;
77f3ba9122SRob Herring }
78f3ba9122SRob Herring
panfrost_ioctl_create_bo(struct drm_device * dev,void * data,struct drm_file * file)79f3ba9122SRob Herring static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
80f3ba9122SRob Herring struct drm_file *file)
81f3ba9122SRob Herring {
82bdefca2dSBoris Brezillon struct panfrost_file_priv *priv = file->driver_priv;
83203270c0SRob Herring struct panfrost_gem_object *bo;
84f3ba9122SRob Herring struct drm_panfrost_create_bo *args = data;
85bdefca2dSBoris Brezillon struct panfrost_gem_mapping *mapping;
864217c6acSSteven Price int ret;
87f3ba9122SRob Herring
88203270c0SRob Herring if (!args->size || args->pad ||
89187d2929SRob Herring (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP)))
90187d2929SRob Herring return -EINVAL;
91187d2929SRob Herring
92187d2929SRob Herring /* Heaps should never be executable */
93187d2929SRob Herring if ((args->flags & PANFROST_BO_HEAP) &&
94187d2929SRob Herring !(args->flags & PANFROST_BO_NOEXEC))
95f3ba9122SRob Herring return -EINVAL;
96f3ba9122SRob Herring
974217c6acSSteven Price bo = panfrost_gem_create(dev, args->size, args->flags);
98203270c0SRob Herring if (IS_ERR(bo))
99203270c0SRob Herring return PTR_ERR(bo);
100f3ba9122SRob Herring
1014217c6acSSteven Price ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
1024217c6acSSteven Price if (ret)
1034217c6acSSteven Price goto out;
104bdefca2dSBoris Brezillon
1054217c6acSSteven Price mapping = panfrost_gem_mapping_get(bo, priv);
1064217c6acSSteven Price if (mapping) {
107bdefca2dSBoris Brezillon args->offset = mapping->mmnode.start << PAGE_SHIFT;
108bdefca2dSBoris Brezillon panfrost_gem_mapping_put(mapping);
1094217c6acSSteven Price } else {
1104217c6acSSteven Price /* This can only happen if the handle from
1114217c6acSSteven Price * drm_gem_handle_create() has already been guessed and freed
1124217c6acSSteven Price * by user space
1134217c6acSSteven Price */
1144217c6acSSteven Price ret = -EINVAL;
1154217c6acSSteven Price }
116f3ba9122SRob Herring
1174217c6acSSteven Price out:
1184217c6acSSteven Price drm_gem_object_put(&bo->base.base);
1194217c6acSSteven Price return ret;
120f3ba9122SRob Herring }
121f3ba9122SRob Herring
122f3ba9122SRob Herring /**
123f3ba9122SRob Herring * panfrost_lookup_bos() - Sets up job->bo[] with the GEM objects
124f3ba9122SRob Herring * referenced by the job.
125f3ba9122SRob Herring * @dev: DRM device
126f3ba9122SRob Herring * @file_priv: DRM file for this fd
127f3ba9122SRob Herring * @args: IOCTL args
128f3ba9122SRob Herring * @job: job being set up
129f3ba9122SRob Herring *
130f3ba9122SRob Herring * Resolve handles from userspace to BOs and attach them to job.
131f3ba9122SRob Herring *
132f3ba9122SRob Herring * Note that this function doesn't need to unreference the BOs on
133f3ba9122SRob Herring * failure, because that will happen at panfrost_job_cleanup() time.
134f3ba9122SRob Herring */
135f3ba9122SRob Herring static int
panfrost_lookup_bos(struct drm_device * dev,struct drm_file * file_priv,struct drm_panfrost_submit * args,struct panfrost_job * job)136f3ba9122SRob Herring panfrost_lookup_bos(struct drm_device *dev,
137f3ba9122SRob Herring struct drm_file *file_priv,
138f3ba9122SRob Herring struct drm_panfrost_submit *args,
139f3ba9122SRob Herring struct panfrost_job *job)
140f3ba9122SRob Herring {
141bdefca2dSBoris Brezillon struct panfrost_file_priv *priv = file_priv->driver_priv;
142bdefca2dSBoris Brezillon struct panfrost_gem_object *bo;
143bdefca2dSBoris Brezillon unsigned int i;
144bdefca2dSBoris Brezillon int ret;
145bdefca2dSBoris Brezillon
146f3ba9122SRob Herring job->bo_count = args->bo_handle_count;
147f3ba9122SRob Herring
148f3ba9122SRob Herring if (!job->bo_count)
149f3ba9122SRob Herring return 0;
150f3ba9122SRob Herring
151bdefca2dSBoris Brezillon ret = drm_gem_objects_lookup(file_priv,
152f3ba9122SRob Herring (void __user *)(uintptr_t)args->bo_handles,
153f3ba9122SRob Herring job->bo_count, &job->bos);
154bdefca2dSBoris Brezillon if (ret)
155bdefca2dSBoris Brezillon return ret;
156bdefca2dSBoris Brezillon
157bdefca2dSBoris Brezillon job->mappings = kvmalloc_array(job->bo_count,
158bdefca2dSBoris Brezillon sizeof(struct panfrost_gem_mapping *),
159bdefca2dSBoris Brezillon GFP_KERNEL | __GFP_ZERO);
160bdefca2dSBoris Brezillon if (!job->mappings)
161bdefca2dSBoris Brezillon return -ENOMEM;
162bdefca2dSBoris Brezillon
163bdefca2dSBoris Brezillon for (i = 0; i < job->bo_count; i++) {
164bdefca2dSBoris Brezillon struct panfrost_gem_mapping *mapping;
165bdefca2dSBoris Brezillon
166bdefca2dSBoris Brezillon bo = to_panfrost_bo(job->bos[i]);
167bdefca2dSBoris Brezillon mapping = panfrost_gem_mapping_get(bo, priv);
168bdefca2dSBoris Brezillon if (!mapping) {
169bdefca2dSBoris Brezillon ret = -EINVAL;
170bdefca2dSBoris Brezillon break;
171bdefca2dSBoris Brezillon }
172bdefca2dSBoris Brezillon
1737e0cf7e9SBoris Brezillon atomic_inc(&bo->gpu_usecount);
174bdefca2dSBoris Brezillon job->mappings[i] = mapping;
175bdefca2dSBoris Brezillon }
176bdefca2dSBoris Brezillon
177bdefca2dSBoris Brezillon return ret;
178f3ba9122SRob Herring }
179f3ba9122SRob Herring
180f3ba9122SRob Herring /**
1817d7a0fc4SDaniel Vetter * panfrost_copy_in_sync() - Sets up job->deps with the sync objects
182f3ba9122SRob Herring * referenced by the job.
183f3ba9122SRob Herring * @dev: DRM device
184f3ba9122SRob Herring * @file_priv: DRM file for this fd
185f3ba9122SRob Herring * @args: IOCTL args
186f3ba9122SRob Herring * @job: job being set up
187f3ba9122SRob Herring *
188f3ba9122SRob Herring * Resolve syncobjs from userspace to fences and attach them to job.
189f3ba9122SRob Herring *
190f3ba9122SRob Herring * Note that this function doesn't need to unreference the fences on
191f3ba9122SRob Herring * failure, because that will happen at panfrost_job_cleanup() time.
192f3ba9122SRob Herring */
193f3ba9122SRob Herring static int
panfrost_copy_in_sync(struct drm_device * dev,struct drm_file * file_priv,struct drm_panfrost_submit * args,struct panfrost_job * job)194f3ba9122SRob Herring panfrost_copy_in_sync(struct drm_device *dev,
195f3ba9122SRob Herring struct drm_file *file_priv,
196f3ba9122SRob Herring struct drm_panfrost_submit *args,
197f3ba9122SRob Herring struct panfrost_job *job)
198f3ba9122SRob Herring {
199f3ba9122SRob Herring u32 *handles;
200f3ba9122SRob Herring int ret = 0;
2017d7a0fc4SDaniel Vetter int i, in_fence_count;
202f3ba9122SRob Herring
2037d7a0fc4SDaniel Vetter in_fence_count = args->in_sync_count;
204f3ba9122SRob Herring
2057d7a0fc4SDaniel Vetter if (!in_fence_count)
206f3ba9122SRob Herring return 0;
207f3ba9122SRob Herring
2087d7a0fc4SDaniel Vetter handles = kvmalloc_array(in_fence_count, sizeof(u32), GFP_KERNEL);
209f3ba9122SRob Herring if (!handles) {
210f3ba9122SRob Herring ret = -ENOMEM;
211f3ba9122SRob Herring DRM_DEBUG("Failed to allocate incoming syncobj handles\n");
212f3ba9122SRob Herring goto fail;
213f3ba9122SRob Herring }
214f3ba9122SRob Herring
215f3ba9122SRob Herring if (copy_from_user(handles,
216f3ba9122SRob Herring (void __user *)(uintptr_t)args->in_syncs,
2177d7a0fc4SDaniel Vetter in_fence_count * sizeof(u32))) {
218f3ba9122SRob Herring ret = -EFAULT;
219f3ba9122SRob Herring DRM_DEBUG("Failed to copy in syncobj handles\n");
220f3ba9122SRob Herring goto fail;
221f3ba9122SRob Herring }
222f3ba9122SRob Herring
2237d7a0fc4SDaniel Vetter for (i = 0; i < in_fence_count; i++) {
2244636c4a5SMaíra Canal ret = drm_sched_job_add_syncobj_dependency(&job->base, file_priv,
2254636c4a5SMaíra Canal handles[i], 0);
2267d7a0fc4SDaniel Vetter if (ret)
227f3ba9122SRob Herring goto fail;
228f3ba9122SRob Herring }
229f3ba9122SRob Herring
230f3ba9122SRob Herring fail:
231f3ba9122SRob Herring kvfree(handles);
232f3ba9122SRob Herring return ret;
233f3ba9122SRob Herring }
234f3ba9122SRob Herring
panfrost_ioctl_submit(struct drm_device * dev,void * data,struct drm_file * file)235f3ba9122SRob Herring static int panfrost_ioctl_submit(struct drm_device *dev, void *data,
236f3ba9122SRob Herring struct drm_file *file)
237f3ba9122SRob Herring {
238f3ba9122SRob Herring struct panfrost_device *pfdev = dev->dev_private;
2396e516fafSSteven Price struct panfrost_file_priv *file_priv = file->driver_priv;
240f3ba9122SRob Herring struct drm_panfrost_submit *args = data;
2416ff408e6STomeu Vizoso struct drm_syncobj *sync_out = NULL;
242f3ba9122SRob Herring struct panfrost_job *job;
24353516280SDaniel Vetter int ret = 0, slot;
244f3ba9122SRob Herring
2456ff408e6STomeu Vizoso if (!args->jc)
2466ff408e6STomeu Vizoso return -EINVAL;
2476ff408e6STomeu Vizoso
2486ff408e6STomeu Vizoso if (args->requirements && args->requirements != PANFROST_JD_REQ_FS)
2496ff408e6STomeu Vizoso return -EINVAL;
2506ff408e6STomeu Vizoso
2516ff408e6STomeu Vizoso if (args->out_sync > 0) {
2526ff408e6STomeu Vizoso sync_out = drm_syncobj_find(file, args->out_sync);
2536ff408e6STomeu Vizoso if (!sync_out)
2546ff408e6STomeu Vizoso return -ENODEV;
2556ff408e6STomeu Vizoso }
2566ff408e6STomeu Vizoso
257f3ba9122SRob Herring job = kzalloc(sizeof(*job), GFP_KERNEL);
2586ff408e6STomeu Vizoso if (!job) {
2596ff408e6STomeu Vizoso ret = -ENOMEM;
260771d2053SBoris Brezillon goto out_put_syncout;
2616ff408e6STomeu Vizoso }
262f3ba9122SRob Herring
263f3ba9122SRob Herring kref_init(&job->refcount);
264f3ba9122SRob Herring
265f3ba9122SRob Herring job->pfdev = pfdev;
266f3ba9122SRob Herring job->jc = args->jc;
267f3ba9122SRob Herring job->requirements = args->requirements;
268f3ba9122SRob Herring job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev);
2696e516fafSSteven Price job->mmu = file_priv->mmu;
270f11b0417SAdrián Larumbe job->engine_usage = &file_priv->engine_usage;
271f3ba9122SRob Herring
27253516280SDaniel Vetter slot = panfrost_job_get_slot(job);
27353516280SDaniel Vetter
27453516280SDaniel Vetter ret = drm_sched_job_init(&job->base,
2756e516fafSSteven Price &file_priv->sched_entity[slot],
276a78422e9SDanilo Krummrich 1, NULL);
27753516280SDaniel Vetter if (ret)
278771d2053SBoris Brezillon goto out_put_job;
27953516280SDaniel Vetter
280f3ba9122SRob Herring ret = panfrost_copy_in_sync(dev, file, args, job);
281f3ba9122SRob Herring if (ret)
282771d2053SBoris Brezillon goto out_cleanup_job;
283f3ba9122SRob Herring
284f3ba9122SRob Herring ret = panfrost_lookup_bos(dev, file, args, job);
285f3ba9122SRob Herring if (ret)
286771d2053SBoris Brezillon goto out_cleanup_job;
287f3ba9122SRob Herring
288f3ba9122SRob Herring ret = panfrost_job_push(job);
289f3ba9122SRob Herring if (ret)
290771d2053SBoris Brezillon goto out_cleanup_job;
291f3ba9122SRob Herring
292f3ba9122SRob Herring /* Update the return sync object for the job */
2936ff408e6STomeu Vizoso if (sync_out)
294f3ba9122SRob Herring drm_syncobj_replace_fence(sync_out, job->render_done_fence);
295f3ba9122SRob Herring
296771d2053SBoris Brezillon out_cleanup_job:
297771d2053SBoris Brezillon if (ret)
29853516280SDaniel Vetter drm_sched_job_cleanup(&job->base);
299771d2053SBoris Brezillon out_put_job:
300f3ba9122SRob Herring panfrost_job_put(job);
301771d2053SBoris Brezillon out_put_syncout:
302cc2e787eSTomeu Vizoso if (sync_out)
3036ff408e6STomeu Vizoso drm_syncobj_put(sync_out);
304f3ba9122SRob Herring
305f3ba9122SRob Herring return ret;
306f3ba9122SRob Herring }
307f3ba9122SRob Herring
308f3ba9122SRob Herring static int
panfrost_ioctl_wait_bo(struct drm_device * dev,void * data,struct drm_file * file_priv)309f3ba9122SRob Herring panfrost_ioctl_wait_bo(struct drm_device *dev, void *data,
310f3ba9122SRob Herring struct drm_file *file_priv)
311f3ba9122SRob Herring {
312f3ba9122SRob Herring long ret;
313f3ba9122SRob Herring struct drm_panfrost_wait_bo *args = data;
314f3ba9122SRob Herring struct drm_gem_object *gem_obj;
315f3ba9122SRob Herring unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns);
316f3ba9122SRob Herring
317f3ba9122SRob Herring if (args->pad)
318f3ba9122SRob Herring return -EINVAL;
319f3ba9122SRob Herring
320f3ba9122SRob Herring gem_obj = drm_gem_object_lookup(file_priv, args->handle);
321f3ba9122SRob Herring if (!gem_obj)
322f3ba9122SRob Herring return -ENOENT;
323f3ba9122SRob Herring
3247bc80a54SChristian König ret = dma_resv_wait_timeout(gem_obj->resv, DMA_RESV_USAGE_READ,
3257bc80a54SChristian König true, timeout);
326f3ba9122SRob Herring if (!ret)
327f3ba9122SRob Herring ret = timeout ? -ETIMEDOUT : -EBUSY;
328f3ba9122SRob Herring
329496d0cc6SEmil Velikov drm_gem_object_put(gem_obj);
330f3ba9122SRob Herring
331f3ba9122SRob Herring return ret;
332f3ba9122SRob Herring }
333f3ba9122SRob Herring
panfrost_ioctl_mmap_bo(struct drm_device * dev,void * data,struct drm_file * file_priv)334f3ba9122SRob Herring static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data,
335f3ba9122SRob Herring struct drm_file *file_priv)
336f3ba9122SRob Herring {
337f3ba9122SRob Herring struct drm_panfrost_mmap_bo *args = data;
338e6be0a99SRob Herring struct drm_gem_object *gem_obj;
339e6be0a99SRob Herring int ret;
340f3ba9122SRob Herring
341f3ba9122SRob Herring if (args->flags != 0) {
342f3ba9122SRob Herring DRM_INFO("unknown mmap_bo flags: %d\n", args->flags);
343f3ba9122SRob Herring return -EINVAL;
344f3ba9122SRob Herring }
345f3ba9122SRob Herring
346e6be0a99SRob Herring gem_obj = drm_gem_object_lookup(file_priv, args->handle);
347e6be0a99SRob Herring if (!gem_obj) {
348e6be0a99SRob Herring DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
349e6be0a99SRob Herring return -ENOENT;
350e6be0a99SRob Herring }
351e6be0a99SRob Herring
352187d2929SRob Herring /* Don't allow mmapping of heap objects as pages are not pinned. */
3533bb69dbcSBoris Brezillon if (to_panfrost_bo(gem_obj)->is_heap) {
3543bb69dbcSBoris Brezillon ret = -EINVAL;
3553bb69dbcSBoris Brezillon goto out;
3563bb69dbcSBoris Brezillon }
357187d2929SRob Herring
358e6be0a99SRob Herring ret = drm_gem_create_mmap_offset(gem_obj);
359e6be0a99SRob Herring if (ret == 0)
360e6be0a99SRob Herring args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
361e6be0a99SRob Herring
3623bb69dbcSBoris Brezillon out:
363496d0cc6SEmil Velikov drm_gem_object_put(gem_obj);
364e6be0a99SRob Herring return ret;
365f3ba9122SRob Herring }
366f3ba9122SRob Herring
panfrost_ioctl_get_bo_offset(struct drm_device * dev,void * data,struct drm_file * file_priv)367f3ba9122SRob Herring static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data,
368f3ba9122SRob Herring struct drm_file *file_priv)
369f3ba9122SRob Herring {
370bdefca2dSBoris Brezillon struct panfrost_file_priv *priv = file_priv->driver_priv;
371f3ba9122SRob Herring struct drm_panfrost_get_bo_offset *args = data;
372bdefca2dSBoris Brezillon struct panfrost_gem_mapping *mapping;
373f3ba9122SRob Herring struct drm_gem_object *gem_obj;
374f3ba9122SRob Herring struct panfrost_gem_object *bo;
375f3ba9122SRob Herring
376f3ba9122SRob Herring gem_obj = drm_gem_object_lookup(file_priv, args->handle);
377f3ba9122SRob Herring if (!gem_obj) {
378f3ba9122SRob Herring DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
379f3ba9122SRob Herring return -ENOENT;
380f3ba9122SRob Herring }
381f3ba9122SRob Herring bo = to_panfrost_bo(gem_obj);
382f3ba9122SRob Herring
383bdefca2dSBoris Brezillon mapping = panfrost_gem_mapping_get(bo, priv);
384496d0cc6SEmil Velikov drm_gem_object_put(gem_obj);
385bdefca2dSBoris Brezillon
386bdefca2dSBoris Brezillon if (!mapping)
387bdefca2dSBoris Brezillon return -EINVAL;
388bdefca2dSBoris Brezillon
389bdefca2dSBoris Brezillon args->offset = mapping->mmnode.start << PAGE_SHIFT;
390bdefca2dSBoris Brezillon panfrost_gem_mapping_put(mapping);
391f3ba9122SRob Herring return 0;
392f3ba9122SRob Herring }
393f3ba9122SRob Herring
panfrost_ioctl_madvise(struct drm_device * dev,void * data,struct drm_file * file_priv)394013b6510SRob Herring static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
395013b6510SRob Herring struct drm_file *file_priv)
396013b6510SRob Herring {
397bdefca2dSBoris Brezillon struct panfrost_file_priv *priv = file_priv->driver_priv;
398013b6510SRob Herring struct drm_panfrost_madvise *args = data;
399013b6510SRob Herring struct panfrost_device *pfdev = dev->dev_private;
400013b6510SRob Herring struct drm_gem_object *gem_obj;
401bdefca2dSBoris Brezillon struct panfrost_gem_object *bo;
402bdefca2dSBoris Brezillon int ret = 0;
403013b6510SRob Herring
404013b6510SRob Herring gem_obj = drm_gem_object_lookup(file_priv, args->handle);
405013b6510SRob Herring if (!gem_obj) {
406013b6510SRob Herring DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
407013b6510SRob Herring return -ENOENT;
408013b6510SRob Herring }
409013b6510SRob Herring
410bdefca2dSBoris Brezillon bo = to_panfrost_bo(gem_obj);
411bdefca2dSBoris Brezillon
41221aa27ddSDmitry Osipenko ret = dma_resv_lock_interruptible(bo->base.base.resv, NULL);
41321aa27ddSDmitry Osipenko if (ret)
41421aa27ddSDmitry Osipenko goto out_put_object;
41521aa27ddSDmitry Osipenko
41670cc7795SBoris Brezillon mutex_lock(&pfdev->shrinker_lock);
417bdefca2dSBoris Brezillon mutex_lock(&bo->mappings.lock);
418bdefca2dSBoris Brezillon if (args->madv == PANFROST_MADV_DONTNEED) {
419bdefca2dSBoris Brezillon struct panfrost_gem_mapping *first;
420bdefca2dSBoris Brezillon
421bdefca2dSBoris Brezillon first = list_first_entry(&bo->mappings.list,
422bdefca2dSBoris Brezillon struct panfrost_gem_mapping,
423bdefca2dSBoris Brezillon node);
424bdefca2dSBoris Brezillon
425bdefca2dSBoris Brezillon /*
426bdefca2dSBoris Brezillon * If we want to mark the BO purgeable, there must be only one
427bdefca2dSBoris Brezillon * user: the caller FD.
428bdefca2dSBoris Brezillon * We could do something smarter and mark the BO purgeable only
429bdefca2dSBoris Brezillon * when all its users have marked it purgeable, but globally
430bdefca2dSBoris Brezillon * visible/shared BOs are likely to never be marked purgeable
431bdefca2dSBoris Brezillon * anyway, so let's not bother.
432bdefca2dSBoris Brezillon */
433bdefca2dSBoris Brezillon if (!list_is_singular(&bo->mappings.list) ||
4347fdc48ccSBoris Brezillon WARN_ON_ONCE(first->mmu != priv->mmu)) {
435bdefca2dSBoris Brezillon ret = -EINVAL;
436bdefca2dSBoris Brezillon goto out_unlock_mappings;
437bdefca2dSBoris Brezillon }
438bdefca2dSBoris Brezillon }
439bdefca2dSBoris Brezillon
440a193f3b4SThomas Zimmermann args->retained = drm_gem_shmem_madvise(&bo->base, args->madv);
441013b6510SRob Herring
442013b6510SRob Herring if (args->retained) {
443013b6510SRob Herring if (args->madv == PANFROST_MADV_DONTNEED)
4449fc33eaaSDmitry Osipenko list_move_tail(&bo->base.madv_list,
44570cc7795SBoris Brezillon &pfdev->shrinker_list);
446013b6510SRob Herring else if (args->madv == PANFROST_MADV_WILLNEED)
447013b6510SRob Herring list_del_init(&bo->base.madv_list);
448013b6510SRob Herring }
449bdefca2dSBoris Brezillon
450bdefca2dSBoris Brezillon out_unlock_mappings:
451bdefca2dSBoris Brezillon mutex_unlock(&bo->mappings.lock);
45270cc7795SBoris Brezillon mutex_unlock(&pfdev->shrinker_lock);
45321aa27ddSDmitry Osipenko dma_resv_unlock(bo->base.base.resv);
45421aa27ddSDmitry Osipenko out_put_object:
455496d0cc6SEmil Velikov drm_gem_object_put(gem_obj);
456bdefca2dSBoris Brezillon return ret;
457013b6510SRob Herring }
458013b6510SRob Herring
panfrost_unstable_ioctl_check(void)45992f0ad0bSBoris Brezillon int panfrost_unstable_ioctl_check(void)
46092f0ad0bSBoris Brezillon {
46192f0ad0bSBoris Brezillon if (!unstable_ioctls)
46292f0ad0bSBoris Brezillon return -ENOSYS;
46392f0ad0bSBoris Brezillon
46492f0ad0bSBoris Brezillon return 0;
46592f0ad0bSBoris Brezillon }
46692f0ad0bSBoris Brezillon
467f3ba9122SRob Herring static int
panfrost_open(struct drm_device * dev,struct drm_file * file)468f3ba9122SRob Herring panfrost_open(struct drm_device *dev, struct drm_file *file)
469f3ba9122SRob Herring {
4707282f764SRob Herring int ret;
471f3ba9122SRob Herring struct panfrost_device *pfdev = dev->dev_private;
472f3ba9122SRob Herring struct panfrost_file_priv *panfrost_priv;
473f3ba9122SRob Herring
474f3ba9122SRob Herring panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL);
475f3ba9122SRob Herring if (!panfrost_priv)
476f3ba9122SRob Herring return -ENOMEM;
477f3ba9122SRob Herring
478f3ba9122SRob Herring panfrost_priv->pfdev = pfdev;
479f3ba9122SRob Herring file->driver_priv = panfrost_priv;
480f3ba9122SRob Herring
4817fdc48ccSBoris Brezillon panfrost_priv->mmu = panfrost_mmu_ctx_create(pfdev);
4827fdc48ccSBoris Brezillon if (IS_ERR(panfrost_priv->mmu)) {
4837fdc48ccSBoris Brezillon ret = PTR_ERR(panfrost_priv->mmu);
4847fdc48ccSBoris Brezillon goto err_free;
4857fdc48ccSBoris Brezillon }
4867282f764SRob Herring
4877282f764SRob Herring ret = panfrost_job_open(panfrost_priv);
4887282f764SRob Herring if (ret)
4897282f764SRob Herring goto err_job;
4907282f764SRob Herring
4917282f764SRob Herring return 0;
4927282f764SRob Herring
4937282f764SRob Herring err_job:
4947fdc48ccSBoris Brezillon panfrost_mmu_ctx_put(panfrost_priv->mmu);
4957fdc48ccSBoris Brezillon err_free:
4967282f764SRob Herring kfree(panfrost_priv);
4977282f764SRob Herring return ret;
498f3ba9122SRob Herring }
499f3ba9122SRob Herring
500f3ba9122SRob Herring static void
panfrost_postclose(struct drm_device * dev,struct drm_file * file)501f3ba9122SRob Herring panfrost_postclose(struct drm_device *dev, struct drm_file *file)
502f3ba9122SRob Herring {
503f3ba9122SRob Herring struct panfrost_file_priv *panfrost_priv = file->driver_priv;
504f3ba9122SRob Herring
5050a523998SBoris Brezillon panfrost_perfcnt_close(file);
506f3ba9122SRob Herring panfrost_job_close(panfrost_priv);
507f3ba9122SRob Herring
5087fdc48ccSBoris Brezillon panfrost_mmu_ctx_put(panfrost_priv->mmu);
509f3ba9122SRob Herring kfree(panfrost_priv);
510f3ba9122SRob Herring }
511f3ba9122SRob Herring
512f3ba9122SRob Herring static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
513f3ba9122SRob Herring #define PANFROST_IOCTL(n, func, flags) \
514f3ba9122SRob Herring DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags)
515f3ba9122SRob Herring
516c1572b75SEmil Velikov PANFROST_IOCTL(SUBMIT, submit, DRM_RENDER_ALLOW),
517f3ba9122SRob Herring PANFROST_IOCTL(WAIT_BO, wait_bo, DRM_RENDER_ALLOW),
518f3ba9122SRob Herring PANFROST_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW),
519f3ba9122SRob Herring PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW),
520f3ba9122SRob Herring PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW),
521f3ba9122SRob Herring PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW),
5227786fd10SBoris Brezillon PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW),
5237786fd10SBoris Brezillon PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW),
524013b6510SRob Herring PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW),
525f3ba9122SRob Herring };
526f3ba9122SRob Herring
panfrost_gpu_show_fdinfo(struct panfrost_device * pfdev,struct panfrost_file_priv * panfrost_priv,struct drm_printer * p)527f11b0417SAdrián Larumbe static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev,
528f11b0417SAdrián Larumbe struct panfrost_file_priv *panfrost_priv,
529f11b0417SAdrián Larumbe struct drm_printer *p)
530f11b0417SAdrián Larumbe {
531f11b0417SAdrián Larumbe int i;
532f11b0417SAdrián Larumbe
533f11b0417SAdrián Larumbe /*
534f11b0417SAdrián Larumbe * IMPORTANT NOTE: drm-cycles and drm-engine measurements are not
535f11b0417SAdrián Larumbe * accurate, as they only provide a rough estimation of the number of
536f11b0417SAdrián Larumbe * GPU cycles and CPU time spent in a given context. This is due to two
537f11b0417SAdrián Larumbe * different factors:
538f11b0417SAdrián Larumbe * - Firstly, we must consider the time the CPU and then the kernel
539f11b0417SAdrián Larumbe * takes to process the GPU interrupt, which means additional time and
540f11b0417SAdrián Larumbe * GPU cycles will be added in excess to the real figure.
541f11b0417SAdrián Larumbe * - Secondly, the pipelining done by the Job Manager (2 job slots per
542f11b0417SAdrián Larumbe * engine) implies there is no way to know exactly how much time each
543f11b0417SAdrián Larumbe * job spent on the GPU.
544f11b0417SAdrián Larumbe */
545f11b0417SAdrián Larumbe
546f11b0417SAdrián Larumbe static const char * const engine_names[] = {
547f11b0417SAdrián Larumbe "fragment", "vertex-tiler", "compute-only"
548f11b0417SAdrián Larumbe };
549f11b0417SAdrián Larumbe
550f11b0417SAdrián Larumbe BUILD_BUG_ON(ARRAY_SIZE(engine_names) != NUM_JOB_SLOTS);
551f11b0417SAdrián Larumbe
552f11b0417SAdrián Larumbe for (i = 0; i < NUM_JOB_SLOTS - 1; i++) {
553dfe4fd26SAdrián Larumbe if (pfdev->profile_mode) {
554f11b0417SAdrián Larumbe drm_printf(p, "drm-engine-%s:\t%llu ns\n",
555f11b0417SAdrián Larumbe engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]);
556f11b0417SAdrián Larumbe drm_printf(p, "drm-cycles-%s:\t%llu\n",
557f11b0417SAdrián Larumbe engine_names[i], panfrost_priv->engine_usage.cycles[i]);
558dfe4fd26SAdrián Larumbe }
559f11b0417SAdrián Larumbe drm_printf(p, "drm-maxfreq-%s:\t%lu Hz\n",
560f11b0417SAdrián Larumbe engine_names[i], pfdev->pfdevfreq.fast_rate);
561f11b0417SAdrián Larumbe drm_printf(p, "drm-curfreq-%s:\t%lu Hz\n",
562f11b0417SAdrián Larumbe engine_names[i], pfdev->pfdevfreq.current_frequency);
563f11b0417SAdrián Larumbe }
564f11b0417SAdrián Larumbe }
565f11b0417SAdrián Larumbe
panfrost_show_fdinfo(struct drm_printer * p,struct drm_file * file)566f11b0417SAdrián Larumbe static void panfrost_show_fdinfo(struct drm_printer *p, struct drm_file *file)
567f11b0417SAdrián Larumbe {
568f11b0417SAdrián Larumbe struct drm_device *dev = file->minor->dev;
569f11b0417SAdrián Larumbe struct panfrost_device *pfdev = dev->dev_private;
570f11b0417SAdrián Larumbe
571f11b0417SAdrián Larumbe panfrost_gpu_show_fdinfo(pfdev, file->driver_priv, p);
5729ccdac7aSAdrián Larumbe
5739ccdac7aSAdrián Larumbe drm_show_memory_stats(p, file);
574f11b0417SAdrián Larumbe }
575f11b0417SAdrián Larumbe
576f11b0417SAdrián Larumbe static const struct file_operations panfrost_drm_driver_fops = {
577f11b0417SAdrián Larumbe .owner = THIS_MODULE,
578f11b0417SAdrián Larumbe DRM_GEM_FOPS,
579f11b0417SAdrián Larumbe .show_fdinfo = drm_show_fdinfo,
580f11b0417SAdrián Larumbe };
581f3ba9122SRob Herring
5821c2b9390SRob Herring /*
5831c2b9390SRob Herring * Panfrost driver version:
5841c2b9390SRob Herring * - 1.0 - initial interface
5851c2b9390SRob Herring * - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO
5863e2926f8SAlyssa Rosenzweig * - 1.2 - adds AFBC_FEATURES query
5871c2b9390SRob Herring */
58870a59dd8SDaniel Vetter static const struct drm_driver panfrost_drm_driver = {
5890424fdafSDaniel Vetter .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
590f3ba9122SRob Herring .open = panfrost_open,
591f3ba9122SRob Herring .postclose = panfrost_postclose,
592f11b0417SAdrián Larumbe .show_fdinfo = panfrost_show_fdinfo,
593f3ba9122SRob Herring .ioctls = panfrost_drm_driver_ioctls,
594f3ba9122SRob Herring .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls),
595f3ba9122SRob Herring .fops = &panfrost_drm_driver_fops,
596f3ba9122SRob Herring .name = "panfrost",
597f3ba9122SRob Herring .desc = "panfrost DRM",
598f3ba9122SRob Herring .date = "20180908",
599f3ba9122SRob Herring .major = 1,
6003e2926f8SAlyssa Rosenzweig .minor = 2,
601f3ba9122SRob Herring
602f3ba9122SRob Herring .gem_create_object = panfrost_gem_create_object,
603f3ba9122SRob Herring .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
604f3ba9122SRob Herring };
605f3ba9122SRob Herring
panfrost_probe(struct platform_device * pdev)606f3ba9122SRob Herring static int panfrost_probe(struct platform_device *pdev)
607f3ba9122SRob Herring {
608f3ba9122SRob Herring struct panfrost_device *pfdev;
609f3ba9122SRob Herring struct drm_device *ddev;
610f3ba9122SRob Herring int err;
611f3ba9122SRob Herring
612f3ba9122SRob Herring pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL);
613f3ba9122SRob Herring if (!pfdev)
614f3ba9122SRob Herring return -ENOMEM;
615f3ba9122SRob Herring
616f3ba9122SRob Herring pfdev->pdev = pdev;
617f3ba9122SRob Herring pfdev->dev = &pdev->dev;
618f3ba9122SRob Herring
619f3ba9122SRob Herring platform_set_drvdata(pdev, pfdev);
620f3ba9122SRob Herring
6213e1399bcSNicolas Boichat pfdev->comp = of_device_get_match_data(&pdev->dev);
6223e1399bcSNicolas Boichat if (!pfdev->comp)
6233e1399bcSNicolas Boichat return -ENODEV;
6243e1399bcSNicolas Boichat
625268af50fSRobin Murphy pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
626268af50fSRobin Murphy
62781d9d7f8STom Rix /* Allocate and initialize the DRM device. */
628f3ba9122SRob Herring ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev);
629f3ba9122SRob Herring if (IS_ERR(ddev))
630f3ba9122SRob Herring return PTR_ERR(ddev);
631f3ba9122SRob Herring
632f3ba9122SRob Herring ddev->dev_private = pfdev;
633f3ba9122SRob Herring pfdev->ddev = ddev;
634f3ba9122SRob Herring
635013b6510SRob Herring mutex_init(&pfdev->shrinker_lock);
636013b6510SRob Herring INIT_LIST_HEAD(&pfdev->shrinker_list);
637f3ba9122SRob Herring
638f3ba9122SRob Herring err = panfrost_device_init(pfdev);
639f3ba9122SRob Herring if (err) {
6405450f361SRobin Murphy if (err != -EPROBE_DEFER)
641f3ba9122SRob Herring dev_err(&pdev->dev, "Fatal error during GPU init\n");
642f3ba9122SRob Herring goto err_out0;
643f3ba9122SRob Herring }
644f3ba9122SRob Herring
64563543079SRob Herring pm_runtime_set_active(pfdev->dev);
64663543079SRob Herring pm_runtime_mark_last_busy(pfdev->dev);
64763543079SRob Herring pm_runtime_enable(pfdev->dev);
64863543079SRob Herring pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */
64963543079SRob Herring pm_runtime_use_autosuspend(pfdev->dev);
65063543079SRob Herring
651f3ba9122SRob Herring /*
652f3ba9122SRob Herring * Register the DRM device with the core and the connectors with
653f3ba9122SRob Herring * sysfs
654f3ba9122SRob Herring */
655f3ba9122SRob Herring err = drm_dev_register(ddev, 0);
656f3ba9122SRob Herring if (err < 0)
65725e247bbSClément Péron goto err_out1;
658f3ba9122SRob Herring
659e11c4f3aSQi Zheng err = panfrost_gem_shrinker_init(ddev);
660e11c4f3aSQi Zheng if (err)
661e11c4f3aSQi Zheng goto err_out2;
662013b6510SRob Herring
663f3ba9122SRob Herring return 0;
664f3ba9122SRob Herring
665e11c4f3aSQi Zheng err_out2:
666e11c4f3aSQi Zheng drm_dev_unregister(ddev);
667f3ba9122SRob Herring err_out1:
66825e247bbSClément Péron pm_runtime_disable(pfdev->dev);
669f3ba9122SRob Herring panfrost_device_fini(pfdev);
670876b15d2SSteven Price pm_runtime_set_suspended(pfdev->dev);
671f3ba9122SRob Herring err_out0:
672f3ba9122SRob Herring drm_dev_put(ddev);
673f3ba9122SRob Herring return err;
674f3ba9122SRob Herring }
675f3ba9122SRob Herring
panfrost_remove(struct platform_device * pdev)676e41977a8SUwe Kleine-König static void panfrost_remove(struct platform_device *pdev)
677f3ba9122SRob Herring {
678f3ba9122SRob Herring struct panfrost_device *pfdev = platform_get_drvdata(pdev);
679f3ba9122SRob Herring struct drm_device *ddev = pfdev->ddev;
680f3ba9122SRob Herring
681f3ba9122SRob Herring drm_dev_unregister(ddev);
682013b6510SRob Herring panfrost_gem_shrinker_cleanup(ddev);
683aebe8c22SRob Herring
684f3ba9122SRob Herring pm_runtime_get_sync(pfdev->dev);
685aebe8c22SRob Herring pm_runtime_disable(pfdev->dev);
686876b15d2SSteven Price panfrost_device_fini(pfdev);
687876b15d2SSteven Price pm_runtime_set_suspended(pfdev->dev);
688aebe8c22SRob Herring
689f3ba9122SRob Herring drm_dev_put(ddev);
690f3ba9122SRob Herring }
691f3ba9122SRob Herring
profiling_show(struct device * dev,struct device_attribute * attr,char * buf)692b12f3ea7SAdrián Larumbe static ssize_t profiling_show(struct device *dev,
693b12f3ea7SAdrián Larumbe struct device_attribute *attr, char *buf)
694b12f3ea7SAdrián Larumbe {
695b12f3ea7SAdrián Larumbe struct panfrost_device *pfdev = dev_get_drvdata(dev);
696b12f3ea7SAdrián Larumbe
697b12f3ea7SAdrián Larumbe return sysfs_emit(buf, "%d\n", pfdev->profile_mode);
698b12f3ea7SAdrián Larumbe }
699b12f3ea7SAdrián Larumbe
profiling_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)700b12f3ea7SAdrián Larumbe static ssize_t profiling_store(struct device *dev,
701b12f3ea7SAdrián Larumbe struct device_attribute *attr,
702b12f3ea7SAdrián Larumbe const char *buf, size_t len)
703b12f3ea7SAdrián Larumbe {
704b12f3ea7SAdrián Larumbe struct panfrost_device *pfdev = dev_get_drvdata(dev);
705b12f3ea7SAdrián Larumbe bool value;
706b12f3ea7SAdrián Larumbe int err;
707b12f3ea7SAdrián Larumbe
708b12f3ea7SAdrián Larumbe err = kstrtobool(buf, &value);
709b12f3ea7SAdrián Larumbe if (err)
710b12f3ea7SAdrián Larumbe return err;
711b12f3ea7SAdrián Larumbe
712b12f3ea7SAdrián Larumbe pfdev->profile_mode = value;
713b12f3ea7SAdrián Larumbe
714b12f3ea7SAdrián Larumbe return len;
715b12f3ea7SAdrián Larumbe }
716b12f3ea7SAdrián Larumbe
717b12f3ea7SAdrián Larumbe static DEVICE_ATTR_RW(profiling);
718b12f3ea7SAdrián Larumbe
719b12f3ea7SAdrián Larumbe static struct attribute *panfrost_attrs[] = {
720b12f3ea7SAdrián Larumbe &dev_attr_profiling.attr,
721b12f3ea7SAdrián Larumbe NULL,
722b12f3ea7SAdrián Larumbe };
723b12f3ea7SAdrián Larumbe
724b12f3ea7SAdrián Larumbe ATTRIBUTE_GROUPS(panfrost);
725b12f3ea7SAdrián Larumbe
72687686cc8SViresh Kumar /*
72787686cc8SViresh Kumar * The OPP core wants the supply names to be NULL terminated, but we need the
72887686cc8SViresh Kumar * correct num_supplies value for regulator core. Hence, we NULL terminate here
72987686cc8SViresh Kumar * and then initialize num_supplies with ARRAY_SIZE - 1.
73087686cc8SViresh Kumar */
73187686cc8SViresh Kumar static const char * const default_supplies[] = { "mali", NULL };
7323e1399bcSNicolas Boichat static const struct panfrost_compatible default_data = {
73387686cc8SViresh Kumar .num_supplies = ARRAY_SIZE(default_supplies) - 1,
7343e1399bcSNicolas Boichat .supply_names = default_supplies,
735506629c8SNicolas Boichat .num_pm_domains = 1, /* optional */
736506629c8SNicolas Boichat .pm_domain_names = NULL,
7373e1399bcSNicolas Boichat };
7383e1399bcSNicolas Boichat
739afcd0c7dSNeil Armstrong static const struct panfrost_compatible amlogic_data = {
74087686cc8SViresh Kumar .num_supplies = ARRAY_SIZE(default_supplies) - 1,
741afcd0c7dSNeil Armstrong .supply_names = default_supplies,
742afcd0c7dSNeil Armstrong .vendor_quirk = panfrost_gpu_amlogic_quirk,
743afcd0c7dSNeil Armstrong };
744afcd0c7dSNeil Armstrong
745ab1a072cSAngeloGioacchino Del Regno /*
746ab1a072cSAngeloGioacchino Del Regno * The old data with two power supplies for MT8183 is here only to
747ab1a072cSAngeloGioacchino Del Regno * keep retro-compatibility with older devicetrees, as DVFS will
748ab1a072cSAngeloGioacchino Del Regno * not work with this one.
749ab1a072cSAngeloGioacchino Del Regno *
750ab1a072cSAngeloGioacchino Del Regno * On new devicetrees please use the _b variant with a single and
751ab1a072cSAngeloGioacchino Del Regno * coupled regulators instead.
752ab1a072cSAngeloGioacchino Del Regno */
75387686cc8SViresh Kumar static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL };
754d52ce709SJiapeng Chong static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
7551275e417SNicolas Boichat static const struct panfrost_compatible mediatek_mt8183_data = {
75687686cc8SViresh Kumar .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1,
7571275e417SNicolas Boichat .supply_names = mediatek_mt8183_supplies,
7581275e417SNicolas Boichat .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
7591275e417SNicolas Boichat .pm_domain_names = mediatek_mt8183_pm_domains,
7601275e417SNicolas Boichat };
7611275e417SNicolas Boichat
762ab1a072cSAngeloGioacchino Del Regno static const char * const mediatek_mt8183_b_supplies[] = { "mali", NULL };
763ab1a072cSAngeloGioacchino Del Regno static const struct panfrost_compatible mediatek_mt8183_b_data = {
764ab1a072cSAngeloGioacchino Del Regno .num_supplies = ARRAY_SIZE(mediatek_mt8183_b_supplies) - 1,
765ab1a072cSAngeloGioacchino Del Regno .supply_names = mediatek_mt8183_b_supplies,
766ab1a072cSAngeloGioacchino Del Regno .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
767ab1a072cSAngeloGioacchino Del Regno .pm_domain_names = mediatek_mt8183_pm_domains,
768540527b1SAngeloGioacchino Del Regno .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
769ab1a072cSAngeloGioacchino Del Regno };
770ab1a072cSAngeloGioacchino Del Regno
771901cdf66SAngeloGioacchino Del Regno static const char * const mediatek_mt8186_pm_domains[] = { "core0", "core1" };
772901cdf66SAngeloGioacchino Del Regno static const struct panfrost_compatible mediatek_mt8186_data = {
773901cdf66SAngeloGioacchino Del Regno .num_supplies = ARRAY_SIZE(mediatek_mt8183_b_supplies) - 1,
774901cdf66SAngeloGioacchino Del Regno .supply_names = mediatek_mt8183_b_supplies,
775901cdf66SAngeloGioacchino Del Regno .num_pm_domains = ARRAY_SIZE(mediatek_mt8186_pm_domains),
776901cdf66SAngeloGioacchino Del Regno .pm_domain_names = mediatek_mt8186_pm_domains,
777540527b1SAngeloGioacchino Del Regno .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
778901cdf66SAngeloGioacchino Del Regno };
779901cdf66SAngeloGioacchino Del Regno
78072533b67SAngeloGioacchino Del Regno /* MT8188 uses the same power domains and power supplies as MT8183 */
78172533b67SAngeloGioacchino Del Regno static const struct panfrost_compatible mediatek_mt8188_data = {
78272533b67SAngeloGioacchino Del Regno .num_supplies = ARRAY_SIZE(mediatek_mt8183_b_supplies) - 1,
78372533b67SAngeloGioacchino Del Regno .supply_names = mediatek_mt8183_b_supplies,
78472533b67SAngeloGioacchino Del Regno .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
78572533b67SAngeloGioacchino Del Regno .pm_domain_names = mediatek_mt8183_pm_domains,
78672533b67SAngeloGioacchino Del Regno .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
78772533b67SAngeloGioacchino Del Regno };
78872533b67SAngeloGioacchino Del Regno
7894c681180SAlyssa Rosenzweig static const char * const mediatek_mt8192_supplies[] = { "mali", NULL };
7904c681180SAlyssa Rosenzweig static const char * const mediatek_mt8192_pm_domains[] = { "core0", "core1", "core2",
7914c681180SAlyssa Rosenzweig "core3", "core4" };
7924c681180SAlyssa Rosenzweig static const struct panfrost_compatible mediatek_mt8192_data = {
7934c681180SAlyssa Rosenzweig .num_supplies = ARRAY_SIZE(mediatek_mt8192_supplies) - 1,
7944c681180SAlyssa Rosenzweig .supply_names = mediatek_mt8192_supplies,
7954c681180SAlyssa Rosenzweig .num_pm_domains = ARRAY_SIZE(mediatek_mt8192_pm_domains),
7964c681180SAlyssa Rosenzweig .pm_domain_names = mediatek_mt8192_pm_domains,
797540527b1SAngeloGioacchino Del Regno .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
7984c681180SAlyssa Rosenzweig };
7994c681180SAlyssa Rosenzweig
800f3ba9122SRob Herring static const struct of_device_id dt_match[] = {
801afcd0c7dSNeil Armstrong /* Set first to probe before the generic compatibles */
802afcd0c7dSNeil Armstrong { .compatible = "amlogic,meson-gxm-mali",
803afcd0c7dSNeil Armstrong .data = &amlogic_data, },
804afcd0c7dSNeil Armstrong { .compatible = "amlogic,meson-g12a-mali",
805afcd0c7dSNeil Armstrong .data = &amlogic_data, },
8063e1399bcSNicolas Boichat { .compatible = "arm,mali-t604", .data = &default_data, },
8073e1399bcSNicolas Boichat { .compatible = "arm,mali-t624", .data = &default_data, },
8083e1399bcSNicolas Boichat { .compatible = "arm,mali-t628", .data = &default_data, },
8093e1399bcSNicolas Boichat { .compatible = "arm,mali-t720", .data = &default_data, },
8103e1399bcSNicolas Boichat { .compatible = "arm,mali-t760", .data = &default_data, },
8113e1399bcSNicolas Boichat { .compatible = "arm,mali-t820", .data = &default_data, },
8123e1399bcSNicolas Boichat { .compatible = "arm,mali-t830", .data = &default_data, },
8133e1399bcSNicolas Boichat { .compatible = "arm,mali-t860", .data = &default_data, },
8143e1399bcSNicolas Boichat { .compatible = "arm,mali-t880", .data = &default_data, },
81572ef7fe9STomeu Vizoso { .compatible = "arm,mali-bifrost", .data = &default_data, },
816952cd974SAlyssa Rosenzweig { .compatible = "arm,mali-valhall-jm", .data = &default_data, },
8171275e417SNicolas Boichat { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data },
818ab1a072cSAngeloGioacchino Del Regno { .compatible = "mediatek,mt8183b-mali", .data = &mediatek_mt8183_b_data },
819901cdf66SAngeloGioacchino Del Regno { .compatible = "mediatek,mt8186-mali", .data = &mediatek_mt8186_data },
82072533b67SAngeloGioacchino Del Regno { .compatible = "mediatek,mt8188-mali", .data = &mediatek_mt8188_data },
8214c681180SAlyssa Rosenzweig { .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data },
822f3ba9122SRob Herring {}
823f3ba9122SRob Herring };
824f3ba9122SRob Herring MODULE_DEVICE_TABLE(of, dt_match);
825f3ba9122SRob Herring
826f3ba9122SRob Herring static struct platform_driver panfrost_driver = {
827f3ba9122SRob Herring .probe = panfrost_probe,
828e41977a8SUwe Kleine-König .remove_new = panfrost_remove,
829f3ba9122SRob Herring .driver = {
830f3ba9122SRob Herring .name = "panfrost",
83153d36818SPaul Cercueil .pm = pm_ptr(&panfrost_pm_ops),
832f3ba9122SRob Herring .of_match_table = dt_match,
833b12f3ea7SAdrián Larumbe .dev_groups = panfrost_groups,
834f3ba9122SRob Herring },
835f3ba9122SRob Herring };
836f3ba9122SRob Herring module_platform_driver(panfrost_driver);
837f3ba9122SRob Herring
838f3ba9122SRob Herring MODULE_AUTHOR("Panfrost Project Developers");
839f3ba9122SRob Herring MODULE_DESCRIPTION("Panfrost DRM Driver");
840f3ba9122SRob Herring MODULE_LICENSE("GPL v2");
841*80f4e627SDragan Simic MODULE_SOFTDEP("pre: governor_simpleondemand");
842