1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2020-2021 NXP
6 #include <linux/init.h>
7 #include <linux/device.h>
8 #include <linux/ioctl.h>
9 #include <linux/list.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/pm_runtime.h>
14 #include <media/v4l2-device.h>
15 #include <linux/debugfs.h>
18 #include "vpu_helpers.h"
23 struct print_buf_desc {
33 static char *vb2_stat_name[] = {
34 [VB2_BUF_STATE_DEQUEUED] = "dequeued",
35 [VB2_BUF_STATE_IN_REQUEST] = "in_request",
36 [VB2_BUF_STATE_PREPARING] = "preparing",
37 [VB2_BUF_STATE_QUEUED] = "queued",
38 [VB2_BUF_STATE_ACTIVE] = "active",
39 [VB2_BUF_STATE_DONE] = "done",
40 [VB2_BUF_STATE_ERROR] = "error",
43 static char *vpu_stat_name[] = {
44 [VPU_BUF_STATE_IDLE] = "idle",
45 [VPU_BUF_STATE_INUSE] = "inuse",
46 [VPU_BUF_STATE_DECODED] = "decoded",
47 [VPU_BUF_STATE_READY] = "ready",
48 [VPU_BUF_STATE_SKIP] = "skip",
49 [VPU_BUF_STATE_ERROR] = "error",
52 static int vpu_dbg_instance(struct seq_file *s, void *data)
54 struct vpu_inst *inst = s->private;
60 if (!inst->fh.m2m_ctx)
62 num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(inst->type));
63 if (seq_write(s, str, num))
66 num = scnprintf(str, sizeof(str), "tgig = %d,pid = %d\n", inst->tgid, inst->pid);
67 if (seq_write(s, str, num))
69 num = scnprintf(str, sizeof(str), "state = %d\n", inst->state);
70 if (seq_write(s, str, num))
72 num = scnprintf(str, sizeof(str),
73 "min_buffer_out = %d, min_buffer_cap = %d\n",
74 inst->min_buffer_out, inst->min_buffer_cap);
75 if (seq_write(s, str, num))
78 vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
79 num = scnprintf(str, sizeof(str),
80 "output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
83 inst->out_format.pixfmt,
84 inst->out_format.pixfmt >> 8,
85 inst->out_format.pixfmt >> 16,
86 inst->out_format.pixfmt >> 24,
87 inst->out_format.width,
88 inst->out_format.height,
89 vq->last_buffer_dequeued);
90 if (seq_write(s, str, num))
92 for (i = 0; i < inst->out_format.num_planes; i++) {
93 num = scnprintf(str, sizeof(str), " %d(%d)",
94 inst->out_format.sizeimage[i],
95 inst->out_format.bytesperline[i]);
96 if (seq_write(s, str, num))
99 if (seq_write(s, "\n", 1))
102 vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
103 num = scnprintf(str, sizeof(str),
104 "capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
105 vb2_is_streaming(vq),
107 inst->cap_format.pixfmt,
108 inst->cap_format.pixfmt >> 8,
109 inst->cap_format.pixfmt >> 16,
110 inst->cap_format.pixfmt >> 24,
111 inst->cap_format.width,
112 inst->cap_format.height,
113 vq->last_buffer_dequeued);
114 if (seq_write(s, str, num))
116 for (i = 0; i < inst->cap_format.num_planes; i++) {
117 num = scnprintf(str, sizeof(str), " %d(%d)",
118 inst->cap_format.sizeimage[i],
119 inst->cap_format.bytesperline[i]);
120 if (seq_write(s, str, num))
123 if (seq_write(s, "\n", 1))
125 num = scnprintf(str, sizeof(str), "crop: (%d, %d) %d x %d\n",
130 if (seq_write(s, str, num))
133 vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
134 for (i = 0; i < vq->num_buffers; i++) {
135 struct vb2_buffer *vb = vq->bufs[i];
136 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
138 if (vb->state == VB2_BUF_STATE_DEQUEUED)
140 num = scnprintf(str, sizeof(str),
141 "output [%2d] state = %10s, %8s\n",
142 i, vb2_stat_name[vb->state],
143 vpu_stat_name[vpu_get_buffer_state(vbuf)]);
144 if (seq_write(s, str, num))
148 vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
149 for (i = 0; i < vq->num_buffers; i++) {
150 struct vb2_buffer *vb = vq->bufs[i];
151 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
153 if (vb->state == VB2_BUF_STATE_DEQUEUED)
155 num = scnprintf(str, sizeof(str),
156 "capture[%2d] state = %10s, %8s\n",
157 i, vb2_stat_name[vb->state],
158 vpu_stat_name[vpu_get_buffer_state(vbuf)]);
159 if (seq_write(s, str, num))
163 num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence);
164 if (seq_write(s, str, num))
167 if (inst->use_stream_buffer) {
168 num = scnprintf(str, sizeof(str), "stream_buffer = %d / %d, <%pad, 0x%x>\n",
169 vpu_helper_get_used_space(inst),
170 inst->stream_buffer.length,
171 &inst->stream_buffer.phys,
172 inst->stream_buffer.length);
173 if (seq_write(s, str, num))
176 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&inst->msg_fifo));
177 if (seq_write(s, str, num))
180 num = scnprintf(str, sizeof(str), "flow :\n");
181 if (seq_write(s, str, num))
184 mutex_lock(&inst->core->cmd_lock);
185 for (i = 0; i < ARRAY_SIZE(inst->flows); i++) {
186 u32 idx = (inst->flow_idx + i) % (ARRAY_SIZE(inst->flows));
188 if (!inst->flows[idx])
190 num = scnprintf(str, sizeof(str), "\t[%s]0x%x\n",
191 inst->flows[idx] >= VPU_MSG_ID_NOOP ? "M" : "C",
193 if (seq_write(s, str, num)) {
194 mutex_unlock(&inst->core->cmd_lock);
198 mutex_unlock(&inst->core->cmd_lock);
202 num = call_vop(inst, get_debug_info, str, sizeof(str), i++);
205 if (seq_write(s, str, num))
212 static int vpu_dbg_core(struct seq_file *s, void *data)
214 struct vpu_core *core = s->private;
215 struct vpu_shared_addr *iface = core->iface;
219 num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(core->type));
220 if (seq_write(s, str, num))
223 num = scnprintf(str, sizeof(str), "boot_region = <%pad, 0x%x>\n",
224 &core->fw.phys, core->fw.length);
225 if (seq_write(s, str, num))
227 num = scnprintf(str, sizeof(str), "rpc_region = <%pad, 0x%x> used = 0x%x\n",
228 &core->rpc.phys, core->rpc.length, core->rpc.bytesused);
229 if (seq_write(s, str, num))
231 num = scnprintf(str, sizeof(str), "fwlog_region = <%pad, 0x%x>\n",
232 &core->log.phys, core->log.length);
233 if (seq_write(s, str, num))
236 num = scnprintf(str, sizeof(str), "state = %d\n", core->state);
237 if (seq_write(s, str, num))
239 if (core->state == VPU_CORE_DEINIT)
241 num = scnprintf(str, sizeof(str), "fw version = %d.%d.%d\n",
242 (core->fw_version >> 16) & 0xff,
243 (core->fw_version >> 8) & 0xff,
244 core->fw_version & 0xff);
245 if (seq_write(s, str, num))
247 num = scnprintf(str, sizeof(str), "instances = %d/%d (0x%02lx), %d\n",
248 hweight32(core->instance_mask),
249 core->supported_instance_count,
251 core->request_count);
252 if (seq_write(s, str, num))
254 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&core->msg_fifo));
255 if (seq_write(s, str, num))
257 num = scnprintf(str, sizeof(str),
258 "cmd_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
259 iface->cmd_desc->start,
260 iface->cmd_desc->end,
261 iface->cmd_desc->wptr,
262 iface->cmd_desc->rptr);
263 if (seq_write(s, str, num))
265 num = scnprintf(str, sizeof(str),
266 "msg_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
267 iface->msg_desc->start,
268 iface->msg_desc->end,
269 iface->msg_desc->wptr,
270 iface->msg_desc->rptr);
271 if (seq_write(s, str, num))
277 static int vpu_dbg_fwlog(struct seq_file *s, void *data)
279 struct vpu_core *core = s->private;
280 struct print_buf_desc *print_buf;
286 if (!core->log.virt || core->state == VPU_CORE_DEINIT)
289 print_buf = core->log.virt;
290 rptr = print_buf->read;
291 wptr = print_buf->write;
295 else if (rptr < wptr)
296 length = wptr - rptr;
298 length = print_buf->bytes + wptr - rptr;
300 if (s->count + length >= s->size) {
305 if (rptr + length >= print_buf->bytes) {
306 int num = print_buf->bytes - rptr;
308 if (seq_write(s, print_buf->buffer + rptr, num))
315 if (seq_write(s, print_buf->buffer + rptr, length))
320 print_buf->read = rptr;
325 static int vpu_dbg_inst_open(struct inode *inode, struct file *filp)
327 return single_open(filp, vpu_dbg_instance, inode->i_private);
330 static ssize_t vpu_dbg_inst_write(struct file *file,
331 const char __user *user_buf, size_t size, loff_t *ppos)
333 struct seq_file *s = file->private_data;
334 struct vpu_inst *inst = s->private;
336 vpu_session_debug(inst);
341 static ssize_t vpu_dbg_core_write(struct file *file,
342 const char __user *user_buf, size_t size, loff_t *ppos)
344 struct seq_file *s = file->private_data;
345 struct vpu_core *core = s->private;
347 pm_runtime_resume_and_get(core->dev);
348 mutex_lock(&core->lock);
349 if (core->state != VPU_CORE_DEINIT && !core->instance_mask) {
350 dev_info(core->dev, "reset\n");
351 if (!vpu_core_sw_reset(core)) {
352 core->state = VPU_CORE_ACTIVE;
356 mutex_unlock(&core->lock);
357 pm_runtime_put_sync(core->dev);
362 static int vpu_dbg_core_open(struct inode *inode, struct file *filp)
364 return single_open(filp, vpu_dbg_core, inode->i_private);
367 static int vpu_dbg_fwlog_open(struct inode *inode, struct file *filp)
369 return single_open(filp, vpu_dbg_fwlog, inode->i_private);
372 static const struct file_operations vpu_dbg_inst_fops = {
373 .owner = THIS_MODULE,
374 .open = vpu_dbg_inst_open,
375 .release = single_release,
377 .write = vpu_dbg_inst_write,
380 static const struct file_operations vpu_dbg_core_fops = {
381 .owner = THIS_MODULE,
382 .open = vpu_dbg_core_open,
383 .release = single_release,
385 .write = vpu_dbg_core_write,
388 static const struct file_operations vpu_dbg_fwlog_fops = {
389 .owner = THIS_MODULE,
390 .open = vpu_dbg_fwlog_open,
391 .release = single_release,
395 int vpu_inst_create_dbgfs_file(struct vpu_inst *inst)
400 if (!inst || !inst->core || !inst->core->vpu)
403 vpu = inst->core->vpu;
410 scnprintf(name, sizeof(name), "instance.%d.%d", inst->core->id, inst->id);
411 inst->debugfs = debugfs_create_file((const char *)name,
412 VERIFY_OCTAL_PERMISSIONS(0644),
420 int vpu_inst_remove_dbgfs_file(struct vpu_inst *inst)
425 debugfs_remove(inst->debugfs);
426 inst->debugfs = NULL;
431 int vpu_core_create_dbgfs_file(struct vpu_core *core)
436 if (!core || !core->vpu)
443 if (!core->debugfs) {
444 scnprintf(name, sizeof(name), "core.%d", core->id);
445 core->debugfs = debugfs_create_file((const char *)name,
446 VERIFY_OCTAL_PERMISSIONS(0644),
451 if (!core->debugfs_fwlog) {
452 scnprintf(name, sizeof(name), "fwlog.%d", core->id);
453 core->debugfs_fwlog = debugfs_create_file((const char *)name,
454 VERIFY_OCTAL_PERMISSIONS(0444),
457 &vpu_dbg_fwlog_fops);
463 int vpu_core_remove_dbgfs_file(struct vpu_core *core)
467 debugfs_remove(core->debugfs);
468 core->debugfs = NULL;
469 debugfs_remove(core->debugfs_fwlog);
470 core->debugfs_fwlog = NULL;
475 void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow)
480 inst->flows[inst->flow_idx] = flow;
481 inst->flow_idx = (inst->flow_idx + 1) % (ARRAY_SIZE(inst->flows));