media: platform: rockchip: cif: support rv1126 mipi interface for linear and hdr mode

Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Change-Id: I073bdafe037498519bb5cd14cb6a64b26f5dd1f5
This commit is contained in:
Allon Huang
2020-05-11 09:27:25 +08:00
committed by Tao Huang
parent 9835c70741
commit 80dc82ec94
7 changed files with 399 additions and 51 deletions

View File

@@ -17,6 +17,7 @@
#include <media/videobuf2-dma-contig.h>
#include "dev.h"
#include "mipi-csi2.h"
#define CIF_REQ_BUFS_MIN 1
#define CIF_MIN_WIDTH 64
@@ -132,66 +133,79 @@ static const struct cif_output_fmt out_fmts[] = {
.cplanes = 1,
.mplanes = 1,
.bpp = { 8 },
.raw_bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.cplanes = 1,
.mplanes = 1,
.bpp = { 8 },
.raw_bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
.cplanes = 1,
.mplanes = 1,
.bpp = { 8 },
.raw_bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.cplanes = 1,
.mplanes = 1,
.bpp = { 8 },
.raw_bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB12,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG12,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG12,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR12,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR16,
.cplanes = 1,
.mplanes = 1,
.bpp = { 16 },
.raw_bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_Y16,
.cplanes = 1,
@@ -365,6 +379,37 @@ static struct v4l2_subdev *get_remote_sensor(struct rkcif_stream *stream)
return media_entity_to_v4l2_subdev(sensor_me);
}
static void get_remote_mipi_sensor(struct rkcif_stream *stream,
struct v4l2_subdev **sensor_sd)
{
struct media_graph graph;
struct media_entity *entity = &stream->vnode.vdev.entity;
struct media_device *mdev = entity->graph_obj.mdev;
int ret;
/* Walk the graph to locate sensor nodes. */
mutex_lock(&mdev->graph_mutex);
ret = media_graph_walk_init(&graph, mdev);
if (ret) {
mutex_unlock(&mdev->graph_mutex);
*sensor_sd = NULL;
return;
}
media_graph_walk_start(&graph, entity);
while ((entity = media_graph_walk_next(&graph))) {
if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
break;
}
mutex_unlock(&mdev->graph_mutex);
media_graph_walk_cleanup(&graph);
if (entity)
*sensor_sd = media_entity_to_v4l2_subdev(entity);
else
*sensor_sd = NULL;
}
static struct rkcif_sensor_info *sd_to_sensor(struct rkcif_device *dev,
struct v4l2_subdev *sd)
{
@@ -394,6 +439,8 @@ static int rkcif_update_sensor_info(struct rkcif_stream *stream)
return ret;
stream->cifdev->active_sensor = sensor;
get_remote_mipi_sensor(stream, &stream->cifdev->mipi_sensor);
return ret;
}
@@ -412,6 +459,12 @@ static unsigned char get_data_type(u32 pixelformat, u8 cmd_mode_en)
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10:
return 0x2b;
/* csi raw12 */
case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 0x2c;
/* csi uyvy 422 */
case MEDIA_BUS_FMT_UYVY8_2X8:
case MEDIA_BUS_FMT_VYUY8_2X8:
@@ -1060,7 +1113,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream,
} else {
channel->width = stream->pixm.width;
channel->height = stream->pixm.height;
channel->crop_en = 1;
channel->crop_en = 0;
}
fmt = find_output_fmt(stream, stream->pixm.pixelformat);
@@ -1070,7 +1123,16 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream,
return -EINVAL;
}
channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);
if (dev->hdr.mode == NO_HDR) {
if (channel->fmt_val == CSI_WRDDR_TYPE_RAW10 ||
channel->fmt_val == CSI_WRDDR_TYPE_RAW12)
channel->virtual_width = ALIGN(channel->width * 2, 8);
else
channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8);
} else {
channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 8);
}
if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888)
channel->width = channel->width * fmt->bpp[0] / 8;
/*
@@ -1113,6 +1175,17 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
CSI_DMA_END_INTSTAT(channel->id) |
CSI_LINE_INTSTAT(channel->id)));
/* enable mipi id0 frame start int for sof(long frame) */
if (dev->hdr.mode != NO_HDR &&
channel->id == RKCIF_STREAM_MIPI_ID0)
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_START_INTEN(channel->id));
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1,
0x3fff << 16 | 0x3fff);
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3,
0x3fff << 16 | 0x3fff);
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_DMA_END_INTEN(channel->id));
@@ -1145,6 +1218,9 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
val = CSI_ENABLE_CAPTURE | channel->fmt_val |
channel->cmd_mode_en << 4 | channel->crop_en << 5 |
channel->id << 8 | channel->data_type << 10 ;
if (dev->hdr.mode != NO_HDR)
val |= CSI_ENABLE_MIPI_COMPACT;
rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val);
return 0;
@@ -1157,6 +1233,7 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream)
struct csi_channel_info *channel;
stream->frame_idx = 0;
rkcif_csi_get_vc_num(dev, flags);
channel = &dev->channels[stream->id];
@@ -1173,26 +1250,29 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream)
static void rkcif_stream_stop(struct rkcif_stream *stream)
{
struct rkcif_device *cif_dev = stream->cifdev;
void __iomem *base = cif_dev->base_addr;
u32 val;
int id;
struct rkcif_device *cif_dev = stream->cifdev;
if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
id = stream->id;
val = read_cif_reg(base, CIF_CSI_ID0_CTRL0 + 0x8 * id);
write_cif_reg(base, CIF_CSI_ID0_CTRL0 + 0x8 * id,
(val & (~CSI_ENABLE_CAPTURE)));
write_cif_reg_or(base, CIF_CSI_INTSTAT,
CSI_START_INTSTAT(id) |
CSI_DMA_END_INTSTAT(id) |
CSI_LINE_INTSTAT(id));
write_cif_reg_and(base, CIF_CSI_INTEN,
~(CSI_START_INTEN(id) |
CSI_DMA_END_INTEN(id) |
CSI_LINE_INTEN(id)));
write_cif_reg_and(base, CIF_CSI_INTEN,
~CSI_ALL_ERROR_INTEN);
val = rkcif_read_register(cif_dev, get_reg_index_of_id_ctrl0(id));
rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id),
val & (~CSI_ENABLE_CAPTURE));
rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT,
CSI_START_INTSTAT(id) |
CSI_DMA_END_INTSTAT(id) |
CSI_LINE_INTSTAT(id));
rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
~(CSI_START_INTEN(id) |
CSI_DMA_END_INTEN(id) |
CSI_LINE_INTEN(id)));
rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN,
~CSI_ALL_ERROR_INTEN);
} else {
val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL);
rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL,
@@ -1332,6 +1412,7 @@ 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 = NULL;
unsigned int val;
int ret;
mutex_lock(&dev->stream_lock);
@@ -1360,6 +1441,29 @@ static void rkcif_stop_streaming(struct vb2_queue *queue)
stream->next_buf != stream->curr_buf)
list_add_tail(&stream->next_buf->queue, &stream->buf_head);
if (dev->hdr.mode != NO_HDR) {
unsigned int index;
struct rkcif_buffer *tmp_buf;
bool has_added = false;
for (index = 0; index < RDBK_MAX; index++) {
if (dev->rdbk_buf[index]) {
if (dev->rdbk_buf[index] != stream->curr_buf &&
dev->rdbk_buf[index] != stream->next_buf) {
list_for_each_entry(tmp_buf, &stream->buf_head, queue) {
if (tmp_buf == dev->rdbk_buf[index]) {
has_added = true;
break;
}
}
if (!has_added)
list_add_tail(&dev->rdbk_buf[index]->queue,
&stream->buf_head);
}
dev->rdbk_buf[index] = NULL;
}
}
}
stream->curr_buf = NULL;
stream->next_buf = NULL;
@@ -1374,9 +1478,35 @@ static void rkcif_stop_streaming(struct vb2_queue *queue)
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);
v4l2_err(v4l2_dev, "pipeline close failed error:%d\n", ret);
if (dev->hdr.mode == HDR_X2) {
if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY) {
dev->can_be_reset = true;
}
} else if (dev->hdr.mode == HDR_X3) {
if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_READY &&
dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_READY &&
dev->stream[RKCIF_STREAM_MIPI_ID2].state == RKCIF_STATE_READY) {
dev->can_be_reset = true;
}
} else {
dev->can_be_reset = true;
}
if (dev->can_be_reset) {
if (dev->hdr.mode != NO_HDR) {
val = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_CTRL);
val |= CIF_MIPI_LVDS_SW_DMA_IDLE;
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val);
usleep_range(5, 10);
rkcif_soft_reset(dev, false);
} else {
rkcif_soft_reset(dev, false);
}
dev->can_be_reset = false;
}
pm_runtime_put(dev->dev);
mutex_unlock(&dev->stream_lock);
@@ -1663,6 +1793,7 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
struct rkcif_device *dev = stream->cifdev;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
struct rkcif_sensor_info *sensor_info = dev->active_sensor;
struct rkmodule_hdr_cfg hdr_cfg;
/* struct v4l2_subdev *sd; */
int ret;
@@ -1684,6 +1815,19 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
}
}
if (dev->mipi_sensor) {
if (!dev->has_get_hdr) {
ret = v4l2_subdev_call(dev->mipi_sensor,
core, ioctl,
RKMODULE_GET_HDR_CFG,
&hdr_cfg);
if (!ret) {
dev->hdr.mode = hdr_cfg.hdr_mode;
dev->has_get_hdr = true;
}
}
}
ret = rkcif_sanity_check_fmt(stream, NULL);
if (ret < 0)
goto destroy_buf;
@@ -1814,6 +1958,8 @@ static void rkcif_set_fmt(struct rkcif_stream *stream,
struct v4l2_rect input_rect;
unsigned int imagesize = 0, planes;
u32 xsubs = 1, ysubs = 1, i;
struct rkmodule_hdr_cfg hdr_cfg;
int ret;
fmt = find_output_fmt(stream, pixm->pixelformat);
if (!fmt)
@@ -1826,6 +1972,19 @@ static void rkcif_set_fmt(struct rkcif_stream *stream,
get_input_fmt(dev->active_sensor->sd,
&input_rect, stream->id + 1);
if (dev->mipi_sensor) {
if (!dev->has_get_hdr) {
ret = v4l2_subdev_call(dev->mipi_sensor,
core, ioctl,
RKMODULE_GET_HDR_CFG,
&hdr_cfg);
if (!ret) {
dev->hdr.mode = hdr_cfg.hdr_mode;
dev->has_get_hdr = true;
}
}
}
/* CIF has not scale function,
* the size should not be larger than input
*/
@@ -1854,8 +2013,13 @@ static void rkcif_set_fmt(struct rkcif_stream *stream,
height = pixm->height / ysubs;
}
bpp = rkcif_align_bits_per_pixel(fmt, i);
bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH;
if (dev->hdr.mode == NO_HDR) {
bpp = rkcif_align_bits_per_pixel(fmt, i);
bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH;
} else {
/* compact mode need bytesperline 4byte align */
bpl = ALIGN(width * fmt->raw_bpp / 8, 4);
}
size = bpl * height;
imagesize += size;
@@ -1980,7 +2144,6 @@ static int rkcif_fh_release(struct file *filp)
else if (atomic_read(&cifdev->fh_cnt) < 0)
atomic_set(&cifdev->fh_cnt, 0);
mutex_unlock(&cifdev->stream_lock);
stream->cifdev->active_sensor = NULL;
return ret;
}
@@ -2405,10 +2568,11 @@ void rkcif_irq_oneframe(struct rkcif_device *cif_dev)
rkcif_write_register(cif_dev, CIF_REG_DVP_FRAME_STATUS,
cif_frmst & FRM0_STAT_CLS);
if (vb_done)
rkcif_vb_done_oneframe(stream, vb_done);
stream->frame_idx++;
if (vb_done) {
vb_done->sequence = stream->frame_idx;
rkcif_vb_done_oneframe(stream, vb_done);
}
}
}
@@ -2446,10 +2610,72 @@ static int rkcif_csi_g_mipi_id(struct v4l2_device *v4l2_dev,
return -EINVAL;
}
static void rdbk_frame_end(struct rkcif_stream *stream)
{
struct rkcif_device *dev = stream->cifdev;
u64 l_ts, s_ts;
if (stream->id != RKCIF_STREAM_MIPI_ID1)
return;
if (dev->hdr.mode == HDR_X3) {
/* TODO: HDR_X3 */
} else if (dev->hdr.mode == HDR_X2) {
if (dev->rdbk_buf[RDBK_L] && dev->rdbk_buf[RDBK_S]) {
l_ts = dev->rdbk_buf[RDBK_L]->vb.vb2_buf.timestamp;
s_ts = dev->rdbk_buf[RDBK_S]->vb.vb2_buf.timestamp;
if ((s_ts - l_ts) > 30000000LL || s_ts < l_ts) {
v4l2_err(&dev->v4l2_dev,
"HDR_X2:timestamp is not match (%lld, %lld)\n",
l_ts, s_ts);
goto RDBK_FRM_UNMATCH;
}
dev->rdbk_buf[RDBK_S]->vb.sequence =
dev->rdbk_buf[RDBK_L]->vb.sequence;
rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_L]->vb);
rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb);
} else {
if (!dev->rdbk_buf[RDBK_L])
v4l2_err(&dev->v4l2_dev, "lost long frames\n");
if (!dev->rdbk_buf[RDBK_S])
v4l2_err(&dev->v4l2_dev, "lost short frames\n");
goto RDBK_FRM_UNMATCH;
}
} else {
rkcif_vb_done_oneframe(stream, &dev->rdbk_buf[RDBK_S]->vb);
}
dev->rdbk_buf[RDBK_L] = NULL;
dev->rdbk_buf[RDBK_M] = NULL;
dev->rdbk_buf[RDBK_S] = NULL;
return;
RDBK_FRM_UNMATCH:
if (dev->rdbk_buf[RDBK_L]) {
dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
rkcif_buf_queue(&dev->rdbk_buf[RDBK_L]->vb.vb2_buf);
}
if (dev->rdbk_buf[RDBK_M]) {
dev->rdbk_buf[RDBK_M]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
rkcif_buf_queue(&dev->rdbk_buf[RDBK_M]->vb.vb2_buf);
}
if (dev->rdbk_buf[RDBK_S]) {
dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
rkcif_buf_queue(&dev->rdbk_buf[RDBK_S]->vb.vb2_buf);
}
dev->rdbk_buf[RDBK_L] = NULL;
dev->rdbk_buf[RDBK_M] = NULL;
dev->rdbk_buf[RDBK_S] = NULL;
}
void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
{
/* TODO: xuhf-debug: add stream type */
struct rkcif_stream *stream;
struct rkcif_buffer *active_buf = NULL;
void __iomem *base = cif_dev->base_addr;
unsigned int intstat, i = 0xff;
@@ -2462,6 +2688,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
intstat = read_cif_reg(base, CIF_CSI_INTSTAT);
lastline = read_cif_reg(base, CIF_CSI_LINE_CNT_ID0_1);
/* clear all interrupts that has been triggered */
write_cif_reg(base, CIF_CSI_INTSTAT, intstat);
@@ -2474,18 +2701,28 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
if (intstat & CSI_BANDWIDTH_LACK) {
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: csi bandwidth lack!!\n");
"ERROR: csi bandwidth lack, intstat:0x%x!!\n",
intstat);
return;
}
mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat);
if (mipi_id < 0) {
if (intstat & CSI_ALL_ERROR_INTEN) {
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: irq[%d] is invalid: 0x%x, lastline: %d, return!!!\n",
i, intstat, lastline & 0x3fff);
"ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat);
return;
}
if (intstat & CSI_FRAME0_START_ID0)
rkcif_csi2_event_inc_sof();
if (intstat & CSI_FRAME1_START_ID0)
rkcif_csi2_event_inc_sof();
/* if do not reach frame dma end, return irq */
mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat);
if (mipi_id < 0)
return;
for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) {
mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev,
intstat);
@@ -2506,41 +2743,70 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
switch (mipi_id) {
case RKCIF_STREAM_MIPI_ID0:
stream->frame_phase =
SW_FRM_END_ID0(intstat);
stream->frame_phase = SW_FRM_END_ID0(intstat);
intstat &= ~CSI_FRAME_END_ID0;
break;
case RKCIF_STREAM_MIPI_ID1:
stream->frame_phase =
SW_FRM_END_ID1(intstat);
stream->frame_phase = SW_FRM_END_ID1(intstat);
intstat &= ~CSI_FRAME_END_ID1;
break;
case RKCIF_STREAM_MIPI_ID2:
stream->frame_phase =
SW_FRM_END_ID2(intstat);
stream->frame_phase = SW_FRM_END_ID2(intstat);
intstat &= ~CSI_FRAME_END_ID2;
break;
case RKCIF_STREAM_MIPI_ID3:
stream->frame_phase =
SW_FRM_END_ID3(intstat);
stream->frame_phase = SW_FRM_END_ID3(intstat);
intstat &= ~CSI_FRAME_END_ID3;
break;
}
stream->frame_idx++;
active_buf = NULL;
if (stream->frame_phase & CIF_CSI_FRAME1_READY) {
if (stream->next_buf)
vb_done = &stream->next_buf->vb;
active_buf = stream->next_buf;
} else if (stream->frame_phase & CIF_CSI_FRAME0_READY) {
if (stream->curr_buf)
vb_done = &stream->curr_buf->vb;
active_buf = stream->curr_buf;
}
rkcif_assign_new_buffer_pingpong(stream, 0, mipi_id);
if (vb_done)
rkcif_vb_done_oneframe(stream, vb_done);
if (active_buf) {
vb_done = &active_buf->vb;
vb_done->vb2_buf.timestamp = ktime_get_ns();
vb_done->sequence = stream->frame_idx;
}
stream->frame_idx++;
if (cif_dev->hdr.mode == NO_HDR) {
if (active_buf)
rkcif_vb_done_oneframe(stream, vb_done);
} else if (cif_dev->hdr.mode == HDR_X2) {
if (mipi_id == RKCIF_STREAM_MIPI_ID0) {
if (cif_dev->rdbk_buf[RDBK_L]) {
v4l2_err(&cif_dev->v4l2_dev,
"multiple long data in hdr frame,frm_idx:%d,state:0x%x\n",
stream->frame_idx,
cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state);
cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_L]->vb.vb2_buf);
}
cif_dev->rdbk_buf[RDBK_L] = active_buf;
} else if (mipi_id == RKCIF_STREAM_MIPI_ID1) {
if (cif_dev->rdbk_buf[RDBK_S]) {
v4l2_err(&cif_dev->v4l2_dev,
"multiple short data in hdr frame, state:0x%x\n",
cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state);
cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
rkcif_buf_queue(&cif_dev->rdbk_buf[RDBK_S]->vb.vb2_buf);
}
cif_dev->rdbk_buf[RDBK_S] = active_buf;
rdbk_frame_end(stream);
}
} else if (cif_dev->hdr.mode == HDR_X3) {
/*TODO: HDR_X3*/
}
}
} else {
u32 lastline, lastpix, ctl, cif_frmst, frmid;
@@ -2620,10 +2886,11 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
rkcif_assign_new_buffer_oneframe(stream,
RKCIF_YUV_ADDR_STATE_UPDATE);
if (vb_done)
rkcif_vb_done_oneframe(stream, vb_done);
stream->frame_idx++;
if (vb_done) {
vb_done->sequence = stream->frame_idx;
rkcif_vb_done_oneframe(stream, vb_done);
}
}
}
}

