1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2017 Etnaviv Project
4  * Copyright (C) 2017 Zodiac Inflight Innovations
5  */
6 
7 #include "common.xml.h"
8 #include "etnaviv_gpu.h"
9 #include "etnaviv_perfmon.h"
10 #include "state_hi.xml.h"
11 
12 struct etnaviv_pm_domain;
13 
14 struct etnaviv_pm_signal {
15 	char name[64];
16 	u32 data;
17 
18 	u32 (*sample)(struct etnaviv_gpu *gpu,
19 		      const struct etnaviv_pm_domain *domain,
20 		      const struct etnaviv_pm_signal *signal);
21 };
22 
23 struct etnaviv_pm_domain {
24 	char name[64];
25 
26 	/* profile register */
27 	u32 profile_read;
28 	u32 profile_config;
29 
30 	u8 nr_signals;
31 	const struct etnaviv_pm_signal *signal;
32 };
33 
34 struct etnaviv_pm_domain_meta {
35 	const struct etnaviv_pm_domain *domains;
36 	u32 nr_domains;
37 };
38 
39 static u32 perf_reg_read(struct etnaviv_gpu *gpu,
40 	const struct etnaviv_pm_domain *domain,
41 	const struct etnaviv_pm_signal *signal)
42 {
43 	gpu_write(gpu, domain->profile_config, signal->data);
44 
45 	return gpu_read(gpu, domain->profile_read);
46 }
47 
48 static u32 pipe_reg_read(struct etnaviv_gpu *gpu,
49 	const struct etnaviv_pm_domain *domain,
50 	const struct etnaviv_pm_signal *signal)
51 {
52 	u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
53 	u32 value = 0;
54 	unsigned i;
55 
56 	for (i = 0; i < gpu->identity.pixel_pipes; i++) {
57 		clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
58 		clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(i);
59 		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
60 		gpu_write(gpu, domain->profile_config, signal->data);
61 		value += gpu_read(gpu, domain->profile_read);
62 	}
63 
64 	/* switch back to pixel pipe 0 to prevent GPU hang */
65 	clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
66 	clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(0);
67 	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
68 
69 	return value;
70 }
71 
72 static u32 hi_total_cycle_read(struct etnaviv_gpu *gpu,
73 	const struct etnaviv_pm_domain *domain,
74 	const struct etnaviv_pm_signal *signal)
75 {
76 	u32 reg = VIVS_HI_PROFILE_TOTAL_CYCLES;
77 
78 	if (gpu->identity.model == chipModel_GC880 ||
79 		gpu->identity.model == chipModel_GC2000 ||
80 		gpu->identity.model == chipModel_GC2100)
81 		reg = VIVS_MC_PROFILE_CYCLE_COUNTER;
82 
83 	return gpu_read(gpu, reg);
84 }
85 
86 static u32 hi_total_idle_cycle_read(struct etnaviv_gpu *gpu,
87 	const struct etnaviv_pm_domain *domain,
88 	const struct etnaviv_pm_signal *signal)
89 {
90 	u32 reg = VIVS_HI_PROFILE_IDLE_CYCLES;
91 
92 	if (gpu->identity.model == chipModel_GC880 ||
93 		gpu->identity.model == chipModel_GC2000 ||
94 		gpu->identity.model == chipModel_GC2100)
95 		reg = VIVS_HI_PROFILE_TOTAL_CYCLES;
96 
97 	return gpu_read(gpu, reg);
98 }
99 
100 static const struct etnaviv_pm_domain doms_3d[] = {
101 	{
102 		.name = "HI",
103 		.profile_read = VIVS_MC_PROFILE_HI_READ,
104 		.profile_config = VIVS_MC_PROFILE_CONFIG2,
105 		.nr_signals = 5,
106 		.signal = (const struct etnaviv_pm_signal[]) {
107 			{
108 				"TOTAL_CYCLES",
109 				0,
110 				&hi_total_cycle_read
111 			},
112 			{
113 				"IDLE_CYCLES",
114 				0,
115 				&hi_total_idle_cycle_read
116 			},
117 			{
118 				"AXI_CYCLES_READ_REQUEST_STALLED",
119 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED,
120 				&perf_reg_read
121 			},
122 			{
123 				"AXI_CYCLES_WRITE_REQUEST_STALLED",
124 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED,
125 				&perf_reg_read
126 			},
127 			{
128 				"AXI_CYCLES_WRITE_DATA_STALLED",
129 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED,
130 				&perf_reg_read
131 			}
132 		}
133 	},
134 	{
135 		.name = "PE",
136 		.profile_read = VIVS_MC_PROFILE_PE_READ,
137 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
138 		.nr_signals = 4,
139 		.signal = (const struct etnaviv_pm_signal[]) {
140 			{
141 				"PIXEL_COUNT_KILLED_BY_COLOR_PIPE",
142 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE,
143 				&pipe_reg_read
144 			},
145 			{
146 				"PIXEL_COUNT_KILLED_BY_DEPTH_PIPE",
147 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE,
148 				&pipe_reg_read
149 			},
150 			{
151 				"PIXEL_COUNT_DRAWN_BY_COLOR_PIPE",
152 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE,
153 				&pipe_reg_read
154 			},
155 			{
156 				"PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE",
157 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE,
158 				&pipe_reg_read
159 			}
160 		}
161 	},
162 	{
163 		.name = "SH",
164 		.profile_read = VIVS_MC_PROFILE_SH_READ,
165 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
166 		.nr_signals = 9,
167 		.signal = (const struct etnaviv_pm_signal[]) {
168 			{
169 				"SHADER_CYCLES",
170 				VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES,
171 				&perf_reg_read
172 			},
173 			{
174 				"PS_INST_COUNTER",
175 				VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER,
176 				&perf_reg_read
177 			},
178 			{
179 				"RENDERED_PIXEL_COUNTER",
180 				VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER,
181 				&perf_reg_read
182 			},
183 			{
184 				"VS_INST_COUNTER",
185 				VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER,
186 				&pipe_reg_read
187 			},
188 			{
189 				"RENDERED_VERTICE_COUNTER",
190 				VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER,
191 				&pipe_reg_read
192 			},
193 			{
194 				"VTX_BRANCH_INST_COUNTER",
195 				VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER,
196 				&pipe_reg_read
197 			},
198 			{
199 				"VTX_TEXLD_INST_COUNTER",
200 				VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER,
201 				&pipe_reg_read
202 			},
203 			{
204 				"PXL_BRANCH_INST_COUNTER",
205 				VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER,
206 				&pipe_reg_read
207 			},
208 			{
209 				"PXL_TEXLD_INST_COUNTER",
210 				VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER,
211 				&pipe_reg_read
212 			}
213 		}
214 	},
215 	{
216 		.name = "PA",
217 		.profile_read = VIVS_MC_PROFILE_PA_READ,
218 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
219 		.nr_signals = 6,
220 		.signal = (const struct etnaviv_pm_signal[]) {
221 			{
222 				"INPUT_VTX_COUNTER",
223 				VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER,
224 				&perf_reg_read
225 			},
226 			{
227 				"INPUT_PRIM_COUNTER",
228 				VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER,
229 				&perf_reg_read
230 			},
231 			{
232 				"OUTPUT_PRIM_COUNTER",
233 				VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER,
234 				&perf_reg_read
235 			},
236 			{
237 				"DEPTH_CLIPPED_COUNTER",
238 				VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER,
239 				&pipe_reg_read
240 			},
241 			{
242 				"TRIVIAL_REJECTED_COUNTER",
243 				VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER,
244 				&pipe_reg_read
245 			},
246 			{
247 				"CULLED_COUNTER",
248 				VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER,
249 				&pipe_reg_read
250 			}
251 		}
252 	},
253 	{
254 		.name = "SE",
255 		.profile_read = VIVS_MC_PROFILE_SE_READ,
256 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
257 		.nr_signals = 2,
258 		.signal = (const struct etnaviv_pm_signal[]) {
259 			{
260 				"CULLED_TRIANGLE_COUNT",
261 				VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT,
262 				&perf_reg_read
263 			},
264 			{
265 				"CULLED_LINES_COUNT",
266 				VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT,
267 				&perf_reg_read
268 			}
269 		}
270 	},
271 	{
272 		.name = "RA",
273 		.profile_read = VIVS_MC_PROFILE_RA_READ,
274 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
275 		.nr_signals = 7,
276 		.signal = (const struct etnaviv_pm_signal[]) {
277 			{
278 				"VALID_PIXEL_COUNT",
279 				VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT,
280 				&perf_reg_read
281 			},
282 			{
283 				"TOTAL_QUAD_COUNT",
284 				VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT,
285 				&perf_reg_read
286 			},
287 			{
288 				"VALID_QUAD_COUNT_AFTER_EARLY_Z",
289 				VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z,
290 				&perf_reg_read
291 			},
292 			{
293 				"TOTAL_PRIMITIVE_COUNT",
294 				VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT,
295 				&perf_reg_read
296 			},
297 			{
298 				"PIPE_CACHE_MISS_COUNTER",
299 				VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER,
300 				&perf_reg_read
301 			},
302 			{
303 				"PREFETCH_CACHE_MISS_COUNTER",
304 				VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER,
305 				&perf_reg_read
306 			},
307 			{
308 				"CULLED_QUAD_COUNT",
309 				VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT,
310 				&perf_reg_read
311 			}
312 		}
313 	},
314 	{
315 		.name = "TX",
316 		.profile_read = VIVS_MC_PROFILE_TX_READ,
317 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
318 		.nr_signals = 9,
319 		.signal = (const struct etnaviv_pm_signal[]) {
320 			{
321 				"TOTAL_BILINEAR_REQUESTS",
322 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS,
323 				&perf_reg_read
324 			},
325 			{
326 				"TOTAL_TRILINEAR_REQUESTS",
327 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS,
328 				&perf_reg_read
329 			},
330 			{
331 				"TOTAL_DISCARDED_TEXTURE_REQUESTS",
332 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS,
333 				&perf_reg_read
334 			},
335 			{
336 				"TOTAL_TEXTURE_REQUESTS",
337 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS,
338 				&perf_reg_read
339 			},
340 			{
341 				"MEM_READ_COUNT",
342 				VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT,
343 				&perf_reg_read
344 			},
345 			{
346 				"MEM_READ_IN_8B_COUNT",
347 				VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT,
348 				&perf_reg_read
349 			},
350 			{
351 				"CACHE_MISS_COUNT",
352 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT,
353 				&perf_reg_read
354 			},
355 			{
356 				"CACHE_HIT_TEXEL_COUNT",
357 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT,
358 				&perf_reg_read
359 			},
360 			{
361 				"CACHE_MISS_TEXEL_COUNT",
362 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT,
363 				&perf_reg_read
364 			}
365 		}
366 	},
367 	{
368 		.name = "MC",
369 		.profile_read = VIVS_MC_PROFILE_MC_READ,
370 		.profile_config = VIVS_MC_PROFILE_CONFIG2,
371 		.nr_signals = 3,
372 		.signal = (const struct etnaviv_pm_signal[]) {
373 			{
374 				"TOTAL_READ_REQ_8B_FROM_PIPELINE",
375 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE,
376 				&perf_reg_read
377 			},
378 			{
379 				"TOTAL_READ_REQ_8B_FROM_IP",
380 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP,
381 				&perf_reg_read
382 			},
383 			{
384 				"TOTAL_WRITE_REQ_8B_FROM_PIPELINE",
385 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE,
386 				&perf_reg_read
387 			}
388 		}
389 	}
390 };
391 
392 static const struct etnaviv_pm_domain doms_2d[] = {
393 	{
394 		.name = "PE",
395 		.profile_read = VIVS_MC_PROFILE_PE_READ,
396 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
397 		.nr_signals = 1,
398 		.signal = (const struct etnaviv_pm_signal[]) {
399 			{
400 				"PIXELS_RENDERED_2D",
401 				VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D,
402 				&pipe_reg_read
403 			}
404 		}
405 	}
406 };
407 
408 static const struct etnaviv_pm_domain doms_vg[] = {
409 };
410 
411 static const struct etnaviv_pm_domain_meta doms_meta[] = {
412 	{
413 		.nr_domains = ARRAY_SIZE(doms_3d),
414 		.domains = &doms_3d[0]
415 	},
416 	{
417 		.nr_domains = ARRAY_SIZE(doms_2d),
418 		.domains = &doms_2d[0]
419 	},
420 	{
421 		.nr_domains = ARRAY_SIZE(doms_vg),
422 		.domains = &doms_vg[0]
423 	}
424 };
425 
426 int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
427 	struct drm_etnaviv_pm_domain *domain)
428 {
429 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe];
430 	const struct etnaviv_pm_domain *dom;
431 
432 	if (domain->iter >= meta->nr_domains)
433 		return -EINVAL;
434 
435 	dom = meta->domains + domain->iter;
436 
437 	domain->id = domain->iter;
438 	domain->nr_signals = dom->nr_signals;
439 	strncpy(domain->name, dom->name, sizeof(domain->name));
440 
441 	domain->iter++;
442 	if (domain->iter == meta->nr_domains)
443 		domain->iter = 0xff;
444 
445 	return 0;
446 }
447 
448 int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
449 	struct drm_etnaviv_pm_signal *signal)
450 {
451 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe];
452 	const struct etnaviv_pm_domain *dom;
453 	const struct etnaviv_pm_signal *sig;
454 
455 	if (signal->domain >= meta->nr_domains)
456 		return -EINVAL;
457 
458 	dom = meta->domains + signal->domain;
459 
460 	if (signal->iter >= dom->nr_signals)
461 		return -EINVAL;
462 
463 	sig = &dom->signal[signal->iter];
464 
465 	signal->id = signal->iter;
466 	strncpy(signal->name, sig->name, sizeof(signal->name));
467 
468 	signal->iter++;
469 	if (signal->iter == dom->nr_signals)
470 		signal->iter = 0xffff;
471 
472 	return 0;
473 }
474 
475 int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r,
476 	u32 exec_state)
477 {
478 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state];
479 	const struct etnaviv_pm_domain *dom;
480 
481 	if (r->domain >= meta->nr_domains)
482 		return -EINVAL;
483 
484 	dom = meta->domains + r->domain;
485 
486 	if (r->signal >= dom->nr_signals)
487 		return -EINVAL;
488 
489 	return 0;
490 }
491 
492 void etnaviv_perfmon_process(struct etnaviv_gpu *gpu,
493 	const struct etnaviv_perfmon_request *pmr, u32 exec_state)
494 {
495 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state];
496 	const struct etnaviv_pm_domain *dom;
497 	const struct etnaviv_pm_signal *sig;
498 	u32 *bo = pmr->bo_vma;
499 	u32 val;
500 
501 	dom = meta->domains + pmr->domain;
502 	sig = &dom->signal[pmr->signal];
503 	val = sig->sample(gpu, dom, sig);
504 
505 	*(bo + pmr->offset) = val;
506 }
507