271 lines · 6.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * Copyright (C) 2025 Advanced Micro Devices, Inc. */ #include "isp4.h"#include "isp4_debug.h"#include "isp4_hw_reg.h"#include "isp4_interface.h" #define ISP4DBG_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)#define ISP4DBG_MACRO_2_STR(X) #X#define ISP4DBG_ONE_TIME_LOG_LEN 510 #ifdef CONFIG_DEBUG_FS void isp_debugfs_create(struct isp4_device *isp_dev){	isp_dev->isp_subdev.debugfs_dir = debugfs_create_dir("amd_isp4", NULL);	debugfs_create_bool("fw_log_enable", 0644,			    isp_dev->isp_subdev.debugfs_dir,			    &isp_dev->isp_subdev.enable_fw_log);	isp_dev->isp_subdev.fw_log_output =		devm_kzalloc(isp_dev->isp_subdev.dev,			     ISP4DBG_FW_LOG_RINGBUF_SIZE + 32,			     GFP_KERNEL);} void isp_debugfs_remove(struct isp4_device *isp_dev){	debugfs_remove_recursive(isp_dev->isp_subdev.debugfs_dir);	isp_dev->isp_subdev.debugfs_dir = NULL;} static u32 isp_fw_fill_rb_log(struct isp4_subdev *isp, void *sys, u32 rb_size){	struct isp4_interface *ispif = &isp->ispif;	char *buf = isp->fw_log_output;	struct device *dev = isp->dev;	u32 rd_ptr, wr_ptr;	u32 total_cnt = 0;	u32 offset = 0;	u32 cnt; 	if (!sys || !rb_size)		return 0; 	guard(mutex)(&ispif->isp4if_mutex); 	rd_ptr = isp4hw_rreg(isp->mmio, ISP_LOG_RB_RPTR0);	wr_ptr = isp4hw_rreg(isp->mmio, ISP_LOG_RB_WPTR0); 	do {		if (wr_ptr > rd_ptr)			cnt = wr_ptr - rd_ptr;		else if (wr_ptr < rd_ptr)			cnt = rb_size - rd_ptr;		else			goto quit; 		if (cnt > rb_size) {			dev_err(dev, "fail bad fw log size %u\n", cnt);			goto quit;		} 		memcpy(buf + offset, sys + rd_ptr, cnt); 		offset += cnt;		total_cnt += cnt;		rd_ptr = (rd_ptr + cnt) % rb_size;	} while (rd_ptr < wr_ptr); 	isp4hw_wreg(isp->mmio, ISP_LOG_RB_RPTR0, rd_ptr); quit:	return total_cnt;} void isp_fw_log_print(struct isp4_subdev *isp){	struct isp4_interface *ispif = &isp->ispif;	char *fw_log_buf = isp->fw_log_output;	u32 cnt; 	if (!isp->enable_fw_log || !fw_log_buf)		return; 	cnt = isp_fw_fill_rb_log(isp, ispif->fw_log_buf->sys_addr,				 ispif->fw_log_buf->mem_size); 	if (cnt) {		char temp_ch;		char *str;		char *end;		/* line end */		char *le; 		str = (char *)fw_log_buf;		end = ((char *)fw_log_buf + cnt);		fw_log_buf[cnt] = 0; 		while (str < end) {			le = strchr(str, 0x0A);			if ((le && str + ISP4DBG_ONE_TIME_LOG_LEN >= le) ||			    (!le && str + ISP4DBG_ONE_TIME_LOG_LEN >= end)) {				if (le)					*le = 0; 				if (*str != '\0')					dev_dbg(isp->dev, "%s", str); 				if (le) {					*le = 0x0A;					str = le + 1;				} else {					break;				}			} else {				u32 tmp_len = ISP4DBG_ONE_TIME_LOG_LEN; 				temp_ch = str[tmp_len];				str[tmp_len] = 0;				dev_dbg(isp->dev, "%s", str);				str[tmp_len] = temp_ch;				str = &str[tmp_len];			}		}	}}#endif char *isp4dbg_get_buf_src_str(u32 src){	switch (src) {	case ISP4FW_BUFFER_SOURCE_STREAM:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_SOURCE_STREAM);	default:		return "Unknown buf source";	}} char *isp4dbg_get_buf_done_str(u32 status){	switch (status) {	case ISP4FW_BUFFER_STATUS_INVALID:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_INVALID);	case ISP4FW_BUFFER_STATUS_SKIPPED:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_SKIPPED);	case ISP4FW_BUFFER_STATUS_EXIST:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_EXIST);	case ISP4FW_BUFFER_STATUS_DONE:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_DONE);	case ISP4FW_BUFFER_STATUS_LACK:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_LACK);	case ISP4FW_BUFFER_STATUS_DIRTY:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_DIRTY);	case ISP4FW_BUFFER_STATUS_MAX:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_STATUS_MAX);	default:		return "Unknown Buf Done Status";	}} char *isp4dbg_get_img_fmt_str(int fmt /* enum isp4fw_image_format * */){	switch (fmt) {	case ISP4FW_IMAGE_FORMAT_NV12:		return "NV12";	case ISP4FW_IMAGE_FORMAT_YUV422INTERLEAVED:		return "YUV422INTERLEAVED";	default:		return "unknown fmt";	}} void isp4dbg_show_bufmeta_info(struct device *dev, char *pre,			       void *in, void *orig_buf){	struct isp4fw_buffer_meta_info *p;	struct isp4if_img_buf_info *orig; 	if (!in)		return; 	if (!pre)		pre = ""; 	p = in;	orig = orig_buf; 	dev_dbg(dev, "%s(%s) en:%d,stat:%s(%u),src:%s\n", pre,		isp4dbg_get_img_fmt_str(p->image_prop.image_format),		p->enabled, isp4dbg_get_buf_done_str(p->status), p->status,		isp4dbg_get_buf_src_str(p->source)); 	dev_dbg(dev, "%p,0x%llx(%u) %p,0x%llx(%u) %p,0x%llx(%u)\n",		orig->planes[0].sys_addr, orig->planes[0].mc_addr,		orig->planes[0].len, orig->planes[1].sys_addr,		orig->planes[1].mc_addr, orig->planes[1].len,		orig->planes[2].sys_addr, orig->planes[2].mc_addr,		orig->planes[2].len);} char *isp4dbg_get_buf_type(u32 type){	/* enum isp4fw_buffer_type */	switch (type) {	case ISP4FW_BUFFER_TYPE_PREVIEW:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_PREVIEW);	case ISP4FW_BUFFER_TYPE_META_INFO:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_META_INFO);	case ISP4FW_BUFFER_TYPE_MEM_POOL:		return ISP4DBG_MACRO_2_STR(ISP4FW_BUFFER_TYPE_MEM_POOL);	default:		return "unknown type";	}} char *isp4dbg_get_cmd_str(u32 cmd){	switch (cmd) {	case ISP4FW_CMD_ID_START_STREAM:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_START_STREAM);	case ISP4FW_CMD_ID_STOP_STREAM:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_STOP_STREAM);	case ISP4FW_CMD_ID_SEND_BUFFER:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SEND_BUFFER);	case ISP4FW_CMD_ID_SET_STREAM_CONFIG:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SET_STREAM_CONFIG);	case ISP4FW_CMD_ID_SET_OUT_CHAN_PROP:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_SET_OUT_CHAN_PROP);	case ISP4FW_CMD_ID_ENABLE_OUT_CHAN:		return ISP4DBG_MACRO_2_STR(ISP4FW_CMD_ID_ENABLE_OUT_CHAN);	default:		return "unknown cmd";	}} char *isp4dbg_get_resp_str(u32 cmd){	switch (cmd) {	case ISP4FW_RESP_ID_CMD_DONE:		return ISP4DBG_MACRO_2_STR(ISP4FW_RESP_ID_CMD_DONE);	case ISP4FW_RESP_ID_NOTI_FRAME_DONE:		return ISP4DBG_MACRO_2_STR(ISP4FW_RESP_ID_NOTI_FRAME_DONE);	default:		return "unknown respid";	}} char *isp4dbg_get_if_stream_str(u32 stream /* enum fw_cmd_resp_stream_id */){	switch (stream) {	case ISP4IF_STREAM_ID_GLOBAL:		return "STREAM_GLOBAL";	case ISP4IF_STREAM_ID_1:		return "STREAM1";	default:		return "unknown streamID";	}} char *isp4dbg_get_out_ch_str(int ch /* enum isp4fw_pipe_out_ch */){	switch ((enum isp4fw_pipe_out_ch)ch) {	case ISP4FW_ISP_PIPE_OUT_CH_PREVIEW:		return "prev";	default:		return "unknown channel";	}}