162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/* Copyright (C) 2014-2018 Broadcom */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/circ_buf.h>
562306a36Sopenharmony_ci#include <linux/ctype.h>
662306a36Sopenharmony_ci#include <linux/debugfs.h>
762306a36Sopenharmony_ci#include <linux/seq_file.h>
862306a36Sopenharmony_ci#include <linux/string_helpers.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <drm/drm_debugfs.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "v3d_drv.h"
1362306a36Sopenharmony_ci#include "v3d_regs.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define REGDEF(reg) { reg, #reg }
1662306a36Sopenharmony_cistruct v3d_reg_def {
1762306a36Sopenharmony_ci	u32 reg;
1862306a36Sopenharmony_ci	const char *name;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const struct v3d_reg_def v3d_hub_reg_defs[] = {
2262306a36Sopenharmony_ci	REGDEF(V3D_HUB_AXICFG),
2362306a36Sopenharmony_ci	REGDEF(V3D_HUB_UIFCFG),
2462306a36Sopenharmony_ci	REGDEF(V3D_HUB_IDENT0),
2562306a36Sopenharmony_ci	REGDEF(V3D_HUB_IDENT1),
2662306a36Sopenharmony_ci	REGDEF(V3D_HUB_IDENT2),
2762306a36Sopenharmony_ci	REGDEF(V3D_HUB_IDENT3),
2862306a36Sopenharmony_ci	REGDEF(V3D_HUB_INT_STS),
2962306a36Sopenharmony_ci	REGDEF(V3D_HUB_INT_MSK_STS),
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	REGDEF(V3D_MMU_CTL),
3262306a36Sopenharmony_ci	REGDEF(V3D_MMU_VIO_ADDR),
3362306a36Sopenharmony_ci	REGDEF(V3D_MMU_VIO_ID),
3462306a36Sopenharmony_ci	REGDEF(V3D_MMU_DEBUG_INFO),
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const struct v3d_reg_def v3d_gca_reg_defs[] = {
3862306a36Sopenharmony_ci	REGDEF(V3D_GCA_SAFE_SHUTDOWN),
3962306a36Sopenharmony_ci	REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK),
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct v3d_reg_def v3d_core_reg_defs[] = {
4362306a36Sopenharmony_ci	REGDEF(V3D_CTL_IDENT0),
4462306a36Sopenharmony_ci	REGDEF(V3D_CTL_IDENT1),
4562306a36Sopenharmony_ci	REGDEF(V3D_CTL_IDENT2),
4662306a36Sopenharmony_ci	REGDEF(V3D_CTL_MISCCFG),
4762306a36Sopenharmony_ci	REGDEF(V3D_CTL_INT_STS),
4862306a36Sopenharmony_ci	REGDEF(V3D_CTL_INT_MSK_STS),
4962306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT0CS),
5062306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT0CA),
5162306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT0EA),
5262306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT1CS),
5362306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT1CA),
5462306a36Sopenharmony_ci	REGDEF(V3D_CLE_CT1EA),
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	REGDEF(V3D_PTB_BPCA),
5762306a36Sopenharmony_ci	REGDEF(V3D_PTB_BPCS),
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	REGDEF(V3D_GMP_STATUS),
6062306a36Sopenharmony_ci	REGDEF(V3D_GMP_CFG),
6162306a36Sopenharmony_ci	REGDEF(V3D_GMP_VIO_ADDR),
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	REGDEF(V3D_ERR_FDBGO),
6462306a36Sopenharmony_ci	REGDEF(V3D_ERR_FDBGB),
6562306a36Sopenharmony_ci	REGDEF(V3D_ERR_FDBGS),
6662306a36Sopenharmony_ci	REGDEF(V3D_ERR_STAT),
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const struct v3d_reg_def v3d_csd_reg_defs[] = {
7062306a36Sopenharmony_ci	REGDEF(V3D_CSD_STATUS),
7162306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG0),
7262306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG1),
7362306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG2),
7462306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG3),
7562306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG4),
7662306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG5),
7762306a36Sopenharmony_ci	REGDEF(V3D_CSD_CURRENT_CFG6),
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct drm_debugfs_entry *entry = m->private;
8362306a36Sopenharmony_ci	struct drm_device *dev = entry->dev;
8462306a36Sopenharmony_ci	struct v3d_dev *v3d = to_v3d_dev(dev);
8562306a36Sopenharmony_ci	int i, core;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) {
8862306a36Sopenharmony_ci		seq_printf(m, "%s (0x%04x): 0x%08x\n",
8962306a36Sopenharmony_ci			   v3d_hub_reg_defs[i].name, v3d_hub_reg_defs[i].reg,
9062306a36Sopenharmony_ci			   V3D_READ(v3d_hub_reg_defs[i].reg));
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (v3d->ver < 41) {
9462306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
9562306a36Sopenharmony_ci			seq_printf(m, "%s (0x%04x): 0x%08x\n",
9662306a36Sopenharmony_ci				   v3d_gca_reg_defs[i].name,
9762306a36Sopenharmony_ci				   v3d_gca_reg_defs[i].reg,
9862306a36Sopenharmony_ci				   V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	for (core = 0; core < v3d->cores; core++) {
10362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) {
10462306a36Sopenharmony_ci			seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
10562306a36Sopenharmony_ci				   core,
10662306a36Sopenharmony_ci				   v3d_core_reg_defs[i].name,
10762306a36Sopenharmony_ci				   v3d_core_reg_defs[i].reg,
10862306a36Sopenharmony_ci				   V3D_CORE_READ(core,
10962306a36Sopenharmony_ci						 v3d_core_reg_defs[i].reg));
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		if (v3d_has_csd(v3d)) {
11362306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
11462306a36Sopenharmony_ci				seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
11562306a36Sopenharmony_ci					   core,
11662306a36Sopenharmony_ci					   v3d_csd_reg_defs[i].name,
11762306a36Sopenharmony_ci					   v3d_csd_reg_defs[i].reg,
11862306a36Sopenharmony_ci					   V3D_CORE_READ(core,
11962306a36Sopenharmony_ci							 v3d_csd_reg_defs[i].reg));
12062306a36Sopenharmony_ci			}
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct drm_debugfs_entry *entry = m->private;
13062306a36Sopenharmony_ci	struct drm_device *dev = entry->dev;
13162306a36Sopenharmony_ci	struct v3d_dev *v3d = to_v3d_dev(dev);
13262306a36Sopenharmony_ci	u32 ident0, ident1, ident2, ident3, cores;
13362306a36Sopenharmony_ci	int core;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ident0 = V3D_READ(V3D_HUB_IDENT0);
13662306a36Sopenharmony_ci	ident1 = V3D_READ(V3D_HUB_IDENT1);
13762306a36Sopenharmony_ci	ident2 = V3D_READ(V3D_HUB_IDENT2);
13862306a36Sopenharmony_ci	ident3 = V3D_READ(V3D_HUB_IDENT3);
13962306a36Sopenharmony_ci	cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	seq_printf(m, "Revision:   %d.%d.%d.%d\n",
14262306a36Sopenharmony_ci		   V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER),
14362306a36Sopenharmony_ci		   V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV),
14462306a36Sopenharmony_ci		   V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV),
14562306a36Sopenharmony_ci		   V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPIDX));
14662306a36Sopenharmony_ci	seq_printf(m, "MMU:        %s\n",
14762306a36Sopenharmony_ci		   str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU));
14862306a36Sopenharmony_ci	seq_printf(m, "TFU:        %s\n",
14962306a36Sopenharmony_ci		   str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU));
15062306a36Sopenharmony_ci	seq_printf(m, "TSY:        %s\n",
15162306a36Sopenharmony_ci		   str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY));
15262306a36Sopenharmony_ci	seq_printf(m, "MSO:        %s\n",
15362306a36Sopenharmony_ci		   str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO));
15462306a36Sopenharmony_ci	seq_printf(m, "L3C:        %s (%dkb)\n",
15562306a36Sopenharmony_ci		   str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_L3C),
15662306a36Sopenharmony_ci		   V3D_GET_FIELD(ident2, V3D_HUB_IDENT2_L3C_NKB));
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	for (core = 0; core < cores; core++) {
15962306a36Sopenharmony_ci		u32 misccfg;
16062306a36Sopenharmony_ci		u32 nslc, ntmu, qups;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		ident0 = V3D_CORE_READ(core, V3D_CTL_IDENT0);
16362306a36Sopenharmony_ci		ident1 = V3D_CORE_READ(core, V3D_CTL_IDENT1);
16462306a36Sopenharmony_ci		ident2 = V3D_CORE_READ(core, V3D_CTL_IDENT2);
16562306a36Sopenharmony_ci		misccfg = V3D_CORE_READ(core, V3D_CTL_MISCCFG);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		nslc = V3D_GET_FIELD(ident1, V3D_IDENT1_NSLC);
16862306a36Sopenharmony_ci		ntmu = V3D_GET_FIELD(ident1, V3D_IDENT1_NTMU);
16962306a36Sopenharmony_ci		qups = V3D_GET_FIELD(ident1, V3D_IDENT1_QUPS);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		seq_printf(m, "Core %d:\n", core);
17262306a36Sopenharmony_ci		seq_printf(m, "  Revision:     %d.%d\n",
17362306a36Sopenharmony_ci			   V3D_GET_FIELD(ident0, V3D_IDENT0_VER),
17462306a36Sopenharmony_ci			   V3D_GET_FIELD(ident1, V3D_IDENT1_REV));
17562306a36Sopenharmony_ci		seq_printf(m, "  Slices:       %d\n", nslc);
17662306a36Sopenharmony_ci		seq_printf(m, "  TMUs:         %d\n", nslc * ntmu);
17762306a36Sopenharmony_ci		seq_printf(m, "  QPUs:         %d\n", nslc * qups);
17862306a36Sopenharmony_ci		seq_printf(m, "  Semaphores:   %d\n",
17962306a36Sopenharmony_ci			   V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM));
18062306a36Sopenharmony_ci		seq_printf(m, "  BCG int:      %d\n",
18162306a36Sopenharmony_ci			   (ident2 & V3D_IDENT2_BCG_INT) != 0);
18262306a36Sopenharmony_ci		seq_printf(m, "  Override TMU: %d\n",
18362306a36Sopenharmony_ci			   (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct drm_debugfs_entry *entry = m->private;
19262306a36Sopenharmony_ci	struct drm_device *dev = entry->dev;
19362306a36Sopenharmony_ci	struct v3d_dev *v3d = to_v3d_dev(dev);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	mutex_lock(&v3d->bo_lock);
19662306a36Sopenharmony_ci	seq_printf(m, "allocated bos:          %d\n",
19762306a36Sopenharmony_ci		   v3d->bo_stats.num_allocated);
19862306a36Sopenharmony_ci	seq_printf(m, "allocated bo size (kb): %ld\n",
19962306a36Sopenharmony_ci		   (long)v3d->bo_stats.pages_allocated << (PAGE_SHIFT - 10));
20062306a36Sopenharmony_ci	mutex_unlock(&v3d->bo_lock);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int v3d_measure_clock(struct seq_file *m, void *unused)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct drm_debugfs_entry *entry = m->private;
20862306a36Sopenharmony_ci	struct drm_device *dev = entry->dev;
20962306a36Sopenharmony_ci	struct v3d_dev *v3d = to_v3d_dev(dev);
21062306a36Sopenharmony_ci	uint32_t cycles;
21162306a36Sopenharmony_ci	int core = 0;
21262306a36Sopenharmony_ci	int measure_ms = 1000;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (v3d->ver >= 40) {
21562306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
21662306a36Sopenharmony_ci			       V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
21762306a36Sopenharmony_ci					     V3D_PCTR_S0));
21862306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
21962306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
22062306a36Sopenharmony_ci	} else {
22162306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
22262306a36Sopenharmony_ci			       V3D_PCTR_CYCLE_COUNT);
22362306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
22462306a36Sopenharmony_ci		V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
22562306a36Sopenharmony_ci			       V3D_V3_PCTR_0_EN_ENABLE |
22662306a36Sopenharmony_ci			       1);
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci	msleep(measure_ms);
22962306a36Sopenharmony_ci	cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
23262306a36Sopenharmony_ci		   cycles,
23362306a36Sopenharmony_ci		   cycles / (measure_ms * 1000),
23462306a36Sopenharmony_ci		   (cycles / (measure_ms * 100)) % 10);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct drm_debugfs_info v3d_debugfs_list[] = {
24062306a36Sopenharmony_ci	{"v3d_ident", v3d_v3d_debugfs_ident, 0},
24162306a36Sopenharmony_ci	{"v3d_regs", v3d_v3d_debugfs_regs, 0},
24262306a36Sopenharmony_ci	{"measure_clock", v3d_measure_clock, 0},
24362306a36Sopenharmony_ci	{"bo_stats", v3d_debugfs_bo_stats, 0},
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_civoid
24762306a36Sopenharmony_civ3d_debugfs_init(struct drm_minor *minor)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	drm_debugfs_add_files(minor->dev, v3d_debugfs_list, ARRAY_SIZE(v3d_debugfs_list));
25062306a36Sopenharmony_ci}
251