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 <xuhf@rock-chips.com>
This commit is contained in:
Xu Hongfei
2019-05-18 12:50:34 +08:00
committed by Tao Huang
parent ebf350dee0
commit b5a1e17100
5 changed files with 203 additions and 253 deletions

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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