From 6a556c2b9e5db4bda5f47695b99b2ed11561920d Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Thu, 17 Aug 2023 21:14:07 +0800 Subject: [PATCH] media: rockchip: vicap: resume/suspend with rtt Signed-off-by: Zefa Chen Change-Id: Ic45894930f97eb8b4e32fc202630f88a5f6e67be --- drivers/media/platform/rockchip/cif/capture.c | 160 ++++++++++++++++-- drivers/media/platform/rockchip/cif/dev.c | 30 +++- drivers/media/platform/rockchip/cif/dev.h | 12 ++ .../media/platform/rockchip/cif/subdev-itf.c | 2 +- 4 files changed, 187 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index bf2266ff12c5..539380e6af4f 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "dev.h" #include "mipi-csi2.h" @@ -2074,9 +2075,16 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, stream->next_buf_toisp = NULL; stream->curr_buf_toisp = NULL; } - if (stream->lack_buf_cnt == 2) { + if (stream->lack_buf_cnt == 2 || stream->is_single_cap) { stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; rkcif_stop_dma_capture(stream); + stream->is_single_cap = false; + if ((dev->hdr.hdr_mode == NO_HDR && atomic_read(&dev->streamoff_cnt) == 1) || + (dev->hdr.hdr_mode == HDR_X2 && atomic_read(&dev->streamoff_cnt) == 2) || + (dev->hdr.hdr_mode == HDR_X3 && atomic_read(&dev->streamoff_cnt) == 3)) { + dev->sensor_work.on = 0; + schedule_work(&dev->sensor_work.work); + } } if (active_buf) { if (stream->frame_idx == 1) @@ -5057,8 +5065,10 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, } } mutex_unlock(&hw_dev->dev_lock); - if (dev->can_be_reset && dev->chip_id >= CHIP_RK3588_CIF) + if (dev->can_be_reset && dev->chip_id >= CHIP_RK3588_CIF) { rkcif_do_soft_reset(dev); + atomic_set(&dev->streamoff_cnt, 0); + } if (dev->can_be_reset && can_reset) { dev->can_be_reset = false; dev->reset_work_cancel = true; @@ -6610,6 +6620,7 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) stream->buf_owner = 0; stream->buf_replace_cnt = 0; stream->is_stop_capture = false; + stream->is_single_cap = false; atomic_set(&stream->buf_cnt, 0); } @@ -9764,6 +9775,7 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) if (stream->buf_owner == RKCIF_DMAEN_BY_ISP) stream->buf_owner = RKCIF_DMAEN_BY_ISP_TO_VICAP; + atomic_dec(&cif_dev->streamoff_cnt); if (stream->dma_en) { stream->dma_en |= stream->to_en_dma; stream->to_en_dma = 0; @@ -9834,7 +9846,7 @@ static int rkcif_stop_dma_capture(struct rkcif_stream *stream) return -EINVAL; stream->dma_en &= ~stream->to_stop_dma; - + atomic_inc(&cif_dev->streamoff_cnt); if (stream->dma_en != 0) { if (stream->dma_en & RKCIF_DMAEN_BY_ISP) stream->buf_owner = RKCIF_DMAEN_BY_ISP; @@ -10221,6 +10233,72 @@ static bool rkcif_check_buffer_prepare(struct rkcif_stream *stream) return is_update; } +static bool rkcif_check_single_dev_stream_on(struct rkcif_hw *hw) +{ + struct rkcif_device *cif_dev = NULL; + struct rkcif_stream *stream = NULL; + int i = 0, j = 0; + int stream_cnt = 0; + + if (hw->dev_num == 1) + return true; + for (i = 0; i < hw->dev_num; i++) { + cif_dev = hw->cif_dev[i]; + for (j = 0; j < RKCIF_MAX_STREAM_MIPI; i++) { + stream = &cif_dev->stream[j]; + if (stream->state == RKCIF_STATE_STREAMING || + stream->state == RKCIF_STATE_RESET_IN_STREAMING) { + stream_cnt++; + break; + } + } + } + if (stream_cnt > 1) + return false; + return true; +} + +static void rkcif_get_resmem_head(struct rkcif_device *cif_dev) +{ + void *resmem_va = phys_to_virt(cif_dev->resmem_pa); + struct rkisp_thunderboot_resmem_head *head = NULL; + int size = 0; + int offset = 0; + int ret = 0; + int cam_idx = 0; + char cam_idx_str[3] = {0}; + + cif_dev->resume_mode = RKISP_RTT_MODE_NORMAL; + if (!cif_dev->is_thunderboot && !cif_dev->is_rtt_suspend) + return; + strscpy(cam_idx_str, cif_dev->terminal_sensor.sd->name + 1, 2); + cam_idx_str[2] = '\0'; + ret = kstrtoint(cam_idx_str, 0, &cam_idx); + if (ret) { + v4l2_err(&cif_dev->v4l2_dev, + "get camera index fail\n"); + return; + } + + if (cif_dev->chip_id == CHIP_RV1106_CIF) { + size = sizeof(struct rkisp32_thunderboot_resmem_head); + offset = size * cam_idx; + } + + if (size && size < cif_dev->resmem_size) { + dma_sync_single_for_cpu(cif_dev->dev, cif_dev->resmem_addr + offset, + size, DMA_FROM_DEVICE); + if (cif_dev->chip_id == CHIP_RV1106_CIF) { + struct rkisp32_thunderboot_resmem_head *tmp = resmem_va + offset; + + head = &tmp->head; + cif_dev->resume_mode = head->rtt_mode; + } + } + v4l2_err(&cif_dev->v4l2_dev, + "get camera index %02x, resume_mode 0x%x\n", cam_idx, cif_dev->resume_mode); +} + static int rkcif_subdevs_set_power(struct rkcif_device *cif_dev, int on) { struct sditf_priv *priv = cif_dev->sditf[0]; @@ -10240,19 +10318,45 @@ static int rkcif_subdevs_set_power(struct rkcif_device *cif_dev, int on) return ret; } +static void rkcif_sensor_quick_streaming_cb(void *data) +{ + struct v4l2_subdev *subdevs = (struct v4l2_subdev *)data; + int on = 1; + + v4l2_subdev_call(subdevs, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); +} + static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) { struct rkcif_pipeline *p = &cif_dev->pipe; + struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; 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 (p->subdevs[i] == terminal_sensor->sd && cif_dev->is_rtt_suspend) { + if (!rk_tb_mcu_is_done() && on) { + cif_dev->tb_client.data = p->subdevs[i]; + cif_dev->tb_client.cb = rkcif_sensor_quick_streaming_cb; + rk_tb_client_register_cb(&cif_dev->tb_client); + } else { + ret = v4l2_subdev_call(p->subdevs[i], core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + if (ret) + v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, + "%s:quick stream %s subdev:%s failed\n", + __func__, on ? "on" : "off", + p->subdevs[i]->name); + } + } else { + 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) { @@ -10329,7 +10433,8 @@ int rkcif_stream_suspend(struct rkcif_device *cif_dev, int mode) } } - rkcif_subdevs_set_power(cif_dev, on); + if (!cif_dev->resume_mode) + rkcif_subdevs_set_power(cif_dev, on); if (suspend_cnt == 0) goto out_suspend; @@ -10351,15 +10456,34 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) int on = 0; int resume_cnt = 0; unsigned long flags; + bool is_single_dev = false; 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) + rkcif_get_resmem_head(cif_dev); + is_single_dev = rkcif_check_single_dev_stream_on(cif_dev->hw_dev); + if (cif_dev->resume_mode == RKISP_RTT_MODE_ONE_FRAME) { capture_mode = RKCIF_STREAM_MODE_TOISP_RDBK; - else - capture_mode = RKCIF_STREAM_MODE_CAPTURE; + if (priv) + priv->mode.rdbk_mode = RKISP_VICAP_RDBK_AUTO; + } else if (cif_dev->resume_mode == RKISP_RTT_MODE_MULTI_FRAME) { + if (is_single_dev) { + capture_mode = RKCIF_STREAM_MODE_TOISP; + if (priv) + priv->mode.rdbk_mode = RKISP_VICAP_ONLINE; + } else { + capture_mode = RKCIF_STREAM_MODE_TOISP_RDBK; + if (priv) + priv->mode.rdbk_mode = RKISP_VICAP_RDBK_AUTO; + } + } else { + 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; @@ -10369,6 +10493,8 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) continue; stream->fs_cnt_in_single_frame = 0; + if (cif_dev->resume_mode == RKISP_RTT_MODE_ONE_FRAME) + stream->is_single_cap = true; 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) { @@ -10425,6 +10551,8 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) ((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); + if (priv && cif_dev->resume_mode == RKISP_RTT_MODE_MULTI_FRAME && stream->total_buf_num) + rkcif_init_rx_buf(stream, priv->buf_num); stream->lack_buf_cnt = 0; if (cif_dev->active_sensor && @@ -10447,11 +10575,13 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) on = 1; - rkcif_subdevs_set_power(cif_dev, on); + if (!cif_dev->resume_mode) + rkcif_subdevs_set_power(cif_dev, on); if (resume_cnt == 0) goto out_resume; + atomic_set(&cif_dev->streamoff_cnt, 0); rkcif_subdevs_set_stream(cif_dev, on); if (cif_dev->chip_id < CHIP_RK3588_CIF) diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 20bfc14cea18..df28f35d70ad 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1908,6 +1908,21 @@ static void rkcif_init_reset_monitor(struct rkcif_device *dev) INIT_WORK(&dev->reset_work.work, rkcif_reset_work); } +void rkcif_set_sensor_stream(struct work_struct *work) +{ + struct rkcif_sensor_work *sensor_work = container_of(work, + struct rkcif_sensor_work, + work); + struct rkcif_device *cif_dev = container_of(sensor_work, + struct rkcif_device, + sensor_work); + + v4l2_subdev_call(cif_dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_SET_QUICK_STREAM, + &sensor_work->on); +} + int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int inf_id) { struct device *dev = cif_dev->dev; @@ -1927,6 +1942,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int atomic_set(&cif_dev->pipe.power_cnt, 0); atomic_set(&cif_dev->pipe.stream_cnt, 0); atomic_set(&cif_dev->power_cnt, 0); + atomic_set(&cif_dev->streamoff_cnt, 0); cif_dev->is_start_hdr = false; cif_dev->pipe.open = rkcif_pipeline_open; cif_dev->pipe.close = rkcif_pipeline_close; @@ -1940,11 +1956,14 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->early_line = 0; cif_dev->is_thunderboot = false; cif_dev->rdbk_debug = 0; + + cif_dev->resume_mode = 0; memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info)); if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; INIT_WORK(&cif_dev->err_state_work.work, rkcif_err_print_work); + INIT_WORK(&cif_dev->sensor_work.work, rkcif_set_sensor_stream); if (cif_dev->chip_id < CHIP_RV1126_CIF) { if (cif_dev->inf_id == RKCIF_MIPI_LVDS) { @@ -2118,6 +2137,8 @@ static int rkcif_get_reserved_mem(struct rkcif_device *cif_dev) struct resource r; int ret; + cif_dev->is_thunderboot = false; + cif_dev->is_rtt_suspend = false; /* Get reserved memory region from Device-tree */ np = of_parse_phandle(dev->of_node, "memory-region-thunderboot", 0); if (!np) { @@ -2133,7 +2154,14 @@ static int rkcif_get_reserved_mem(struct rkcif_device *cif_dev) cif_dev->resmem_pa = r.start; cif_dev->resmem_size = resource_size(&r); - cif_dev->is_thunderboot = true; + cif_dev->resmem_addr = dma_map_single(dev, phys_to_virt(r.start), + sizeof(struct rkisp_thunderboot_resmem_head), + DMA_BIDIRECTIONAL); + + if (device_property_read_bool(dev, "rtt-suspend")) + cif_dev->is_rtt_suspend = true; + else + cif_dev->is_thunderboot = true; dev_info(dev, "Allocated reserved memory, paddr: 0x%x, size 0x%x\n", (u32)cif_dev->resmem_pa, (u32)cif_dev->resmem_size); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 573c25a45083..193931cdfbef 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -557,6 +557,7 @@ struct rkcif_stream { bool is_change_toisp; bool is_stop_capture; bool is_wait_dma_stop; + bool is_single_cap; }; struct rkcif_lvds_subdev { @@ -803,6 +804,11 @@ enum rkcif_resume_user { RKCIF_RESUME_ISP, }; +struct rkcif_sensor_work { + struct work_struct work; + int on; +}; + /* * struct rkcif_device - ISP platform device * @base_addr: base register address @@ -831,6 +837,7 @@ struct rkcif_device { int chip_id; atomic_t stream_cnt; atomic_t power_cnt; + atomic_t streamoff_cnt; struct mutex stream_lock; /* lock between streams */ struct mutex scale_lock; /* lock between scale dev */ struct mutex tools_lock; /* lock between tools dev */ @@ -863,6 +870,7 @@ struct rkcif_device { struct completion cmpl_ntf; struct csi2_dphy_hw *dphy_hw; phys_addr_t resmem_pa; + dma_addr_t resmem_addr; size_t resmem_size; struct rk_tb_client tb_client; bool is_start_hdr; @@ -873,6 +881,8 @@ struct rkcif_device { bool is_thunderboot; bool is_rdbk_to_online; bool is_support_tools; + bool is_rtt_suspend; + int rdbk_debug; struct rkcif_sync_cfg sync_cfg; int sditf_cnt; @@ -881,6 +891,8 @@ struct rkcif_device { int sensor_linetime; u32 err_state; struct rkcif_err_state_work err_state_work; + struct rkcif_sensor_work sensor_work; + int resume_mode; }; extern struct platform_driver rkcif_plat_drv; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 3cf217dde1fd..85384fa7d2a7 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -870,7 +870,7 @@ 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) { + if (!stream->dma_en && cif_dev->resume_mode != RKISP_RTT_MODE_ONE_FRAME) { stream->to_en_dma = RKCIF_DMAEN_BY_ISP; rkcif_enable_dma_capture(stream, true); }