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