1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2014-2018 Broadcom */
4 #include <linux/circ_buf.h>
5 #include <linux/ctype.h>
6 #include <linux/debugfs.h>
7 #include <linux/pm_runtime.h>
8 #include <linux/seq_file.h>
14 #define REGDEF(reg) { reg, #reg }
20 static const struct v3d_reg_def v3d_hub_reg_defs
[] = {
21 REGDEF(V3D_HUB_AXICFG
),
22 REGDEF(V3D_HUB_UIFCFG
),
23 REGDEF(V3D_HUB_IDENT0
),
24 REGDEF(V3D_HUB_IDENT1
),
25 REGDEF(V3D_HUB_IDENT2
),
26 REGDEF(V3D_HUB_IDENT3
),
27 REGDEF(V3D_HUB_INT_STS
),
28 REGDEF(V3D_HUB_INT_MSK_STS
),
31 static const struct v3d_reg_def v3d_gca_reg_defs
[] = {
32 REGDEF(V3D_GCA_SAFE_SHUTDOWN
),
33 REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK
),
36 static const struct v3d_reg_def v3d_core_reg_defs
[] = {
37 REGDEF(V3D_CTL_IDENT0
),
38 REGDEF(V3D_CTL_IDENT1
),
39 REGDEF(V3D_CTL_IDENT2
),
40 REGDEF(V3D_CTL_MISCCFG
),
41 REGDEF(V3D_CTL_INT_STS
),
42 REGDEF(V3D_CTL_INT_MSK_STS
),
43 REGDEF(V3D_CLE_CT0CS
),
44 REGDEF(V3D_CLE_CT0CA
),
45 REGDEF(V3D_CLE_CT0EA
),
46 REGDEF(V3D_CLE_CT1CS
),
47 REGDEF(V3D_CLE_CT1CA
),
48 REGDEF(V3D_CLE_CT1EA
),
54 REGDEF(V3D_MMU_VIO_ADDR
),
56 REGDEF(V3D_GMP_STATUS
),
58 REGDEF(V3D_GMP_VIO_ADDR
),
61 static int v3d_v3d_debugfs_regs(struct seq_file
*m
, void *unused
)
63 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
64 struct drm_device
*dev
= node
->minor
->dev
;
65 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
68 for (i
= 0; i
< ARRAY_SIZE(v3d_hub_reg_defs
); i
++) {
69 seq_printf(m
, "%s (0x%04x): 0x%08x\n",
70 v3d_hub_reg_defs
[i
].name
, v3d_hub_reg_defs
[i
].reg
,
71 V3D_READ(v3d_hub_reg_defs
[i
].reg
));
75 for (i
= 0; i
< ARRAY_SIZE(v3d_gca_reg_defs
); i
++) {
76 seq_printf(m
, "%s (0x%04x): 0x%08x\n",
77 v3d_gca_reg_defs
[i
].name
,
78 v3d_gca_reg_defs
[i
].reg
,
79 V3D_GCA_READ(v3d_gca_reg_defs
[i
].reg
));
83 for (core
= 0; core
< v3d
->cores
; core
++) {
84 for (i
= 0; i
< ARRAY_SIZE(v3d_core_reg_defs
); i
++) {
85 seq_printf(m
, "core %d %s (0x%04x): 0x%08x\n",
87 v3d_core_reg_defs
[i
].name
,
88 v3d_core_reg_defs
[i
].reg
,
90 v3d_core_reg_defs
[i
].reg
));
97 static int v3d_v3d_debugfs_ident(struct seq_file
*m
, void *unused
)
99 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
100 struct drm_device
*dev
= node
->minor
->dev
;
101 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
102 u32 ident0
, ident1
, ident2
, ident3
, cores
;
105 ret
= pm_runtime_get_sync(v3d
->dev
);
109 ident0
= V3D_READ(V3D_HUB_IDENT0
);
110 ident1
= V3D_READ(V3D_HUB_IDENT1
);
111 ident2
= V3D_READ(V3D_HUB_IDENT2
);
112 ident3
= V3D_READ(V3D_HUB_IDENT3
);
113 cores
= V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_NCORES
);
115 seq_printf(m
, "Revision: %d.%d.%d.%d\n",
116 V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_TVER
),
117 V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_REV
),
118 V3D_GET_FIELD(ident3
, V3D_HUB_IDENT3_IPREV
),
119 V3D_GET_FIELD(ident3
, V3D_HUB_IDENT3_IPIDX
));
120 seq_printf(m
, "MMU: %s\n",
121 (ident2
& V3D_HUB_IDENT2_WITH_MMU
) ? "yes" : "no");
122 seq_printf(m
, "TFU: %s\n",
123 (ident1
& V3D_HUB_IDENT1_WITH_TFU
) ? "yes" : "no");
124 seq_printf(m
, "TSY: %s\n",
125 (ident1
& V3D_HUB_IDENT1_WITH_TSY
) ? "yes" : "no");
126 seq_printf(m
, "MSO: %s\n",
127 (ident1
& V3D_HUB_IDENT1_WITH_MSO
) ? "yes" : "no");
128 seq_printf(m
, "L3C: %s (%dkb)\n",
129 (ident1
& V3D_HUB_IDENT1_WITH_L3C
) ? "yes" : "no",
130 V3D_GET_FIELD(ident2
, V3D_HUB_IDENT2_L3C_NKB
));
132 for (core
= 0; core
< cores
; core
++) {
134 u32 nslc
, ntmu
, qups
;
136 ident0
= V3D_CORE_READ(core
, V3D_CTL_IDENT0
);
137 ident1
= V3D_CORE_READ(core
, V3D_CTL_IDENT1
);
138 ident2
= V3D_CORE_READ(core
, V3D_CTL_IDENT2
);
139 misccfg
= V3D_CORE_READ(core
, V3D_CTL_MISCCFG
);
141 nslc
= V3D_GET_FIELD(ident1
, V3D_IDENT1_NSLC
);
142 ntmu
= V3D_GET_FIELD(ident1
, V3D_IDENT1_NTMU
);
143 qups
= V3D_GET_FIELD(ident1
, V3D_IDENT1_QUPS
);
145 seq_printf(m
, "Core %d:\n", core
);
146 seq_printf(m
, " Revision: %d.%d\n",
147 V3D_GET_FIELD(ident0
, V3D_IDENT0_VER
),
148 V3D_GET_FIELD(ident1
, V3D_IDENT1_REV
));
149 seq_printf(m
, " Slices: %d\n", nslc
);
150 seq_printf(m
, " TMUs: %d\n", nslc
* ntmu
);
151 seq_printf(m
, " QPUs: %d\n", nslc
* qups
);
152 seq_printf(m
, " Semaphores: %d\n",
153 V3D_GET_FIELD(ident1
, V3D_IDENT1_NSEM
));
154 seq_printf(m
, " BCG int: %d\n",
155 (ident2
& V3D_IDENT2_BCG_INT
) != 0);
156 seq_printf(m
, " Override TMU: %d\n",
157 (misccfg
& V3D_MISCCFG_OVRTMUOUT
) != 0);
160 pm_runtime_mark_last_busy(v3d
->dev
);
161 pm_runtime_put_autosuspend(v3d
->dev
);
166 static int v3d_debugfs_bo_stats(struct seq_file
*m
, void *unused
)
168 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
169 struct drm_device
*dev
= node
->minor
->dev
;
170 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
172 mutex_lock(&v3d
->bo_lock
);
173 seq_printf(m
, "allocated bos: %d\n",
174 v3d
->bo_stats
.num_allocated
);
175 seq_printf(m
, "allocated bo size (kb): %ld\n",
176 (long)v3d
->bo_stats
.pages_allocated
<< (PAGE_SHIFT
- 10));
177 mutex_unlock(&v3d
->bo_lock
);
182 static int v3d_measure_clock(struct seq_file
*m
, void *unused
)
184 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
185 struct drm_device
*dev
= node
->minor
->dev
;
186 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
189 int measure_ms
= 1000;
191 if (v3d
->ver
>= 40) {
192 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_SRC_0_3
,
193 V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT
,
195 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_CLR
, 1);
196 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_EN
, 1);
198 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_PCTRS0
,
199 V3D_PCTR_CYCLE_COUNT
);
200 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_CLR
, 1);
201 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_EN
,
202 V3D_V3_PCTR_0_EN_ENABLE
|
206 cycles
= V3D_CORE_READ(core
, V3D_PCTR_0_PCTR0
);
208 seq_printf(m
, "cycles: %d (%d.%d Mhz)\n",
210 cycles
/ (measure_ms
* 1000),
211 (cycles
/ (measure_ms
* 100)) % 10);
216 static const struct drm_info_list v3d_debugfs_list
[] = {
217 {"v3d_ident", v3d_v3d_debugfs_ident
, 0},
218 {"v3d_regs", v3d_v3d_debugfs_regs
, 0},
219 {"measure_clock", v3d_measure_clock
, 0},
220 {"bo_stats", v3d_debugfs_bo_stats
, 0},
224 v3d_debugfs_init(struct drm_minor
*minor
)
226 return drm_debugfs_create_files(v3d_debugfs_list
,
227 ARRAY_SIZE(v3d_debugfs_list
),
228 minor
->debugfs_root
, minor
);