From 75dc121c3a610e4f9989ee2dfa4ad0e6e9f87b45 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 23 Aug 2022 19:34:31 +0800 Subject: [PATCH] media: rockchip: vicap support wake up buffer with mode of rdbk by isp driver in this mode,buffer wake up earlier, isp can process images earlier Signed-off-by: Zefa Chen Change-Id: I75da9ac768f17f6ebc745f57a32e6cd753f9be3e --- drivers/media/platform/rockchip/cif/capture.c | 186 ++++++++++++++++-- drivers/media/platform/rockchip/cif/dev.c | 1 + drivers/media/platform/rockchip/cif/dev.h | 2 + .../media/platform/rockchip/cif/subdev-itf.c | 68 +++++++ 4 files changed, 238 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 6d1f5f267f0a..68557de9d680 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -2312,6 +2312,99 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) return ret; } +static int rkcif_get_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) +{ + struct rkisp_rx_buf *dbufs = NULL; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!list_empty(&stream->rx_buf_head)) { + if (stream->line_int_cnt % 2) { + dbufs = list_first_entry(&stream->rx_buf_head, + struct rkisp_rx_buf, list); + if (dbufs) { + list_del(&dbufs->list); + stream->curr_buf_toisp = to_cif_rx_buf(dbufs); + } + } else { + dbufs = list_first_entry(&stream->rx_buf_head, + struct rkisp_rx_buf, list); + if (dbufs) { + list_del(&dbufs->list); + stream->next_buf_toisp = to_cif_rx_buf(dbufs); + } + } + stream->is_buf_active = true; + if (stream->lack_buf_cnt) + stream->lack_buf_cnt--; + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + if (stream->curr_buf_toisp && stream->next_buf_toisp && + stream->curr_buf_toisp != stream->next_buf_toisp) { + if (stream->line_int_cnt % 2) + stream->curr_buf_toisp = stream->next_buf_toisp; + else + stream->next_buf_toisp = stream->curr_buf_toisp; + stream->is_buf_active = true; + ret = 0; + if (stream->cifdev->rdbk_debug) + v4l2_info(&stream->cifdev->v4l2_dev, + "hold buf %x\n", + (u32)stream->next_buf_toisp->dummy.dma_addr); + } else { + stream->is_buf_active = false; + ret = -EINVAL; + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + return ret; +} + +static int rkcif_update_new_buffer_wake_up_mode_rdbk(struct rkcif_stream *stream) +{ + struct rkcif_device *dev = stream->cifdev; + struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkcif_rx_buffer *buffer = NULL; + u32 frm_addr_y; + int channel_id = stream->id; + int ret = 0; + unsigned long flags; + + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(channel_id) : + get_reg_index_of_frm1_y_addr(channel_id); + } else { + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(channel_id) : + get_dvp_reg_index_of_frm1_y_addr(channel_id); + } + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->is_buf_active) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY) + buffer = stream->curr_buf_toisp; + else if (stream->frame_phase == CIF_CSI_FRAME1_READY) + buffer = stream->next_buf_toisp; + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (buffer) { + rkcif_write_register(dev, frm_addr_y, + buffer->dummy.dma_addr); + if (dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&dev->v4l2_dev, + "rdbk update, seq %d, reg %x, buf %x\n", + stream->frame_idx - 1, + frm_addr_y, (u32)buffer->dummy.dma_addr); + } + return ret; +} + static void rkcif_assign_dummy_buffer(struct rkcif_stream *stream) { struct rkcif_device *dev = stream->cifdev; @@ -3888,6 +3981,10 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, rkcif_do_cru_reset(dev); dev->can_be_reset = false; dev->reset_work_cancel = true; + dev->early_line = 0; + dev->sensor_linetime = 0; + dev->wait_line = 0; + stream->is_line_wake_up = false; } } if (!atomic_read(&dev->pipe.stream_cnt) && dev->dummy_buf.vaddr) @@ -7276,6 +7373,46 @@ static void rkcif_line_wake_up(struct rkcif_stream *stream, int mipi_id) rkcif_buf_done_prepare(stream, active_buf, mipi_id, mode); } +static int rkcif_stop_dma_capture(struct rkcif_stream *stream); +static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) +{ + u32 mode; + struct rkcif_rx_buffer *active_buf = NULL; + struct sditf_priv *priv = NULL; + int ret = 0; + + mode = stream->line_int_cnt % 2; + if (mode) { + if (stream->curr_buf_toisp) + active_buf = stream->curr_buf_toisp; + } else { + if (stream->next_buf_toisp) + active_buf = stream->next_buf_toisp; + } + + if (!active_buf) { + v4l2_err(&stream->cifdev->v4l2_dev, + "err buffer state in %s\n", + __func__); + return; + } + + if (stream->stopping) { + stream->is_can_stop = true; + return; + } + ret = rkcif_get_new_buffer_wake_up_mode_rdbk(stream); + if (!ret) { + priv = stream->cifdev->sditf[0]; + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + active_buf->dbufs.sequence = stream->frame_idx - 1; + active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); + stream->buf_num_toisp--; + } + } +} + static void rkcif_deal_readout_time(struct rkcif_stream *stream) { struct rkcif_device *cif_dev = stream->cifdev; @@ -7378,9 +7515,12 @@ static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, if (cif_dev->inf_id == RKCIF_MIPI_LVDS) rkcif_deal_readout_time(stream); - rkcif_assign_new_buffer_pingpong_toisp(stream, - RKCIF_YUV_ADDR_STATE_UPDATE, - mipi_id); + if (!stream->is_line_wake_up) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); + else + rkcif_update_new_buffer_wake_up_mode_rdbk(stream); } static u32 rkcif_get_sof(struct rkcif_device *cif_dev) @@ -7965,7 +8105,12 @@ int rkcif_reset_notifier(struct notifier_block *nb, static void rkcif_modify_line_int(struct rkcif_stream *stream, bool en) { struct rkcif_device *cif_dev = stream->cifdev; + u32 line_intr_en = 0; + if (cif_dev->chip_id >= CHIP_RK3588_CIF) + line_intr_en = CSI_LINE_INTEN_RK3588(stream->id); + else + line_intr_en = CSI_LINE_INTEN(stream->id); if (en) { if (cif_dev->wait_line_bak != cif_dev->wait_line) { cif_dev->wait_line_bak = cif_dev->wait_line; @@ -7975,10 +8120,10 @@ static void rkcif_modify_line_int(struct rkcif_stream *stream, bool en) cif_dev->wait_line << 16 | cif_dev->wait_line); } rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_LINE_INTEN(stream->id)); + line_intr_en); } else { rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, - ~(CSI_LINE_INTEN(stream->id))); + ~line_intr_en); } } @@ -7990,6 +8135,18 @@ static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream) if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) return; + if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) && + stream->id == RKCIF_STREAM_MIPI_ID0) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } else if (cif_dev->hdr.hdr_mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } else if (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) { + if (cif_dev->wait_line != cif_dev->wait_line_cache) + cif_dev->wait_line = cif_dev->wait_line_cache; + } + if (cif_dev->wait_line && (!stream->is_line_wake_up)) { stream->is_line_wake_up = true; if (stream->frame_phase == CIF_CSI_FRAME0_READY) @@ -8003,18 +8160,6 @@ static void rkcif_detect_wake_up_mode_change(struct rkcif_stream *stream) rkcif_modify_line_int(stream, true); stream->is_line_inten = true; } - - if ((cif_dev->hdr.hdr_mode == NO_HDR || cif_dev->hdr.hdr_mode == HDR_COMPR) && - stream->id == RKCIF_STREAM_MIPI_ID0) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; - } else if (cif_dev->hdr.hdr_mode == HDR_X2 && stream->id == RKCIF_STREAM_MIPI_ID1) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; - } else if (cif_dev->hdr.hdr_mode == HDR_X3 && stream->id == RKCIF_STREAM_MIPI_ID2) { - if (cif_dev->wait_line != cif_dev->wait_line_cache) - cif_dev->wait_line = cif_dev->wait_line_cache; - } } u32 rkcif_mbus_pixelcode_to_v4l2(u32 pixelcode) @@ -8710,11 +8855,14 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream->is_finish_stop_dma = true; } } - if (intstat & CSI_LINE_INTSTAT(i)) { + if (intstat & CSI_LINE_INTSTAT_V1(i)) { stream = &cif_dev->stream[i]; if (stream->is_line_inten) { stream->line_int_cnt++; - rkcif_line_wake_up(stream, stream->id); + if (cif_dev->sditf[0] && cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) + rkcif_line_wake_up_rdbk(stream, stream->id); + else + rkcif_line_wake_up(stream, stream->id); rkcif_modify_line_int(stream, false); stream->is_line_inten = false; } diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 0d41a5234082..2ca33ecaa2d7 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1848,6 +1848,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->sditf_cnt = 0; cif_dev->is_notifier_isp = false; cif_dev->sensor_linetime = 0; + cif_dev->early_line = 0; cif_dev->rdbk_debug = 0; if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index fff850a6e5ad..6fbd7d7e9b13 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -812,6 +812,8 @@ struct rkcif_device { int rdbk_debug; int sync_type; int sditf_cnt; + u32 early_line; + int isp_runtime_max; int sensor_linetime; }; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 0463ba43a194..3202f5e03720 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -588,10 +588,12 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, { struct sditf_priv *priv = to_sditf_priv(sd); struct rkcif_device *cif_dev = priv->cif_dev; + struct rkcif_sensor_info *sensor = &cif_dev->terminal_sensor; struct rkcif_stream *stream = NULL; struct rkisp_rx_buf *dbufs; struct rkcif_rx_buffer *rx_buf = NULL; unsigned long flags; + u32 diff_time = 1000000; if (!buf) { v4l2_err(&cif_dev->v4l2_dev, "buf is NULL\n"); @@ -637,6 +639,72 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, } spin_unlock_irqrestore(&stream->vbq_lock, flags); + + if (dbufs->runtime_us && cif_dev->early_line == 0) { + u32 numerator, denominator; + u32 def_fps = 0; + int line_time = 0; + int vblank_def = 0; + int vblank_curr = 0; + + numerator = sensor->fi.interval.numerator; + denominator = sensor->fi.interval.denominator; + if (!numerator || !denominator) { + v4l2_err(&cif_dev->v4l2_dev, + "get frame interval fail, numerator %d, denominator %d\n", + numerator, denominator); + return -EINVAL; + } + def_fps = denominator / numerator; + if (!def_fps) { + v4l2_err(&cif_dev->v4l2_dev, + "get fps fail, numerator %d, denominator %d\n", + numerator, denominator); + return -EINVAL; + } + vblank_def = rkcif_get_sensor_vblank_def(cif_dev); + vblank_curr = rkcif_get_sensor_vblank(cif_dev); + if (!vblank_def || !vblank_curr) { + v4l2_err(&cif_dev->v4l2_dev, + "get vblank fail, vblank_def %d, vblank_curr %d\n", + vblank_def, vblank_curr); + return -EINVAL; + } + line_time = div_u64(1000000000, def_fps); + line_time = div_u64(line_time, vblank_def + sensor->raw_rect.height); + if (!line_time) { + v4l2_err(&cif_dev->v4l2_dev, + "get line time fail, line_time %d\n", + line_time); + return -EINVAL; + } + if (vblank_curr * line_time < 1000) + v4l2_warn(&cif_dev->v4l2_dev, + "vblank < 1ms, val %d\n", + vblank_curr * line_time); + cif_dev->isp_runtime_max = dbufs->runtime_us; + cif_dev->sensor_linetime = line_time; + cif_dev->early_line = div_u64(dbufs->runtime_us * 1000 - diff_time, line_time); + cif_dev->wait_line_cache = sensor->raw_rect.height - cif_dev->early_line; + if (cif_dev->rdbk_debug && + dbufs->sequence < 15) + v4l2_info(&cif_dev->v4l2_dev, + "%s, isp runtime %d, line time %d, early_line %d, line_intr_cnt %d, seq %d, dma_addr %x\n", + __func__, dbufs->runtime_us, line_time, + cif_dev->early_line, cif_dev->wait_line_cache, + dbufs->sequence, (u32)rx_buf->dummy.dma_addr); + } else { + if (dbufs->runtime_us > cif_dev->isp_runtime_max + cif_dev->sensor_linetime) { + cif_dev->isp_runtime_max = dbufs->runtime_us; + cif_dev->early_line = div_u64(dbufs->runtime_us * 1000 - diff_time, cif_dev->sensor_linetime); + cif_dev->wait_line_cache = sensor->raw_rect.height - cif_dev->early_line; + } + if (cif_dev->rdbk_debug && + dbufs->sequence < 15) + v4l2_info(&cif_dev->v4l2_dev, + "isp runtime %d, seq %d, dma addr %x\n", + dbufs->runtime_us, dbufs->sequence, (u32)rx_buf->dummy.dma_addr); + } return 0; }