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