diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 68557de9d680..5e9f4dba8bc2 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1265,7 +1265,7 @@ static enum cif_reg_index get_dvp_reg_index_of_frm1_uv_addr(int channel_id) return index; } -static int rkcif_get_linetime(struct rkcif_stream *stream) +int rkcif_get_linetime(struct rkcif_stream *stream) { struct rkcif_device *cif_dev = stream->cifdev; struct rkcif_sensor_info *sensor = &cif_dev->terminal_sensor; @@ -1459,15 +1459,15 @@ static void rkcif_s_rx_buffer(struct rkcif_device *dev, struct rkisp_rx_buf *dbu sd = media_entity_to_v4l2_subdev(pad->entity); else return; - - v4l2_subdev_call(sd, video, s_rx_buffer, dbufs, NULL); if (dev->rdbk_debug && dbufs->sequence < 15) { rx_buf = to_cif_rx_buf(dbufs); v4l2_info(&dev->v4l2_dev, - "s_buf seq %d dma addr %x\n", - dbufs->sequence, (u32)rx_buf->dummy.dma_addr); + "s_buf seq %d dma addr %x, %lld\n", + dbufs->sequence, (u32)rx_buf->dummy.dma_addr, + ktime_get_ns()); } + v4l2_subdev_call(sd, video, s_rx_buffer, dbufs, NULL); } static void rkcif_enable_skip_frame(struct rkcif_stream *stream, int cap_m, int skip_n) @@ -1598,9 +1598,12 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.is_first = true; active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; rkcif_s_rx_buffer(dev, &active_buf->dbufs); + stream->buf_num_toisp--; } else { rkcif_s_rx_buffer(dev, &stream->next_buf_toisp->dbufs); + stream->buf_num_toisp--; } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { if (stream->curr_buf_toisp == stream->next_buf_toisp) @@ -1621,9 +1624,12 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.is_first = true; active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; rkcif_s_rx_buffer(dev, &active_buf->dbufs); + stream->buf_num_toisp--; } else { rkcif_s_rx_buffer(dev, &stream->curr_buf_toisp->dbufs); + stream->buf_num_toisp--; } } if (stream->lack_buf_cnt) @@ -1660,6 +1666,7 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.is_first = true; active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; rkcif_s_rx_buffer(dev, &active_buf->dbufs); } else { if (stream->cifdev->rdbk_debug && dev->dummy_buf.vaddr) @@ -1730,9 +1737,9 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (dev->chip_id > CHIP_RK3568_CIF && dev->hdr.hdr_mode == NO_HDR && - dev->sensor_linetime > 0 && cur_time - stream->readout.fe_timestamp < (vblank_ns - 500000) && - stream->lack_buf_cnt == 2) { + stream->lack_buf_cnt == 2 && + 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; @@ -1744,8 +1751,9 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (dev->rdbk_debug > 2 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, - "check update, cur %lld, fe %lld, vb %u\n", - cur_time, stream->readout.fe_timestamp, vblank_ns); + "check update, cur %lld, fe %lld, vb %u lack_buf %d\n", + cur_time, stream->readout.fe_timestamp, + vblank_ns, 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) { @@ -1810,6 +1818,7 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (active_buf) { active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; rkcif_s_rx_buffer(dev, &active_buf->dbufs); } if (dev->dummy_buf.vaddr) @@ -2105,6 +2114,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, dbufs = &stream->curr_buf_toisp->dbufs; } rkcif_s_rx_buffer(dev, dbufs); + stream->buf_num_toisp--; } } else { if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { @@ -2125,6 +2135,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, dbufs = &stream->curr_buf_toisp->dbufs; } rkcif_s_rx_buffer(dev, dbufs); + stream->buf_num_toisp--; if (stream->curr_buf && stream->frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = NULL; if (stream->buf_replace_cnt) @@ -2177,6 +2188,7 @@ stop_dma: dbufs = &stream->curr_buf_toisp->dbufs; } rkcif_s_rx_buffer(dev, dbufs); + stream->buf_num_toisp--; if (stream->frame_phase == CIF_CSI_FRAME0_READY) { list_add_tail(&stream->curr_buf->queue, &stream->buf_head); stream->curr_buf = NULL; @@ -3161,6 +3173,8 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode stream->buf_wake_up_cnt = 0; stream->frame_phase = 0; stream->lack_buf_cnt = 0; + stream->is_in_vblank = false; + stream->is_change_toisp = false; } rkcif_csi_get_vc_num(dev, flags); @@ -3572,20 +3586,35 @@ void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) { struct rkcif_rx_buffer *buf; struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; int i = 0; unsigned long flags; + if (!priv) + return; + spin_lock_irqsave(&stream->vbq_lock, flags); stream->curr_buf_toisp = NULL; stream->next_buf_toisp = NULL; INIT_LIST_HEAD(&stream->rx_buf_head); spin_unlock_irqrestore(&stream->vbq_lock, flags); + if (dev->is_thunderboot) + spin_lock_irqsave(&dev->buffree_lock, flags); for (i = 0; i < buf_num; i++) { buf = &stream->rx_buf[i]; if (buf->dummy.is_free) continue; - rkcif_free_buffer(dev, &buf->dummy); + if (!dev->is_thunderboot) + rkcif_free_buffer(dev, &buf->dummy); + else + list_add_tail(&buf->dbufs.list, &priv->buf_free_list); + } + + if (dev->is_thunderboot) { + spin_unlock_irqrestore(&dev->buffree_lock, flags); + schedule_work(&priv->buffree_work.work); + dev->is_thunderboot = false; } stream->dma_en &= ~RKCIF_DMAEN_BY_ISP; v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, @@ -3638,21 +3667,35 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) dummy->size = pixm->plane_fmt[0].sizeimage; dummy->is_need_vaddr = true; dummy->is_need_dbuf = true; - ret = rkcif_alloc_buffer(dev, dummy); - if (ret) { - priv->buf_num = i; - v4l2_err(&dev->v4l2_dev, - "alloc buf num %d, require buf num %d\n", - i, buf_num); - break; + if (dev->is_thunderboot) { + buf->buf_idx = i; + ret = rkcif_alloc_reserved_mem_buf(dev, buf); + if (ret) { + priv->buf_num = i; + v4l2_err(&dev->v4l2_dev, + "reserved mem support alloc buf num %d, require buf num %d\n", + i, buf_num); + break; + } + } else { + ret = rkcif_alloc_buffer(dev, dummy); + if (ret) { + priv->buf_num = i; + v4l2_err(&dev->v4l2_dev, + "alloc buf num %d, require buf num %d\n", + i, buf_num); + break; + } + buf->dbufs.dbuf = dummy->dbuf; } - buf->dbufs.dbuf = dummy->dbuf; buf->dbufs.is_init = false; buf->dbufs.type = frm_type; list_add_tail(&buf->dbufs.list, &stream->rx_buf_head); + dummy->is_free = false; if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) { buf->dbufs.is_first = true; rkcif_s_rx_buffer(dev, &buf->dbufs); + stream->buf_num_toisp--; } v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev, "init rx_buf,dma_addr 0x%llx size: 0x%x\n", @@ -4547,6 +4590,8 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) stream->buf_wake_up_cnt = 0; stream->lack_buf_cnt = 0; stream->frame_phase = 0; + stream->is_in_vblank = false; + stream->is_change_toisp = false; } sensor_info = dev->active_sensor; @@ -7379,6 +7424,7 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) u32 mode; struct rkcif_rx_buffer *active_buf = NULL; struct sditf_priv *priv = NULL; + unsigned long flags; int ret = 0; mode = stream->line_int_cnt % 2; @@ -7402,11 +7448,29 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) return; } ret = rkcif_get_new_buffer_wake_up_mode_rdbk(stream); + v4l2_dbg(3, rkcif_debug, &stream->cifdev->v4l2_dev, + "%d frame_idx %d, last_rx_buf_idx %d cur dma buf %x\n", + __LINE__, stream->frame_idx, stream->last_rx_buf_idx, + (u32)active_buf->dummy.dma_addr); if (!ret) { priv = stream->cifdev->sditf[0]; if (priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { + spin_lock_irqsave(&stream->vbq_lock, flags); + if ((stream->frame_idx - 1) == stream->last_rx_buf_idx && + stream->cifdev->is_thunderboot) { + stream->cur_stream_mode &= ~RKCIF_STREAM_MODE_TOISP_RDBK; + stream->cur_stream_mode |= RKCIF_STREAM_MODE_TOISP; + if (stream->cifdev->hdr.hdr_mode == NO_HDR) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + rkcif_stop_dma_capture(stream); + active_buf->dbufs.is_switch = true; + stream->cifdev->wait_line = 0; + stream->is_line_wake_up = false; + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); active_buf->dbufs.sequence = stream->frame_idx - 1; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; + stream->last_frame_idx = stream->frame_idx; rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); stream->buf_num_toisp--; } @@ -8431,6 +8495,13 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, stream->stopping = false; wake_up(&stream->wq_stopped); } + + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15) + v4l2_info(&priv->cif_dev->v4l2_dev, + "toisp fe %d\n", + stream->frame_idx - 1); + if (stream->to_en_dma) rkcif_enable_dma_capture(stream, false); if (stream->to_en_scale) { @@ -8462,6 +8533,11 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, else stream = &priv->cif_dev->stream[src_id % 4]; stream->frame_idx++; + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15) + v4l2_info(&priv->cif_dev->v4l2_dev, + "toisp sof seq %d\n", + stream->frame_idx - 1); switch (ch) { case RKCIF_TOISP_CH0: val = TOISP_FS_CH0(index); @@ -8627,6 +8703,12 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) rkcif_send_sof(cif_dev); if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode) detect_stream->frame_idx++; + if (detect_stream->cifdev->rdbk_debug && + detect_stream->frame_idx < 15) + v4l2_info(&cif_dev->v4l2_dev, + "sof %d %lld\n", + detect_stream->frame_idx - 1, + ktime_get_ns()); } } @@ -8769,7 +8851,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (stream->state != RKCIF_STATE_STREAMING) continue; - + stream->is_in_vblank = true; switch (mipi_id) { case RKCIF_STREAM_MIPI_ID0: stream->frame_phase = SW_FRM_END_ID0(intstat); @@ -8788,6 +8870,14 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) intstat &= ~CSI_FRAME_END_ID3; break; } + if (stream->cifdev->rdbk_debug && + stream->frame_idx < 15) + v4l2_info(&cif_dev->v4l2_dev, + "fe %d, phase %d, %lld\n", + stream->frame_idx - 1, + stream->frame_phase, + ktime_get_ns()); + if (stream->crop_dyn_en) rkcif_dynamic_crop(stream); @@ -8802,6 +8892,8 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) rkcif_modify_frame_skip_config(stream); } else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { rkcif_update_stream_toisp(cif_dev, stream, mipi_id); + } else if (stream->is_change_toisp) { + sditf_change_to_online(cif_dev->sditf[0]); } spin_lock_irqsave(&stream->vbq_lock, flags); @@ -8849,6 +8941,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream->frame_idx++; spin_unlock_irqrestore(&stream->fps_lock, flags); } + stream->is_in_vblank = false; if (stream->to_stop_dma) { ret = rkcif_stop_dma_capture(stream); if (!ret) @@ -8859,6 +8952,11 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream = &cif_dev->stream[i]; if (stream->is_line_inten) { stream->line_int_cnt++; + if (cif_dev->rdbk_debug > 1 && + stream->frame_idx < 15) + v4l2_info(&cif_dev->v4l2_dev, + "line int %lld\n", + stream->line_int_cnt); if (cif_dev->sditf[0] && cif_dev->sditf[0]->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) rkcif_line_wake_up_rdbk(stream, stream->id); else @@ -8924,7 +9022,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) if (stream->state != RKCIF_STATE_STREAMING) continue; - + stream->is_in_vblank = true; switch (ch_id) { case RKCIF_STREAM_MIPI_ID0: stream->frame_phase = SW_FRM_END_ID0(intstat); @@ -8954,8 +9052,10 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) cif_dev->irq_stats.all_frm_end_cnt++; } - if (intstat & DVP_FRAME0_START_ID0 || intstat & DVP_FRAME1_START_ID0) + if (intstat & DVP_FRAME0_START_ID0 || intstat & DVP_FRAME1_START_ID0) { + stream->is_in_vblank = false; rkcif_deal_sof(cif_dev); + } if (stream->crop_dyn_en) rkcif_dynamic_crop(stream); diff --git a/drivers/media/platform/rockchip/cif/common.c b/drivers/media/platform/rockchip/cif/common.c index 81d9f7e81142..d9493b2adf6c 100644 --- a/drivers/media/platform/rockchip/cif/common.c +++ b/drivers/media/platform/rockchip/cif/common.c @@ -186,3 +186,181 @@ void rkcif_free_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_bu mutex_unlock(&hw->dev_lock); } +struct rkcif_shm_data { + void *vaddr; + int vmap_cnt; + int npages; + struct page *pages[]; +}; + +static struct sg_table *rkcif_shm_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction dir) +{ + struct rkcif_shm_data *data = attachment->dmabuf->priv; + struct sg_table *table; + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + return ERR_PTR(-ENOMEM); + + sg_alloc_table_from_pages(table, data->pages, data->npages, 0, + data->npages << PAGE_SHIFT, GFP_KERNEL); + + dma_map_sgtable(attachment->dev, table, dir, DMA_ATTR_SKIP_CPU_SYNC); + + return table; +} + +static void rkcif_shm_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction dir) +{ + dma_unmap_sgtable(attachment->dev, table, dir, DMA_ATTR_SKIP_CPU_SYNC); + sg_free_table(table); + kfree(table); +} + +static void *rkcif_shm_vmap(struct dma_buf *dma_buf) +{ + struct rkcif_shm_data *data = dma_buf->priv; + + data->vaddr = vmap(data->pages, data->npages, VM_MAP, PAGE_KERNEL); + data->vmap_cnt++; + return data->vaddr; +} + +static void rkcif_shm_vunmap(struct dma_buf *dma_buf, void *vaddr) +{ + struct rkcif_shm_data *data = dma_buf->priv; + + vunmap(data->vaddr); + data->vaddr = NULL; + data->vmap_cnt--; +} + +static int rkcif_shm_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) +{ + struct rkcif_shm_data *data = dma_buf->priv; + unsigned long vm_start = vma->vm_start; + int i; + + for (i = 0; i < data->npages; i++) { + remap_pfn_range(vma, vm_start, page_to_pfn(data->pages[i]), + PAGE_SIZE, vma->vm_page_prot); + vm_start += PAGE_SIZE; + } + + return 0; +} + +static int rkcif_shm_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir) +{ + struct dma_buf_attachment *attachment; + struct sg_table *table; + + attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node); + table = attachment->priv; + dma_sync_sg_for_cpu(NULL, table->sgl, table->nents, dir); + + return 0; +} + +static int rkcif_shm_end_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir) +{ + struct dma_buf_attachment *attachment; + struct sg_table *table; + + attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node); + table = attachment->priv; + dma_sync_sg_for_device(NULL, table->sgl, table->nents, dir); + + return 0; +} + +static void rkcif_shm_release(struct dma_buf *dma_buf) +{ + struct rkcif_shm_data *data = dma_buf->priv; + + if (data->vmap_cnt) { + WARN(1, "%s: buffer still mapped in the kernel\n", __func__); + rkcif_shm_vunmap(dma_buf, data->vaddr); + } + kfree(data); +} + +static const struct dma_buf_ops rkcif_shm_dmabuf_ops = { + .map_dma_buf = rkcif_shm_map_dma_buf, + .unmap_dma_buf = rkcif_shm_unmap_dma_buf, + .release = rkcif_shm_release, + .mmap = rkcif_shm_mmap, + .vmap = rkcif_shm_vmap, + .vunmap = rkcif_shm_vunmap, + .begin_cpu_access = rkcif_shm_begin_cpu_access, + .end_cpu_access = rkcif_shm_end_cpu_access, +}; + +static struct dma_buf *rkcif_shm_alloc(struct rkisp_thunderboot_shmem *shmem) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *dmabuf; + struct rkcif_shm_data *data; + int i, npages; + + npages = PAGE_ALIGN(shmem->shm_size) / PAGE_SIZE; + data = kmalloc(sizeof(*data) + npages * sizeof(struct page *), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + data->vmap_cnt = 0; + data->npages = npages; + for (i = 0; i < npages; i++) + data->pages[i] = phys_to_page(shmem->shm_start + i * PAGE_SIZE); + + exp_info.ops = &rkcif_shm_dmabuf_ops; + exp_info.size = npages * PAGE_SIZE; + exp_info.flags = O_RDWR; + exp_info.priv = data; + + dmabuf = dma_buf_export(&exp_info); + + return dmabuf; +} + +int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf) +{ + struct rkcif_dummy_buffer *dummy = &buf->dummy; + + dummy->dma_addr = dev->resmem_pa + dummy->size * buf->buf_idx; + if (dummy->dma_addr + dummy->size > dev->resmem_pa + dev->resmem_size) + return -EINVAL; + buf->dbufs.dma = dummy->dma_addr; + buf->dbufs.is_resmem = true; + buf->shmem.shm_start = dummy->dma_addr; + buf->shmem.shm_size = dummy->size; + dummy->dbuf = rkcif_shm_alloc(&buf->shmem); + if (dummy->is_need_vaddr) + dummy->vaddr = dummy->dbuf->ops->vmap(dummy->dbuf); + return 0; +} + +void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf) +{ + struct rkcif_dummy_buffer *dummy = &buf->dummy; + + if (buf->dummy.is_free) + return; + + if (dev->rdbk_debug) + v4l2_info(&dev->v4l2_dev, + "free reserved mem addr 0x%x\n", + (u32)dummy->dma_addr); + + if (dummy->is_need_vaddr) + dummy->dbuf->ops->vunmap(dummy->dbuf, dummy->vaddr); +#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP + free_reserved_area(phys_to_virt(buf->shmem.shm_start), + phys_to_virt(buf->shmem.shm_start + buf->shmem.shm_size), + -1, "rkisp_thunderboot"); +#endif + buf->dummy.is_free = true; +} + diff --git a/drivers/media/platform/rockchip/cif/common.h b/drivers/media/platform/rockchip/cif/common.h index 86dbd55d1283..7bdfe4f40223 100644 --- a/drivers/media/platform/rockchip/cif/common.h +++ b/drivers/media/platform/rockchip/cif/common.h @@ -23,5 +23,8 @@ void rkcif_free_buffer(struct rkcif_device *dev, int rkcif_alloc_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf); void rkcif_free_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_buffer *buf); +int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf); +void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf); + #endif /* _RKCIF_COMMON_H */ diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index 2ca33ecaa2d7..fa85aed2f5c1 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -28,6 +28,8 @@ #include "procfs.h" #include #include "../../../../phy/rockchip/phy-rockchip-csi2-dphy-common.h" +#include +#include #define RKCIF_VERNO_LEN 10 @@ -1833,6 +1835,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int mutex_init(&cif_dev->scale_lock); mutex_init(&cif_dev->tools_lock); spin_lock_init(&cif_dev->hdr_lock); + spin_lock_init(&cif_dev->buffree_lock); spin_lock_init(&cif_dev->reset_watchdog_timer.timer_lock); spin_lock_init(&cif_dev->reset_watchdog_timer.csi2_err_lock); atomic_set(&cif_dev->pipe.power_cnt, 0); @@ -1849,6 +1852,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->is_notifier_isp = false; cif_dev->sensor_linetime = 0; cif_dev->early_line = 0; + cif_dev->is_thunderboot = false; cif_dev->rdbk_debug = 0; if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; @@ -2003,6 +2007,35 @@ static void rkcif_parse_dts(struct rkcif_device *cif_dev) dev_info(cif_dev->dev, "rkcif wait line %d\n", cif_dev->wait_line); } +static int rkcif_get_reserved_mem(struct rkcif_device *cif_dev) +{ + struct device *dev = cif_dev->dev; + struct device_node *np; + struct resource r; + int ret; + + /* Get reserved memory region from Device-tree */ + np = of_parse_phandle(dev->of_node, "memory-region-thunderboot", 0); + if (!np) { + dev_info(dev, "No memory-region-thunderboot specified\n"); + return 0; + } + + ret = of_address_to_resource(np, 0, &r); + if (ret) { + dev_err(dev, "No memory address assigned to the region\n"); + return ret; + } + + cif_dev->resmem_pa = r.start; + cif_dev->resmem_size = resource_size(&r); + 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); + return ret; +} + static int rkcif_plat_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -2044,6 +2077,10 @@ static int rkcif_plat_probe(struct platform_device *pdev) return ret; } + ret = rkcif_get_reserved_mem(cif_dev); + if (ret) + return ret; + if (rkcif_proc_init(cif_dev)) dev_warn(dev, "dev:%s create proc failed\n", dev_name(dev)); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 6fbd7d7e9b13..46477f8a1511 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -442,8 +442,10 @@ enum rkcif_capture_mode { }; struct rkcif_rx_buffer { + int buf_idx; struct rkisp_rx_buf dbufs; struct rkcif_dummy_buffer dummy; + struct rkisp_thunderboot_shmem shmem; }; enum rkcif_dma_en_mode { @@ -521,6 +523,8 @@ struct rkcif_stream { int lack_buf_cnt; unsigned int buf_wake_up_cnt; struct rkcif_skip_info skip_info; + int last_rx_buf_idx; + int last_frame_idx; bool stopping; bool crop_enable; bool crop_dyn_en; @@ -534,6 +538,8 @@ struct rkcif_stream { bool is_high_align; bool to_en_scale; bool is_finish_stop_dma; + bool is_in_vblank; + bool is_change_toisp; }; struct rkcif_lvds_subdev { @@ -793,6 +799,7 @@ struct rkcif_device { struct proc_dir_entry *proc_dir; struct rkcif_irq_stats irq_stats; spinlock_t hdr_lock; /* lock for hdr buf sync */ + spinlock_t buffree_lock; struct rkcif_timer reset_watchdog_timer; struct rkcif_work_struct reset_work; int id_use_cnt; @@ -804,11 +811,14 @@ struct rkcif_device { struct rkcif_dummy_buffer dummy_buf; struct completion cmpl_ntf; struct csi2_dphy_hw *dphy_hw; + phys_addr_t resmem_pa; + size_t resmem_size; bool is_start_hdr; bool reset_work_cancel; bool iommu_en; bool is_use_dummybuf; bool is_notifier_isp; + bool is_thunderboot; int rdbk_debug; int sync_type; int sditf_cnt; @@ -892,6 +902,7 @@ void rkcif_config_dvp_pin(struct rkcif_device *dev, bool on); s32 rkcif_get_sensor_vblank_def(struct rkcif_device *dev); s32 rkcif_get_sensor_vblank(struct rkcif_device *dev); +int rkcif_get_linetime(struct rkcif_stream *stream); void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream); diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 72b5f39275a7..476ecb62e8a1 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -22,12 +22,41 @@ #include "dev.h" #include #include +#include "common.h" static inline struct sditf_priv *to_sditf_priv(struct v4l2_subdev *subdev) { return container_of(subdev, struct sditf_priv, sd); } +void sditf_buffree_work(struct work_struct *work) +{ + struct sditf_work_struct *buffree_work = container_of(work, + struct sditf_work_struct, + work); + struct sditf_priv *priv = container_of(buffree_work, + struct sditf_priv, + buffree_work); + struct rkcif_rx_buffer *rx_buf = NULL; + struct rkisp_rx_buf *dbufs = NULL; + unsigned long flags; + LIST_HEAD(local_list); + + spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags); + list_replace_init(&priv->buf_free_list, &local_list); + while (!list_empty(&local_list)) { + dbufs = list_first_entry(&local_list, + struct rkisp_rx_buf, list); + if (dbufs) { + list_del(&dbufs->list); + rx_buf = container_of(dbufs, struct rkcif_rx_buffer, dbufs); + if (rx_buf) + rkcif_free_reserved_mem_buf(priv->cif_dev, rx_buf); + } + } + spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags); +} + static void sditf_get_hdr_mode(struct sditf_priv *priv) { struct rkcif_device *cif_dev = priv->cif_dev; @@ -474,6 +503,23 @@ static void sditf_channel_disable(struct sditf_priv *priv, int user) priv->toisp_inf.ch_info[2].is_valid = false; } +void sditf_change_to_online(struct sditf_priv *priv) +{ + struct rkcif_device *cif_dev = priv->cif_dev; + + priv->mode.rdbk_mode = RKISP_VICAP_ONLINE; + if (priv->toisp_inf.link_mode == TOISP0) { + sditf_channel_enable(priv, 0); + } else if (priv->toisp_inf.link_mode == TOISP1) { + sditf_channel_enable(priv, 1); + } else if (priv->toisp_inf.link_mode == TOISP_UNITE) { + sditf_channel_enable(priv, 0); + sditf_channel_enable(priv, 1); + } + if (priv->hdr_cfg.hdr_mode == NO_HDR) + rkcif_free_rx_buf(&cif_dev->stream[0], priv->buf_num); +} + static int sditf_start_stream(struct sditf_priv *priv) { struct rkcif_device *cif_dev = priv->cif_dev; @@ -506,6 +552,7 @@ static int sditf_start_stream(struct sditf_priv *priv) rkcif_do_start_stream(&cif_dev->stream[1], mode); rkcif_do_start_stream(&cif_dev->stream[2], mode); } + INIT_LIST_HEAD(&priv->buf_free_list); return 0; } @@ -604,8 +651,9 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, struct rkcif_stream *stream = NULL; struct rkisp_rx_buf *dbufs; struct rkcif_rx_buffer *rx_buf = NULL; - unsigned long flags; + unsigned long flags, buffree_flags; u32 diff_time = 1000000; + u32 early_time = 0; if (!buf) { v4l2_err(&cif_dev->v4l2_dev, "buf is NULL\n"); @@ -642,80 +690,88 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, rx_buf = to_cif_rx_buf(dbufs); spin_lock_irqsave(&stream->vbq_lock, flags); + stream->buf_num_toisp++; + stream->last_rx_buf_idx = dbufs->sequence + 1; + + if (!list_empty(&stream->rx_buf_head) && + cif_dev->is_thunderboot) { + spin_lock_irqsave(&cif_dev->buffree_lock, buffree_flags); + list_add_tail(&dbufs->list, &priv->buf_free_list); + spin_unlock_irqrestore(&cif_dev->buffree_lock, buffree_flags); + schedule_work(&priv->buffree_work.work); + } + if (!rx_buf->dummy.is_free) { list_add_tail(&dbufs->list, &stream->rx_buf_head); rkcif_assign_check_buffer_update_toisp(stream); - if (cif_dev->rdbk_debug) - memset(rx_buf->dummy.vaddr + rx_buf->dummy.size - 1920 * 10, - 0x00, 1920 * 10); + if (cif_dev->rdbk_debug) { + u32 offset = 0; + + offset = rx_buf->dummy.size - stream->pixm.plane_fmt[0].bytesperline * 3; + memset(rx_buf->dummy.vaddr + offset, + 0x00, stream->pixm.plane_fmt[0].bytesperline * 3); + if (cif_dev->is_thunderboot) + dma_sync_single_for_device(cif_dev->dev, + rx_buf->dummy.dma_addr + rx_buf->dummy.size - + stream->pixm.plane_fmt[0].bytesperline * 3, + stream->pixm.plane_fmt[0].bytesperline * 3, + DMA_FROM_DEVICE); + else + cif_dev->hw_dev->mem_ops->prepare(rx_buf->dummy.mem_priv); + } } + if (dbufs->is_switch) { + if (stream->is_in_vblank) + sditf_change_to_online(priv); + else + stream->is_change_toisp = true; + v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, + "switch to online mode\n"); + } spin_unlock_irqrestore(&stream->vbq_lock, flags); if (dbufs->runtime_us && cif_dev->early_line == 0) { - u32 numerator, denominator; - u32 def_fps = 0; - int line_time = 0; - int vblank_def = 0; - int vblank_curr = 0; - - numerator = sensor->fi.interval.numerator; - denominator = sensor->fi.interval.denominator; - if (!numerator || !denominator) { - v4l2_err(&cif_dev->v4l2_dev, - "get frame interval fail, numerator %d, denominator %d\n", - numerator, denominator); - return -EINVAL; - } - def_fps = denominator / numerator; - if (!def_fps) { - v4l2_err(&cif_dev->v4l2_dev, - "get fps fail, numerator %d, denominator %d\n", - numerator, denominator); - return -EINVAL; - } - vblank_def = rkcif_get_sensor_vblank_def(cif_dev); - vblank_curr = rkcif_get_sensor_vblank(cif_dev); - if (!vblank_def || !vblank_curr) { - v4l2_err(&cif_dev->v4l2_dev, - "get vblank fail, vblank_def %d, vblank_curr %d\n", - vblank_def, vblank_curr); - return -EINVAL; - } - line_time = div_u64(1000000000, def_fps); - line_time = div_u64(line_time, vblank_def + sensor->raw_rect.height); - if (!line_time) { - v4l2_err(&cif_dev->v4l2_dev, - "get line time fail, line_time %d\n", - line_time); - return -EINVAL; - } - if (vblank_curr * line_time < 1000) - v4l2_warn(&cif_dev->v4l2_dev, - "vblank < 1ms, val %d\n", - vblank_curr * line_time); + if (cif_dev->sensor_linetime) + cif_dev->sensor_linetime = rkcif_get_linetime(stream); cif_dev->isp_runtime_max = dbufs->runtime_us; - cif_dev->sensor_linetime = line_time; - cif_dev->early_line = div_u64(dbufs->runtime_us * 1000 - diff_time, line_time); + if (cif_dev->is_thunderboot) + diff_time = 200000; + else + diff_time = 1000000; + if (dbufs->runtime_us * 1000 + cif_dev->sensor_linetime > diff_time) + early_time = dbufs->runtime_us * 1000 - diff_time; + else + early_time = diff_time; + cif_dev->early_line = div_u64(early_time, cif_dev->sensor_linetime); cif_dev->wait_line_cache = sensor->raw_rect.height - cif_dev->early_line; if (cif_dev->rdbk_debug && dbufs->sequence < 15) v4l2_info(&cif_dev->v4l2_dev, "%s, isp runtime %d, line time %d, early_line %d, line_intr_cnt %d, seq %d, dma_addr %x\n", - __func__, dbufs->runtime_us, line_time, + __func__, dbufs->runtime_us, cif_dev->sensor_linetime, cif_dev->early_line, cif_dev->wait_line_cache, dbufs->sequence, (u32)rx_buf->dummy.dma_addr); } else { - if (dbufs->runtime_us > cif_dev->isp_runtime_max + cif_dev->sensor_linetime) { + if (dbufs->runtime_us < cif_dev->isp_runtime_max) { cif_dev->isp_runtime_max = dbufs->runtime_us; - cif_dev->early_line = div_u64(dbufs->runtime_us * 1000 - diff_time, cif_dev->sensor_linetime); + if (cif_dev->is_thunderboot) + diff_time = 200000; + else + diff_time = 1000000; + if (dbufs->runtime_us * 1000 + cif_dev->sensor_linetime > diff_time) + early_time = dbufs->runtime_us * 1000 - diff_time; + else + early_time = diff_time; + cif_dev->early_line = div_u64(early_time, cif_dev->sensor_linetime); cif_dev->wait_line_cache = sensor->raw_rect.height - cif_dev->early_line; } if (cif_dev->rdbk_debug && dbufs->sequence < 15) v4l2_info(&cif_dev->v4l2_dev, - "isp runtime %d, seq %d, dma addr %x\n", - dbufs->runtime_us, dbufs->sequence, (u32)rx_buf->dummy.dma_addr); + "isp runtime %d, seq %d, early_line %d, dma addr %x\n", + dbufs->runtime_us, dbufs->sequence, + cif_dev->early_line, (u32)rx_buf->dummy.dma_addr); } return 0; } @@ -986,7 +1042,7 @@ static int rkcif_subdev_media_init(struct sditf_priv *priv) strncpy(priv->sd.name, dev_name(cif_dev->dev), sizeof(priv->sd.name)); priv->cap_info.width = 0; priv->cap_info.height = 0; - priv->mode.rdbk_mode = RKISP_VICAP_ONLINE; + priv->mode.rdbk_mode = RKISP_VICAP_RDBK_AIQ; priv->toisp_inf.link_mode = TOISP_NONE; priv->toisp_inf.ch_info[0].is_valid = false; priv->toisp_inf.ch_info[1].is_valid = false; @@ -995,6 +1051,8 @@ static int rkcif_subdev_media_init(struct sditf_priv *priv) sditf_subdev_notifier(priv); atomic_set(&priv->power_cnt, 0); atomic_set(&priv->stream_cnt, 0); + INIT_WORK(&priv->buffree_work.work, sditf_buffree_work); + INIT_LIST_HEAD(&priv->buf_free_list); return 0; } diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.h b/drivers/media/platform/rockchip/cif/subdev-itf.h index 965b79924b74..1c917f2f5e92 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.h +++ b/drivers/media/platform/rockchip/cif/subdev-itf.h @@ -54,6 +54,11 @@ struct toisp_info { enum toisp_link_mode link_mode; }; +struct sditf_work_struct { + struct work_struct work; + struct rkisp_rx_buffer *buf; +}; + struct sditf_priv { struct device *dev; struct v4l2_async_notifier notifier; @@ -67,6 +72,8 @@ struct sditf_priv { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_subdev *sensor_sd; + struct sditf_work_struct buffree_work; + struct list_head buf_free_list; int buf_num; int num_sensors; int combine_index; @@ -76,5 +83,6 @@ struct sditf_priv { }; extern struct platform_driver rkcif_subdev_driver; +void sditf_change_to_online(struct sditf_priv *priv); #endif