From b5a1e17100dde5eea9ad725521d81ea45e1801f8 Mon Sep 17 00:00:00 2001 From: Xu Hongfei Date: Sat, 18 May 2019 12:50:34 +0800 Subject: [PATCH] media: rockchip: rk-cif: v0.1.2 Compatible with cif only have single dma mode in driver Change-Id: I5f2296549e20e3db1d8883474936e2892afc3ff0 Signed-off-by: Xu Hongfei --- drivers/media/platform/rockchip/cif/capture.c | 334 +++++++----------- drivers/media/platform/rockchip/cif/dev.c | 68 +++- drivers/media/platform/rockchip/cif/dev.h | 45 ++- drivers/media/platform/rockchip/cif/regs.h | 5 + drivers/media/platform/rockchip/cif/version.h | 4 +- 5 files changed, 203 insertions(+), 253 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index bc888a263fd0..2019ea9f9c63 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -523,22 +523,22 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream, /* Set up an empty buffer for the next frame */ spin_lock(&stream->vbq_lock); if (!list_empty(&stream->buf_head)) { - if (stream->frame_phase == 0 || init) { + if (stream->frame_phase == CIF_CSI_FRAME0_READY || init) { stream->curr_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); list_del(&stream->curr_buf->queue); buffer = stream->curr_buf; } - if (stream->frame_phase == 1 || init) { + if (stream->frame_phase == CIF_CSI_FRAME1_READY || init) { stream->next_buf = list_first_entry(&stream->buf_head, struct rkcif_buffer, queue); list_del(&stream->next_buf->queue); buffer = stream->next_buf; } } else { - if (stream->frame_phase == 0) + if (stream->frame_phase & CIF_CSI_FRAME0_READY) stream->curr_buf = NULL; - if (stream->frame_phase == 1) + if (stream->frame_phase & CIF_CSI_FRAME1_READY) stream->next_buf = NULL; buffer = NULL; @@ -582,16 +582,16 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream, } if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) { - frm_addr_y = stream->frame_phase == 1 ? + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ? (CIF_CSI_FRM1_ADDR_Y_ID0 + 0x20 * csi_ch) : (CIF_CSI_FRM0_ADDR_Y_ID0 + 0x20 * csi_ch); - frm_addr_uv = stream->frame_phase == 1 ? + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ? (CIF_CSI_FRM1_ADDR_UV_ID0 + 0x20 * csi_ch) : (CIF_CSI_FRM0_ADDR_UV_ID0 + 0x20 * csi_ch); } else { - frm_addr_y = stream->frame_phase == 1 ? + frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ? CIF_FRM1_ADDR_Y : CIF_FRM0_ADDR_Y; - frm_addr_uv = stream->frame_phase == 1 ? + frm_addr_uv = stream->frame_phase & CIF_CSI_FRAME1_READY ? CIF_FRM1_ADDR_UV : CIF_FRM0_ADDR_UV; } @@ -714,12 +714,9 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream, CSI_LINE_INTSTAT(channel->id))); write_cif_reg_or(base, CIF_CSI_INTEN, CSI_DMA_END_INTEN(channel->id)); - mutex_lock(&dev->dev_lock); - if (!dev->working) { - write_cif_reg(base, CIF_CSI_WATER_LINE, 0x70012); - write_cif_reg_or(base, CIF_CSI_INTEN, CSI_ALL_ERROR_INTEN); - } - mutex_unlock(&dev->dev_lock); + + write_cif_reg(base, CIF_CSI_WATER_LINE, 0x70012); + write_cif_reg_or(base, CIF_CSI_INTEN, CSI_ALL_ERROR_INTEN); write_cif_reg(base, CIF_CSI_ID0_CTRL1 + 0x8 * channel->id, channel->width | (channel->height << 16)); @@ -787,9 +784,8 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) ~(CSI_START_INTEN(id) | CSI_DMA_END_INTEN(id) | CSI_LINE_INTEN(id))); - if (!cif_dev->working) - write_cif_reg_and(base, CIF_CSI_INTEN, - ~CSI_ALL_ERROR_INTEN); + write_cif_reg_and(base, CIF_CSI_INTEN, + ~CSI_ALL_ERROR_INTEN); } else { val = read_cif_reg(base, CIF_CTRL); write_cif_reg(base, CIF_CTRL, val & (~ENABLE_CAPTURE)); @@ -916,39 +912,10 @@ static void rkcif_stop_streaming(struct vb2_queue *queue) struct rkcif_device *dev = stream->cifdev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; struct rkcif_buffer *buf; - int i, ret; + int ret; stream->stopping = true; - /* TODO: Determines whether to close the subdevice */ - for (i = 0; i < 4; i++) { - if (i == stream->id) - continue; - - if (dev->stream[i].state == RKCIF_STATE_STREAMING) - break; - } - mutex_lock(&dev->dev_lock); - /* - * TODO: According to the number of actual stream on - * deciding whether to shut down - */ - if (i > 2) { - pr_err("%s: dev isn't working!\n", __func__); - dev->working = false; - } - mutex_unlock(&dev->dev_lock); - - media_entity_pipeline_stop(&node->vdev.entity); - mutex_lock(&dev->dev_lock); - if (!dev->working) { - ret = dev->pipe.set_stream(&dev->pipe, false); - if (ret < 0) - v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n", - ret); - } - mutex_unlock(&dev->dev_lock); - ret = wait_event_timeout(stream->wq_stopped, stream->state != RKCIF_STATE_STREAMING, msecs_to_jiffies(1000)); @@ -957,6 +924,12 @@ static void rkcif_stop_streaming(struct vb2_queue *queue) stream->stopping = false; } + media_entity_pipeline_stop(&node->vdev.entity); + ret = dev->pipe.set_stream(&dev->pipe, false); + if (ret < 0) + v4l2_err(v4l2_dev, "pipeline stream-off failed error:%d\n", + ret); + /* release buffers */ if (stream->curr_buf) { list_add_tail(&stream->curr_buf->queue, &stream->buf_head); @@ -976,16 +949,12 @@ static void rkcif_stop_streaming(struct vb2_queue *queue) rkcif_destroy_dummy_buf(stream); - mutex_lock(&dev->dev_lock); - if (!dev->working) { - ret = dev->pipe.close(&dev->pipe); - if (ret < 0) - v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", - ret); - pm_runtime_put(dev->dev); - dev->is_cif_rst = false; - } - mutex_unlock(&dev->dev_lock); + ret = dev->pipe.close(&dev->pipe); + if (ret < 0) + v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", + ret); + /* rkcif_soft_reset(dev, false); */ + pm_runtime_put(dev->dev); } /* @@ -1099,12 +1068,13 @@ static int rkcif_stream_start(struct rkcif_stream *stream) write_cif_reg(base, CIF_INTEN, FRAME_END_EN | PST_INF_FRAME_END); if (dev->chip_id == CHIP_RK1808_CIF && - rkcif_determine_input_mode(stream) == INPUT_MODE_BT1120) + rkcif_determine_input_mode(stream) == INPUT_MODE_BT1120) { write_cif_reg(base, CIF_CTRL, AXI_BURST_16 | MODE_PINGPONG | ENABLE_CAPTURE); - else + } else { write_cif_reg(base, CIF_CTRL, AXI_BURST_16 | MODE_ONEFRAME | ENABLE_CAPTURE); + } stream->state = RKCIF_STATE_STREAMING; @@ -1187,26 +1157,20 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) goto destroy_buf; } - mutex_lock(&dev->dev_lock); /* enable clocks/power-domains */ - if (!dev->working) { - ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to get runtime pm, %d\n", - ret); - mutex_unlock(&dev->dev_lock); - goto destroy_dummy_buf; - } - - ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); - if (ret < 0) { - v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", - ret); - mutex_unlock(&dev->dev_lock); - goto destroy_dummy_buf; - } + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to get runtime pm, %d\n", + ret); + goto destroy_buf; + } + + ret = dev->pipe.open(&dev->pipe, &node->vdev.entity, true); + if (ret < 0) { + v4l2_err(v4l2_dev, "open cif pipeline failed %d\n", + ret); + goto destroy_buf; } - mutex_unlock(&dev->dev_lock); if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) { ret = rkcif_csi_stream_start(stream); @@ -1216,16 +1180,10 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) if (ret < 0) goto runtime_put; - mutex_lock(&dev->dev_lock); /* start sub-devices */ - if (!dev->working) { - ret = dev->pipe.set_stream(&dev->pipe, true); - if (ret < 0) { - mutex_unlock(&dev->dev_lock); - goto stop_stream; - } - } - mutex_unlock(&dev->dev_lock); + ret = dev->pipe.set_stream(&dev->pipe, true); + if (ret < 0) + goto stop_stream; ret = media_entity_pipeline_start(&node->vdev.entity, &dev->pipe.pipe); if (ret < 0) { @@ -1234,25 +1192,15 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count) goto pipe_stream_off; } - mutex_lock(&dev->dev_lock); - dev->working = true; - mutex_unlock(&dev->dev_lock); v4l2_info(&dev->v4l2_dev, "%s successfully!\n", __func__); return 0; pipe_stream_off: - mutex_lock(&dev->dev_lock); - if (!dev->working) - dev->pipe.set_stream(&dev->pipe, false); - mutex_unlock(&dev->dev_lock); - + dev->pipe.set_stream(&dev->pipe, false); stop_stream: rkcif_stream_stop(stream); runtime_put: - mutex_lock(&dev->dev_lock); - if (!dev->working) - pm_runtime_put(dev->dev); - mutex_unlock(&dev->dev_lock); + pm_runtime_put(dev->dev); destroy_buf: if (stream->next_buf) vb2_buffer_done(&stream->next_buf->vb.vb2_buf, @@ -1268,7 +1216,7 @@ destroy_buf: vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); list_del(&buf->queue); } -destroy_dummy_buf: + rkcif_destroy_dummy_buf(stream); return ret; } @@ -1328,9 +1276,9 @@ static void rkcif_set_fmt(struct rkcif_stream *stream, * the size should not be larger than input */ pixm->width = clamp_t(u32, pixm->width, - CIF_MIN_WIDTH, CIF_MAX_WIDTH); + CIF_MIN_WIDTH, input_rect.width); pixm->height = clamp_t(u32, pixm->height, - CIF_MIN_HEIGHT, CIF_MAX_HEIGHT); + CIF_MIN_HEIGHT, input_rect.height); pixm->num_planes = fmt->mplanes; pixm->field = V4L2_FIELD_NONE; pixm->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -1414,33 +1362,32 @@ void rkcif_stream_init(struct rkcif_device *dev, u32 id) static int rkcif_fh_open(struct file *filp) { -#if 1 struct video_device *vdev = video_devdata(filp); struct rkcif_vdev_node *vnode = vdev_to_node(vdev); struct rkcif_stream *stream = to_rkcif_stream(vnode); struct rkcif_device *cifdev = stream->cifdev; + int ret; + + /* Make sure active sensor is valid before .set_fmt() */ + if (!cifdev->active_sensor) { + ret = rkcif_update_sensor_info(stream); + if (ret < 0) { + v4l2_err(vdev, + "update sensor info failed %d\n", + ret); + return ret; + } + } /* - * [> Make sure active sensor is valid before .set_fmt() <] - * cifdev->active_sensor = get_active_sensor(stream); - * if (!cifdev->active_sensor) { - * v4l2_err(vdev, "Not sensor linked\n"); - * return -EINVAL; - * } - */ - - - /* Soft reset via CRU. + * Soft reset via CRU. * Because CRU would reset iommu too, so there's not chance * to reset cif once we hold buffers after buf queued */ - mutex_lock(&cifdev->dev_lock); - if (!cifdev->is_cif_rst) { - rkcif_soft_reset(cifdev); - cifdev->is_cif_rst = true; - } - mutex_unlock(&cifdev->dev_lock); -#endif + if (cifdev->chip_id == CHIP_RK1808_CIF) + atomic_inc(&cifdev->fh_cnt); + else + rkcif_soft_reset(cifdev, true); ret = vb2_fop_release(file); if (!ret) { @@ -1452,9 +1399,28 @@ static int rkcif_fh_open(struct file *filp) return ret; } +static int rkcif_fh_release(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct rkcif_vdev_node *vnode = vdev_to_node(vdev); + struct rkcif_stream *stream = to_rkcif_stream(vnode); + struct rkcif_device *cifdev = stream->cifdev; + int ret = 0; + + ret = vb2_fop_release(filp); + mutex_lock(&cifdev->stream_lock); + if (!atomic_dec_return(&cifdev->fh_cnt)) + rkcif_soft_reset(cifdev, true); + else if (atomic_read(&cifdev->fh_cnt) < 0) + atomic_set(&cifdev->fh_cnt, 0); + mutex_unlock(&cifdev->stream_lock); + + return ret; +} + static const struct v4l2_file_operations rkcif_fops = { .open = rkcif_fh_open, - .release = rkcif_fop_release, + .release = rkcif_fh_release, .unlocked_ioctl = video_ioctl2, .poll = vb2_fop_poll, .mmap = vb2_fop_mmap, @@ -1664,26 +1630,29 @@ unreg: return ret; } -void rkcif_unregister_stream_vdevs(struct rkcif_device *dev) +void rkcif_unregister_stream_vdevs(struct rkcif_device *dev, + int stream_num) { struct rkcif_stream *stream; int i; - for (i = 0; i < RKCIF_MAX_STREAM; i++) { + for (i = 0; i < stream_num; i++) { stream = &dev->stream[i]; rkcif_unregister_stream_vdev(stream); } } -int rkcif_register_stream_vdevs(struct rkcif_device *dev) +int rkcif_register_stream_vdevs(struct rkcif_device *dev, + int stream_num, + bool is_multi_input) { struct rkcif_stream *stream; int i, j, ret; - for (i = 0; i < RKCIF_MAX_STREAM; i++) { + for (i = 0; i < stream_num; i++) { stream = &dev->stream[i]; stream->cifdev = dev; - ret = rkcif_register_stream_vdev(stream, true); + ret = rkcif_register_stream_vdev(stream, is_multi_input); if (ret < 0) goto err; } @@ -1777,37 +1746,34 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev) } } -static int rkcif_csi_g_mipi_id(unsigned int intstat) +static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev, + unsigned int intstat) { if (intstat & CSI_FRAME_END_ID0) { if ((intstat & CSI_FRAME_END_ID0) == - CSI_FRAME_END_ID0) { - return -EINVAL; - } + CSI_FRAME_END_ID0) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID0\n"); return RKCIF_STREAM_MIPI_ID0; } if (intstat & CSI_FRAME_END_ID1) { if ((intstat & CSI_FRAME_END_ID1) == - CSI_FRAME_END_ID0) { - return -EINVAL; - } + CSI_FRAME_END_ID1) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID1\n"); return RKCIF_STREAM_MIPI_ID1; } if (intstat & CSI_FRAME_END_ID2) { if ((intstat & CSI_FRAME_END_ID2) == - CSI_FRAME_END_ID0) { - return -EINVAL; - } + CSI_FRAME_END_ID2) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID2\n"); return RKCIF_STREAM_MIPI_ID2; } if (intstat & CSI_FRAME_END_ID3) { if ((intstat & CSI_FRAME_END_ID3) == - CSI_FRAME_END_ID0) { - return -EINVAL; - } + CSI_FRAME_END_ID3) + v4l2_warn(v4l2_dev, "frame0/1 trigger simultaneously in ID3\n"); return RKCIF_STREAM_MIPI_ID3; } @@ -1844,7 +1810,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) return; } - mipi_id = rkcif_csi_g_mipi_id(intstat); + mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat); if (mipi_id < 0) { v4l2_err(&cif_dev->v4l2_dev, "ERROR: irq[%d] is invalid: 0x%x, lastline: %d, return!!!\n", @@ -1853,7 +1819,8 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) } for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { - mipi_id = rkcif_csi_g_mipi_id(intstat); + mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, + intstat); if (mipi_id < 0) continue; @@ -1869,100 +1836,37 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev) if (stream->state != RKCIF_STATE_STREAMING) continue; - if (stream->frame_idx == 0) { - switch (mipi_id) { + switch (mipi_id) { case RKCIF_STREAM_MIPI_ID0: stream->frame_phase = - intstat & CSI_FRAME0_END_ID0 ? 0 : 1; + SW_FRM_END_ID0(intstat); + intstat &= ~CSI_FRAME_END_ID0; break; case RKCIF_STREAM_MIPI_ID1: stream->frame_phase = - intstat & CSI_FRAME0_END_ID1 ? 0 : 1; + SW_FRM_END_ID1(intstat); + intstat &= ~CSI_FRAME_END_ID1; break; case RKCIF_STREAM_MIPI_ID2: stream->frame_phase = - intstat & CSI_FRAME0_END_ID2 ? 0 : 1; + SW_FRM_END_ID2(intstat); + intstat &= ~CSI_FRAME_END_ID2; break; case RKCIF_STREAM_MIPI_ID3: stream->frame_phase = - intstat & CSI_FRAME0_END_ID3 ? 0 : 1; + SW_FRM_END_ID3(intstat); + intstat &= ~CSI_FRAME_END_ID3; break; - } - } else { - stream->frame_phase ^= 1; } - if (mipi_id == RKCIF_STREAM_MIPI_ID0) { - if (intstat & CSI_FRAME0_END_ID0 && - stream->frame_phase != 0) { - stream->frame_phase = 0; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id0 last frame1 intr miss\n"); - } - if (intstat & CSI_FRAME1_END_ID0 && - stream->frame_phase != 1) { - stream->frame_phase = 1; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id0 last frame0 intr miss\n"); - } - intstat &= ~CSI_FRAME_END_ID0; - } - - if (mipi_id == RKCIF_STREAM_MIPI_ID1) { - if (intstat & CSI_FRAME0_END_ID1 && - stream->frame_phase != 0) { - stream->frame_phase = 0; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id1 last frame1 intr miss\n"); - } - if (intstat & CSI_FRAME1_END_ID1 && - stream->frame_phase != 1) { - stream->frame_phase = 1; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id1 last frame0 intr miss\n"); - } - intstat &= ~CSI_FRAME_END_ID1; - } - - if (mipi_id == RKCIF_STREAM_MIPI_ID2) { - if (intstat & CSI_FRAME0_END_ID2 && - stream->frame_phase != 0) { - stream->frame_phase = 0; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id2 last frame1 intr miss\n"); - } - if (intstat & CSI_FRAME1_END_ID2 && - stream->frame_phase != 1) { - stream->frame_phase = 1; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id2 last frame0 intr miss\n"); - } - intstat &= ~CSI_FRAME_END_ID2; - } - - if (mipi_id == RKCIF_STREAM_MIPI_ID3) { - if (intstat & CSI_FRAME0_END_ID3 && - stream->frame_phase != 0) { - stream->frame_phase = 0; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id3 last frame1 intr miss\n"); - } - if (intstat & CSI_FRAME1_END_ID3 && - stream->frame_phase != 1) { - stream->frame_phase = 1; - v4l2_err(&cif_dev->v4l2_dev, - "ERROR: id3 last frame0 intr miss\n"); - } - intstat &= ~CSI_FRAME_END_ID3; - } - - if (stream->frame_phase == 1) { + if (stream->frame_phase & CIF_CSI_FRAME1_READY) { if (stream->next_buf) vb_done = &stream->next_buf->vb; - } else { + } else if (stream->frame_phase & CIF_CSI_FRAME0_READY) { if (stream->curr_buf) vb_done = &stream->curr_buf->vb; } + rkcif_assign_new_buffer_pingpong(stream, 0, mipi_id); if (vb_done) diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index a4fbacd06683..a10856c3c6cf 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -37,7 +37,7 @@ struct cif_match_data { int rsts_num; }; -int rkcif_debug = 3; +int rkcif_debug; module_param_named(debug, rkcif_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -205,9 +205,14 @@ err_stream_off: /***************************** media controller *******************************/ static int rkcif_create_links(struct rkcif_device *dev) { - unsigned int s, pad, id; + unsigned int s, pad, id, stream_num = 0; int ret; + if (dev->chip_id == CHIP_RK1808_CIF) + stream_num = RKCIF_MULTI_STREAMS_NUM; + else + stream_num = RKCIF_SINGLE_STREAM; + /* sensor links(or mipi-phy) */ for (s = 0; s < dev->num_sensors; ++s) { struct rkcif_sensor_info *sensor = &dev->sensors[s]; @@ -223,13 +228,14 @@ static int rkcif_create_links(struct rkcif_device *dev) return -ENXIO; } - for (id = 0; id < RKCIF_MAX_STREAM_MIPI; id++) { + for (id = 0; id < stream_num; id++) { ret = media_entity_create_link( &sensor->sd->entity, pad, &dev->stream[id].vnode.vdev.entity, 0, - id == pad - 1 ? MEDIA_LNK_FL_ENABLED : 0); + (dev->chip_id != CHIP_RK1808_CIF) | (id == pad - 1) ? + MEDIA_LNK_FL_ENABLED : 0); if (ret) { dev_err(dev->dev, "failed to create link for %s\n", @@ -358,13 +364,23 @@ static int cif_subdev_notifier(struct rkcif_device *cif_dev) static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev) { - int ret; + int stream_num = 0, ret; cif_dev->alloc_ctx = vb2_dma_contig_init_ctx(cif_dev->v4l2_dev.dev); - ret = rkcif_register_stream_vdevs(cif_dev); - if (ret < 0) - goto err_cleanup_ctx; + if (cif_dev->chip_id == CHIP_RK1808_CIF) { + stream_num = RKCIF_MULTI_STREAMS_NUM; + ret = rkcif_register_stream_vdevs(cif_dev, stream_num, + true); + if (ret < 0) + goto err_cleanup_ctx; + } else { + stream_num = RKCIF_SINGLE_STREAM; + ret = rkcif_register_stream_vdevs(cif_dev, stream_num, + false); + if (ret < 0) + goto err_cleanup_ctx; + } ret = cif_subdev_notifier(cif_dev); if (ret < 0) { @@ -375,7 +391,7 @@ static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev) return 0; err_unreg_stream_vdev: - rkcif_unregister_stream_vdevs(cif_dev); + rkcif_unregister_stream_vdevs(cif_dev, stream_num); err_cleanup_ctx: vb2_dma_contig_cleanup_ctx(cif_dev->alloc_ctx); @@ -544,10 +560,13 @@ static inline bool is_iommu_enable(struct device *dev) return true; } -void rkcif_soft_reset(struct rkcif_device *cif_dev) +void rkcif_soft_reset(struct rkcif_device *cif_dev, bool is_rst_iommu) { unsigned int i; + if (cif_dev->iommu_en && is_rst_iommu) + rkcif_iommu_cleanup(cif_dev); + for (i = 0; i < ARRAY_SIZE(cif_dev->cif_rst); i++) if (cif_dev->cif_rst[i]) reset_control_assert(cif_dev->cif_rst[i]); @@ -556,6 +575,8 @@ void rkcif_soft_reset(struct rkcif_device *cif_dev) if (cif_dev->cif_rst[i]) reset_control_deassert(cif_dev->cif_rst[i]); + if (cif_dev->iommu_en && is_rst_iommu) + rkcif_iommu_init(cif_dev); } static int rkcif_plat_probe(struct platform_device *pdev) @@ -644,18 +665,23 @@ static int rkcif_plat_probe(struct platform_device *pdev) cif_dev->cif_rst[i] = rst; } + mutex_init(&cif_dev->stream_lock); atomic_set(&cif_dev->pipe.power_cnt, 0); atomic_set(&cif_dev->pipe.stream_cnt, 0); - mutex_init(&cif_dev->dev_lock); + atomic_set(&cif_dev->fh_cnt, 0); cif_dev->pipe.open = rkcif_pipeline_open; cif_dev->pipe.close = rkcif_pipeline_close; cif_dev->pipe.set_stream = rkcif_pipeline_set_stream; - rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID0); - rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID1); - rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID2); - rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3); - rkcif_stream_init(cif_dev, RKCIF_STREAM_DVP); + if (data->chip_id == CHIP_RK1808_CIF) { + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID0); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID1); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID2); + rkcif_stream_init(cif_dev, RKCIF_STREAM_MIPI_ID3); + rkcif_stream_init(cif_dev, RKCIF_STREAM_DVP); + } else { + rkcif_stream_init(cif_dev, RKCIF_STREAM_CIF); + } strlcpy(cif_dev->media_dev.model, "rkcif", sizeof(cif_dev->media_dev.model)); @@ -691,13 +717,14 @@ static int rkcif_plat_probe(struct platform_device *pdev) "No reserved memory region assign to CIF\n"); } - rkcif_soft_reset(cif_dev); pm_runtime_enable(&pdev->dev); mutex_lock(&rkcif_dev_mutex); list_add_tail(&cif_dev->list, &rkcif_device_list); mutex_unlock(&rkcif_dev_mutex); + rkcif_soft_reset(cif_dev, true); + return 0; err_unreg_media_dev: @@ -709,13 +736,18 @@ err_unreg_v4l2_dev: static int rkcif_plat_remove(struct platform_device *pdev) { + int stream_num = 0; struct rkcif_device *cif_dev = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); media_device_unregister(&cif_dev->media_dev); v4l2_device_unregister(&cif_dev->v4l2_dev); - rkcif_unregister_stream_vdevs(cif_dev); + if (cif_dev->chip_id == CHIP_RK1808_CIF) + stream_num = RKCIF_MULTI_STREAMS_NUM; + else + stream_num = RKCIF_SINGLE_STREAM; + rkcif_unregister_stream_vdevs(cif_dev, stream_num); vb2_dma_contig_cleanup_ctx(cif_dev->alloc_ctx); return 0; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 56b4f9f262d1..eb0c903be7a8 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -19,6 +19,8 @@ #define CIF_DRIVER_NAME "rkcif" #define CIF_VIDEODEVICE_NAME "stream_cif" +#define RKCIF_SINGLE_STREAM 1 +#define RKCIF_STREAM_CIF 0 #define CIF_DVP_VDEV_NAME CIF_VIDEODEVICE_NAME "_dvp" #define CIF_MIPI_ID0_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id0" #define CIF_MIPI_ID1_VDEV_NAME CIF_VIDEODEVICE_NAME "_mipi_id1" @@ -29,7 +31,7 @@ * Rk1808 support 5 channel inputs simultaneously: * dvp + 4 mipi virtual channels */ -#define RKCIF_MAX_STREAM 5 +#define RKCIF_MULTI_STREAMS_NUM 5 #define RKCIF_STREAM_MIPI_ID0 0 #define RKCIF_STREAM_MIPI_ID1 1 #define RKCIF_STREAM_MIPI_ID2 2 @@ -46,19 +48,12 @@ #define RKCIF_DEFAULT_WIDTH 640 #define RKCIF_DEFAULT_HEIGHT 480 -#define write_cif_reg(base, addr, val) \ - do { \ - writel(val, (addr) + (base)); \ - } while (0) +#define write_cif_reg(base, addr, val) writel(val, (addr) + (base)) #define read_cif_reg(base, addr) readl((addr) + (base)) #define write_cif_reg_or(base, addr, val) \ - do { \ - writel(readl((addr) + (base)) | (val), (addr) + (base)); \ - } while (0) + writel(readl((addr) + (base)) | (val), (addr) + (base)) #define write_cif_reg_and(base, addr, val) \ - do { \ - writel(readl((addr) + (base)) & (val), (addr) + (base)); \ - } while (0) + writel(readl((addr) + (base)) & (val), (addr) + (base)) enum rkcif_state { RKCIF_STATE_DISABLED, @@ -186,6 +181,15 @@ struct rkcif_vdev_node { struct media_pad pad; }; +/* + * the mark that csi frame0/1 interrupts enabled + * in CIF_MIPI_INTEN + */ +enum cif_frame_ready { + CIF_CSI_FRAME0_READY = 0x1, + CIF_CSI_FRAME1_READY +}; + /* * struct rkcif_stream - Stream states TODO * @@ -280,24 +284,27 @@ struct rkcif_device { u32 num_sensors; struct rkcif_sensor_info *active_sensor; - struct rkcif_stream stream[RKCIF_MAX_STREAM]; + struct rkcif_stream stream[RKCIF_MULTI_STREAMS_NUM]; struct rkcif_pipeline pipe; struct csi_channel_info channels[RKCIF_MAX_CSI_CHANNEL]; int num_channels; int chip_id; - bool working; - bool is_cif_rst; - /* dev operate mutex */ - struct mutex dev_lock; + atomic_t stream_cnt; + atomic_t fh_cnt; + struct mutex stream_lock; /* lock between streams */ }; -void rkcif_unregister_stream_vdevs(struct rkcif_device *dev); -int rkcif_register_stream_vdevs(struct rkcif_device *dev); +void rkcif_unregister_stream_vdevs(struct rkcif_device *dev, + int stream_num); +int rkcif_register_stream_vdevs(struct rkcif_device *dev, + int stream_num, + bool is_multi_input); void rkcif_stream_init(struct rkcif_device *dev, u32 id); void rkcif_irq_oneframe(struct rkcif_device *cif_dev); void rkcif_irq_pingpong(struct rkcif_device *cif_dev); -void rkcif_soft_reset(struct rkcif_device *cif_dev); +void rkcif_soft_reset(struct rkcif_device *cif_dev, + bool is_rst_iommu); #endif diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index 3173cf68ef13..3ff91189fc83 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -265,4 +265,9 @@ #define SW_DATATYPE_LS(x) ((x) << 20) #define SW_DATATYPE_LE(x) ((x) << 26) +#define SW_FRM_END_ID0(x) (((x) & CSI_FRAME_END_ID0) >> 8) +#define SW_FRM_END_ID1(x) (((x) & CSI_FRAME_END_ID1) >> 10) +#define SW_FRM_END_ID2(x) (((x) & CSI_FRAME_END_ID2) >> 12) +#define SW_FRM_END_ID3(x) (((x) & CSI_FRAME_END_ID3) >> 14) + #endif diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 1f8ba5049a06..11b55fe2222f 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -12,9 +12,11 @@ *1. First version; *v0.1.1 *support the mipi vc multi-channel input in cif driver for rk1808 + *v0.1.2 + *Compatible with cif only have single dma mode in driver * */ -#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x1) +#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x2) #endif