From 992ff35c2db2a8ffc942c1028dd83f735cd0844c Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Fri, 11 Jul 2025 11:59:55 +0800 Subject: [PATCH] media: rockchip: vicap support get error info Change-Id: I61fc0834e3574876f40d563290222044550594a4 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 74 +++++++++++++++---- drivers/media/platform/rockchip/cif/dev.h | 2 + .../media/platform/rockchip/cif/mipi-csi2.c | 71 ++++++++++++++++++ .../media/platform/rockchip/cif/mipi-csi2.h | 5 ++ 4 files changed, 139 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 5659bed0cb48..8ee8030b5f9a 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -6912,20 +6912,8 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, ret = dev->pipe.close(&dev->pipe); if (ret < 0) v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret); - if (dev->hdr.hdr_mode == HDR_X2) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) { - dev->can_be_reset = true; - } - } else if (dev->hdr.hdr_mode == HDR_X3) { - if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY && - dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) { - dev->can_be_reset = true; - } - } else { + if (atomic_read(&dev->pipe.stream_cnt) == 0) dev->can_be_reset = true; - } mutex_lock(&hw_dev->dev_lock); for (i = 0; i < hw_dev->dev_num; i++) { if (atomic_read(&hw_dev->cif_dev[i]->pipe.stream_cnt) != 0) { @@ -9903,6 +9891,55 @@ void rkcif_flip_end_wait_work(struct work_struct *work) mutex_unlock(&dev->stream_lock); } +static int rkcif_get_error_info(struct rkcif_device *cif_dev, + struct rkmodule_error_info *err_info) +{ + int count = 0; + int is_dvp = (cif_dev->inf_id == RKCIF_DVP); + + memset(err_info, 0, sizeof(*err_info)); + + if (is_dvp) + count = snprintf(err_info->detail, sizeof(err_info->detail), "rkcif_dvp:"); + else + count = snprintf(err_info->detail, sizeof(err_info->detail), "rkcif_mipi%d:", cif_dev->csi_host_idx); + +#define APPEND_STAT(field) \ + do {\ + ssize_t remaining = sizeof(err_info->detail) - count;\ + if (remaining > 0) { \ + int written = snprintf(err_info->detail + count, remaining, "%lld,", cif_dev->irq_stats.field); \ + if (written >= 0) { \ + count += written; \ + } \ + } \ + } while (0) + + APPEND_STAT(bus0_err); + APPEND_STAT(bus1_err); + + if (is_dvp) { + APPEND_STAT(dvp_overflow_cnt); + APPEND_STAT(dvp_bwidth_lack_cnt); + APPEND_STAT(dvp_size_err_cnt); + } else { + APPEND_STAT(csi_overflow_cnt); + APPEND_STAT(csi_bwidth_lack_cnt); + APPEND_STAT(csi_size_err_cnt); + } + + count += snprintf(err_info->detail + count, sizeof(err_info->detail) - count, + "%lld,%lld,%lld,%lld,", + cif_dev->irq_stats.not_active_buf_cnt[0], + cif_dev->irq_stats.not_active_buf_cnt[1], + cif_dev->irq_stats.not_active_buf_cnt[2], + cif_dev->irq_stats.not_active_buf_cnt[3]); + + err_info->err_code = cif_dev->irq_stats.all_err_cnt ? BIT(0) : 0; + + return 0; +} + static int rkcif_do_reset_work(struct rkcif_device *cif_dev, enum rkmodule_reset_src reset_src); @@ -9933,6 +9970,7 @@ static long rkcif_ioctl_default(struct file *file, void *fh, u32 vblank = 0; struct rkisp_vicap_mode vicap_mode; struct v4l2_subdev *sd = NULL; + struct rkmodule_error_info *err_info; switch (cmd) { case RKCIF_CMD_GET_CSI_MEMORY_MODE: @@ -10235,6 +10273,10 @@ static long rkcif_ioctl_default(struct file *file, void *fh, else dev->is_support_get_exp = false; break; + case RKMODULE_GET_ERROR_INFO: + err_info = (struct rkmodule_error_info *)arg; + ret = rkcif_get_error_info(dev, err_info); + break; default: return -EINVAL; } @@ -14102,12 +14144,16 @@ unsigned int rkcif_irq_global(struct rkcif_device *cif_dev) v4l2_err(&cif_dev->v4l2_dev, "ERROR: AXI0 bus err intstat_glb:0x%x !!\n", intstat_glb); + cif_dev->irq_stats.bus0_err++; + cif_dev->irq_stats.all_err_cnt++; return 0; } if (cif_dev->chip_id == CHIP_RK3588_CIF && intstat_glb & SCALE_TOISP_AXI1_ERR) { v4l2_err(&cif_dev->v4l2_dev, "ERROR: AXI1 bus err intstat_glb:0x%x !!\n", intstat_glb); + cif_dev->irq_stats.bus1_err++; + cif_dev->irq_stats.all_err_cnt++; return 0; } return intstat_glb; @@ -15029,12 +15075,14 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (cif_dev->chip_id >= CHIP_RV1103B_CIF) rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, ~0x000f0000); } + cif_dev->irq_stats.all_err_cnt++; return; } if (intstat & CSI_FIFO_OVERFLOW_V1) { cif_dev->irq_stats.csi_overflow_cnt++; cif_dev->err_state |= RKCIF_ERR_OVERFLOW; + cif_dev->irq_stats.all_err_cnt++; return; } diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index ca6e0983b186..c3dbe068391e 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -398,6 +398,8 @@ struct rkcif_irq_stats { u64 frm_end_cnt[RKCIF_MAX_STREAM_MIPI]; u64 not_active_buf_cnt[RKCIF_MAX_STREAM_MIPI]; u64 trig_simult_cnt[RKCIF_MAX_STREAM_MIPI]; + u64 bus0_err; + u64 bus1_err; u64 all_err_cnt; }; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index 8258dfd669a2..9cefbbcbde04 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -641,12 +641,51 @@ static void csi2_quick_stream_off(struct csi2_dev *csi2) } } +static int csi2_get_error_info(struct csi2_dev *csi2, + struct rkmodule_error_info *err_info) +{ + int count = 0; + + memset(err_info, 0, sizeof(*err_info)); + + count = snprintf(err_info->detail, sizeof(err_info->detail), "%s:", csi2->dev_name); + +#define APPEND_STAT(field) \ + do {\ + ssize_t remaining = sizeof(err_info->detail) - count;\ + if (remaining > 0) { \ + int written = snprintf(err_info->detail + count, remaining, "%u,", csi2->err_list[field].cnt); \ + if (written >= 0) { \ + count += written; \ + } \ + } \ + } while (0) + + APPEND_STAT(RK_CSI2_ERR_SOTSYN); + APPEND_STAT(RK_CSI2_ERR_FS_FE_MIS); + APPEND_STAT(RK_CSI2_ERR_FRM_SEQ_ERR); + APPEND_STAT(RK_CSI2_ERR_CRC_ONCE); + APPEND_STAT(RK_CSI2_ERR_CRC); + APPEND_STAT(RK_CSI2_ERR_ECC2); + APPEND_STAT(RK_CSI2_ERR_CTRL); + APPEND_STAT(RK_CSI2_ERR_ULPM); + APPEND_STAT(RK_CSI2_ERR_SOT); + APPEND_STAT(RK_CSI2_ERR_ECC); + APPEND_STAT(RK_CSI2_ERR_ID); + APPEND_STAT(RK_CSI2_ERR_CODE); + + err_info->err_code = csi2->err_list[RK_CSI2_ERR_ALL].cnt ? BIT(0) : 0; + + return 0; +} + static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct csi2_dev *csi2 = sd_to_dev(sd); struct v4l2_subdev *sensor = get_remote_sensor(sd); long ret = 0; int i = 0; + struct rkmodule_error_info *err_info; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: @@ -667,6 +706,10 @@ static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg else csi2_quick_stream_off(csi2); break; + case RKMODULE_GET_ERROR_INFO: + err_info = (struct rkmodule_error_info *)arg; + ret = csi2_get_error_info(csi2, err_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -683,6 +726,7 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, struct rkcif_csi_info csi_info; int sw_dbg = 0; long ret; + struct rkmodule_error_info *err_info; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: @@ -697,6 +741,22 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, ret = rkcif_csi2_ioctl(sd, cmd, &sw_dbg); break; + case RKMODULE_GET_ERROR_INFO: + err_info = kzalloc(sizeof(*err_info), GFP_KERNEL); + if (!err_info) { + ret = -ENOMEM; + return ret; + } + + ret = rkcif_csi2_ioctl(sd, cmd, err_info); + if (!ret) { + if (copy_to_user(up, err_info, sizeof(*err_info))) { + kfree(err_info); + return -EFAULT; + } + } + kfree(err_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -960,6 +1020,7 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) char err_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; u64 cur_timestamp = ktime_get_ns(); + struct csi2_err_stats *err_list = NULL; if (!csi2_hw) { disable_irq_nosync(irq); @@ -975,26 +1036,36 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2); if (val) { if (val & CSIHOST_ERR2_PHYERR_ESC) { + err_list = &csi2->err_list[RK_CSI2_ERR_ULPM]; + err_list->cnt++; csi2_find_err_vc(val & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info); csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_PHYERR_SOTHS) { + err_list = &csi2->err_list[RK_CSI2_ERR_SOT]; + err_list->cnt++; csi2_find_err_vc((val >> 4) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info); csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_ECC_CORRECTED) { + err_list = &csi2->err_list[RK_CSI2_ERR_ECC]; + err_list->cnt++; csi2_find_err_vc((val >> 8) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info); csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_ERR_ID) { + err_list = &csi2->err_list[RK_CSI2_ERR_ID]; + err_list->cnt++; csi2_find_err_vc((val >> 12) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info); csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_PHYERR_CODEHS) { + err_list = &csi2->err_list[RK_CSI2_ERR_CODE]; + err_list->cnt++; snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) "); csi2_err_strncat(err_str, cur_str); } diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 93c4bc3fbc9b..02489e4f33d6 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -115,6 +115,11 @@ enum csi2_err { RK_CSI2_ERR_CRC, RK_CSI2_ERR_ECC2, RK_CSI2_ERR_CTRL, + RK_CSI2_ERR_ULPM, + RK_CSI2_ERR_SOT, + RK_CSI2_ERR_ECC, + RK_CSI2_ERR_ID, + RK_CSI2_ERR_CODE, RK_CSI2_ERR_ALL, RK_CSI2_ERR_MAX };