View File

@@ -748,6 +748,10 @@ static const struct cif_reg rv1126_cif_regs[] = {
[CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3] = CIF_REG(CIF_CSI_FRM1_VLW_UV_ID3),
[CIF_REG_MIPI_LVDS_INTEN] = CIF_REG(CIF_CSI_INTEN),
[CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG(CIF_CSI_INTSTAT),
[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG(CIF_CSI_LINE_INT_NUM_ID0_1),
[CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG(CIF_CSI_LINE_INT_NUM_ID2_3),
[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG(CIF_CSI_LINE_CNT_ID0_1),
[CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG(CIF_CSI_LINE_CNT_ID2_3),
[CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG(CIF_CSI_ID0_CROP_START),
[CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG(CIF_CSI_ID1_CROP_START),
[CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG(CIF_CSI_ID2_CROP_START),
@@ -1038,6 +1042,8 @@ static int rkcif_plat_probe(struct platform_device *pdev)
}
cif_dev->cif_regs = data->cif_regs;
cif_dev->has_get_hdr = false;
cif_dev->hdr.mode = NO_HDR;
mutex_init(&cif_dev->stream_lock);
atomic_set(&cif_dev->pipe.power_cnt, 0);

View File

@@ -15,6 +15,7 @@
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mc.h>
#include <linux/rk-camera-module.h>
#include "regs.h"
#include "version.h"
@@ -50,6 +51,15 @@
#define RKCIF_DEFAULT_WIDTH 640
#define RKCIF_DEFAULT_HEIGHT 480
/*
* for HDR mode sync buf
*/
#define RDBK_MAX 3
#define RDBK_L 0
#define RDBK_M 1
#define RDBK_S 2
#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) \
@@ -144,6 +154,7 @@ struct rkcif_sensor_info {
* @cplanes: number of colour planes
* @fmt_val: the fmt val corresponding to CIF_FOR register
* @bpp: bits per pixel for each cplanes
* @raw_bpp: bits per pixel for raw format
*/
struct cif_output_fmt {
u32 fourcc;
@@ -151,6 +162,7 @@ struct cif_output_fmt {
u8 mplanes;
u32 fmt_val;
u8 bpp[VIDEO_MAX_PLANES];
u8 raw_bpp;
};
enum cif_fmt_type {
@@ -206,6 +218,13 @@ enum cif_frame_ready {
CIF_CSI_FRAME1_READY
};
/* struct rkcif_hdr - hdr configured
* @op_mode: hdr optional mode
*/
struct rkcif_hdr {
u8 mode;
};
/*
* struct rkcif_stream - Stream states TODO
*
@@ -299,6 +318,7 @@ struct rkcif_device {
struct rkcif_sensor_info sensors[RKCIF_MAX_SENSOR];
u32 num_sensors;
struct rkcif_sensor_info *active_sensor;
struct v4l2_subdev *mipi_sensor;
struct rkcif_stream stream[RKCIF_MULTI_STREAMS_NUM];
struct rkcif_pipeline pipe;
@@ -308,9 +328,13 @@ struct rkcif_device {
int chip_id;
atomic_t stream_cnt;
atomic_t fh_cnt;
struct mutex stream_lock; /* lock between streams */
struct mutex stream_lock; /* lock between streams */
enum rkcif_workmode workmode;
const struct cif_reg *cif_regs;
const struct cif_reg *cif_regs;
bool has_get_hdr;
bool can_be_reset;
struct rkcif_hdr hdr;
struct rkcif_buffer *rdbk_buf[RDBK_MAX];
};
void rkcif_write_register(struct rkcif_device *dev,

View File

@@ -17,7 +17,9 @@
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-event.h>
#include "mipi-csi2.h"
/*
* there must be 5 pads: 1 input pad from sensor, and
* the 4 virtual channel output pads
@@ -91,6 +93,7 @@ struct csi2_dev {
struct csi2_sensor sensors[MAX_CSI2_SENSORS];
const struct csi2_match_data *match_data;
int num_sensors;
atomic_t frm_sync_seq;
};
#define DEVICE_NAME "rockchip-mipi-csi2"
@@ -115,6 +118,8 @@ struct csi2_dev {
#define write_csihost_reg(base, addr, val) writel(val, (addr) + (base))
#define read_csihost_reg(base, addr) readl((addr) + (base))
static struct csi2_dev *g_csi2_dev;
static inline struct csi2_dev *sd_to_dev(struct v4l2_subdev *sdev)
{
return container_of(sdev, struct csi2_dev, sd);
@@ -213,6 +218,7 @@ static int csi2_start(struct csi2_dev *csi2)
if (ret)
goto err_assert_reset;
atomic_set(&csi2->frm_sync_seq, 0);
return 0;
err_assert_reset:
@@ -371,6 +377,32 @@ static const struct media_entity_operations csi2_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
void rkcif_csi2_event_inc_sof(void)
{
if (g_csi2_dev) {
struct v4l2_event event = {
.type = V4L2_EVENT_FRAME_SYNC,
.u.frame_sync.frame_sequence =
atomic_inc_return(&g_csi2_dev->frm_sync_seq) - 1,
};
v4l2_event_queue(g_csi2_dev->sd.devnode, &event);
}
}
static int rkcif_csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
if (sub->type != V4L2_EVENT_FRAME_SYNC)
return -EINVAL;
return v4l2_event_subscribe(fh, sub, 0, NULL);
}
static const struct v4l2_subdev_core_ops csi2_core_ops = {
.subscribe_event = rkcif_csi2_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_video_ops csi2_video_ops = {
.g_mbus_config = csi2_g_mbus_config,
.s_stream = csi2_s_stream,
@@ -382,6 +414,7 @@ static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
};
static const struct v4l2_subdev_ops csi2_subdev_ops = {
.core = &csi2_core_ops,
.video = &csi2_video_ops,
.pad = &csi2_pad_ops,
};
@@ -607,7 +640,7 @@ static int csi2_probe(struct platform_device *pdev)
csi2->sd.entity.ops = &csi2_entity_ops;
csi2->sd.dev = &pdev->dev;
csi2->sd.owner = THIS_MODULE;
csi2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
csi2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
ret = strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
platform_set_drvdata(pdev, &csi2->sd);
/* csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; */
@@ -675,7 +708,8 @@ static int csi2_probe(struct platform_device *pdev)
ret = csi2_notifier(csi2);
if (ret)
goto rmmutex;
v4l2_info(&csi2->sd, "probe success!\n");
v4l2_info(&csi2->sd, "probe success, v4l2_dev:%s!\n", csi2->sd.v4l2_dev->name);
g_csi2_dev = csi2;
return 0;

View File

@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2020 Rockchip Electronics Co., Ltd. */
#ifndef _RKCIF_MIPI_CSI2_H_
#define _RKCIF_MIPI_CSI2_H_
void rkcif_csi2_event_inc_sof(void);
#endif

View File

@@ -413,6 +413,10 @@ enum cif_reg_index {
#define CSI_CONFIG_FIFO_OVERFLOW (0x1 << 18)
#define CSI_BANDWIDTH_LACK (0x1 << 19)
#define CSI_RX_FIFO_OVERFLOW (0x1 << 20)
#define CSI_LINE_ID0_INTST (0x1 << 21)
#define CSI_LINE_ID1_INTST (0x1 << 22)
#define CSI_LINE_ID2_INTST (0x1 << 23)
#define CSI_LINE_ID3_INTST (0x1 << 24)
#define CSI_FRAME_END_ID0 (CSI_FRAME0_END_ID0 |\
CSI_FRAME1_END_ID0)
@@ -426,6 +430,10 @@ enum cif_reg_index {
CSI_DMA_UV_FIFO_OVERFLOW | \
CSI_CONFIG_FIFO_OVERFLOW | \
CSI_RX_FIFO_OVERFLOW)
/* CIF_MIPI_LVDS_CTRL */
#define CIF_MIPI_LVDS_SW_DMA_IDLE (0x1 << 16)
#define CIF_MIPI_LVDS_SW_PRESS_VALUE(val) (((val) & 0x3) << 13)
#define CIF_MIPI_LVDS_SW_SEL_LVDS (0x1 << 8)
/* CSI Host Registers Define */
#define CSIHOST_N_LANES 0x04

View File

@@ -26,6 +26,7 @@
*v0.1.3
*1. support kernel-4.19 and support vicap single dvp for rv1126
*2. support vicap + mipi(single) for rv1126
*3. support vicap + mipi hdr for rv1126
*/
#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x3)