18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright 2019 Collabora Ltd */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <drm/drm_file.h>
58c2ecf20Sopenharmony_ci#include <drm/drm_gem_shmem_helper.h>
68c2ecf20Sopenharmony_ci#include <drm/panfrost_drm.h>
78c2ecf20Sopenharmony_ci#include <linux/completion.h>
88c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
98c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "panfrost_device.h"
148c2ecf20Sopenharmony_ci#include "panfrost_features.h"
158c2ecf20Sopenharmony_ci#include "panfrost_gem.h"
168c2ecf20Sopenharmony_ci#include "panfrost_issues.h"
178c2ecf20Sopenharmony_ci#include "panfrost_job.h"
188c2ecf20Sopenharmony_ci#include "panfrost_mmu.h"
198c2ecf20Sopenharmony_ci#include "panfrost_perfcnt.h"
208c2ecf20Sopenharmony_ci#include "panfrost_regs.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define COUNTERS_PER_BLOCK		64
238c2ecf20Sopenharmony_ci#define BYTES_PER_COUNTER		4
248c2ecf20Sopenharmony_ci#define BLOCKS_PER_COREGROUP		8
258c2ecf20Sopenharmony_ci#define V4_SHADERS_PER_COREGROUP	4
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct panfrost_perfcnt {
288c2ecf20Sopenharmony_ci	struct panfrost_gem_mapping *mapping;
298c2ecf20Sopenharmony_ci	size_t bosize;
308c2ecf20Sopenharmony_ci	void *buf;
318c2ecf20Sopenharmony_ci	struct panfrost_file_priv *user;
328c2ecf20Sopenharmony_ci	struct mutex lock;
338c2ecf20Sopenharmony_ci	struct completion dump_comp;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_civoid panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	complete(&pfdev->perfcnt->dump_comp);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_civoid panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u64 gpuva;
498c2ecf20Sopenharmony_ci	int ret;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	reinit_completion(&pfdev->perfcnt->dump_comp);
528c2ecf20Sopenharmony_ci	gpuva = pfdev->perfcnt->mapping->mmnode.start << PAGE_SHIFT;
538c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_BASE_LO, gpuva);
548c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_BASE_HI, gpuva >> 32);
558c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_INT_CLEAR,
568c2ecf20Sopenharmony_ci		  GPU_IRQ_CLEAN_CACHES_COMPLETED |
578c2ecf20Sopenharmony_ci		  GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
588c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
598c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible_timeout(&pfdev->perfcnt->dump_comp,
608c2ecf20Sopenharmony_ci							msecs_to_jiffies(1000));
618c2ecf20Sopenharmony_ci	if (!ret)
628c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
638c2ecf20Sopenharmony_ci	else if (ret > 0)
648c2ecf20Sopenharmony_ci		ret = 0;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return ret;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
708c2ecf20Sopenharmony_ci					  struct drm_file *file_priv,
718c2ecf20Sopenharmony_ci					  unsigned int counterset)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct panfrost_file_priv *user = file_priv->driver_priv;
748c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
758c2ecf20Sopenharmony_ci	struct drm_gem_shmem_object *bo;
768c2ecf20Sopenharmony_ci	u32 cfg, as;
778c2ecf20Sopenharmony_ci	int ret;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (user == perfcnt->user)
808c2ecf20Sopenharmony_ci		return 0;
818c2ecf20Sopenharmony_ci	else if (perfcnt->user)
828c2ecf20Sopenharmony_ci		return -EBUSY;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(pfdev->dev);
858c2ecf20Sopenharmony_ci	if (ret < 0)
868c2ecf20Sopenharmony_ci		goto err_put_pm;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize);
898c2ecf20Sopenharmony_ci	if (IS_ERR(bo)) {
908c2ecf20Sopenharmony_ci		ret = PTR_ERR(bo);
918c2ecf20Sopenharmony_ci		goto err_put_pm;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Map the perfcnt buf in the address space attached to file_priv. */
958c2ecf20Sopenharmony_ci	ret = panfrost_gem_open(&bo->base, file_priv);
968c2ecf20Sopenharmony_ci	if (ret)
978c2ecf20Sopenharmony_ci		goto err_put_bo;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	perfcnt->mapping = panfrost_gem_mapping_get(to_panfrost_bo(&bo->base),
1008c2ecf20Sopenharmony_ci						    user);
1018c2ecf20Sopenharmony_ci	if (!perfcnt->mapping) {
1028c2ecf20Sopenharmony_ci		ret = -EINVAL;
1038c2ecf20Sopenharmony_ci		goto err_close_bo;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	perfcnt->buf = drm_gem_shmem_vmap(&bo->base);
1078c2ecf20Sopenharmony_ci	if (IS_ERR(perfcnt->buf)) {
1088c2ecf20Sopenharmony_ci		ret = PTR_ERR(perfcnt->buf);
1098c2ecf20Sopenharmony_ci		goto err_put_mapping;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/*
1138c2ecf20Sopenharmony_ci	 * Invalidate the cache and clear the counters to start from a fresh
1148c2ecf20Sopenharmony_ci	 * state.
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci	reinit_completion(&pfdev->perfcnt->dump_comp);
1178c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_INT_CLEAR,
1188c2ecf20Sopenharmony_ci		  GPU_IRQ_CLEAN_CACHES_COMPLETED |
1198c2ecf20Sopenharmony_ci		  GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
1208c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
1218c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_INV_CACHES);
1228c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&pfdev->perfcnt->dump_comp,
1238c2ecf20Sopenharmony_ci					  msecs_to_jiffies(1000));
1248c2ecf20Sopenharmony_ci	if (!ret) {
1258c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
1268c2ecf20Sopenharmony_ci		goto err_vunmap;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	perfcnt->user = user;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	as = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
1328c2ecf20Sopenharmony_ci	cfg = GPU_PERFCNT_CFG_AS(as) |
1338c2ecf20Sopenharmony_ci	      GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/*
1368c2ecf20Sopenharmony_ci	 * Bifrost GPUs have 2 set of counters, but we're only interested by
1378c2ecf20Sopenharmony_ci	 * the first one for now.
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	if (panfrost_model_is_bifrost(pfdev))
1408c2ecf20Sopenharmony_ci		cfg |= GPU_PERFCNT_CFG_SETSEL(counterset);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
1438c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
1448c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/*
1478c2ecf20Sopenharmony_ci	 * Due to PRLAM-8186 we need to disable the Tiler before we enable HW
1488c2ecf20Sopenharmony_ci	 * counters.
1498c2ecf20Sopenharmony_ci	 */
1508c2ecf20Sopenharmony_ci	if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
1518c2ecf20Sopenharmony_ci		gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
1528c2ecf20Sopenharmony_ci	else
1538c2ecf20Sopenharmony_ci		gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
1588c2ecf20Sopenharmony_ci		gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* The BO ref is retained by the mapping. */
1618c2ecf20Sopenharmony_ci	drm_gem_object_put(&bo->base);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cierr_vunmap:
1668c2ecf20Sopenharmony_ci	drm_gem_shmem_vunmap(&bo->base, perfcnt->buf);
1678c2ecf20Sopenharmony_cierr_put_mapping:
1688c2ecf20Sopenharmony_ci	panfrost_gem_mapping_put(perfcnt->mapping);
1698c2ecf20Sopenharmony_cierr_close_bo:
1708c2ecf20Sopenharmony_ci	panfrost_gem_close(&bo->base, file_priv);
1718c2ecf20Sopenharmony_cierr_put_bo:
1728c2ecf20Sopenharmony_ci	drm_gem_object_put(&bo->base);
1738c2ecf20Sopenharmony_cierr_put_pm:
1748c2ecf20Sopenharmony_ci	pm_runtime_put(pfdev->dev);
1758c2ecf20Sopenharmony_ci	return ret;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
1798c2ecf20Sopenharmony_ci					   struct drm_file *file_priv)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct panfrost_file_priv *user = file_priv->driver_priv;
1828c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (user != perfcnt->user)
1858c2ecf20Sopenharmony_ci		return -EINVAL;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
1888c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
1898c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
1908c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
1918c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_CFG,
1928c2ecf20Sopenharmony_ci		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	perfcnt->user = NULL;
1958c2ecf20Sopenharmony_ci	drm_gem_shmem_vunmap(&perfcnt->mapping->obj->base.base, perfcnt->buf);
1968c2ecf20Sopenharmony_ci	perfcnt->buf = NULL;
1978c2ecf20Sopenharmony_ci	panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
1988c2ecf20Sopenharmony_ci	panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
1998c2ecf20Sopenharmony_ci	panfrost_gem_mapping_put(perfcnt->mapping);
2008c2ecf20Sopenharmony_ci	perfcnt->mapping = NULL;
2018c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(pfdev->dev);
2028c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(pfdev->dev);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return 0;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciint panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
2088c2ecf20Sopenharmony_ci				  struct drm_file *file_priv)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct panfrost_device *pfdev = dev->dev_private;
2118c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
2128c2ecf20Sopenharmony_ci	struct drm_panfrost_perfcnt_enable *req = data;
2138c2ecf20Sopenharmony_ci	int ret;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ret = panfrost_unstable_ioctl_check();
2168c2ecf20Sopenharmony_ci	if (ret)
2178c2ecf20Sopenharmony_ci		return ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Only Bifrost GPUs have 2 set of counters. */
2208c2ecf20Sopenharmony_ci	if (req->counterset > (panfrost_model_is_bifrost(pfdev) ? 1 : 0))
2218c2ecf20Sopenharmony_ci		return -EINVAL;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	mutex_lock(&perfcnt->lock);
2248c2ecf20Sopenharmony_ci	if (req->enable)
2258c2ecf20Sopenharmony_ci		ret = panfrost_perfcnt_enable_locked(pfdev, file_priv,
2268c2ecf20Sopenharmony_ci						     req->counterset);
2278c2ecf20Sopenharmony_ci	else
2288c2ecf20Sopenharmony_ci		ret = panfrost_perfcnt_disable_locked(pfdev, file_priv);
2298c2ecf20Sopenharmony_ci	mutex_unlock(&perfcnt->lock);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return ret;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ciint panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
2358c2ecf20Sopenharmony_ci				struct drm_file *file_priv)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct panfrost_device *pfdev = dev->dev_private;
2388c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
2398c2ecf20Sopenharmony_ci	struct drm_panfrost_perfcnt_dump *req = data;
2408c2ecf20Sopenharmony_ci	void __user *user_ptr = (void __user *)(uintptr_t)req->buf_ptr;
2418c2ecf20Sopenharmony_ci	int ret;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	ret = panfrost_unstable_ioctl_check();
2448c2ecf20Sopenharmony_ci	if (ret)
2458c2ecf20Sopenharmony_ci		return ret;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	mutex_lock(&perfcnt->lock);
2488c2ecf20Sopenharmony_ci	if (perfcnt->user != file_priv->driver_priv) {
2498c2ecf20Sopenharmony_ci		ret = -EINVAL;
2508c2ecf20Sopenharmony_ci		goto out;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	ret = panfrost_perfcnt_dump_locked(pfdev);
2548c2ecf20Sopenharmony_ci	if (ret)
2558c2ecf20Sopenharmony_ci		goto out;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (copy_to_user(user_ptr, perfcnt->buf, perfcnt->bosize))
2588c2ecf20Sopenharmony_ci		ret = -EFAULT;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciout:
2618c2ecf20Sopenharmony_ci	mutex_unlock(&perfcnt->lock);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return ret;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_civoid panfrost_perfcnt_close(struct drm_file *file_priv)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct panfrost_file_priv *pfile = file_priv->driver_priv;
2698c2ecf20Sopenharmony_ci	struct panfrost_device *pfdev = pfile->pfdev;
2708c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	pm_runtime_get_sync(pfdev->dev);
2738c2ecf20Sopenharmony_ci	mutex_lock(&perfcnt->lock);
2748c2ecf20Sopenharmony_ci	if (perfcnt->user == pfile)
2758c2ecf20Sopenharmony_ci		panfrost_perfcnt_disable_locked(pfdev, file_priv);
2768c2ecf20Sopenharmony_ci	mutex_unlock(&perfcnt->lock);
2778c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(pfdev->dev);
2788c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(pfdev->dev);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciint panfrost_perfcnt_init(struct panfrost_device *pfdev)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct panfrost_perfcnt *perfcnt;
2848c2ecf20Sopenharmony_ci	size_t size;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (panfrost_has_hw_feature(pfdev, HW_FEATURE_V4)) {
2878c2ecf20Sopenharmony_ci		unsigned int ncoregroups;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		ncoregroups = hweight64(pfdev->features.l2_present);
2908c2ecf20Sopenharmony_ci		size = ncoregroups * BLOCKS_PER_COREGROUP *
2918c2ecf20Sopenharmony_ci		       COUNTERS_PER_BLOCK * BYTES_PER_COUNTER;
2928c2ecf20Sopenharmony_ci	} else {
2938c2ecf20Sopenharmony_ci		unsigned int nl2c, ncores;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		/*
2968c2ecf20Sopenharmony_ci		 * TODO: define a macro to extract the number of l2 caches from
2978c2ecf20Sopenharmony_ci		 * mem_features.
2988c2ecf20Sopenharmony_ci		 */
2998c2ecf20Sopenharmony_ci		nl2c = ((pfdev->features.mem_features >> 8) & GENMASK(3, 0)) + 1;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		/*
3028c2ecf20Sopenharmony_ci		 * shader_present might be sparse, but the counters layout
3038c2ecf20Sopenharmony_ci		 * forces to dump unused regions too, hence the fls64() call
3048c2ecf20Sopenharmony_ci		 * instead of hweight64().
3058c2ecf20Sopenharmony_ci		 */
3068c2ecf20Sopenharmony_ci		ncores = fls64(pfdev->features.shader_present);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		/*
3098c2ecf20Sopenharmony_ci		 * There's always one JM and one Tiler block, hence the '+ 2'
3108c2ecf20Sopenharmony_ci		 * here.
3118c2ecf20Sopenharmony_ci		 */
3128c2ecf20Sopenharmony_ci		size = (nl2c + ncores + 2) *
3138c2ecf20Sopenharmony_ci		       COUNTERS_PER_BLOCK * BYTES_PER_COUNTER;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	perfcnt = devm_kzalloc(pfdev->dev, sizeof(*perfcnt), GFP_KERNEL);
3178c2ecf20Sopenharmony_ci	if (!perfcnt)
3188c2ecf20Sopenharmony_ci		return -ENOMEM;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	perfcnt->bosize = size;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* Start with everything disabled. */
3238c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_CFG,
3248c2ecf20Sopenharmony_ci		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
3258c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
3268c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
3278c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
3288c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	init_completion(&perfcnt->dump_comp);
3318c2ecf20Sopenharmony_ci	mutex_init(&perfcnt->lock);
3328c2ecf20Sopenharmony_ci	pfdev->perfcnt = perfcnt;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_civoid panfrost_perfcnt_fini(struct panfrost_device *pfdev)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	/* Disable everything before leaving. */
3408c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PERFCNT_CFG,
3418c2ecf20Sopenharmony_ci		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
3428c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
3438c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
3448c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
3458c2ecf20Sopenharmony_ci	gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
3468c2ecf20Sopenharmony_ci}
347