From af37f2152d1bdc8e2859810c51bc441bf67e780d Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Fri, 21 Jul 2023 10:55:50 +0800 Subject: [PATCH] media: rockchip: vicap fixes suspend/resume Signed-off-by: Zefa Chen Change-Id: I1d7e7d8f521fca3bda4f3599a7b34233e1a94bc2 Signed-off-by: Mingwei Yan --- drivers/media/platform/rockchip/cif/capture.c | 359 ++++++++++++++++-- drivers/media/platform/rockchip/cif/dev.c | 19 +- drivers/media/platform/rockchip/cif/dev.h | 11 + drivers/media/platform/rockchip/cif/hw.c | 37 ++ drivers/media/platform/rockchip/cif/regs.h | 9 + .../media/platform/rockchip/cif/subdev-itf.c | 48 +++ .../media/platform/rockchip/cif/subdev-itf.h | 1 + 7 files changed, 451 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index e45139b21c7a..7bc7ac932b00 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1913,6 +1913,9 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } else { rkcif_write_register(dev, frm0_addr_y, buff_addr_y); } + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } if (!stream->next_buf_toisp) { @@ -1938,6 +1941,9 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } else { rkcif_write_register(dev, frm1_addr_y, buff_addr_y); } + } else { + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -1970,10 +1976,7 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, spin_lock_irqsave(&stream->vbq_lock, flags); if (!list_empty(&stream->rx_buf_head)) { if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - if (stream->curr_buf_toisp == stream->next_buf_toisp) - active_buf = NULL; - else - active_buf = stream->curr_buf_toisp; + active_buf = stream->curr_buf_toisp; buffer = list_first_entry(&stream->rx_buf_head, struct rkcif_rx_buffer, list); @@ -1999,15 +2002,13 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, rkcif_rdbk_frame_end_toisp(stream, active_buf); } } else { - rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (active_buf) + rkcif_s_rx_buffer(dev, &active_buf->dbufs); if (dev->is_support_tools && stream->tools_vdev) rkcif_rdbk_with_tools(stream, active_buf); } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { - if (stream->curr_buf_toisp == stream->next_buf_toisp) - active_buf = NULL; - else - active_buf = stream->next_buf_toisp; + active_buf = stream->next_buf_toisp; buffer = list_first_entry(&stream->rx_buf_head, struct rkcif_rx_buffer, list); if (buffer) { @@ -2032,7 +2033,8 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, rkcif_rdbk_frame_end_toisp(stream, active_buf); } } else { - rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (active_buf) + rkcif_s_rx_buffer(dev, &active_buf->dbufs); if (dev->is_support_tools && stream->tools_vdev) rkcif_rdbk_with_tools(stream, active_buf); } @@ -2068,6 +2070,18 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, "stream[%d] hold buf %x\n", stream->id, (u32)stream->next_buf_toisp->dummy.dma_addr); + } else { + if (stream->curr_buf_toisp) + active_buf = stream->curr_buf_toisp; + else if (stream->next_buf_toisp) + active_buf = stream->next_buf_toisp; + + stream->next_buf_toisp = NULL; + stream->curr_buf_toisp = NULL; + } + if (stream->lack_buf_cnt == 2) { + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + rkcif_stop_dma_capture(stream); } if (active_buf) { if (stream->frame_idx == 1) @@ -2078,8 +2092,6 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, stream->last_frame_idx = stream->frame_idx; if (dev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(dev, &active_buf->dbufs); - if (dev->is_support_tools && stream->tools_vdev) - rkcif_rdbk_with_tools(stream, active_buf); atomic_dec(&stream->buf_cnt); } else { rkcif_rdbk_frame_end_toisp(stream, active_buf); @@ -2091,8 +2103,8 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, stream->id, stream->frame_idx - 1); } - if (dev->is_support_tools && stream->tools_vdev && stream->curr_buf_toisp) - rkcif_rdbk_with_tools(stream, stream->curr_buf_toisp); + if (dev->is_support_tools && stream->tools_vdev && active_buf) + rkcif_rdbk_with_tools(stream, active_buf); } out_get_buf: @@ -2152,6 +2164,7 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) int frame_phase = 0; int frame_phase_next = 0; bool is_early_update = false; + bool is_dual_update = false; if (stream->curr_buf_toisp != stream->next_buf_toisp) { if (dev->rdbk_debug > 2 && @@ -2169,19 +2182,19 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) vblank_ns = vblank * dev->sensor_linetime; cur_time = ktime_get_ns(); + frame_phase = stream->frame_phase & CIF_CSI_FRAME0_READY ? + CIF_CSI_FRAME0_READY : CIF_CSI_FRAME1_READY; + frame_phase_next = stream->frame_phase & CIF_CSI_FRAME0_READY ? + CIF_CSI_FRAME1_READY : CIF_CSI_FRAME0_READY; if (dev->chip_id > CHIP_RK3568_CIF && dev->hdr.hdr_mode == NO_HDR && cur_time - stream->readout.fe_timestamp < (vblank_ns - 500000) && stream->lack_buf_cnt == 2 && - stream->frame_idx > stream->last_frame_idx) { + stream->frame_idx > stream->last_frame_idx) is_early_update = true; - frame_phase = stream->frame_phase & CIF_CSI_FRAME0_READY ? - CIF_CSI_FRAME1_READY : CIF_CSI_FRAME0_READY; - frame_phase_next = stream->frame_phase & CIF_CSI_FRAME0_READY ? - CIF_CSI_FRAME0_READY : CIF_CSI_FRAME1_READY; - } else { - frame_phase = stream->frame_phase; - } + else if (!stream->dma_en) + is_dual_update = true; + if (dev->rdbk_debug > 2 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2295,6 +2308,29 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) } else { rkcif_write_register(dev, frm_addr_y, buff_addr_y); } + } else if (is_dual_update) { + if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || + mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || + mbus_cfg->type == V4L2_MBUS_CCP2) { + frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ? + get_reg_index_of_frm0_y_addr(stream->id) : + get_reg_index_of_frm1_y_addr(stream->id); + } else { + frm_addr_y = frame_phase_next & CIF_CSI_FRAME0_READY ? + get_dvp_reg_index_of_frm0_y_addr(stream->id) : + get_dvp_reg_index_of_frm1_y_addr(stream->id); + } + if (frame_phase == CIF_CSI_FRAME0_READY) + stream->next_buf_toisp = stream->curr_buf_toisp; + else + stream->curr_buf_toisp = stream->next_buf_toisp; + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } } } @@ -2675,7 +2711,8 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } else { dbufs = &stream->curr_buf_toisp->dbufs; } - rkcif_s_rx_buffer(dev, dbufs); + if (dbufs) + rkcif_s_rx_buffer(dev, dbufs); if (stream->curr_buf && stream->frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = NULL; if (stream->buf_replace_cnt) @@ -4690,12 +4727,14 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) buf->dbufs.is_uncompact = false; else buf->dbufs.is_uncompact = true; - if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) { + if (priv && i == 0) { buf->dbufs.is_first = true; - rkcif_s_rx_buffer(dev, &buf->dbufs); + if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) + rkcif_s_rx_buffer(dev, &buf->dbufs); } i++; if (!dev->is_thunderboot && i >= buf_num) { + priv->buf_num = buf_num; break; } else if (i >= RKISP_VICAP_BUF_CNT_MAX) { priv->buf_num = i; @@ -10263,6 +10302,247 @@ static bool rkcif_check_buffer_prepare(struct rkcif_stream *stream) return is_update; } +static int rkcif_subdevs_set_power(struct rkcif_device *cif_dev, int on) +{ + struct sditf_priv *priv = cif_dev->sditf[0]; + int ret = 0; + int i = 0; + + if (cif_dev->terminal_sensor.sd) + ret = v4l2_subdev_call(cif_dev->terminal_sensor.sd, + core, s_power, on); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, + s_power, on); + } + } + return ret; +} + +static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) +{ + struct rkcif_pipeline *p = &cif_dev->pipe; + struct sditf_priv *priv = cif_dev->sditf[0]; + int i = 0; + int ret = 0; + + for (i = 0; i < p->num_subdevs; i++) { + ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + if (ret) + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s:stream %s subdev:%s failed\n", + __func__, on ? "on" : "off", p->subdevs[i]->name); + } + + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) { + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, video, s_stream, on); + if (ret) + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s:stream %s subdev:%s failed\n", + __func__, on ? "on" : "off", + cif_dev->sditf[i]->sensor_sd->name); + } + } + } + return ret; +} + +int rkcif_stream_suspend(struct rkcif_device *cif_dev, int mode) +{ + struct rkcif_stream *stream = NULL; + struct rkcif_resume_info *resume_info = &cif_dev->reset_work.resume_info; + struct sditf_priv *priv = cif_dev->sditf[0]; + int ret = 0; + int i = 0; + int sof_cnt = 0; + int on = 0; + int suspend_cnt = 0; + + mutex_lock(&cif_dev->stream_lock); + + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && mode == RKCIF_RESUME_CIF) + goto out_suspend; + + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + stream = &cif_dev->stream[i]; + + if (stream->state == RKCIF_STATE_STREAMING) { + suspend_cnt++; + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "stream[%d] stopping\n", stream->id); + if (stream->dma_en) { + stream->stopping = true; + ret = wait_event_timeout(stream->wq_stopped, + stream->state != RKCIF_STATE_STREAMING, + msecs_to_jiffies(500)); + if (!ret) { + rkcif_stream_stop(stream); + stream->stopping = false; + } + } else { + rkcif_stream_stop(stream); + } + + if (stream->id == RKCIF_STREAM_MIPI_ID0) { + sof_cnt = rkcif_get_sof(cif_dev); + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s: stream[%d] sync frmid & csi_sof, frm_id:%d, csi_sof:%d\n", + __func__, + stream->id, + stream->frame_idx, + sof_cnt); + + resume_info->frm_sync_seq = stream->frame_idx; + } + + stream->state = RKCIF_STATE_RESET_IN_STREAMING; + stream->is_fs_fe_not_paired = false; + stream->fs_cnt_in_single_frame = 0; + + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s stop stream[%d] in streaming, frm_id:%d, csi_sof:%d\n", + __func__, stream->id, stream->frame_idx, rkcif_get_sof(cif_dev)); + + } + } + + rkcif_subdevs_set_power(cif_dev, on); + + if (suspend_cnt == 0) + goto out_suspend; + + rkcif_subdevs_set_stream(cif_dev, on); + +out_suspend: + mutex_unlock(&cif_dev->stream_lock); + return 0; +} + +int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) +{ + struct rkcif_stream *stream = NULL; + struct sditf_priv *priv = cif_dev->sditf[0]; + int ret = 0; + int i = 0; + u32 capture_mode = 0; + int on = 0; + int resume_cnt = 0; + unsigned long flags; + + mutex_lock(&cif_dev->stream_lock); + + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) + capture_mode = RKCIF_STREAM_MODE_TOISP; + else if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) + capture_mode = RKCIF_STREAM_MODE_TOISP_RDBK; + else + capture_mode = RKCIF_STREAM_MODE_CAPTURE; + if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && mode == RKCIF_RESUME_CIF) + goto out_resume; + + for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { + stream = &cif_dev->stream[i]; + if (stream->state != RKCIF_STATE_RESET_IN_STREAMING) + continue; + + stream->fs_cnt_in_single_frame = 0; + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ) { + if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { + if (stream->curr_buf == stream->next_buf) { + if (stream->curr_buf) + list_add_tail(&stream->curr_buf->queue, &stream->buf_head); + } else { + if (stream->curr_buf) + list_add_tail(&stream->curr_buf->queue, &stream->buf_head); + if (stream->next_buf) + list_add_tail(&stream->next_buf->queue, &stream->buf_head); + } + stream->curr_buf = NULL; + stream->next_buf = NULL; + } + } else { + if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE) { + if (stream->curr_buf_toisp == stream->next_buf_toisp) { + if (stream->curr_buf_toisp) + list_add_tail(&stream->curr_buf_toisp->list, &stream->rx_buf_head); + } else { + if (stream->curr_buf_toisp) + list_add_tail(&stream->curr_buf_toisp->list, &stream->rx_buf_head); + if (stream->next_buf_toisp) + list_add_tail(&stream->next_buf_toisp->list, &stream->rx_buf_head); + } + stream->curr_buf_toisp = NULL; + stream->next_buf_toisp = NULL; + } else { + if (stream->curr_buf_toisp == stream->next_buf_toisp) { + if (stream->curr_buf_toisp) + list_add_tail(&stream->curr_buf_toisp->list, &stream->rx_buf_head); + } else { + if (stream->curr_buf_toisp) + list_add_tail(&stream->curr_buf_toisp->list, &stream->rx_buf_head); + if (stream->next_buf_toisp) + list_add_tail(&stream->next_buf_toisp->list, &stream->rx_buf_head); + } + stream->curr_buf_toisp = NULL; + stream->next_buf_toisp = NULL; + } + } + + spin_unlock_irqrestore(&stream->vbq_lock, flags); + + if (capture_mode == RKCIF_STREAM_MODE_TOISP) + sditf_change_to_online(priv); + else + sditf_disable_immediately(priv); + + if (!stream->total_buf_num && priv && + (capture_mode == RKCIF_STREAM_MODE_TOISP_RDBK || + (capture_mode == RKCIF_STREAM_MODE_TOISP && + ((priv->hdr_cfg.hdr_mode == HDR_X2 && stream->id == 0) || + (priv->hdr_cfg.hdr_mode == HDR_X3 && (stream->id == 0 || stream->id == 1)))))) + rkcif_init_rx_buf(stream, 1); + + stream->lack_buf_cnt = 0; + if (cif_dev->active_sensor && + (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) + ret = rkcif_csi_stream_start(stream, capture_mode); + else + ret = rkcif_stream_start(stream, capture_mode); + if (ret) + v4l2_err(&cif_dev->v4l2_dev, "%s:resume stream[%d] failed\n", + __func__, stream->id); + + resume_cnt++; + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "resume stream[%d], frm_idx:%d, csi_sof:%d\n", + stream->id, stream->frame_idx, + rkcif_get_sof(cif_dev)); + } + + on = 1; + + rkcif_subdevs_set_power(cif_dev, on); + + if (resume_cnt == 0) + goto out_resume; + + rkcif_subdevs_set_stream(cif_dev, on); + + if (cif_dev->chip_id < CHIP_RK3588_CIF) + rkcif_start_luma(&cif_dev->luma_vdev, + cif_dev->stream[RKCIF_STREAM_MIPI_ID0].cif_fmt_in); +out_resume: + mutex_unlock(&cif_dev->stream_lock); + return 0; +} + void rkcif_err_print_work(struct work_struct *work) { struct rkcif_err_state_work *err_state_work = container_of(work, @@ -10322,10 +10602,18 @@ void rkcif_err_print_work(struct work_struct *work) v4l2_err(&dev->v4l2_dev, "stream[3], frm0/frm1 end simultaneously,frm id:%d, cnt %llu\n", dev->stream[3].frame_idx, dev->irq_stats.trig_simult_cnt[3]); - if (err_state & RKCIF_ERR_SIZE) - v4l2_err(&dev->v4l2_dev, - "ERROR: csi size err, intstat:0x%x, lastline:0x%x, cnt %llu\n", - intstat, lastline, dev->irq_stats.csi_size_err_cnt); + if (err_state & RKCIF_ERR_SIZE) { + if (dev->chip_id >= CHIP_RK3588_CIF) + v4l2_err(&dev->v4l2_dev, + "ERROR: csi size err, intstat:0x%x, size:0x%x,0x%x,0x%x,0x%x, cnt %llu\n", + intstat, err_state_work->size_id0, err_state_work->size_id1, + err_state_work->size_id2, err_state_work->size_id3, + dev->irq_stats.csi_size_err_cnt); + else + v4l2_err(&dev->v4l2_dev, + "ERROR: csi size err, intstat:0x%x, lastline:0x%x, cnt %llu\n", + intstat, lastline, dev->irq_stats.csi_size_err_cnt); + } if (err_state & RKCIF_ERR_OVERFLOW) v4l2_err(&dev->v4l2_dev, "ERROR: csi fifo overflow, intstat:0x%x, lastline:0x%x, cnt %llu\n", @@ -10379,13 +10667,22 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (intstat) { rkcif_write_register(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, intstat); v4l2_dbg(2, rkcif_debug, &cif_dev->v4l2_dev, - "intstat 0x%x\n", - intstat); + "intstat 0x%x\n", intstat); } else { return; } if (intstat & CSI_SIZE_ERR) { + if (cif_dev->chip_id >= CHIP_RK3588_CIF) { + cif_dev->err_state_work.size_id0 = rkcif_read_register(cif_dev, + CIF_REG_MIPI_FRAME_SIZE_ID0); + cif_dev->err_state_work.size_id1 = rkcif_read_register(cif_dev, + CIF_REG_MIPI_FRAME_SIZE_ID1); + cif_dev->err_state_work.size_id2 = rkcif_read_register(cif_dev, + CIF_REG_MIPI_FRAME_SIZE_ID2); + cif_dev->err_state_work.size_id3 = rkcif_read_register(cif_dev, + CIF_REG_MIPI_FRAME_SIZE_ID3); + } cif_dev->irq_stats.csi_size_err_cnt++; cif_dev->err_state |= RKCIF_ERR_SIZE; rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000); diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 6f41ab36a23a..20bfc14cea18 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -2211,6 +2211,21 @@ static int rkcif_plat_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused rkcif_runtime_prepare(struct device *dev) +{ + struct rkcif_device *cif_dev = dev_get_drvdata(dev); + + rkcif_stream_suspend(cif_dev, RKCIF_RESUME_CIF); + return 0; +} + +static void __maybe_unused rkcif_runtime_complete(struct device *dev) +{ + struct rkcif_device *cif_dev = dev_get_drvdata(dev); + + rkcif_stream_resume(cif_dev, RKCIF_RESUME_CIF); +} + static int __maybe_unused rkcif_runtime_suspend(struct device *dev) { struct rkcif_device *cif_dev = dev_get_drvdata(dev); @@ -2281,8 +2296,8 @@ late_initcall(rkcif_clr_unready_dev); #endif static const struct dev_pm_ops rkcif_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + .prepare = rkcif_runtime_prepare, + .complete = rkcif_runtime_complete, SET_RUNTIME_PM_OPS(rkcif_runtime_suspend, rkcif_runtime_resume, NULL) }; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index d995f58ef99f..573c25a45083 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -792,6 +792,15 @@ struct rkcif_err_state_work { u32 intstat; u32 lastline; u32 lastpixel; + u32 size_id0; + u32 size_id1; + u32 size_id2; + u32 size_id3; +}; + +enum rkcif_resume_user { + RKCIF_RESUME_CIF, + RKCIF_RESUME_ISP, }; /* @@ -968,5 +977,7 @@ void rkcif_rockit_dev_init(struct rkcif_device *dev); void rkcif_rockit_dev_deinit(void); void rkcif_err_print_work(struct work_struct *work); +int rkcif_stream_suspend(struct rkcif_device *cif_dev, int mode); +int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode); #endif diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index bf5653961509..516a0bc692ca 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -699,6 +699,10 @@ static const struct cif_reg rk3588_cif_regs[] = { [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID1), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID2), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID3), + [CIF_REG_MIPI_FRAME_SIZE_ID0] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID0), + [CIF_REG_MIPI_FRAME_SIZE_ID1] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID1), + [CIF_REG_MIPI_FRAME_SIZE_ID2] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID2), + [CIF_REG_MIPI_FRAME_SIZE_ID3] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID3), [CIF_REG_MIPI_ON_PAD] = CIF_REG(CSI_MIPI0_ON_PAD), [CIF_REG_GLB_CTRL] = CIF_REG(GLB_CTRL), @@ -823,6 +827,10 @@ static const struct cif_reg rv1106_cif_regs[] = { [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID1), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID2), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID3), + [CIF_REG_MIPI_FRAME_SIZE_ID0] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID0), + [CIF_REG_MIPI_FRAME_SIZE_ID1] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID1), + [CIF_REG_MIPI_FRAME_SIZE_ID2] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID2), + [CIF_REG_MIPI_FRAME_SIZE_ID3] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID3), [CIF_REG_MIPI_ON_PAD] = CIF_REG(CSI_MIPI0_ON_PAD), [CIF_REG_LVDS_ID0_CTRL0] = CIF_REG(CIF_LVDS0_ID0_CTRL0), [CIF_REG_LVDS_ID1_CTRL0] = CIF_REG(CIF_LVDS0_ID1_CTRL0), @@ -942,6 +950,10 @@ static const struct cif_reg rk3562_cif_regs[] = { [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID1), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID2), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG(CSI_MIPI0_EFFECT_CODE_ID3), + [CIF_REG_MIPI_FRAME_SIZE_ID0] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID0), + [CIF_REG_MIPI_FRAME_SIZE_ID1] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID1), + [CIF_REG_MIPI_FRAME_SIZE_ID2] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID2), + [CIF_REG_MIPI_FRAME_SIZE_ID3] = CIF_REG(CSI_MIPI0_FRAME_SIZE_ID3), [CIF_REG_MIPI_ON_PAD] = CIF_REG(CSI_MIPI0_ON_PAD), [CIF_REG_GLB_CTRL] = CIF_REG(GLB_CTRL), @@ -1538,7 +1550,32 @@ static int __maybe_unused rkcif_runtime_resume(struct device *dev) return 0; } +static int __maybe_unused rkcif_sleep_suspend(struct device *dev) +{ + struct rkcif_hw *cif_hw = dev_get_drvdata(dev); + + rkcif_disable_sys_clk(cif_hw); + + return pinctrl_pm_select_sleep_state(dev); +} + +static int __maybe_unused rkcif_sleep_resume(struct device *dev) +{ + struct rkcif_hw *cif_hw = dev_get_drvdata(dev); + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret < 0) + return ret; + rkcif_enable_sys_clk(cif_hw); + rkcif_hw_soft_reset(cif_hw, true); + + return 0; +} + static const struct dev_pm_ops rkcif_plat_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rkcif_sleep_suspend, + rkcif_sleep_resume) SET_RUNTIME_PM_OPS(rkcif_runtime_suspend, rkcif_runtime_resume, NULL) }; diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index fccd0057e425..68bc6ef30a79 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -145,6 +145,10 @@ enum cif_reg_index { CIF_REG_LVDS_ID1_CTRL0, CIF_REG_LVDS_ID2_CTRL0, CIF_REG_LVDS_ID3_CTRL0, + CIF_REG_MIPI_FRAME_SIZE_ID0, + CIF_REG_MIPI_FRAME_SIZE_ID1, + CIF_REG_MIPI_FRAME_SIZE_ID2, + CIF_REG_MIPI_FRAME_SIZE_ID3, CIF_REG_MIPI_ON_PAD, CIF_REG_Y_STAT_CONTROL, @@ -421,6 +425,11 @@ enum cif_reg_index { #define CSI_MIPI0_EFFECT_CODE_ID3 0x1B8 #define CSI_MIPI0_ON_PAD 0x1BC +#define CSI_MIPI0_FRAME_SIZE_ID0 0x1C0 +#define CSI_MIPI0_FRAME_SIZE_ID1 0x1C4 +#define CSI_MIPI0_FRAME_SIZE_ID2 0x1C8 +#define CSI_MIPI0_FRAME_SIZE_ID3 0x1CC + /* RV1106 CONTROL Registers Offset */ #define CIF_LVDS0_ID0_CTRL0 0x1D0 #define CIF_LVDS0_ID1_CTRL0 0x1D4 diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 01aefd4e5988..f2a657668b21 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -327,6 +327,7 @@ static void sditf_reinit_mode(struct sditf_priv *priv, struct rkisp_vicap_mode * __func__, mode->rdbk_mode, mode->name, priv->toisp_inf.link_mode); } +static void sditf_channel_disable(struct sditf_priv *priv, int user); static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct sditf_priv *priv = to_sditf_priv(sd); @@ -336,11 +337,14 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct v4l2_subdev *sensor_sd; int *pbuf_num = NULL; int ret = 0; + int *on = NULL; switch (cmd) { case RKISP_VICAP_CMD_MODE: mode = (struct rkisp_vicap_mode *)arg; + mutex_lock(&cif_dev->stream_lock); memcpy(&priv->mode, mode, sizeof(*mode)); + mutex_unlock(&cif_dev->stream_lock); sditf_reinit_mode(priv, &priv->mode); if (priv->is_combine_mode) mode->input.merge_num = cif_dev->sditf_cnt; @@ -363,6 +367,22 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return v4l2_subdev_call(sensor_sd, core, ioctl, cmd, arg); } break; + case RKISP_VICAP_CMD_QUICK_STREAM: + on = (int *)arg; + if (*on) { + rkcif_stream_resume(cif_dev, RKCIF_RESUME_ISP); + } else { + if (priv->toisp_inf.link_mode == TOISP0) { + sditf_channel_disable(priv, 0); + } else if (priv->toisp_inf.link_mode == TOISP1) { + sditf_channel_disable(priv, 1); + } else if (priv->toisp_inf.link_mode == TOISP_UNITE) { + sditf_channel_disable(priv, 0); + sditf_channel_disable(priv, 1); + } + rkcif_stream_suspend(cif_dev, RKCIF_RESUME_ISP); + } + break; default: break; } @@ -382,6 +402,7 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, struct rkmodule_hdr_cfg *hdr_cfg; int buf_num; int ret = 0; + int on; switch (cmd) { case RKISP_VICAP_CMD_MODE: @@ -414,6 +435,11 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, } ret = sditf_ioctl(sd, cmd, hdr_cfg); return ret; + case RKISP_VICAP_CMD_QUICK_STREAM: + if (copy_from_user(&on, up, sizeof(int))) + return -EFAULT; + ret = sditf_ioctl(sd, cmd, &on); + return ret; default: break; } @@ -605,6 +631,21 @@ void sditf_change_to_online(struct sditf_priv *priv) cif_dev->wait_line_bak = 0; } +void sditf_disable_immediately(struct sditf_priv *priv) +{ + struct rkcif_device *cif_dev = priv->cif_dev; + u32 ctrl_val = 0x10101; + + if (priv->toisp_inf.link_mode == TOISP0) { + rkcif_write_register_and(cif_dev, CIF_REG_TOISP0_CTRL, ~ctrl_val); + } else if (priv->toisp_inf.link_mode == TOISP1) { + rkcif_write_register_and(cif_dev, CIF_REG_TOISP1_CTRL, ~ctrl_val); + } else if (priv->toisp_inf.link_mode == TOISP_UNITE) { + rkcif_write_register_and(cif_dev, CIF_REG_TOISP0_CTRL, ~ctrl_val); + rkcif_write_register_and(cif_dev, CIF_REG_TOISP1_CTRL, ~ctrl_val); + } +} + static void sditf_check_capture_mode(struct rkcif_device *cif_dev) { struct rkcif_device *dev = NULL; @@ -828,6 +869,10 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, if (!is_free && (!dbufs->is_switch)) { list_add_tail(&rx_buf->list, &stream->rx_buf_head); rkcif_assign_check_buffer_update_toisp(stream); + if (!stream->dma_en) { + stream->to_en_dma = RKCIF_DMAEN_BY_ISP; + rkcif_enable_dma_capture(stream, true); + } if (cif_dev->rdbk_debug) { u32 offset = 0; @@ -855,6 +900,9 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, } spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (!cif_dev->is_thunderboot) + return 0; + if (dbufs->runtime_us && cif_dev->early_line == 0) { if (!cif_dev->sensor_linetime) cif_dev->sensor_linetime = rkcif_get_linetime(stream); diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.h b/drivers/media/platform/rockchip/cif/subdev-itf.h index 1c917f2f5e92..58c63094a3c8 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.h +++ b/drivers/media/platform/rockchip/cif/subdev-itf.h @@ -84,5 +84,6 @@ struct sditf_priv { extern struct platform_driver rkcif_subdev_driver; void sditf_change_to_online(struct sditf_priv *priv); +void sditf_disable_immediately(struct sditf_priv *priv); #endif