diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 7bf312c49ca1..8f19b4ad44db 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "dev.h" #include "mipi-csi2.h" @@ -1893,6 +1894,12 @@ static void rkcif_s_rx_buffer(struct rkcif_stream *stream, struct rkisp_rx_buf * return; rx_buf = to_cif_rx_buf(dbufs); stream->last_buf_toisp = rx_buf; + if (dev->switch_info.is_use_switch) { + if (!rx_buf->is_init[dev->csi_host_idx_def]) { + dbufs->is_init = false; + rx_buf->is_init[dev->csi_host_idx_def] = true; + } + } if ((dev->rdbk_debug && dbufs->sequence < 15) || rkcif_debug == 3) @@ -2187,6 +2194,7 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, struct rkcif_rx_buffer *rx_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; + struct rkcif_stream *buf_stream = stream; u32 frm0_addr_y; u32 frm1_addr_y; u32 buff_addr_y; @@ -2202,67 +2210,70 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(channel_id); } - spin_lock_irqsave(&stream->vbq_lock, flags); + spin_lock_irqsave(&buf_stream->vbq_lock, flags); + if (dev->switch_info.is_use_switch && + dev->switch_info.switch_dev->switch_info.is_init_buf) + buf_stream = &dev->switch_info.switch_dev->stream[stream->id]; - if (!stream->curr_buf_toisp) { - if (!list_empty(&stream->rx_buf_head)) { - rx_buf = list_first_entry(&stream->rx_buf_head, + if (!buf_stream->curr_buf_toisp) { + if (!list_empty(&buf_stream->rx_buf_head)) { + rx_buf = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (rx_buf) { list_del(&rx_buf->list); - stream->curr_buf_toisp = rx_buf; + buf_stream->curr_buf_toisp = rx_buf; } } } - if (stream->curr_buf_toisp) { - buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (buf_stream->curr_buf_toisp) { + buff_addr_y = buf_stream->curr_buf_toisp->dummy.dma_addr; if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { - rkcif_write_buff_addr_multi_dev_combine(stream, frm0_addr_y, 0, + rkcif_write_buff_addr_multi_dev_combine(buf_stream, frm0_addr_y, 0, buff_addr_y, 0, false); } else { rkcif_write_register(dev, frm0_addr_y, buff_addr_y); } } else { - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; + if (buf_stream->lack_buf_cnt < 2) + buf_stream->lack_buf_cnt++; + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; } - if (!stream->next_buf_toisp) { - if (!list_empty(&stream->rx_buf_head)) { - rx_buf = list_first_entry(&stream->rx_buf_head, + if (!buf_stream->next_buf_toisp) { + if (!list_empty(&buf_stream->rx_buf_head)) { + rx_buf = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (rx_buf) { list_del(&rx_buf->list); - stream->next_buf_toisp = rx_buf; + buf_stream->next_buf_toisp = rx_buf; } else { - stream->next_buf_toisp = stream->curr_buf_toisp; + buf_stream->next_buf_toisp = buf_stream->curr_buf_toisp; } - } else if (stream->curr_buf_toisp) { - stream->next_buf_toisp = stream->curr_buf_toisp; - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_THESAME; - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; + } else if (buf_stream->curr_buf_toisp) { + buf_stream->next_buf_toisp = buf_stream->curr_buf_toisp; + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_THESAME; + if (buf_stream->lack_buf_cnt < 2) + buf_stream->lack_buf_cnt++; } } - if (stream->next_buf_toisp) { - buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (buf_stream->next_buf_toisp) { + buff_addr_y = buf_stream->next_buf_toisp->dummy.dma_addr; if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { - rkcif_write_buff_addr_multi_dev_combine(stream, frm1_addr_y, 0, + rkcif_write_buff_addr_multi_dev_combine(buf_stream, frm1_addr_y, 0, buff_addr_y, 0, false); } else { rkcif_write_register(dev, frm1_addr_y, buff_addr_y); } } else { - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; + if (buf_stream->lack_buf_cnt < 2) + buf_stream->lack_buf_cnt++; } - spin_unlock_irqrestore(&stream->vbq_lock, flags); - stream->buf_owner = RKCIF_DMAEN_BY_ISP; + spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); + buf_stream->buf_owner = RKCIF_DMAEN_BY_ISP; } void rkcif_dphy_quick_stream(struct rkcif_device *dev, int on) @@ -2296,16 +2307,20 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, struct rkcif_rx_buffer *buffer = NULL; struct rkcif_rx_buffer *active_buf = NULL; struct sditf_priv *priv = dev->sditf[0]; + struct rkcif_stream *buf_stream = stream; u32 frm_addr_y, buff_addr_y; unsigned long flags; - spin_lock_irqsave(&stream->vbq_lock, flags); + if (dev->switch_info.is_use_switch && + dev->switch_info.switch_dev->switch_info.is_init_buf) + buf_stream = &dev->switch_info.switch_dev->stream[stream->id]; + spin_lock_irqsave(&buf_stream->vbq_lock, flags); if (dev->is_stop_skip) { dev->is_stop_skip = false; if (((stream->frame_idx - 1) % stream->thunderboot_skip_interval) != 0) { stream->thunderboot_skip_interval = 0; stream->frame_idx = stream->sequence + 1; - spin_unlock_irqrestore(&stream->vbq_lock, flags); + spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); return 0; } else { stream->thunderboot_skip_interval = 0; @@ -2315,7 +2330,7 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, if (dev->is_thunderboot && stream->thunderboot_skip_interval && ((stream->frame_idx - 1) % stream->thunderboot_skip_interval) != 0) { - spin_unlock_irqrestore(&stream->vbq_lock, flags); + spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); return 0; } if (stream->thunderboot_skip_interval) { @@ -2333,7 +2348,7 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, stream->id, stream->sequence, stream->frame_idx - 1); - spin_unlock_irqrestore(&stream->vbq_lock, flags); + spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || @@ -2350,21 +2365,21 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, spin_lock_irqsave(&stream->vbq_lock, flags); if (stream->cur_skip_frame) goto out_get_buf; - memset(&stream->toisp_buf_state, 0, sizeof(stream->toisp_buf_state)); - if (!list_empty(&stream->rx_buf_head)) { - if (stream->curr_buf_toisp && stream->next_buf_toisp && - stream->curr_buf_toisp != stream->next_buf_toisp) - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_ROTATE; + memset(&buf_stream->toisp_buf_state, 0, sizeof(stream->toisp_buf_state)); + if (!list_empty(&buf_stream->rx_buf_head)) { + if (buf_stream->curr_buf_toisp && buf_stream->next_buf_toisp && + buf_stream->curr_buf_toisp != buf_stream->next_buf_toisp) + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_ROTATE; else - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - active_buf = stream->curr_buf_toisp; + active_buf = buf_stream->curr_buf_toisp; - buffer = list_first_entry(&stream->rx_buf_head, + buffer = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (buffer) { list_del(&buffer->list); - stream->curr_buf_toisp = buffer; + buf_stream->curr_buf_toisp = buffer; } if (priv && (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO_ONE_FRAME)) { @@ -2398,12 +2413,12 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, rkcif_rdbk_with_tools(stream, active_buf); } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { - active_buf = stream->next_buf_toisp; - buffer = list_first_entry(&stream->rx_buf_head, + active_buf = buf_stream->next_buf_toisp; + buffer = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (buffer) { list_del(&buffer->list); - stream->next_buf_toisp = buffer; + buf_stream->next_buf_toisp = buffer; } if (priv && (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO_ONE_FRAME)) { @@ -2437,42 +2452,42 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, rkcif_rdbk_with_tools(stream, active_buf); } } - if (stream->lack_buf_cnt) - stream->lack_buf_cnt--; + if (buf_stream->lack_buf_cnt) + buf_stream->lack_buf_cnt--; } else { if (priv->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) goto out_get_buf; - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; + if (buf_stream->lack_buf_cnt < 2) + buf_stream->lack_buf_cnt++; if (dev->hw_dev->dummy_buf.vaddr) { if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - active_buf = stream->curr_buf_toisp; + active_buf = buf_stream->curr_buf_toisp; } else { - active_buf = stream->next_buf_toisp; + active_buf = buf_stream->next_buf_toisp; } - } else if (stream->curr_buf_toisp && stream->next_buf_toisp && - stream->curr_buf_toisp != stream->next_buf_toisp) { + } else if (buf_stream->curr_buf_toisp && buf_stream->next_buf_toisp && + buf_stream->curr_buf_toisp != buf_stream->next_buf_toisp) { if (stream->frame_phase == CIF_CSI_FRAME0_READY) { - active_buf = stream->curr_buf_toisp; - stream->curr_buf_toisp = stream->next_buf_toisp; - buffer = stream->next_buf_toisp; + active_buf = buf_stream->curr_buf_toisp; + buf_stream->curr_buf_toisp = buf_stream->next_buf_toisp; + buffer = buf_stream->next_buf_toisp; } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { - active_buf = stream->next_buf_toisp; - stream->next_buf_toisp = stream->curr_buf_toisp; - buffer = stream->curr_buf_toisp; + active_buf = buf_stream->next_buf_toisp; + buf_stream->next_buf_toisp = buf_stream->curr_buf_toisp; + buffer = buf_stream->curr_buf_toisp; } - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_THESAME; + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_THESAME; if (stream->cifdev->rdbk_debug) v4l2_info(&stream->cifdev->v4l2_dev, "stream[%d] hold buf %x\n", stream->id, - (u32)stream->next_buf_toisp->dummy.dma_addr); + (u32)buf_stream->next_buf_toisp->dummy.dma_addr); } else { - stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; + buf_stream->toisp_buf_state.state = RKCIF_TOISP_BUF_LOSS; - active_buf = stream->curr_buf_toisp; - stream->curr_buf_toisp = NULL; - stream->next_buf_toisp = NULL; + active_buf = buf_stream->curr_buf_toisp; + buf_stream->curr_buf_toisp = NULL; + buf_stream->next_buf_toisp = NULL; } @@ -2507,7 +2522,7 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, rkcif_rdbk_with_tools(stream, active_buf); } out_get_buf: - stream->frame_phase_cache = stream->frame_phase; + buf_stream->frame_phase_cache = stream->frame_phase; if (buffer) { buff_addr_y = buffer->dummy.dma_addr; if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { @@ -2533,7 +2548,7 @@ out_get_buf: rkcif_write_register(dev, frm_addr_y, buff_addr_y); } } - spin_unlock_irqrestore(&stream->vbq_lock, flags); + spin_unlock_irqrestore(&buf_stream->vbq_lock, flags); return 0; } @@ -2555,29 +2570,34 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_rx_buffer *buffer = NULL; struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; + struct rkcif_stream *buf_stream = stream; u32 frm_addr_y, buff_addr_y; int frame_phase = 0; int frame_phase_next = 0; bool is_dual_update = false; uint32_t cur_dma_addr = 0, next_dma_addr = 0; - if (stream->toisp_buf_state.state == RKCIF_TOISP_BUF_ROTATE || - (stream->toisp_buf_state.state == RKCIF_TOISP_BUF_THESAME && - stream->toisp_buf_state.check_cnt >= 1) || - (stream->toisp_buf_state.state == RKCIF_TOISP_BUF_LOSS && - stream->toisp_buf_state.check_cnt >= 2)) { + if (dev->switch_info.is_use_switch && + dev->switch_info.switch_dev->switch_info.is_init_buf) + buf_stream = &dev->switch_info.switch_dev->stream[stream->id]; + + if (buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_ROTATE || + (buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_THESAME && + buf_stream->toisp_buf_state.check_cnt >= 1) || + (buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_LOSS && + buf_stream->toisp_buf_state.check_cnt >= 2)) { if ((dev->rdbk_debug > 2 && stream->frame_idx < 15) || rkcif_debug == 3) { - if (stream->curr_buf_toisp) - cur_dma_addr = stream->curr_buf_toisp->dummy.dma_addr; - if (stream->next_buf_toisp) - next_dma_addr = stream->next_buf_toisp->dummy.dma_addr; + if (buf_stream->curr_buf_toisp) + cur_dma_addr = buf_stream->curr_buf_toisp->dummy.dma_addr; + if (buf_stream->next_buf_toisp) + next_dma_addr = buf_stream->next_buf_toisp->dummy.dma_addr; v4l2_info(&dev->v4l2_dev, "stream[%d] addr check not equal 0x%x 0x%x state %d chech_cnt %d\n", stream->id, cur_dma_addr, - next_dma_addr, stream->toisp_buf_state.state, stream->toisp_buf_state.check_cnt); + next_dma_addr, buf_stream->toisp_buf_state.state, buf_stream->toisp_buf_state.check_cnt); } return; } @@ -2585,20 +2605,20 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) "stream[%d] addr check 0x%x 0x%x state %d chech_cnt %d\n", stream->id, cur_dma_addr, - next_dma_addr, stream->toisp_buf_state.state, stream->toisp_buf_state.check_cnt); + next_dma_addr, buf_stream->toisp_buf_state.state, buf_stream->toisp_buf_state.check_cnt); if (stream->frame_phase == 0) stream->frame_phase = CIF_CSI_FRAME0_READY; frame_phase = stream->frame_phase; - if (stream->toisp_buf_state.state == RKCIF_TOISP_BUF_LOSS && - stream->toisp_buf_state.check_cnt == 0) + if (buf_stream->toisp_buf_state.state == RKCIF_TOISP_BUF_LOSS && + buf_stream->toisp_buf_state.check_cnt == 0) is_dual_update = true; if (dev->rdbk_debug > 2 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, "stream[%d] check update, lack_buf %d\n", - stream->id, stream->lack_buf_cnt); + stream->id, buf_stream->lack_buf_cnt); if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { @@ -2610,14 +2630,14 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) get_dvp_reg_index_of_frm0_y_addr(stream->id) : get_dvp_reg_index_of_frm1_y_addr(stream->id); } - if (!list_empty(&stream->rx_buf_head)) { + if (!list_empty(&buf_stream->rx_buf_head)) { if (frame_phase == CIF_CSI_FRAME0_READY) { - buffer = list_first_entry(&stream->rx_buf_head, + buffer = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (buffer) { list_del(&buffer->list); - stream->curr_buf_toisp = buffer; - buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + buf_stream->curr_buf_toisp = buffer; + buff_addr_y = buf_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, @@ -2632,15 +2652,15 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", stream->id, stream->frame_idx - 1, frm_addr_y, - (u32)stream->curr_buf_toisp->dummy.dma_addr); + (u32)buf_stream->curr_buf_toisp->dummy.dma_addr); } } else if (frame_phase == CIF_CSI_FRAME1_READY) { - buffer = list_first_entry(&stream->rx_buf_head, + buffer = list_first_entry(&buf_stream->rx_buf_head, struct rkcif_rx_buffer, list); if (buffer) { list_del(&buffer->list); - stream->next_buf_toisp = buffer; - buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + buf_stream->next_buf_toisp = buffer; + buff_addr_y = buf_stream->next_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, @@ -2655,11 +2675,11 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) "stream[%d] check update, seq %d, addr 0x%x, buf 0x%x\n", stream->id, stream->frame_idx - 1, frm_addr_y, - (u32)stream->next_buf_toisp->dummy.dma_addr); + (u32)buf_stream->next_buf_toisp->dummy.dma_addr); } } - if (stream->lack_buf_cnt) - stream->lack_buf_cnt--; + if (buf_stream->lack_buf_cnt) + buf_stream->lack_buf_cnt--; } if (is_dual_update) { frame_phase_next = frame_phase & CIF_CSI_FRAME0_READY ? @@ -2683,10 +2703,10 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) 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; + buf_stream->next_buf_toisp = buf_stream->curr_buf_toisp; else - stream->curr_buf_toisp = stream->next_buf_toisp; - buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + buf_stream->curr_buf_toisp = buf_stream->next_buf_toisp; + buff_addr_y = buf_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); @@ -2694,7 +2714,7 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) rkcif_write_register(dev, frm_addr_y, buff_addr_y); } } - stream->toisp_buf_state.check_cnt++; + buf_stream->toisp_buf_state.check_cnt++; } static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, @@ -4647,7 +4667,7 @@ static u32 rkcif_get_split_dphy_mask_rv1103b(struct rkcif_device *dev) { u32 val = 0; - if (dev->hw_dev->dev_num == 2) + if (dev->hw_dev->dev_num >= 2) val = SW_DPHY_SPLIT_EN_RV1103B; return val; } @@ -4781,6 +4801,9 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, dev->chip_id < CHIP_RK3576_CIF ? CSI_START_INTEN(channel->id) : CSI_START_INTEN_RK3576(channel->id)); + if (dev->chip_id >= CHIP_RK3576_CIF) + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_INF_END_INTEN_RK3576(channel->id)); if ((!priv || (priv && priv->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ)) && detect_stream->is_line_wake_up) { @@ -4796,7 +4819,7 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, CSI_DMA_END_INTEN(channel->id)); } - if (stream->cifdev->id_use_cnt == 0) { + if (atomic_read(&stream->cifdev->id_use_cnt) == 0) { if (dev->chip_id > CHIP_RK3562_CIF) { val = CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE | (CIF_MIPI_LVDS_SW_WATER_LINE_25 << 19); @@ -5003,9 +5026,9 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_modify_frame_skip_config(stream); if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { if (index == (capture_info->multi_dev.dev_num - 1)) - stream->cifdev->id_use_cnt++; + atomic_inc(&stream->cifdev->id_use_cnt); } else { - stream->cifdev->id_use_cnt++; + atomic_inc(&stream->cifdev->id_use_cnt); } if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && index < capture_info->multi_dev.dev_num - 1)) { @@ -5072,7 +5095,7 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, CSI_DMA_END_INTEN(channel->id)); } - if (stream->cifdev->id_use_cnt == 0) { + if (atomic_read(&stream->cifdev->id_use_cnt) == 0) { val = (CIF_MIPI_LVDS_SW_WATER_LINE_25 << 19) | (dev->csi_host_idx << 1) | CSI_ENABLE_CAPTURE; if (stream->sw_dbg_en) { @@ -5213,9 +5236,9 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, rkcif_modify_frame_skip_config(stream); if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { if (index == (capture_info->multi_dev.dev_num - 1)) - stream->cifdev->id_use_cnt++; + atomic_inc(&stream->cifdev->id_use_cnt); } else { - stream->cifdev->id_use_cnt++; + atomic_inc(&stream->cifdev->id_use_cnt); } if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && index < capture_info->multi_dev.dev_num - 1)) { @@ -5338,7 +5361,9 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); } } else { - rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + if (!dev->switch_info.is_use_switch || + atomic_inc_return(&dev->hw_dev->switch_stream_cnt[dev->switch_info.host_idx]) == 1) + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); } } else { rkcif_csi_channel_set_rv1126b(stream, channel, mbus_type, mode, 0); @@ -5384,8 +5409,19 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) u32 val; int id; int i = 0; + int ret = 0; + + if (cif_dev->switch_info.is_use_switch) { + ret = atomic_dec_if_positive(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx]); + if (ret) { + stream->state = RKCIF_STATE_READY; + stream->dma_en = 0; + return; + } + } + + atomic_dec_if_positive(&stream->cifdev->id_use_cnt); - stream->cifdev->id_use_cnt--; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { @@ -5436,7 +5472,7 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN); } else { - if (stream->cifdev->id_use_cnt == 0) { + if (atomic_read(&stream->cifdev->id_use_cnt) == 0) { rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN_V1); if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { @@ -6739,11 +6775,10 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, cur_time = rkcif_time_get_ns(dev); if (cur_time > fs_time && cur_time - fs_time < (frame_time_ns - 10000000) && - stream->is_in_vblank) { + stream->is_in_vblank) rkcif_stream_stop(stream); - } else { + else stream->stopping = true; - } } else { stream->stopping = true; } @@ -6917,6 +6952,7 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, } stream->crop_mask = 0; stream->frame_loss = 0; + stream->is_fb_first_frame = true; } if (mode == RKCIF_STREAM_MODE_CAPTURE) { tasklet_disable(&stream->vb_done_tasklet); @@ -8495,7 +8531,8 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, enum rkcif_stream_mode mo } } else { csi_info.csi_num = 1; - dev->csi_host_idx = dev->csi_host_idx_def; + if (!dev->switch_info.is_use_switch) + dev->csi_host_idx = dev->csi_host_idx_def; csi_info.csi_idx[0] = dev->csi_host_idx; } dev->csi_info = csi_info; @@ -9730,6 +9767,8 @@ int rkcif_quick_stream_on(struct rkcif_device *dev, bool is_intr) for (i = 0; i < stream_num; i++) dev->stream[i].cur_skip_frame = dev->stream[i].skip_frame; dev->sditf[0]->mode.rdbk_mode = dev->sditf[0]->mode_src.rdbk_mode; + if (dev->switch_info.is_use_switch) + atomic_inc(&dev->hw_dev->switch_stream_cnt[dev->switch_info.host_idx]); if (dev->sditf[0]->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) { for (i = 0; i < stream_num; i++) { stream = &dev->stream[i]; @@ -10052,6 +10091,8 @@ static long rkcif_ioctl_default(struct file *file, void *fh, cur_stream->to_en_dma = RKCIF_DMAEN_BY_VICAP; rkcif_enable_dma_capture(cur_stream, true); } + if (dev->switch_info.is_use_switch) + atomic_inc(&dev->hw_dev->switch_stream_cnt[dev->switch_info.host_idx]); } mutex_lock(&stream->cifdev->stream_lock); on = 1; @@ -13902,6 +13943,12 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) struct v4l2_subdev *sd = NULL; struct rkisp_vicap_sof sof = {0}; + detect_stream->fs_cnt_in_single_frame++; + if ((!cif_dev->sditf[0] || + cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) && + detect_stream->fs_cnt_in_single_frame > 1) + return; + spin_lock_irqsave(&detect_stream->fps_lock, flags); detect_stream->readout.fs_timestamp = rkcif_time_get_ns(cif_dev); spin_unlock_irqrestore(&detect_stream->fps_lock, flags); @@ -13922,7 +13969,8 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) (!detect_stream->dma_en) && cif_dev->chip_id < CHIP_RK3576_CIF) return; if (cif_dev->sync_cfg.type != NO_SYNC_MODE && - cif_dev->sync_cfg.type != SOFT_SYNC_MODE) { + cif_dev->sync_cfg.type != SOFT_SYNC_MODE && + cif_dev->is_detect_group_sync) { struct rkcif_multi_sync_config *sync_config; sync_config = &hw->sync_config[cif_dev->sync_cfg.group]; @@ -14002,9 +14050,9 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) detect_stream->id, rkcif_get_sof(cif_dev), detect_stream->frame_idx); + if (rkcif_check_frame_active(cif_dev)) + detect_stream->frame_idx++; } - if (rkcif_check_frame_active(cif_dev)) - detect_stream->frame_idx++; spin_unlock_irqrestore(&detect_stream->vbq_lock, flags); if (detect_stream->cifdev->rdbk_debug && detect_stream->frame_idx < 15 && @@ -14067,7 +14115,6 @@ static bool rkcif_check_buffer_prepare(struct rkcif_stream *stream) v4l2_err(&cif_dev->v4l2_dev, "ERR: loss long frame in readback mode\n"); } - spin_unlock_irqrestore(&cif_dev->hw_dev->group_lock, flags); return is_update; } @@ -14364,9 +14411,62 @@ out_suspend: return 0; } +static void rkcif_clean_buffer_state(struct rkcif_stream *stream) +{ + struct sditf_priv *priv = stream->cifdev->sditf[0]; + unsigned long flags; + + spin_lock_irqsave(&stream->vbq_lock, flags); + if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ) { + if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT || + rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) { + 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_RDBK_AIQ) { + 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); +} + int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) { struct rkcif_stream *stream = NULL; + struct rkcif_stream *tmp_stream = NULL; struct sditf_priv *priv = cif_dev->sditf[0]; struct v4l2_subdev *sd = NULL; int ret = 0; @@ -14446,52 +14546,17 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) stream->is_wait_single_cap = false; spin_unlock_irqrestore(&stream->cifdev->stream_spinlock, flags); } - spin_lock_irqsave(&stream->vbq_lock, flags); - if (!priv || priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AIQ) { - if (rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT || - rkcif_get_interlace_mode(stream) == RKCIF_INTERLACE_SOFT_AUTO) { - 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; + if (cif_dev->switch_info.is_use_switch) { + if (atomic_read(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx]) == 0) { + tmp_stream = stream; + if (cif_dev->switch_info.switch_dev->switch_info.is_init_buf) + tmp_stream = &cif_dev->switch_info.switch_dev->stream[stream->id]; + rkcif_clean_buffer_state(tmp_stream); } } else { - if (priv->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) { - 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; - } + rkcif_clean_buffer_state(stream); } - spin_unlock_irqrestore(&stream->vbq_lock, flags); - is_single_dev = rkcif_check_single_dev_stream_on(cif_dev->hw_dev); if (priv) { if (stream->is_single_cap && stream->id == 0) { @@ -14526,7 +14591,8 @@ int rkcif_stream_resume(struct rkcif_device *cif_dev, int mode) if (cif_dev->chip_id == CHIP_RV1106_CIF || is_single_dev) sditf_disable_immediately(priv); if (!stream->rx_buf_num && - capture_mode == RKCIF_STREAM_MODE_TOISP_RDBK) { + capture_mode == RKCIF_STREAM_MODE_TOISP_RDBK && + (!cif_dev->switch_info.is_use_switch)) { if (cif_dev->resume_mode == RKISP_RTT_MODE_ONE_FRAME) rkcif_init_rx_buf(stream, 1); else @@ -14851,11 +14917,19 @@ static void rkcif_check_one_to_multi_sub_stream_stop_state(struct rkcif_device * } } +void rkcif_switch_change(struct rkcif_device *cif_dev, bool is_switch) +{ + if (is_switch) { + gpiod_direction_output_raw(cif_dev->switch_info.gpio_pin, 1); + } else { + gpiod_direction_output_raw(cif_dev->switch_info.gpio_pin, 0); + } +} + /* pingpong irq for rk3588 and next */ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) { struct rkcif_stream *stream; - struct rkcif_stream *detect_stream = &cif_dev->stream[0]; struct v4l2_mbus_config *mbus; struct csi_channel_info *channel = &cif_dev->channels[0]; unsigned int intstat, i = 0xff; @@ -14955,7 +15029,24 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (mipi_id < 0) continue; - stream = &cif_dev->stream[mipi_id]; + if (cif_dev->switch_info.is_use_switch) { + if (cif_dev->switch_info.is_active) { + cif_dev->switch_info.is_active = false; + cif_dev->switch_info.switch_dev->switch_info.is_active = true; + stream = &cif_dev->stream[mipi_id]; + if (cif_dev->switch_info.switch_dev->stream[0].state == RKCIF_STATE_STREAMING) + rkcif_switch_change(cif_dev, !!cif_dev->switch_info.switch_dev->switch_info.gpio_val); + } else { + cif_dev->switch_info.is_active = true; + cif_dev->switch_info.switch_dev->switch_info.is_active = false; + stream = &cif_dev->switch_info.switch_dev->stream[mipi_id]; + if (cif_dev->stream[0].state == RKCIF_STATE_STREAMING) + rkcif_switch_change(cif_dev, !!cif_dev->switch_info.gpio_val); + } + + } else { + stream = &cif_dev->stream[mipi_id]; + } if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) stream->buf_wake_up_cnt++; @@ -15026,7 +15117,8 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) } if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) { if (cif_dev->sync_cfg.type == NO_SYNC_MODE || - cif_dev->sync_cfg.type == SOFT_SYNC_MODE) + cif_dev->sync_cfg.type == SOFT_SYNC_MODE || + !cif_dev->is_detect_group_sync) is_update = true; else is_update = rkcif_check_buffer_prepare(stream); @@ -15044,7 +15136,8 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) "dma capture by isp, dma_en 0x%x\n", stream->dma_en); if (cif_dev->sync_cfg.type == NO_SYNC_MODE || - cif_dev->sync_cfg.type == SOFT_SYNC_MODE) + cif_dev->sync_cfg.type == SOFT_SYNC_MODE || + !cif_dev->is_detect_group_sync) is_update = true; else is_update = rkcif_check_buffer_prepare(stream); @@ -15060,35 +15153,53 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (stream->is_single_cap && !stream->cur_skip_frame) { stream->is_single_cap = false; spin_unlock_irqrestore(&stream->cifdev->stream_spinlock, flags); - if (stream->dma_en & RKCIF_DMAEN_BY_ISP) - stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; - else if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) - stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; - else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) - stream->to_stop_dma = RKCIF_DMAEN_BY_ROCKIT; - rkcif_stop_dma_capture(stream); + if (cif_dev->switch_info.is_use_switch && + atomic_dec_if_positive(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx])) { + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->dma_en &= ~RKCIF_DMAEN_BY_ISP; + else if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->dma_en &= ~RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) + stream->dma_en &= ~RKCIF_DMAEN_BY_ROCKIT; + atomic_inc(&stream->cifdev->streamoff_cnt); + v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, + "%s %d, switch stream %d\n", __func__, __LINE__, + atomic_read(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx])); + } else { + if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + else if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ROCKIT) + stream->to_stop_dma = RKCIF_DMAEN_BY_ROCKIT; + rkcif_stop_dma_capture(stream); + } if (cif_dev->hdr.hdr_mode == HDR_X2) - last_stream = &cif_dev->stream[1]; + last_stream = &stream->cifdev->stream[1]; else if (cif_dev->hdr.hdr_mode == HDR_X3) - last_stream = &cif_dev->stream[2]; + last_stream = &stream->cifdev->stream[2]; else last_stream = stream; spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); if (!last_stream->is_wait_single_cap) { spin_unlock_irqrestore(&stream->cifdev->stream_spinlock, flags); - if ((cif_dev->hdr.hdr_mode == NO_HDR && atomic_read(&cif_dev->streamoff_cnt) == 1) || - (cif_dev->hdr.hdr_mode == HDR_X2 && atomic_read(&cif_dev->streamoff_cnt) == 2) || - (cif_dev->hdr.hdr_mode == HDR_X3 && atomic_read(&cif_dev->streamoff_cnt) == 3)) { - rkcif_dphy_quick_stream(stream->cifdev, on); - cif_dev->sensor_work.on = 0; + if ((last_stream->cifdev->hdr.hdr_mode == NO_HDR && atomic_read(&last_stream->cifdev->streamoff_cnt) == 1) || + (last_stream->cifdev->hdr.hdr_mode == HDR_X2 && atomic_read(&last_stream->cifdev->streamoff_cnt) == 2) || + (last_stream->cifdev->hdr.hdr_mode == HDR_X3 && atomic_read(&last_stream->cifdev->streamoff_cnt) == 3)) { + if (!cif_dev->switch_info.is_use_switch || + atomic_read(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx]) == 0) + rkcif_dphy_quick_stream(stream->cifdev, on); + stream->cifdev->sensor_work.on = 0; atomic_inc(&stream->cifdev->sensor_off); - schedule_work(&cif_dev->sensor_work.work); + schedule_work(&stream->cifdev->sensor_work.work); } } else { last_stream->is_wait_single_cap = false; cif_dev->resume_mode = RKISP_RTT_MODE_MULTI_FRAME; complete(&stream->start_complete); spin_unlock_irqrestore(&stream->cifdev->stream_spinlock, flags); + if (cif_dev->switch_info.is_use_switch) + atomic_inc(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx]); } } else if (stream->lack_buf_cnt == 2 && !stream->cur_skip_frame) { spin_unlock_irqrestore(&stream->cifdev->stream_spinlock, flags); @@ -15122,26 +15233,34 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) rkcif_scale_start(stream->scale_vdev); } rkcif_detect_wake_up_mode_change(stream); - if (cif_dev->chip_id < CHIP_RK3588_CIF && - mipi_id == RKCIF_STREAM_MIPI_ID0) { - if ((intstat & (CSI_FRAME1_START_ID0 | CSI_FRAME0_START_ID0)) == 0 && - detect_stream->fs_cnt_in_single_frame > 1) { - cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS; - detect_stream->is_fs_fe_not_paired = true; - detect_stream->fs_cnt_in_single_frame = 0; + if (mipi_id == RKCIF_STREAM_MIPI_ID0) { + if (stream->fs_cnt_in_single_frame > 1) { + if (cif_dev->chip_id < CHIP_RK3588_CIF) { + cif_dev->err_state |= RKCIF_ERR_ID0_MULTI_FS; + stream->is_fs_fe_not_paired = true; + } + stream->fs_cnt_in_single_frame = 0; } else { - detect_stream->fs_cnt_in_single_frame--; + stream->fs_cnt_in_single_frame--; } } rkcif_monitor_reset_event(cif_dev); cif_dev->irq_stats.frm_end_cnt[stream->id]++; rkcif_check_one_to_multi_sub_stream_stop_state(cif_dev); } - for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { if (intstat & (cif_dev->chip_id < CHIP_RK3576_CIF ? CSI_START_INTSTAT(i) : CSI_START_INTSTAT_RK3576(i))) { - stream = &cif_dev->stream[i]; + if (cif_dev->switch_info.is_use_switch) { + if (cif_dev->switch_info.is_active) + stream = &cif_dev->stream[i]; + else + stream = &cif_dev->switch_info.switch_dev->stream[i]; + } else { + stream = &cif_dev->stream[i]; + } + if (stream->state != RKCIF_STATE_STREAMING) + continue; spin_lock_irqsave(&stream->vbq_lock, flags); if (stream->stopping && stream->dma_en) { if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) @@ -15151,11 +15270,17 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream->is_stop_capture = true; } if (stream->to_stop_dma) { - ret = rkcif_stop_dma_capture(stream); - if (!ret) { + if (cif_dev->switch_info.is_use_switch && + atomic_dec_if_positive(&cif_dev->hw_dev->switch_stream_cnt[cif_dev->switch_info.host_idx])) { + stream->to_stop_dma = 0; stream->is_finish_stop_dma = true; - if (stream->is_wait_stop_complete) - stream->is_pause_stream = true; + } else { + ret = rkcif_stop_dma_capture(stream); + if (!ret) { + stream->is_finish_stop_dma = true; + if (stream->is_wait_stop_complete) + stream->is_pause_stream = true; + } } } spin_unlock_irqrestore(&stream->vbq_lock, flags); @@ -15165,7 +15290,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) spin_lock_irqsave(&stream->vbq_lock, flags); if (!stream->cur_skip_frame && (!cif_dev->is_in_flip)) { spin_unlock_irqrestore(&stream->vbq_lock, flags); - rkcif_deal_sof(cif_dev); + rkcif_deal_sof(stream->cifdev); } else { spin_unlock_irqrestore(&stream->vbq_lock, flags); } @@ -15189,7 +15314,16 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) rkcif_check_mipi_interlaced_frame_id(stream); } if (intstat & CSI_LINE_INTSTAT_V1(i)) { - stream = &cif_dev->stream[i]; + if (cif_dev->switch_info.is_use_switch) { + if (cif_dev->switch_info.is_active) + stream = &cif_dev->stream[i]; + else + stream = &cif_dev->switch_info.switch_dev->stream[i]; + } else { + stream = &cif_dev->stream[i]; + } + if (stream->state != RKCIF_STATE_STREAMING) + continue; if (stream->is_line_inten) { stream->line_int_cnt++; if (cif_dev->rdbk_debug > 1 && diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 27d7a3da08ca..4d450a11acfc 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -2882,7 +2882,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->pipe.close = rkcif_pipeline_close; cif_dev->pipe.set_stream = rkcif_pipeline_set_stream; cif_dev->isr_hdl = rkcif_irq_handler; - cif_dev->id_use_cnt = 0; + atomic_set(&cif_dev->id_use_cnt, 0); memset(&cif_dev->sync_cfg, 0, sizeof(cif_dev->sync_cfg)); cif_dev->sditf_cnt = 0; cif_dev->is_notifier_isp = false; @@ -3090,6 +3090,27 @@ static void rkcif_parse_pins_group(struct rkcif_device *cif_dev) dev_info(cif_dev->dev, "rkcif pins used group %d\n", cif_dev->dvp_pin_group); } +static void rkcif_parse_switch_info(struct rkcif_device *cif_dev) +{ + int ret = 0; + struct device_node *node = cif_dev->dev->of_node; + + memset(&cif_dev->switch_info, 0, sizeof(cif_dev->switch_info)); + ret = of_property_read_u32(node, + OF_CIF_SWITCH_HOST_IDX, + &cif_dev->switch_info.host_idx); + if (ret == 0) { + cif_dev->switch_info.is_use_switch = true; + cif_dev->switch_info.gpio_pin = devm_gpiod_get(cif_dev->dev, "switch", GPIOD_OUT_LOW); + if (IS_ERR(cif_dev->switch_info.gpio_pin)) + dev_err(cif_dev->dev, "get switch gpio failed\n"); + ret = of_property_read_u32(node, + OF_CIF_SWITCH_GPIO_VAL, + &cif_dev->switch_info.gpio_val); + dev_info(cif_dev->dev, "switch gpio val %d\n", cif_dev->switch_info.gpio_val); + } +} + static void rkcif_parse_dts(struct rkcif_device *cif_dev) { int ret = 0; @@ -3112,6 +3133,12 @@ static void rkcif_parse_dts(struct rkcif_device *cif_dev) else cif_dev->is_camera_over_bridge = false; rkcif_parse_pins_group(cif_dev); + rkcif_parse_switch_info(cif_dev); + if (device_property_read_bool(cif_dev->dev, "no-detect-group-sync")) + cif_dev->is_detect_group_sync = false; + else + cif_dev->is_detect_group_sync = true; + dev_err(cif_dev->dev, "rkcif is_detect_group_sync %d\n", cif_dev->is_detect_group_sync); } static int rkcif_get_reserved_mem(struct rkcif_device *cif_dev) diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 4e453927e537..92cf438c9ce5 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -38,6 +38,8 @@ #define OF_CIF_WAIT_LINE "wait-line" #define OF_CIF_FASTBOOT_RESERVED_BUFS "fastboot-reserved-bufs" #define OF_CIF_PINS_GROUP "cif-pins-group" +#define OF_CIF_SWITCH_HOST_IDX "switch-host-idx" +#define OF_CIF_SWITCH_GPIO_VAL "switch-gpio-val" #define CIF_MONITOR_PARA_NUM (5) @@ -93,6 +95,7 @@ #define RKCIF_EXP_NUM_MAX (8) +#define RKCIF_MAX_DEV (8) /* * for distinguishing cropping from senosr or usr */ @@ -480,6 +483,7 @@ struct rkcif_rx_buffer { struct rkcif_dummy_buffer dummy; struct rkisp_thunderboot_shmem shmem; u64 fe_timestamp; + bool is_init[RKCIF_MAX_DEV]; }; enum rkcif_dma_en_mode { @@ -938,6 +942,17 @@ struct rkcif_stream_info { struct sditf_priv *priv; }; +struct rkcif_switch_info { + bool is_use_switch; + bool is_active; + bool is_init; + bool is_init_buf; + int host_idx; + int gpio_val; + struct gpio_desc *gpio_pin; + struct rkcif_device *switch_dev; +}; + /* * struct rkcif_device - ISP platform device * @base_addr: base register address @@ -992,7 +1007,7 @@ struct rkcif_device { spinlock_t stream_spinlock; struct rkcif_timer reset_watchdog_timer; struct rkcif_work_struct reset_work; - int id_use_cnt; + atomic_t id_use_cnt; unsigned int csi_host_idx; unsigned int csi_host_idx_def; unsigned int dvp_sof_in_oneframe; @@ -1030,6 +1045,7 @@ struct rkcif_device { bool is_thunderboot_start; bool is_in_flip; bool is_support_get_exp; + bool is_detect_group_sync; int rdbk_debug; struct rkcif_sync_cfg sync_cfg; int sditf_cnt; @@ -1057,6 +1073,7 @@ struct rkcif_device { u32 pre_buf_addr[MAX_PRE_BUF_NUM]; u64 pre_buf_timestamp[MAX_PRE_BUF_NUM]; u32 dvp_pin_group; + struct rkcif_switch_info switch_info; }; extern struct platform_driver rkcif_plat_drv; @@ -1182,5 +1199,6 @@ void rkcif_set_sof(struct rkcif_device *cif_dev, u32 seq); void rkcif_set_sensor_streamon_in_sync_mode(struct rkcif_device *cif_dev); int rkcif_sensor_set_power(struct rkcif_stream *stream, int on); +void rkcif_switch_change(struct rkcif_device *cif_dev, bool is_switch); #endif diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index 20c6d9adb727..f4207b56b352 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -1331,6 +1331,7 @@ static const struct rkcif_hw_match_data px30_cif_match_data = { .rsts = px30_cif_rsts, .rsts_num = ARRAY_SIZE(px30_cif_rsts), .cif_regs = px30_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk1808_cif_match_data = { @@ -1340,6 +1341,7 @@ static const struct rkcif_hw_match_data rk1808_cif_match_data = { .rsts = rk1808_cif_rsts, .rsts_num = ARRAY_SIZE(rk1808_cif_rsts), .cif_regs = rk1808_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk3128_cif_match_data = { @@ -1349,6 +1351,7 @@ static const struct rkcif_hw_match_data rk3128_cif_match_data = { .rsts = rk3128_cif_rsts, .rsts_num = ARRAY_SIZE(rk3128_cif_rsts), .cif_regs = rk3128_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk3288_cif_match_data = { @@ -1358,6 +1361,7 @@ static const struct rkcif_hw_match_data rk3288_cif_match_data = { .rsts = rk3288_cif_rsts, .rsts_num = ARRAY_SIZE(rk3288_cif_rsts), .cif_regs = rk3288_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk3328_cif_match_data = { @@ -1367,6 +1371,7 @@ static const struct rkcif_hw_match_data rk3328_cif_match_data = { .rsts = rk3328_cif_rsts, .rsts_num = ARRAY_SIZE(rk3328_cif_rsts), .cif_regs = rk3328_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk3368_cif_match_data = { @@ -1376,6 +1381,7 @@ static const struct rkcif_hw_match_data rk3368_cif_match_data = { .rsts = rk3368_cif_rsts, .rsts_num = ARRAY_SIZE(rk3368_cif_rsts), .cif_regs = rk3368_cif_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rv1126_cif_match_data = { @@ -1385,6 +1391,7 @@ static const struct rkcif_hw_match_data rv1126_cif_match_data = { .rsts = rv1126_cif_rsts, .rsts_num = ARRAY_SIZE(rv1126_cif_rsts), .cif_regs = rv1126_cif_regs, + .max_hw = 2, }; static const struct rkcif_hw_match_data rv1126_cif_lite_match_data = { @@ -1394,6 +1401,7 @@ static const struct rkcif_hw_match_data rv1126_cif_lite_match_data = { .rsts = rv1126_cif_lite_rsts, .rsts_num = ARRAY_SIZE(rv1126_cif_lite_rsts), .cif_regs = rv1126_cif_lite_regs, + .max_hw = 1, }; static const struct rkcif_hw_match_data rk3568_cif_match_data = { @@ -1403,6 +1411,7 @@ static const struct rkcif_hw_match_data rk3568_cif_match_data = { .rsts = rk3568_cif_rsts, .rsts_num = ARRAY_SIZE(rk3568_cif_rsts), .cif_regs = rk3568_cif_regs, + .max_hw = 2, }; static const struct rkcif_hw_match_data rk3588_cif_match_data = { @@ -1412,6 +1421,7 @@ static const struct rkcif_hw_match_data rk3588_cif_match_data = { .rsts = rk3588_cif_rsts, .rsts_num = ARRAY_SIZE(rk3588_cif_rsts), .cif_regs = rk3588_cif_regs, + .max_hw = 7, }; static const struct rkcif_hw_match_data rv1106_cif_match_data = { @@ -1421,6 +1431,7 @@ static const struct rkcif_hw_match_data rv1106_cif_match_data = { .rsts = rv1106_cif_rsts, .rsts_num = ARRAY_SIZE(rv1106_cif_rsts), .cif_regs = rv1106_cif_regs, + .max_hw = 3, }; static const struct rkcif_hw_match_data rk3562_cif_match_data = { @@ -1430,6 +1441,7 @@ static const struct rkcif_hw_match_data rk3562_cif_match_data = { .rsts = rk3562_cif_rsts, .rsts_num = ARRAY_SIZE(rk3562_cif_rsts), .cif_regs = rk3562_cif_regs, + .max_hw = 4, }; static const struct rkcif_hw_match_data rk3576_cif_match_data = { @@ -1439,6 +1451,7 @@ static const struct rkcif_hw_match_data rk3576_cif_match_data = { .rsts = rk3576_cif_rsts, .rsts_num = ARRAY_SIZE(rk3576_cif_rsts), .cif_regs = rk3576_cif_regs, + .max_hw = 6, }; static const struct rkcif_hw_match_data rv1103b_cif_match_data = { @@ -1448,6 +1461,7 @@ static const struct rkcif_hw_match_data rv1103b_cif_match_data = { .rsts = rv1103b_cif_rsts, .rsts_num = ARRAY_SIZE(rv1103b_cif_rsts), .cif_regs = rv1103b_cif_regs, + .max_hw = 2, }; static const struct rkcif_hw_match_data rv1126b_cif_match_data = { @@ -1457,6 +1471,7 @@ static const struct rkcif_hw_match_data rv1126b_cif_match_data = { .rsts = rv1126b_cif_rsts, .rsts_num = ARRAY_SIZE(rv1126b_cif_rsts), .cif_regs = rv1126b_cif_regs, + .max_hw = 5, }; static const struct of_device_id rkcif_plat_of_match[] = { @@ -1567,7 +1582,7 @@ static irqreturn_t rkcif_irq_handler(int irq, void *ctx) } for (i = 0; i < cif_hw->dev_num; i++) { - if (cif_hw->cif_dev[i]->isr_hdl) { + if (cif_hw->cif_dev[i]->isr_hdl && i < cif_hw->match_data->max_hw) { cif_hw->cif_dev[i]->isr_hdl(irq, cif_hw->cif_dev[i]); if (cif_hw->cif_dev[i]->err_state && (!work_busy(&cif_hw->cif_dev[i]->err_state_work.work))) { @@ -1575,10 +1590,10 @@ static irqreturn_t rkcif_irq_handler(int irq, void *ctx) cif_hw->cif_dev[i]->err_state = 0; schedule_work(&cif_hw->cif_dev[i]->err_state_work.work); } - if (cif_hw->chip_id >= CHIP_RK3588_CIF && intstat_glb) { - rkcif_irq_handle_toisp(cif_hw->cif_dev[i], intstat_glb); - rkcif_irq_handle_scale(cif_hw->cif_dev[i], intstat_glb); - } + } + if (cif_hw->chip_id >= CHIP_RK3588_CIF && intstat_glb) { + rkcif_irq_handle_toisp(cif_hw->cif_dev[i], intstat_glb); + rkcif_irq_handle_scale(cif_hw->cif_dev[i], intstat_glb); } } irq_stop = ktime_get_ns(); @@ -1838,6 +1853,10 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) spin_lock_init(&cif_hw->group_lock); spin_lock_init(&cif_hw->reset_lock); atomic_set(&cif_hw->power_cnt, 0); + for (i = 0; i < RKCIF_MAX_SWITCH_GROUP; i++) { + atomic_set(&cif_hw->switch_stream_cnt[i], 0); + mutex_init(&cif_hw->switch_mutex_lock[i]); + } cif_hw->is_in_reset = false; cif_hw->iommu_en = is_iommu_enable(dev); diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index b346e186da9d..537dc154b329 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -26,6 +26,7 @@ #define RKCIF_MAX_RESET 15 #define RKCIF_MAX_GROUP 4 +#define RKCIF_MAX_SWITCH_GROUP 2 #define write_cif_reg(base, addr, val) \ writel(val, (addr) + (base)) @@ -121,6 +122,7 @@ struct rkcif_hw_match_data { int clks_num; int rsts_num; const struct cif_reg *cif_regs; + int max_hw; }; /* @@ -145,11 +147,14 @@ struct rkcif_hw { struct rkcif_device *cif_dev[RKCIF_DEV_MAX]; int dev_num; atomic_t power_cnt; + atomic_t switch_stream_cnt[RKCIF_MAX_SWITCH_GROUP]; const struct rkcif_hw_match_data *match_data; struct mutex dev_lock; + struct mutex switch_mutex_lock[RKCIF_MAX_SWITCH_GROUP]; struct rkcif_multi_sync_config sync_config[RKCIF_MAX_GROUP]; spinlock_t group_lock; spinlock_t reset_lock; + spinlock_t switch_lock; struct notifier_block reset_notifier; /* reset for mipi csi crc err */ struct rkcif_dummy_buffer dummy_buf; bool iommu_en; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index 1de4cd09a1dd..bc74726c94c1 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -234,10 +234,39 @@ static void csi2_enable(struct csi2_hw *csi2_hw, write_csihost_reg(base, CSIHOST_RESETN, 1); } +static int csi2_hw_start(struct csi2_hw *csi2_hw, enum host_type_t host_type) +{ + int ret = 0; + + if (atomic_inc_return(&csi2_hw->stream_count) > 1) + return ret; + csi2_hw_do_reset(csi2_hw); + ret = csi2_enable_clks(csi2_hw); + if (ret) { + dev_err(csi2_hw->dev, "%s: enable clks failed, %s\n", + __func__, csi2_hw->dev_name); + return ret; + } + enable_irq(csi2_hw->irq1); + enable_irq(csi2_hw->irq2); + csi2_enable(csi2_hw, host_type); + return ret; +} + +static void csi2_hw_stop(struct csi2_hw *csi2_hw) +{ + if (atomic_dec_return(&csi2_hw->stream_count) > 0) + return; + disable_irq(csi2_hw->irq1); + disable_irq(csi2_hw->irq2); + csi2_disable(csi2_hw); + csi2_disable_clks(csi2_hw); +} + static int csi2_start(struct csi2_dev *csi2) { enum host_type_t host_type; - int ret, i; + int ret = 0, i; int csi_idx = 0; atomic_set(&csi2->frm_sync_seq, 0); @@ -255,16 +284,7 @@ static int csi2_start(struct csi2_dev *csi2) for (i = 0; i < csi2->csi_info.csi_num; i++) { csi_idx = csi2->csi_info.csi_idx[i]; - csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); - ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]); - if (ret) { - v4l2_err(&csi2->sd, "%s: enable clks failed, index %d\n", - __func__, csi_idx); - return ret; - } - enable_irq(csi2->csi2_hw[csi_idx]->irq1); - enable_irq(csi2->csi2_hw[csi_idx]->irq2); - csi2_enable(csi2->csi2_hw[csi_idx], host_type); + ret |= csi2_hw_start(csi2->csi2_hw[csi_idx], host_type); } pr_debug("stream sd: %s\n", csi2->src_sd->name); @@ -281,10 +301,7 @@ static int csi2_start(struct csi2_dev *csi2) err_assert_reset: for (i = 0; i < csi2->csi_info.csi_num; i++) { csi_idx = csi2->csi_info.csi_idx[i]; - disable_irq(csi2->csi2_hw[csi_idx]->irq1); - disable_irq(csi2->csi2_hw[csi_idx]->irq2); - csi2_disable(csi2->csi2_hw[csi_idx]); - csi2_disable_clks(csi2->csi2_hw[csi_idx]); + csi2_hw_stop(csi2->csi2_hw[csi_idx]); } return ret; @@ -304,11 +321,7 @@ static void csi2_stop(struct csi2_dev *csi2) for (i = 0; i < csi2->csi_info.csi_num; i++) { csi_idx = csi2->csi_info.csi_idx[i]; - disable_irq(csi2->csi2_hw[csi_idx]->irq1); - disable_irq(csi2->csi2_hw[csi_idx]->irq2); - csi2_disable(csi2->csi2_hw[csi_idx]); - csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); - csi2_disable_clks(csi2->csi2_hw[csi_idx]); + csi2_hw_stop(csi2->csi2_hw[csi_idx]); } } @@ -1486,6 +1499,7 @@ static int csi2_hw_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No found irq csi-intr2\n"); } platform_set_drvdata(pdev, csi2_hw); + atomic_set(&csi2_hw->stream_count, 0); dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name); return 0; diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 6cfd9f217d47..026b48ff552f 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -195,6 +195,7 @@ struct csi2_hw { int irq1; int irq2; const char *dev_name; + atomic_t stream_count; }; u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev); diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 91126488f15b..eea73b3ced40 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -1171,6 +1171,7 @@ enum cif_reg_index { #define CSI_START_INTEN(id) (0x3 << ((id) * 2)) #define CSI_START_INTEN_RK3576(id) (0x1 << id) +#define CSI_INF_END_INTEN_RK3576(id) (0x10 << id) #define CSI_DMA_END_INTEN(id) (0x3 << ((id) * 2 + 8)) #define CSI_LINE_INTEN(id) (0x1 << ((id) + 21)) #define CSI_LINE_INTEN_RK3588(id) (0x1 << ((id) + 20)) @@ -1214,6 +1215,11 @@ enum cif_reg_index { #define CSI_SIZE_ERR_ID2 (0x1 << 26) #define CSI_SIZE_ERR_ID3 (0x1 << 27) +#define CSI_INF_FRAME_END_ID0 (0x1 << 4) +#define CSI_INF_FRAME_END_ID1 (0x1 << 5) +#define CSI_INF_FRAME_END_ID2 (0x1 << 6) +#define CSI_INF_FRAME_END_ID3 (0x1 << 7) + #define CSI_FRAME_START_ID0 (CSI_FRAME0_START_ID0 |\ CSI_FRAME1_START_ID0) #define CSI_FRAME_START_ID1 (CSI_FRAME0_START_ID1 |\ diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 2f3e8c902010..26a6423d88f2 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -282,6 +282,16 @@ static int sditf_init_buf(struct sditf_priv *priv) struct rkcif_device *cif_dev = priv->cif_dev; int ret = 0; + mutex_lock(&cif_dev->hw_dev->switch_mutex_lock[cif_dev->switch_info.host_idx]); + if (cif_dev->switch_info.is_use_switch) { + if (cif_dev->switch_info.is_init_buf || + cif_dev->switch_info.switch_dev->switch_info.is_init_buf) { + mutex_unlock(&cif_dev->hw_dev->switch_mutex_lock[cif_dev->switch_info.host_idx]); + return 0; + } + cif_dev->switch_info.is_init_buf = true; + } + if (priv->hdr_cfg.hdr_mode == HDR_X2) { if (priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { if (cif_dev->is_thunderboot) @@ -320,6 +330,7 @@ static int sditf_init_buf(struct sditf_priv *priv) ret = -EINVAL; } priv->is_buf_init = true; + mutex_unlock(&cif_dev->hw_dev->switch_mutex_lock[cif_dev->switch_info.host_idx]); return ret; } @@ -344,6 +355,8 @@ static void sditf_free_buf(struct sditf_priv *priv) cif_dev->is_thunderboot = false; } priv->is_buf_init = false; + if (cif_dev->switch_info.is_use_switch) + cif_dev->switch_info.is_init_buf = false; } static int sditf_get_selection(struct v4l2_subdev *sd, @@ -446,6 +459,47 @@ static void sditf_select_sensor_setting_for_thunderboot(struct sditf_priv *priv) } #endif +static struct rkcif_device *rkcif_get_switch_dev(struct rkcif_device *cif_dev) +{ + int i = 0; + + for (i = 0; i < cif_dev->hw_dev->dev_num; i++) { + if (cif_dev->switch_info.host_idx == cif_dev->hw_dev->cif_dev[i]->switch_info.host_idx && + cif_dev != cif_dev->hw_dev->cif_dev[i]) + return cif_dev->hw_dev->cif_dev[i]; + } + return NULL; +} + +static int rkcif_init_switch_info(struct rkcif_device *cif_dev) +{ + cif_dev->csi_host_idx = cif_dev->switch_info.host_idx; + cif_dev->switch_info.is_init = true; + cif_dev->switch_info.switch_dev = rkcif_get_switch_dev(cif_dev); + if (!cif_dev->switch_info.switch_dev) + return -EINVAL; + if (IS_ERR(cif_dev->switch_info.gpio_pin)) + cif_dev->switch_info.gpio_pin = cif_dev->switch_info.switch_dev->switch_info.gpio_pin; + return 0; +} + +static int rkcif_init_switch_infos(struct rkcif_device *cif_dev) +{ + int ret = 0; + + mutex_lock(&cif_dev->hw_dev->switch_mutex_lock[cif_dev->switch_info.host_idx]); + if (!cif_dev->switch_info.is_init) { + cif_dev->switch_info.is_active = true; + ret = rkcif_init_switch_info(cif_dev); + if (!ret) + ret = rkcif_init_switch_info(cif_dev->switch_info.switch_dev); + if (cif_dev->sditf[0]->mode_src.rdbk_mode > RKISP_VICAP_RDBK_AIQ) + rkcif_switch_change(cif_dev, !!cif_dev->switch_info.gpio_val); + } + mutex_unlock(&cif_dev->hw_dev->switch_mutex_lock[cif_dev->switch_info.host_idx]); + return ret; +} + static void sditf_enable_immediately(struct sditf_priv *priv); static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -481,6 +535,10 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) else mode->input.multi_sync = 1; memcpy(&priv->mode_src, mode, sizeof(*mode)); + + if (cif_dev->switch_info.is_use_switch) + ret = rkcif_init_switch_infos(cif_dev); + if (cif_dev->is_thunderboot && cif_dev->is_thunderboot_start) { if (mode->rdbk_mode < RKISP_VICAP_RDBK_AIQ) @@ -1114,6 +1172,8 @@ void sditf_disable_immediately(struct sditf_priv *priv) } } priv->is_toisp_off = true; + if (priv->cif_dev->switch_info.is_use_switch) + priv->cif_dev->switch_info.is_active = false; } static void sditf_enable_immediately(struct sditf_priv *priv) @@ -1137,6 +1197,10 @@ static void sditf_enable_immediately(struct sditf_priv *priv) sditf_channel_enable(priv, 1); } } + if (priv->cif_dev->switch_info.is_use_switch) { + rkcif_switch_change(priv->cif_dev, !!priv->cif_dev->switch_info.gpio_val); + priv->cif_dev->switch_info.is_active = true; + } priv->is_toisp_off = false; } @@ -1284,6 +1348,7 @@ 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_stream *stream = NULL; + struct rkcif_stream *buf_stream = NULL; struct rkisp_rx_buf *dbufs; struct rkcif_rx_buffer *rx_buf = NULL; unsigned long flags, buffree_flags; @@ -1322,6 +1387,10 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, if (!stream) return -EINVAL; + buf_stream = stream; + if (cif_dev->switch_info.is_use_switch && + cif_dev->switch_info.switch_dev->switch_info.is_init_buf) + buf_stream = &cif_dev->switch_info.switch_dev->stream[stream->id]; if (dbufs->sequence == 0 && stream->thunderboot_skip_interval) { @@ -1351,7 +1420,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, } if (!is_free && (!dbufs->is_switch) && stream->state == RKCIF_STATE_STREAMING) { - list_add_tail(&rx_buf->list, &stream->rx_buf_head); + list_add_tail(&rx_buf->list, &buf_stream->rx_buf_head); rkcif_assign_check_buffer_update_toisp(stream); if (cif_dev->resume_mode != RKISP_RTT_MODE_ONE_FRAME && (!stream->is_pause_stream)) {