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