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