1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) STMicroelectronics SA 2015
4  * Authors: Yannick Fertre <yannick.fertre@st.com>
5  *          Hugues Fruchet <hugues.fruchet@st.com>
6  */
7 
8 #include <linux/debugfs.h>
9 
10 #include "hva.h"
11 #include "hva-hw.h"
12 
format_ctx(struct seq_file * s,struct hva_ctx * ctx)13 static void format_ctx(struct seq_file *s, struct hva_ctx *ctx)
14 {
15 	struct hva_streaminfo *stream = &ctx->streaminfo;
16 	struct hva_frameinfo *frame = &ctx->frameinfo;
17 	struct hva_controls *ctrls = &ctx->ctrls;
18 	struct hva_ctx_dbg *dbg = &ctx->dbg;
19 	u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp;
20 
21 	seq_printf(s, "|-%s\n  |\n", ctx->name);
22 
23 	seq_printf(s, "  |-[%sframe info]\n",
24 		   ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default ");
25 	seq_printf(s, "  | |- pixel format=%4.4s\n"
26 		      "  | |- wxh=%dx%d\n"
27 		      "  | |- wxh (w/ encoder alignment constraint)=%dx%d\n"
28 		      "  |\n",
29 		      (char *)&frame->pixelformat,
30 		      frame->width, frame->height,
31 		      frame->aligned_width, frame->aligned_height);
32 
33 	seq_printf(s, "  |-[%sstream info]\n",
34 		   ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default ");
35 	seq_printf(s, "  | |- stream format=%4.4s\n"
36 		      "  | |- wxh=%dx%d\n"
37 		      "  | |- %s\n"
38 		      "  | |- %s\n"
39 		      "  |\n",
40 		      (char *)&stream->streamformat,
41 		      stream->width, stream->height,
42 		      stream->profile, stream->level);
43 
44 	bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
45 	aspect = V4L2_CID_MPEG_VIDEO_ASPECT;
46 	seq_puts(s, "  |-[parameters]\n");
47 	seq_printf(s, "  | |- %s\n"
48 		      "  | |- bitrate=%d bps\n"
49 		      "  | |- GOP size=%d\n"
50 		      "  | |- video aspect=%s\n"
51 		      "  | |- framerate=%d/%d\n",
52 		      v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode],
53 		      ctrls->bitrate,
54 		      ctrls->gop_size,
55 		      v4l2_ctrl_get_menu(aspect)[ctrls->aspect],
56 		      ctrls->time_per_frame.denominator,
57 		      ctrls->time_per_frame.numerator);
58 
59 	entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE;
60 	vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC;
61 	sei_fp =  V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE;
62 	if (stream->streamformat == V4L2_PIX_FMT_H264) {
63 		seq_printf(s, "  | |- %s entropy mode\n"
64 			      "  | |- CPB size=%d kB\n"
65 			      "  | |- DCT8x8 enable=%s\n"
66 			      "  | |- qpmin=%d\n"
67 			      "  | |- qpmax=%d\n"
68 			      "  | |- PAR enable=%s\n"
69 			      "  | |- PAR id=%s\n"
70 			      "  | |- SEI frame packing enable=%s\n"
71 			      "  | |- SEI frame packing type=%s\n",
72 			      v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode],
73 			      ctrls->cpb_size,
74 			      ctrls->dct8x8 ? "true" : "false",
75 			      ctrls->qpmin,
76 			      ctrls->qpmax,
77 			      ctrls->vui_sar ? "true" : "false",
78 			      v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc],
79 			      ctrls->sei_fp ? "true" : "false",
80 			      v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]);
81 	}
82 
83 	if (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) {
84 		seq_puts(s, "  |\n  |-[errors]\n");
85 		seq_printf(s, "  | |- system=%d\n"
86 			      "  | |- encoding=%d\n"
87 			      "  | |- frame=%d\n",
88 			      ctx->sys_errors,
89 			      ctx->encode_errors,
90 			      ctx->frame_errors);
91 	}
92 
93 	seq_puts(s, "  |\n  |-[performances]\n");
94 	seq_printf(s, "  | |- frames encoded=%d\n"
95 		      "  | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n"
96 		      "  | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n"
97 		      "  | |- avg fps (0.1Hz)=%d\n"
98 		      "  | |- max reachable fps (0.1Hz)=%d\n"
99 		      "  | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n"
100 		      "  | |- last bitrate (kbps)=%d\n",
101 		      dbg->cnt_duration,
102 		      dbg->avg_duration,
103 		      dbg->min_duration,
104 		      dbg->max_duration,
105 		      dbg->avg_period,
106 		      dbg->min_period,
107 		      dbg->max_period,
108 		      dbg->avg_fps,
109 		      dbg->max_fps,
110 		      dbg->avg_bitrate,
111 		      dbg->min_bitrate,
112 		      dbg->max_bitrate,
113 		      dbg->last_bitrate);
114 }
115 
116 /*
117  * performance debug info
118  */
hva_dbg_perf_begin(struct hva_ctx * ctx)119 void hva_dbg_perf_begin(struct hva_ctx *ctx)
120 {
121 	u64 div;
122 	u32 period;
123 	u32 bitrate;
124 	struct hva_ctx_dbg *dbg = &ctx->dbg;
125 	ktime_t prev = dbg->begin;
126 
127 	dbg->begin = ktime_get();
128 
129 	if (dbg->is_valid_period) {
130 		/* encoding period */
131 		div = (u64)ktime_us_delta(dbg->begin, prev);
132 		do_div(div, 100);
133 		period = (u32)div;
134 		dbg->min_period = min(period, dbg->min_period);
135 		dbg->max_period = max(period, dbg->max_period);
136 		dbg->total_period += period;
137 		dbg->cnt_period++;
138 
139 		/*
140 		 * minimum and maximum bitrates are based on the
141 		 * encoding period values upon a window of 32 samples
142 		 */
143 		dbg->window_duration += period;
144 		dbg->cnt_window++;
145 		if (dbg->cnt_window >= 32) {
146 			/*
147 			 * bitrate in kbps = (size * 8 / 1000) /
148 			 *                   (duration / 10000)
149 			 *                 = size * 80 / duration
150 			 */
151 			if (dbg->window_duration > 0) {
152 				div = (u64)dbg->window_stream_size * 80;
153 				do_div(div, dbg->window_duration);
154 				bitrate = (u32)div;
155 				dbg->last_bitrate = bitrate;
156 				dbg->min_bitrate = min(bitrate,
157 						       dbg->min_bitrate);
158 				dbg->max_bitrate = max(bitrate,
159 						       dbg->max_bitrate);
160 			}
161 			dbg->window_stream_size = 0;
162 			dbg->window_duration = 0;
163 			dbg->cnt_window = 0;
164 		}
165 	}
166 
167 	/*
168 	 * filter sequences valid for performance:
169 	 * - begin/begin (no stream available) is an invalid sequence
170 	 * - begin/end is a valid sequence
171 	 */
172 	dbg->is_valid_period = false;
173 }
174 
hva_dbg_perf_end(struct hva_ctx * ctx,struct hva_stream * stream)175 void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream)
176 {
177 	struct device *dev = ctx_to_dev(ctx);
178 	u64 div;
179 	u32 duration;
180 	u32 bytesused;
181 	u32 timestamp;
182 	struct hva_ctx_dbg *dbg = &ctx->dbg;
183 	ktime_t end = ktime_get();
184 
185 	/* stream bytesused and timestamp in us */
186 	bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0);
187 	div = stream->vbuf.vb2_buf.timestamp;
188 	do_div(div, 1000);
189 	timestamp = (u32)div;
190 
191 	/* encoding duration */
192 	div = (u64)ktime_us_delta(end, dbg->begin);
193 
194 	dev_dbg(dev,
195 		"%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
196 		ctx->name,
197 		stream->vbuf.sequence,
198 		timestamp,
199 		bytesused, (u32)div);
200 
201 	do_div(div, 100);
202 	duration = (u32)div;
203 
204 	dbg->min_duration = min(duration, dbg->min_duration);
205 	dbg->max_duration = max(duration, dbg->max_duration);
206 	dbg->total_duration += duration;
207 	dbg->cnt_duration++;
208 
209 	/*
210 	 * the average bitrate is based on the total stream size
211 	 * and the total encoding periods
212 	 */
213 	dbg->total_stream_size += bytesused;
214 	dbg->window_stream_size += bytesused;
215 
216 	dbg->is_valid_period = true;
217 }
218 
hva_dbg_perf_compute(struct hva_ctx * ctx)219 static void hva_dbg_perf_compute(struct hva_ctx *ctx)
220 {
221 	u64 div;
222 	struct hva_ctx_dbg *dbg = &ctx->dbg;
223 
224 	if (dbg->cnt_duration > 0) {
225 		div = (u64)dbg->total_duration;
226 		do_div(div, dbg->cnt_duration);
227 		dbg->avg_duration = (u32)div;
228 	} else {
229 		dbg->avg_duration = 0;
230 	}
231 
232 	if (dbg->total_duration > 0) {
233 		div = (u64)dbg->cnt_duration * 100000;
234 		do_div(div, dbg->total_duration);
235 		dbg->max_fps = (u32)div;
236 	} else {
237 		dbg->max_fps = 0;
238 	}
239 
240 	if (dbg->cnt_period > 0) {
241 		div = (u64)dbg->total_period;
242 		do_div(div, dbg->cnt_period);
243 		dbg->avg_period = (u32)div;
244 	} else {
245 		dbg->avg_period = 0;
246 	}
247 
248 	if (dbg->total_period > 0) {
249 		div = (u64)dbg->cnt_period * 100000;
250 		do_div(div, dbg->total_period);
251 		dbg->avg_fps = (u32)div;
252 	} else {
253 		dbg->avg_fps = 0;
254 	}
255 
256 	if (dbg->total_period > 0) {
257 		/*
258 		 * bitrate in kbps = (video size * 8 / 1000) /
259 		 *                   (video duration / 10000)
260 		 *                 = video size * 80 / video duration
261 		 */
262 		div = (u64)dbg->total_stream_size * 80;
263 		do_div(div, dbg->total_period);
264 		dbg->avg_bitrate = (u32)div;
265 	} else {
266 		dbg->avg_bitrate = 0;
267 	}
268 }
269 
270 /*
271  * device debug info
272  */
273 
device_show(struct seq_file * s,void * data)274 static int device_show(struct seq_file *s, void *data)
275 {
276 	struct hva_dev *hva = s->private;
277 
278 	seq_printf(s, "[%s]\n", hva->v4l2_dev.name);
279 	seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num);
280 
281 	return 0;
282 }
283 
encoders_show(struct seq_file * s,void * data)284 static int encoders_show(struct seq_file *s, void *data)
285 {
286 	struct hva_dev *hva = s->private;
287 	unsigned int i = 0;
288 
289 	seq_printf(s, "[encoders]\n|- %d registered encoders:\n",
290 		   hva->nb_of_encoders);
291 
292 	while (hva->encoders[i]) {
293 		seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name,
294 			   (char *)&hva->encoders[i]->pixelformat,
295 			   (char *)&hva->encoders[i]->streamformat);
296 		i++;
297 	}
298 
299 	return 0;
300 }
301 
last_show(struct seq_file * s,void * data)302 static int last_show(struct seq_file *s, void *data)
303 {
304 	struct hva_dev *hva = s->private;
305 	struct hva_ctx *last_ctx = &hva->dbg.last_ctx;
306 
307 	if (last_ctx->flags & HVA_FLAG_STREAMINFO) {
308 		seq_puts(s, "[last encoding]\n");
309 
310 		hva_dbg_perf_compute(last_ctx);
311 		format_ctx(s, last_ctx);
312 	} else {
313 		seq_puts(s, "[no information recorded about last encoding]\n");
314 	}
315 
316 	return 0;
317 }
318 
regs_show(struct seq_file * s,void * data)319 static int regs_show(struct seq_file *s, void *data)
320 {
321 	struct hva_dev *hva = s->private;
322 
323 	hva_hw_dump_regs(hva, s);
324 
325 	return 0;
326 }
327 
328 #define hva_dbg_create_entry(name)					 \
329 	debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
330 			    &name##_fops)
331 
332 DEFINE_SHOW_ATTRIBUTE(device);
333 DEFINE_SHOW_ATTRIBUTE(encoders);
334 DEFINE_SHOW_ATTRIBUTE(last);
335 DEFINE_SHOW_ATTRIBUTE(regs);
336 
hva_debugfs_create(struct hva_dev * hva)337 void hva_debugfs_create(struct hva_dev *hva)
338 {
339 	hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
340 
341 	hva_dbg_create_entry(device);
342 	hva_dbg_create_entry(encoders);
343 	hva_dbg_create_entry(last);
344 	hva_dbg_create_entry(regs);
345 }
346 
hva_debugfs_remove(struct hva_dev * hva)347 void hva_debugfs_remove(struct hva_dev *hva)
348 {
349 	debugfs_remove_recursive(hva->dbg.debugfs_entry);
350 	hva->dbg.debugfs_entry = NULL;
351 }
352 
353 /*
354  * context (instance) debug info
355  */
356 
ctx_show(struct seq_file * s,void * data)357 static int ctx_show(struct seq_file *s, void *data)
358 {
359 	struct hva_ctx *ctx = s->private;
360 
361 	seq_printf(s, "[running encoding %d]\n", ctx->id);
362 
363 	hva_dbg_perf_compute(ctx);
364 	format_ctx(s, ctx);
365 
366 	return 0;
367 }
368 
369 DEFINE_SHOW_ATTRIBUTE(ctx);
370 
hva_dbg_ctx_create(struct hva_ctx * ctx)371 void hva_dbg_ctx_create(struct hva_ctx *ctx)
372 {
373 	struct hva_dev *hva = ctx->hva_dev;
374 	char name[4] = "";
375 
376 	ctx->dbg.min_duration = UINT_MAX;
377 	ctx->dbg.min_period = UINT_MAX;
378 	ctx->dbg.min_bitrate = UINT_MAX;
379 
380 	snprintf(name, sizeof(name), "%d", hva->instance_id);
381 
382 	ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
383 						     hva->dbg.debugfs_entry,
384 						     ctx, &ctx_fops);
385 }
386 
hva_dbg_ctx_remove(struct hva_ctx * ctx)387 void hva_dbg_ctx_remove(struct hva_ctx *ctx)
388 {
389 	struct hva_dev *hva = ctx->hva_dev;
390 
391 	if (ctx->flags & HVA_FLAG_STREAMINFO)
392 		/* save context before removing */
393 		memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx));
394 
395 	debugfs_remove(ctx->dbg.debugfs_entry);
396 }
397