]>
Commit | Line | Data |
---|---|---|
57692c94 EA |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* Copyright (C) 2014-2018 Broadcom */ | |
3 | ||
4 | #include <linux/circ_buf.h> | |
5 | #include <linux/ctype.h> | |
6 | #include <linux/debugfs.h> | |
57692c94 | 7 | #include <linux/seq_file.h> |
b8c75bd9 | 8 | #include <linux/string_helpers.h> |
220989e7 SR |
9 | |
10 | #include <drm/drm_debugfs.h> | |
57692c94 EA |
11 | |
12 | #include "v3d_drv.h" | |
13 | #include "v3d_regs.h" | |
14 | ||
0ad5bc1c | 15 | #define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg } |
57692c94 | 16 | struct v3d_reg_def { |
0ad5bc1c ITQ |
17 | u32 min_ver; |
18 | u32 max_ver; | |
57692c94 EA |
19 | u32 reg; |
20 | const char *name; | |
21 | }; | |
22 | ||
23 | static const struct v3d_reg_def v3d_hub_reg_defs[] = { | |
0ad5bc1c ITQ |
24 | REGDEF(33, 42, V3D_HUB_AXICFG), |
25 | REGDEF(33, 71, V3D_HUB_UIFCFG), | |
26 | REGDEF(33, 71, V3D_HUB_IDENT0), | |
27 | REGDEF(33, 71, V3D_HUB_IDENT1), | |
28 | REGDEF(33, 71, V3D_HUB_IDENT2), | |
29 | REGDEF(33, 71, V3D_HUB_IDENT3), | |
30 | REGDEF(33, 71, V3D_HUB_INT_STS), | |
31 | REGDEF(33, 71, V3D_HUB_INT_MSK_STS), | |
32 | ||
33 | REGDEF(33, 71, V3D_MMU_CTL), | |
34 | REGDEF(33, 71, V3D_MMU_VIO_ADDR), | |
35 | REGDEF(33, 71, V3D_MMU_VIO_ID), | |
36 | REGDEF(33, 71, V3D_MMU_DEBUG_INFO), | |
37 | ||
38 | REGDEF(71, 71, V3D_GMP_STATUS(71)), | |
39 | REGDEF(71, 71, V3D_GMP_CFG(71)), | |
40 | REGDEF(71, 71, V3D_GMP_VIO_ADDR(71)), | |
57692c94 EA |
41 | }; |
42 | ||
43 | static const struct v3d_reg_def v3d_gca_reg_defs[] = { | |
0ad5bc1c ITQ |
44 | REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN), |
45 | REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK), | |
57692c94 EA |
46 | }; |
47 | ||
48 | static const struct v3d_reg_def v3d_core_reg_defs[] = { | |
0ad5bc1c ITQ |
49 | REGDEF(33, 71, V3D_CTL_IDENT0), |
50 | REGDEF(33, 71, V3D_CTL_IDENT1), | |
51 | REGDEF(33, 71, V3D_CTL_IDENT2), | |
52 | REGDEF(33, 71, V3D_CTL_MISCCFG), | |
53 | REGDEF(33, 71, V3D_CTL_INT_STS), | |
54 | REGDEF(33, 71, V3D_CTL_INT_MSK_STS), | |
55 | REGDEF(33, 71, V3D_CLE_CT0CS), | |
56 | REGDEF(33, 71, V3D_CLE_CT0CA), | |
57 | REGDEF(33, 71, V3D_CLE_CT0EA), | |
58 | REGDEF(33, 71, V3D_CLE_CT1CS), | |
59 | REGDEF(33, 71, V3D_CLE_CT1CA), | |
60 | REGDEF(33, 71, V3D_CLE_CT1EA), | |
61 | ||
62 | REGDEF(33, 71, V3D_PTB_BPCA), | |
63 | REGDEF(33, 71, V3D_PTB_BPCS), | |
64 | ||
89fe4601 MC |
65 | REGDEF(33, 42, V3D_GMP_STATUS(33)), |
66 | REGDEF(33, 42, V3D_GMP_CFG(33)), | |
67 | REGDEF(33, 42, V3D_GMP_VIO_ADDR(33)), | |
0ad5bc1c ITQ |
68 | |
69 | REGDEF(33, 71, V3D_ERR_FDBGO), | |
70 | REGDEF(33, 71, V3D_ERR_FDBGB), | |
71 | REGDEF(33, 71, V3D_ERR_FDBGS), | |
72 | REGDEF(33, 71, V3D_ERR_STAT), | |
57692c94 EA |
73 | }; |
74 | ||
d223f98f | 75 | static const struct v3d_reg_def v3d_csd_reg_defs[] = { |
0ad5bc1c | 76 | REGDEF(41, 71, V3D_CSD_STATUS), |
89fe4601 MC |
77 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG0(41)), |
78 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG1(41)), | |
79 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG2(41)), | |
80 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG3(41)), | |
81 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG4(41)), | |
82 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG5(41)), | |
83 | REGDEF(41, 42, V3D_CSD_CURRENT_CFG6(41)), | |
0ad5bc1c ITQ |
84 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG0(71)), |
85 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG1(71)), | |
86 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG2(71)), | |
87 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG3(71)), | |
88 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG4(71)), | |
89 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG5(71)), | |
90 | REGDEF(71, 71, V3D_CSD_CURRENT_CFG6(71)), | |
91 | REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7), | |
d223f98f EA |
92 | }; |
93 | ||
57692c94 EA |
94 | static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) |
95 | { | |
c0dda238 MC |
96 | struct drm_debugfs_entry *entry = m->private; |
97 | struct drm_device *dev = entry->dev; | |
57692c94 EA |
98 | struct v3d_dev *v3d = to_v3d_dev(dev); |
99 | int i, core; | |
100 | ||
101 | for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) { | |
0ad5bc1c ITQ |
102 | const struct v3d_reg_def *def = &v3d_hub_reg_defs[i]; |
103 | ||
104 | if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { | |
105 | seq_printf(m, "%s (0x%04x): 0x%08x\n", | |
106 | def->name, def->reg, V3D_READ(def->reg)); | |
107 | } | |
57692c94 EA |
108 | } |
109 | ||
0ad5bc1c ITQ |
110 | for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { |
111 | const struct v3d_reg_def *def = &v3d_gca_reg_defs[i]; | |
112 | ||
113 | if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { | |
2f20fa8d | 114 | seq_printf(m, "%s (0x%04x): 0x%08x\n", |
0ad5bc1c | 115 | def->name, def->reg, V3D_GCA_READ(def->reg)); |
2f20fa8d | 116 | } |
57692c94 EA |
117 | } |
118 | ||
119 | for (core = 0; core < v3d->cores; core++) { | |
120 | for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) { | |
0ad5bc1c ITQ |
121 | const struct v3d_reg_def *def = &v3d_core_reg_defs[i]; |
122 | ||
123 | if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { | |
124 | seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", | |
125 | core, def->name, def->reg, | |
126 | V3D_CORE_READ(core, def->reg)); | |
127 | } | |
57692c94 | 128 | } |
d223f98f | 129 | |
0ad5bc1c ITQ |
130 | for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { |
131 | const struct v3d_reg_def *def = &v3d_csd_reg_defs[i]; | |
132 | ||
133 | if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) { | |
d223f98f | 134 | seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", |
0ad5bc1c ITQ |
135 | core, def->name, def->reg, |
136 | V3D_CORE_READ(core, def->reg)); | |
d223f98f EA |
137 | } |
138 | } | |
57692c94 EA |
139 | } |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused) | |
145 | { | |
c0dda238 MC |
146 | struct drm_debugfs_entry *entry = m->private; |
147 | struct drm_device *dev = entry->dev; | |
57692c94 EA |
148 | struct v3d_dev *v3d = to_v3d_dev(dev); |
149 | u32 ident0, ident1, ident2, ident3, cores; | |
90a64adb | 150 | int core; |
57692c94 EA |
151 | |
152 | ident0 = V3D_READ(V3D_HUB_IDENT0); | |
153 | ident1 = V3D_READ(V3D_HUB_IDENT1); | |
154 | ident2 = V3D_READ(V3D_HUB_IDENT2); | |
155 | ident3 = V3D_READ(V3D_HUB_IDENT3); | |
156 | cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES); | |
157 | ||
158 | seq_printf(m, "Revision: %d.%d.%d.%d\n", | |
159 | V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER), | |
160 | V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV), | |
161 | V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV), | |
162 | V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPIDX)); | |
163 | seq_printf(m, "MMU: %s\n", | |
b8c75bd9 | 164 | str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU)); |
57692c94 | 165 | seq_printf(m, "TFU: %s\n", |
b8c75bd9 | 166 | str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU)); |
0ad5bc1c ITQ |
167 | if (v3d->ver <= 42) { |
168 | seq_printf(m, "TSY: %s\n", | |
169 | str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY)); | |
170 | } | |
57692c94 | 171 | seq_printf(m, "MSO: %s\n", |
b8c75bd9 | 172 | str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO)); |
57692c94 | 173 | seq_printf(m, "L3C: %s (%dkb)\n", |
b8c75bd9 | 174 | str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_L3C), |
57692c94 EA |
175 | V3D_GET_FIELD(ident2, V3D_HUB_IDENT2_L3C_NKB)); |
176 | ||
177 | for (core = 0; core < cores; core++) { | |
178 | u32 misccfg; | |
179 | u32 nslc, ntmu, qups; | |
180 | ||
181 | ident0 = V3D_CORE_READ(core, V3D_CTL_IDENT0); | |
182 | ident1 = V3D_CORE_READ(core, V3D_CTL_IDENT1); | |
183 | ident2 = V3D_CORE_READ(core, V3D_CTL_IDENT2); | |
184 | misccfg = V3D_CORE_READ(core, V3D_CTL_MISCCFG); | |
185 | ||
186 | nslc = V3D_GET_FIELD(ident1, V3D_IDENT1_NSLC); | |
187 | ntmu = V3D_GET_FIELD(ident1, V3D_IDENT1_NTMU); | |
188 | qups = V3D_GET_FIELD(ident1, V3D_IDENT1_QUPS); | |
189 | ||
190 | seq_printf(m, "Core %d:\n", core); | |
191 | seq_printf(m, " Revision: %d.%d\n", | |
192 | V3D_GET_FIELD(ident0, V3D_IDENT0_VER), | |
193 | V3D_GET_FIELD(ident1, V3D_IDENT1_REV)); | |
194 | seq_printf(m, " Slices: %d\n", nslc); | |
195 | seq_printf(m, " TMUs: %d\n", nslc * ntmu); | |
196 | seq_printf(m, " QPUs: %d\n", nslc * qups); | |
197 | seq_printf(m, " Semaphores: %d\n", | |
198 | V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM)); | |
0ad5bc1c ITQ |
199 | if (v3d->ver <= 42) { |
200 | seq_printf(m, " BCG int: %d\n", | |
201 | (ident2 & V3D_IDENT2_BCG_INT) != 0); | |
202 | } | |
203 | if (v3d->ver < 40) { | |
204 | seq_printf(m, " Override TMU: %d\n", | |
205 | (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); | |
206 | } | |
57692c94 EA |
207 | } |
208 | ||
57692c94 EA |
209 | return 0; |
210 | } | |
211 | ||
212 | static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused) | |
213 | { | |
c0dda238 MC |
214 | struct drm_debugfs_entry *entry = m->private; |
215 | struct drm_device *dev = entry->dev; | |
57692c94 EA |
216 | struct v3d_dev *v3d = to_v3d_dev(dev); |
217 | ||
218 | mutex_lock(&v3d->bo_lock); | |
219 | seq_printf(m, "allocated bos: %d\n", | |
220 | v3d->bo_stats.num_allocated); | |
221 | seq_printf(m, "allocated bo size (kb): %ld\n", | |
222 | (long)v3d->bo_stats.pages_allocated << (PAGE_SHIFT - 10)); | |
223 | mutex_unlock(&v3d->bo_lock); | |
224 | ||
225 | return 0; | |
226 | } | |
227 | ||
6915c9a5 EA |
228 | static int v3d_measure_clock(struct seq_file *m, void *unused) |
229 | { | |
c0dda238 MC |
230 | struct drm_debugfs_entry *entry = m->private; |
231 | struct drm_device *dev = entry->dev; | |
6915c9a5 EA |
232 | struct v3d_dev *v3d = to_v3d_dev(dev); |
233 | uint32_t cycles; | |
234 | int core = 0; | |
235 | int measure_ms = 1000; | |
236 | ||
237 | if (v3d->ver >= 40) { | |
0ad5bc1c | 238 | int cycle_count_reg = V3D_PCTR_CYCLE_COUNT(v3d->ver); |
6915c9a5 | 239 | V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, |
0ad5bc1c | 240 | V3D_SET_FIELD(cycle_count_reg, |
6915c9a5 EA |
241 | V3D_PCTR_S0)); |
242 | V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1); | |
243 | V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1); | |
244 | } else { | |
245 | V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0, | |
0ad5bc1c | 246 | V3D_PCTR_CYCLE_COUNT(v3d->ver)); |
6915c9a5 EA |
247 | V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1); |
248 | V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN, | |
249 | V3D_V3_PCTR_0_EN_ENABLE | | |
250 | 1); | |
251 | } | |
252 | msleep(measure_ms); | |
253 | cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0); | |
254 | ||
255 | seq_printf(m, "cycles: %d (%d.%d Mhz)\n", | |
256 | cycles, | |
257 | cycles / (measure_ms * 1000), | |
258 | (cycles / (measure_ms * 100)) % 10); | |
259 | ||
260 | return 0; | |
261 | } | |
262 | ||
502756e2 MC |
263 | static int v3d_debugfs_mm(struct seq_file *m, void *unused) |
264 | { | |
265 | struct drm_printer p = drm_seq_file_printer(m); | |
266 | struct drm_debugfs_entry *entry = m->private; | |
267 | struct drm_device *dev = entry->dev; | |
268 | struct v3d_dev *v3d = to_v3d_dev(dev); | |
269 | ||
270 | spin_lock(&v3d->mm_lock); | |
271 | drm_mm_print(&v3d->mm, &p); | |
272 | spin_unlock(&v3d->mm_lock); | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
c0dda238 | 277 | static const struct drm_debugfs_info v3d_debugfs_list[] = { |
57692c94 EA |
278 | {"v3d_ident", v3d_v3d_debugfs_ident, 0}, |
279 | {"v3d_regs", v3d_v3d_debugfs_regs, 0}, | |
6915c9a5 | 280 | {"measure_clock", v3d_measure_clock, 0}, |
57692c94 | 281 | {"bo_stats", v3d_debugfs_bo_stats, 0}, |
502756e2 | 282 | {"v3d_mm", v3d_debugfs_mm, 0}, |
57692c94 EA |
283 | }; |
284 | ||
7ce84471 | 285 | void |
57692c94 EA |
286 | v3d_debugfs_init(struct drm_minor *minor) |
287 | { | |
c0dda238 | 288 | drm_debugfs_add_files(minor->dev, v3d_debugfs_list, ARRAY_SIZE(v3d_debugfs_list)); |
57692c94 | 289 | } |