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>
10 #include <drm/drm_debugfs.h>
15 #define REGDEF(reg) { reg, #reg }
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
),
32 REGDEF(V3D_MMU_VIO_ADDR
),
33 REGDEF(V3D_MMU_VIO_ID
),
34 REGDEF(V3D_MMU_DEBUG_INFO
),
37 static const struct v3d_reg_def v3d_gca_reg_defs
[] = {
38 REGDEF(V3D_GCA_SAFE_SHUTDOWN
),
39 REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK
),
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
),
59 REGDEF(V3D_GMP_STATUS
),
61 REGDEF(V3D_GMP_VIO_ADDR
),
63 REGDEF(V3D_ERR_FDBGO
),
64 REGDEF(V3D_ERR_FDBGB
),
65 REGDEF(V3D_ERR_FDBGS
),
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
),
80 static int v3d_v3d_debugfs_regs(struct seq_file
*m
, void *unused
)
82 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
83 struct drm_device
*dev
= node
->minor
->dev
;
84 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
87 for (i
= 0; i
< ARRAY_SIZE(v3d_hub_reg_defs
); i
++) {
88 seq_printf(m
, "%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
));
94 for (i
= 0; i
< ARRAY_SIZE(v3d_gca_reg_defs
); i
++) {
95 seq_printf(m
, "%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
));
102 for (core
= 0; core
< v3d
->cores
; core
++) {
103 for (i
= 0; i
< ARRAY_SIZE(v3d_core_reg_defs
); i
++) {
104 seq_printf(m
, "core %d %s (0x%04x): 0x%08x\n",
106 v3d_core_reg_defs
[i
].name
,
107 v3d_core_reg_defs
[i
].reg
,
109 v3d_core_reg_defs
[i
].reg
));
112 if (v3d_has_csd(v3d
)) {
113 for (i
= 0; i
< ARRAY_SIZE(v3d_csd_reg_defs
); i
++) {
114 seq_printf(m
, "core %d %s (0x%04x): 0x%08x\n",
116 v3d_csd_reg_defs
[i
].name
,
117 v3d_csd_reg_defs
[i
].reg
,
119 v3d_csd_reg_defs
[i
].reg
));
127 static int v3d_v3d_debugfs_ident(struct seq_file
*m
, void *unused
)
129 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
130 struct drm_device
*dev
= node
->minor
->dev
;
131 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
132 u32 ident0
, ident1
, ident2
, ident3
, cores
;
135 ret
= pm_runtime_get_sync(v3d
->drm
.dev
);
139 ident0
= V3D_READ(V3D_HUB_IDENT0
);
140 ident1
= V3D_READ(V3D_HUB_IDENT1
);
141 ident2
= V3D_READ(V3D_HUB_IDENT2
);
142 ident3
= V3D_READ(V3D_HUB_IDENT3
);
143 cores
= V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_NCORES
);
145 seq_printf(m
, "Revision: %d.%d.%d.%d\n",
146 V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_TVER
),
147 V3D_GET_FIELD(ident1
, V3D_HUB_IDENT1_REV
),
148 V3D_GET_FIELD(ident3
, V3D_HUB_IDENT3_IPREV
),
149 V3D_GET_FIELD(ident3
, V3D_HUB_IDENT3_IPIDX
));
150 seq_printf(m
, "MMU: %s\n",
151 (ident2
& V3D_HUB_IDENT2_WITH_MMU
) ? "yes" : "no");
152 seq_printf(m
, "TFU: %s\n",
153 (ident1
& V3D_HUB_IDENT1_WITH_TFU
) ? "yes" : "no");
154 seq_printf(m
, "TSY: %s\n",
155 (ident1
& V3D_HUB_IDENT1_WITH_TSY
) ? "yes" : "no");
156 seq_printf(m
, "MSO: %s\n",
157 (ident1
& V3D_HUB_IDENT1_WITH_MSO
) ? "yes" : "no");
158 seq_printf(m
, "L3C: %s (%dkb)\n",
159 (ident1
& V3D_HUB_IDENT1_WITH_L3C
) ? "yes" : "no",
160 V3D_GET_FIELD(ident2
, V3D_HUB_IDENT2_L3C_NKB
));
162 for (core
= 0; core
< cores
; core
++) {
164 u32 nslc
, ntmu
, qups
;
166 ident0
= V3D_CORE_READ(core
, V3D_CTL_IDENT0
);
167 ident1
= V3D_CORE_READ(core
, V3D_CTL_IDENT1
);
168 ident2
= V3D_CORE_READ(core
, V3D_CTL_IDENT2
);
169 misccfg
= V3D_CORE_READ(core
, V3D_CTL_MISCCFG
);
171 nslc
= V3D_GET_FIELD(ident1
, V3D_IDENT1_NSLC
);
172 ntmu
= V3D_GET_FIELD(ident1
, V3D_IDENT1_NTMU
);
173 qups
= V3D_GET_FIELD(ident1
, V3D_IDENT1_QUPS
);
175 seq_printf(m
, "Core %d:\n", core
);
176 seq_printf(m
, " Revision: %d.%d\n",
177 V3D_GET_FIELD(ident0
, V3D_IDENT0_VER
),
178 V3D_GET_FIELD(ident1
, V3D_IDENT1_REV
));
179 seq_printf(m
, " Slices: %d\n", nslc
);
180 seq_printf(m
, " TMUs: %d\n", nslc
* ntmu
);
181 seq_printf(m
, " QPUs: %d\n", nslc
* qups
);
182 seq_printf(m
, " Semaphores: %d\n",
183 V3D_GET_FIELD(ident1
, V3D_IDENT1_NSEM
));
184 seq_printf(m
, " BCG int: %d\n",
185 (ident2
& V3D_IDENT2_BCG_INT
) != 0);
186 seq_printf(m
, " Override TMU: %d\n",
187 (misccfg
& V3D_MISCCFG_OVRTMUOUT
) != 0);
190 pm_runtime_mark_last_busy(v3d
->drm
.dev
);
191 pm_runtime_put_autosuspend(v3d
->drm
.dev
);
196 static int v3d_debugfs_bo_stats(struct seq_file
*m
, void *unused
)
198 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
199 struct drm_device
*dev
= node
->minor
->dev
;
200 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
202 mutex_lock(&v3d
->bo_lock
);
203 seq_printf(m
, "allocated bos: %d\n",
204 v3d
->bo_stats
.num_allocated
);
205 seq_printf(m
, "allocated bo size (kb): %ld\n",
206 (long)v3d
->bo_stats
.pages_allocated
<< (PAGE_SHIFT
- 10));
207 mutex_unlock(&v3d
->bo_lock
);
212 static int v3d_measure_clock(struct seq_file
*m
, void *unused
)
214 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
215 struct drm_device
*dev
= node
->minor
->dev
;
216 struct v3d_dev
*v3d
= to_v3d_dev(dev
);
219 int measure_ms
= 1000;
222 ret
= pm_runtime_get_sync(v3d
->drm
.dev
);
226 if (v3d
->ver
>= 40) {
227 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_SRC_0_3
,
228 V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT
,
230 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_CLR
, 1);
231 V3D_CORE_WRITE(core
, V3D_V4_PCTR_0_EN
, 1);
233 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_PCTRS0
,
234 V3D_PCTR_CYCLE_COUNT
);
235 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_CLR
, 1);
236 V3D_CORE_WRITE(core
, V3D_V3_PCTR_0_EN
,
237 V3D_V3_PCTR_0_EN_ENABLE
|
241 cycles
= V3D_CORE_READ(core
, V3D_PCTR_0_PCTR0
);
243 seq_printf(m
, "cycles: %d (%d.%d Mhz)\n",
245 cycles
/ (measure_ms
* 1000),
246 (cycles
/ (measure_ms
* 100)) % 10);
248 pm_runtime_mark_last_busy(v3d
->drm
.dev
);
249 pm_runtime_put_autosuspend(v3d
->drm
.dev
);
254 static const struct drm_info_list v3d_debugfs_list
[] = {
255 {"v3d_ident", v3d_v3d_debugfs_ident
, 0},
256 {"v3d_regs", v3d_v3d_debugfs_regs
, 0},
257 {"measure_clock", v3d_measure_clock
, 0},
258 {"bo_stats", v3d_debugfs_bo_stats
, 0},
262 v3d_debugfs_init(struct drm_minor
*minor
)
264 drm_debugfs_create_files(v3d_debugfs_list
,
265 ARRAY_SIZE(v3d_debugfs_list
),
266 minor
->debugfs_root
, minor
);