xref: /linux/drivers/media/platform/amd/isp4/isp4_debug.c (revision 8c13415c8a4383447c21ec832b20b3b283f0e01a)
1*ec4bec22SBin Du // SPDX-License-Identifier: GPL-2.0+
2*ec4bec22SBin Du /*
3*ec4bec22SBin Du  * Copyright (C) 2025 Advanced Micro Devices, Inc.
4*ec4bec22SBin Du  */
5*ec4bec22SBin Du 
6*ec4bec22SBin Du #include "isp4.h"
7*ec4bec22SBin Du #include "isp4_debug.h"
8*ec4bec22SBin Du #include "isp4_hw_reg.h"
9*ec4bec22SBin Du #include "isp4_interface.h"
10*ec4bec22SBin Du 
11*ec4bec22SBin Du #define ISP4DBG_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
12*ec4bec22SBin Du #define ISP4DBG_MACRO_2_STR(X) #X
13*ec4bec22SBin Du #define ISP4DBG_ONE_TIME_LOG_LEN 510
14*ec4bec22SBin Du 
15*ec4bec22SBin Du #ifdef CONFIG_DEBUG_FS
16*ec4bec22SBin Du 
17*ec4bec22SBin Du void isp_debugfs_create(struct isp4_device *isp_dev)
18*ec4bec22SBin Du {
19*ec4bec22SBin Du 	isp_dev->isp_subdev.debugfs_dir = debugfs_create_dir("amd_isp4", NULL);
20*ec4bec22SBin Du 	debugfs_create_bool("fw_log_enable", 0644,
21*ec4bec22SBin Du 			    isp_dev->isp_subdev.debugfs_dir,
22*ec4bec22SBin Du 			    &isp_dev->isp_subdev.enable_fw_log);
23*ec4bec22SBin Du 	isp_dev->isp_subdev.fw_log_output =
24*ec4bec22SBin Du 		devm_kzalloc(isp_dev->isp_subdev.dev,
25*ec4bec22SBin Du 			     ISP4DBG_FW_LOG_RINGBUF_SIZE + 32,
26*ec4bec22SBin Du 			     GFP_KERNEL);
27*ec4bec22SBin Du }
28*ec4bec22SBin Du 
29*ec4bec22SBin Du void isp_debugfs_remove(struct isp4_device *isp_dev)
30*ec4bec22SBin Du {
31*ec4bec22SBin Du 	debugfs_remove_recursive(isp_dev->isp_subdev.debugfs_dir);
32*ec4bec22SBin Du 	isp_dev->isp_subdev.debugfs_dir = NULL;
33*ec4bec22SBin Du }
34*ec4bec22SBin Du 
35*ec4bec22SBin Du static u32 isp_fw_fill_rb_log(struct isp4_subdev *isp, void *sys, u32 rb_size)
36*ec4bec22SBin Du {
37*ec4bec22SBin Du 	struct isp4_interface *ispif = &isp->ispif;
38*ec4bec22SBin Du 	char *buf = isp->fw_log_output;
39*ec4bec22SBin Du 	struct device *dev = isp->dev;
40*ec4bec22SBin Du 	u32 rd_ptr, wr_ptr;
41*ec4bec22SBin Du 	u32 total_cnt = 0;
42*ec4bec22SBin Du 	u32 offset = 0;
43*ec4bec22SBin Du 	u32 cnt;
44*ec4bec22SBin Du 
45*ec4bec22SBin Du 	if (!sys || !rb_size)
46*ec4bec22SBin Du 		return 0;
47*ec4bec22SBin Du 
48*ec4bec22SBin Du 	guard(mutex)(&ispif->isp4if_mutex);
49*ec4bec22SBin Du 
50*ec4bec22SBin Du 	rd_ptr = isp4hw_rreg(isp->mmio, ISP_LOG_RB_RPTR0);
51*ec4bec22SBin Du 	wr_ptr = isp4hw_rreg(isp->mmio, ISP_LOG_RB_WPTR0);
52*ec4bec22SBin Du 
53*ec4bec22SBin Du 	do {
54*ec4bec22SBin Du 		if (wr_ptr > rd_ptr)
55*ec4bec22SBin Du 			cnt = wr_ptr - rd_ptr;
56*ec4bec22SBin Du 		else if (wr_ptr < rd_ptr)
57*ec4bec22SBin Du 			cnt = rb_size - rd_ptr;
58*ec4bec22SBin Du 		else
59*ec4bec22SBin Du 			goto quit;
60*ec4bec22SBin Du 
61*ec4bec22SBin Du 		if (cnt > rb_size) {
62*ec4bec22SBin Du 			dev_err(dev, "fail bad fw log size %u\n", cnt);
63*ec4bec22SBin Du 			goto quit;
64*ec4bec22SBin Du 		}
65*ec4bec22SBin Du 
66*ec4bec22SBin Du 		memcpy(buf + offset, sys + rd_ptr, cnt);
67*ec4bec22SBin Du 
68*ec4bec22SBin Du 		offset += cnt;
69*ec4bec22SBin Du 		total_cnt += cnt;
70*ec4bec22SBin Du 		rd_ptr = (rd_ptr + cnt) % rb_size;
71*ec4bec22SBin Du 	} while (rd_ptr < wr_ptr);
72*ec4bec22SBin Du 
73*ec4bec22SBin Du 	isp4hw_wreg(isp->mmio, ISP_LOG_RB_RPTR0, rd_ptr);
74*ec4bec22SBin Du 
75*ec4bec22SBin Du quit:
76*ec4bec22SBin Du 	return total_cnt;
77*ec4bec22SBin Du }
78*ec4bec22SBin Du 
79*ec4bec22SBin Du void isp_fw_log_print(struct isp4_subdev *isp)
80*ec4bec22SBin Du {
81*ec4bec22SBin Du 	struct isp4_interface *ispif = &isp->ispif;
82*ec4bec22SBin Du 	char *fw_log_buf = isp->fw_log_output;
83*ec4bec22SBin Du 	u32 cnt;
84*ec4bec22SBin Du 
85*ec4bec22SBin Du 	if (!isp->enable_fw_log || !fw_log_buf)
86*ec4bec22SBin Du 		return;
87*ec4bec22SBin Du 
88*ec4bec22SBin Du 	cnt = isp_fw_fill_rb_log(isp, ispif->fw_log_buf->sys_addr,
89*ec4bec22SBin Du 				 ispif->fw_log_buf->mem_size);
90*ec4bec22SBin Du 
91*ec4bec22SBin Du 	if (cnt) {
92*ec4bec22SBin Du 		char temp_ch;
93*ec4bec22SBin Du 		char *str;
94*ec4bec22SBin Du 		char *end;
95*ec4bec22SBin Du 		/* line end */
96*ec4bec22SBin Du 		char *le;
97*ec4bec22SBin Du 
98*ec4bec22SBin Du 		str = (char *)fw_log_buf;
99*ec4bec22SBin Du 		end = ((char *)fw_log_buf + cnt);
100*ec4bec22SBin Du 		fw_log_buf[cnt] = 0;
101*ec4bec22SBin Du 
102*ec4bec22SBin Du 		while (str < end) {
103*ec4bec22SBin Du 			le = strchr(str, 0x0A);
104*ec4bec22SBin Du 			if ((le && str + ISP4DBG_ONE_TIME_LOG_LEN >= le) ||
105*ec4bec22SBin Du 			    (!le && str + ISP4DBG_ONE_TIME_LOG_LEN >= end)) {
106*ec4bec22SBin Du 				if (le)
107*ec4bec22SBin Du 					*le = 0;
108*ec4bec22SBin Du 
109*ec4bec22SBin Du 				if (*str != '\0')
110*ec4bec22SBin Du 					dev_dbg(isp->dev, "%s", str);
111*ec4bec22SBin Du 
112*ec4bec22SBin Du 				if (le) {
113*ec4bec22SBin Du 					*le = 0x0A;
114*ec4bec22SBin Du 					str = le + 1;
115*ec4bec22SBin Du 				} else {
116*ec4bec22SBin Du 					break;
117*ec4bec22SBin Du 				}
118*ec4bec22SBin Du 			} else {
119*ec4bec22SBin Du 				u32 tmp_len = ISP4DBG_ONE_TIME_LOG_LEN;
120*ec4bec22SBin Du 
121*ec4bec22SBin Du 				temp_ch = str[tmp_len];
122*ec4bec22SBin Du 				str[tmp_len] = 0;
123*ec4bec22SBin Du 				dev_dbg(isp->dev, "%s", str);
124*ec4bec22SBin Du 				str[tmp_len] = temp_ch;
125*ec4bec22SBin Du 				str = &str[tmp_len];
126*ec4bec22SBin Du 			}
127*ec4bec22SBin Du 		}
128*ec4bec22SBin Du 	}
129*ec4bec22SBin Du }
130*ec4bec22SBin Du #endif
131*ec4bec22SBin Du 
132*ec4bec22SBin Du char *isp4dbg_get_buf_src_str(u32 src)
133*ec4bec22SBin Du {
134*ec4bec22SBin Du 	switch (src) {
135*ec4bec22SBin Du 	case ISP4FW_BUFFER_SOURCE_STREAM:
136*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_SOURCE_STREAM);
137*ec4bec22SBin Du 	default:
138*ec4bec22SBin Du 		return "Unknown buf source";
139*ec4bec22SBin Du 	}
140*ec4bec22SBin Du }
141*ec4bec22SBin Du 
142*ec4bec22SBin Du char *isp4dbg_get_buf_done_str(u32 status)
143*ec4bec22SBin Du {
144*ec4bec22SBin Du 	switch (status) {
145*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_INVALID:
146*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_INVALID);
147*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_SKIPPED:
148*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_SKIPPED);
149*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_EXIST:
150*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_EXIST);
151*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_DONE:
152*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_DONE);
153*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_LACK:
154*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_LACK);
155*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_DIRTY:
156*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_DIRTY);
157*ec4bec22SBin Du 	case ISP4FW_BUFFER_STATUS_MAX:
158*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_MAX);
159*ec4bec22SBin Du 	default:
160*ec4bec22SBin Du 		return "Unknown Buf Done Status";
161*ec4bec22SBin Du 	}
162*ec4bec22SBin Du }
163*ec4bec22SBin Du 
164*ec4bec22SBin Du char *isp4dbg_get_img_fmt_str(int fmt /* enum isp4fw_image_format * */)
165*ec4bec22SBin Du {
166*ec4bec22SBin Du 	switch (fmt) {
167*ec4bec22SBin Du 	case ISP4FW_IMAGE_FORMAT_NV12:
168*ec4bec22SBin Du 		return "NV12";
169*ec4bec22SBin Du 	case ISP4FW_IMAGE_FORMAT_YUV422INTERLEAVED:
170*ec4bec22SBin Du 		return "YUV422INTERLEAVED";
171*ec4bec22SBin Du 	default:
172*ec4bec22SBin Du 		return "unknown fmt";
173*ec4bec22SBin Du 	}
174*ec4bec22SBin Du }
175*ec4bec22SBin Du 
176*ec4bec22SBin Du void isp4dbg_show_bufmeta_info(struct device *dev, char *pre,
177*ec4bec22SBin Du 			       void *in, void *orig_buf)
178*ec4bec22SBin Du {
179*ec4bec22SBin Du 	struct isp4fw_buffer_meta_info *p;
180*ec4bec22SBin Du 	struct isp4if_img_buf_info *orig;
181*ec4bec22SBin Du 
182*ec4bec22SBin Du 	if (!in)
183*ec4bec22SBin Du 		return;
184*ec4bec22SBin Du 
185*ec4bec22SBin Du 	if (!pre)
186*ec4bec22SBin Du 		pre = "";
187*ec4bec22SBin Du 
188*ec4bec22SBin Du 	p = in;
189*ec4bec22SBin Du 	orig = orig_buf;
190*ec4bec22SBin Du 
191*ec4bec22SBin Du 	dev_dbg(dev, "%s(%s) en:%d,stat:%s(%u),src:%s\n", pre,
192*ec4bec22SBin Du 		isp4dbg_get_img_fmt_str(p->image_prop.image_format),
193*ec4bec22SBin Du 		p->enabled, isp4dbg_get_buf_done_str(p->status), p->status,
194*ec4bec22SBin Du 		isp4dbg_get_buf_src_str(p->source));
195*ec4bec22SBin Du 
196*ec4bec22SBin Du 	dev_dbg(dev, "%p,0x%llx(%u) %p,0x%llx(%u) %p,0x%llx(%u)\n",
197*ec4bec22SBin Du 		orig->planes[0].sys_addr, orig->planes[0].mc_addr,
198*ec4bec22SBin Du 		orig->planes[0].len, orig->planes[1].sys_addr,
199*ec4bec22SBin Du 		orig->planes[1].mc_addr, orig->planes[1].len,
200*ec4bec22SBin Du 		orig->planes[2].sys_addr, orig->planes[2].mc_addr,
201*ec4bec22SBin Du 		orig->planes[2].len);
202*ec4bec22SBin Du }
203*ec4bec22SBin Du 
204*ec4bec22SBin Du char *isp4dbg_get_buf_type(u32 type)
205*ec4bec22SBin Du {
206*ec4bec22SBin Du 	/* enum isp4fw_buffer_type */
207*ec4bec22SBin Du 	switch (type) {
208*ec4bec22SBin Du 	case ISP4FW_BUFFER_TYPE_PREVIEW:
209*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_PREVIEW);
210*ec4bec22SBin Du 	case ISP4FW_BUFFER_TYPE_META_INFO:
211*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_META_INFO);
212*ec4bec22SBin Du 	case ISP4FW_BUFFER_TYPE_MEM_POOL:
213*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_MEM_POOL);
214*ec4bec22SBin Du 	default:
215*ec4bec22SBin Du 		return "unknown type";
216*ec4bec22SBin Du 	}
217*ec4bec22SBin Du }
218*ec4bec22SBin Du 
219*ec4bec22SBin Du char *isp4dbg_get_cmd_str(u32 cmd)
220*ec4bec22SBin Du {
221*ec4bec22SBin Du 	switch (cmd) {
222*ec4bec22SBin Du 	case ISP4FW_CMD_ID_START_STREAM:
223*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_START_STREAM);
224*ec4bec22SBin Du 	case ISP4FW_CMD_ID_STOP_STREAM:
225*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_STOP_STREAM);
226*ec4bec22SBin Du 	case ISP4FW_CMD_ID_SEND_BUFFER:
227*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SEND_BUFFER);
228*ec4bec22SBin Du 	case ISP4FW_CMD_ID_SET_STREAM_CONFIG:
229*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SET_STREAM_CONFIG);
230*ec4bec22SBin Du 	case ISP4FW_CMD_ID_SET_OUT_CHAN_PROP:
231*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SET_OUT_CHAN_PROP);
232*ec4bec22SBin Du 	case ISP4FW_CMD_ID_ENABLE_OUT_CHAN:
233*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_ENABLE_OUT_CHAN);
234*ec4bec22SBin Du 	default:
235*ec4bec22SBin Du 		return "unknown cmd";
236*ec4bec22SBin Du 	}
237*ec4bec22SBin Du }
238*ec4bec22SBin Du 
239*ec4bec22SBin Du char *isp4dbg_get_resp_str(u32 cmd)
240*ec4bec22SBin Du {
241*ec4bec22SBin Du 	switch (cmd) {
242*ec4bec22SBin Du 	case ISP4FW_RESP_ID_CMD_DONE:
243*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_RESP_ID_CMD_DONE);
244*ec4bec22SBin Du 	case ISP4FW_RESP_ID_NOTI_FRAME_DONE:
245*ec4bec22SBin Du 		return ISP4DBG_MACRO_2_STR(ISP4FW_RESP_ID_NOTI_FRAME_DONE);
246*ec4bec22SBin Du 	default:
247*ec4bec22SBin Du 		return "unknown respid";
248*ec4bec22SBin Du 	}
249*ec4bec22SBin Du }
250*ec4bec22SBin Du 
251*ec4bec22SBin Du char *isp4dbg_get_if_stream_str(u32 stream /* enum fw_cmd_resp_stream_id */)
252*ec4bec22SBin Du {
253*ec4bec22SBin Du 	switch (stream) {
254*ec4bec22SBin Du 	case ISP4IF_STREAM_ID_GLOBAL:
255*ec4bec22SBin Du 		return "STREAM_GLOBAL";
256*ec4bec22SBin Du 	case ISP4IF_STREAM_ID_1:
257*ec4bec22SBin Du 		return "STREAM1";
258*ec4bec22SBin Du 	default:
259*ec4bec22SBin Du 		return "unknown streamID";
260*ec4bec22SBin Du 	}
261*ec4bec22SBin Du }
262*ec4bec22SBin Du 
263*ec4bec22SBin Du char *isp4dbg_get_out_ch_str(int ch /* enum isp4fw_pipe_out_ch */)
264*ec4bec22SBin Du {
265*ec4bec22SBin Du 	switch ((enum isp4fw_pipe_out_ch)ch) {
266*ec4bec22SBin Du 	case ISP4FW_ISP_PIPE_OUT_CH_PREVIEW:
267*ec4bec22SBin Du 		return "prev";
268*ec4bec22SBin Du 	default:
269*ec4bec22SBin Du 		return "unknown channel";
270*ec4bec22SBin Du 	}
271*ec4bec22SBin Du }
272