media: platform: rockchip: cif: support lvds for linear and hdr mode

Signed-off-by: Allon Huang <allon.huang@rock-chips.com>
Change-Id: I1aa2ab86b16f16c535c39025603795afbb5e0e94
This commit is contained in:
Allon Huang
2020-07-09 13:46:00 +08:00
committed by Tao Huang
parent 74e1e1627e
commit 00610f370e
5 changed files with 657 additions and 76 deletions

View File

@@ -379,8 +379,8 @@ 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)
static void get_remote_terminal_sensor(struct rkcif_stream *stream,
struct v4l2_subdev **sensor_sd)
{
struct media_graph graph;
struct media_entity *entity = &stream->vnode.vdev.entity;
@@ -419,6 +419,13 @@ static struct rkcif_sensor_info *sd_to_sensor(struct rkcif_device *dev,
if (dev->sensors[i].sd == sd)
return &dev->sensors[i];
if (i == dev->num_sensors) {
for (i = 0; i < dev->num_sensors; ++i) {
if (dev->sensors[i].mbus.type == V4L2_MBUS_CCP2)
return &dev->lvds_subdev.sensor_self;
}
}
return NULL;
}
@@ -433,13 +440,17 @@ static int rkcif_update_sensor_info(struct rkcif_stream *stream)
return -ENODEV;
sensor = sd_to_sensor(stream->cifdev, sensor_sd);
if (!sensor) {
v4l2_err(&stream->cifdev->v4l2_dev, "get sensor for updating failed!\n");
return -ENODEV;
}
ret = v4l2_subdev_call(sensor->sd, video, g_mbus_config,
&sensor->mbus);
if (ret && ret != -ENOIOCTLCMD)
return ret;
stream->cifdev->active_sensor = sensor;
get_remote_mipi_sensor(stream, &stream->cifdev->mipi_sensor);
get_remote_terminal_sensor(stream, &stream->cifdev->terminal_sensor);
return ret;
}
@@ -831,6 +842,106 @@ static enum cif_reg_index get_reg_index_of_id_crop_start(int channel_id)
return index;
}
static enum cif_reg_index get_reg_index_of_lvds_sav_eav_act0(int channel_id)
{
enum cif_reg_index index;
switch (channel_id) {
case 0:
index = CIF_REG_LVDS_SAV_EAV_ACT0_ID0;
break;
case 1:
index = CIF_REG_LVDS_SAV_EAV_ACT0_ID1;
break;
case 2:
index = CIF_REG_LVDS_SAV_EAV_ACT0_ID2;
break;
case 3:
index = CIF_REG_LVDS_SAV_EAV_ACT0_ID3;
break;
default:
index = CIF_REG_LVDS_SAV_EAV_ACT0_ID0;
break;
}
return index;
}
static enum cif_reg_index get_reg_index_of_lvds_sav_eav_act1(int channel_id)
{
enum cif_reg_index index;
switch (channel_id) {
case 0:
index = CIF_REG_LVDS_SAV_EAV_ACT1_ID0;
break;
case 1:
index = CIF_REG_LVDS_SAV_EAV_ACT1_ID1;
break;
case 2:
index = CIF_REG_LVDS_SAV_EAV_ACT1_ID2;
break;
case 3:
index = CIF_REG_LVDS_SAV_EAV_ACT1_ID3;
break;
default:
index = CIF_REG_LVDS_SAV_EAV_ACT1_ID0;
break;
}
return index;
}
static enum cif_reg_index get_reg_index_of_lvds_sav_eav_blk0(int channel_id)
{
enum cif_reg_index index;
switch (channel_id) {
case 0:
index = CIF_REG_LVDS_SAV_EAV_BLK0_ID0;
break;
case 1:
index = CIF_REG_LVDS_SAV_EAV_BLK0_ID1;
break;
case 2:
index = CIF_REG_LVDS_SAV_EAV_BLK0_ID2;
break;
case 3:
index = CIF_REG_LVDS_SAV_EAV_BLK0_ID3;
break;
default:
index = CIF_REG_LVDS_SAV_EAV_BLK0_ID0;
break;
}
return index;
}
static enum cif_reg_index get_reg_index_of_lvds_sav_eav_blk1(int channel_id)
{
enum cif_reg_index index;
switch (channel_id) {
case 0:
index = CIF_REG_LVDS_SAV_EAV_BLK1_ID0;
break;
case 1:
index = CIF_REG_LVDS_SAV_EAV_BLK1_ID1;
break;
case 2:
index = CIF_REG_LVDS_SAV_EAV_BLK1_ID2;
break;
case 3:
index = CIF_REG_LVDS_SAV_EAV_BLK1_ID3;
break;
default:
index = CIF_REG_LVDS_SAV_EAV_BLK1_ID0;
break;
}
return index;
}
/***************************** stream operations ******************************/
static void rkcif_assign_new_buffer_oneframe(struct rkcif_stream *stream,
enum rkcif_yuvaddr_state stat)
@@ -937,6 +1048,7 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
{
struct rkcif_dummy_buffer *dummy_buf = &stream->dummy_buf;
struct rkcif_device *dev = stream->cifdev;
struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus;
struct rkcif_buffer *buffer = NULL;
u32 frm_addr_y, frm_addr_uv;
@@ -944,7 +1056,8 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
u32 frm0_addr_y, frm0_addr_uv;
u32 frm1_addr_y, frm1_addr_uv;
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
frm0_addr_y = get_reg_index_of_frm0_y_addr(csi_ch);
frm0_addr_uv = get_reg_index_of_frm0_uv_addr(csi_ch);
frm1_addr_y = get_reg_index_of_frm1_y_addr(csi_ch);
@@ -995,7 +1108,8 @@ static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
}
spin_unlock(&stream->vbq_lock);
} else {
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
frm_addr_y = stream->frame_phase & CIF_CSI_FRAME1_READY ?
get_reg_index_of_frm1_y_addr(csi_ch) :
get_reg_index_of_frm0_y_addr(csi_ch);
@@ -1086,6 +1200,56 @@ static void rkcif_csi_get_vc_num(struct rkcif_device *dev,
dev->channels[0].vc = 0;
}
static void rkcif_csi_set_lvds_sav_eav(struct rkcif_stream *stream,
struct csi_channel_info *channel)
{
struct rkcif_device *dev = stream->cifdev;
struct rkmodule_lvds_cfg *lvds_cfg = &channel->lvds_cfg;
struct rkmodule_lvds_frame_sync_code *frm_sync_code = NULL;
struct rkmodule_lvds_frm_sync_code *odd_sync_code = NULL;
struct rkmodule_lvds_frm_sync_code *even_sync_code = NULL;
if (dev->hdr.mode == NO_HDR) {
frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LINEAR];
odd_sync_code = &frm_sync_code->odd_sync_code;
even_sync_code = odd_sync_code;
} else {
if (channel->id == RKCIF_STREAM_MIPI_ID0)
frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG];
else if (channel->id == RKCIF_STREAM_MIPI_ID1)
frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_SHORT];
else if (channel->id == RKCIF_STREAM_MIPI_ID2)
frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_MEDIUM];
else
frm_sync_code = &lvds_cfg->frm_sync_code[LVDS_CODE_GRP_LONG];
odd_sync_code = &frm_sync_code->odd_sync_code;
even_sync_code = &frm_sync_code->even_sync_code;
}
if (odd_sync_code && even_sync_code) {
rkcif_write_register(stream->cifdev,
get_reg_index_of_lvds_sav_eav_act0(channel->id),
SW_LVDS_EAV_ACT(odd_sync_code->act.eav) |
SW_LVDS_SAV_ACT(odd_sync_code->act.sav));
rkcif_write_register(stream->cifdev,
get_reg_index_of_lvds_sav_eav_blk0(channel->id),
SW_LVDS_EAV_BLK(odd_sync_code->blk.eav) |
SW_LVDS_SAV_BLK(odd_sync_code->blk.sav));
rkcif_write_register(stream->cifdev,
get_reg_index_of_lvds_sav_eav_act1(channel->id),
SW_LVDS_EAV_ACT(even_sync_code->act.eav) |
SW_LVDS_SAV_ACT(even_sync_code->act.sav));
rkcif_write_register(stream->cifdev,
get_reg_index_of_lvds_sav_eav_blk1(channel->id),
SW_LVDS_EAV_BLK(even_sync_code->blk.eav) |
SW_LVDS_SAV_BLK(even_sync_code->blk.sav));
}
}
static int rkcif_csi_channel_init(struct rkcif_stream *stream,
struct csi_channel_info *channel)
{
@@ -1123,6 +1287,11 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream,
return -EINVAL;
}
/*
* for mipi or lvds, when enable compact, the virtual width of raw10/raw12
* needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode
* needs aligned with :ALIGN(bits_per_pixel * width * 2, 8)
*/
if (dev->hdr.mode == NO_HDR) {
if (channel->fmt_val == CSI_WRDDR_TYPE_RAW10 ||
channel->fmt_val == CSI_WRDDR_TYPE_RAW12)
@@ -1156,9 +1325,10 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream,
}
static int rkcif_csi_channel_set(struct rkcif_stream *stream,
struct csi_channel_info *channel)
struct csi_channel_info *channel,
enum v4l2_mbus_type mbus_type)
{
unsigned int val;
unsigned int val = 0x0;
struct rkcif_device *dev = stream->cifdev;
if (channel->id >= 4)
@@ -1191,7 +1361,24 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
rkcif_write_register(dev, CIF_REG_MIPI_WATER_LINE, 0x70012);
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, 0x7075);
val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x3) |
CIF_MIPI_LVDS_SW_PRESS_ENABLE |
CIF_MIPI_LVDS_SW_HURRY_VALUE(0x3) |
CIF_MIPI_LVDS_SW_HURRY_ENABLE |
CIF_MIPI_LVDS_SW_WATER_LINE_25 |
CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE;
if (mbus_type == V4L2_MBUS_CSI2) {
val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS;
} else if (mbus_type == V4L2_MBUS_CCP2) {
if (channel->fmt_val == CSI_WRDDR_TYPE_RAW12)
val |= CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS;
else if (channel->fmt_val == CSI_WRDDR_TYPE_RAW10)
val |= CIF_MIPI_LVDS_SW_LVDS_WIDTH_10BITS;
else
val |= CIF_MIPI_LVDS_SW_LVDS_WIDTH_8BITS;
val |= CIF_MIPI_LVDS_SW_SEL_LVDS;
}
rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val);
rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN,
CSI_ALL_ERROR_INTEN);
@@ -1215,12 +1402,23 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
/* Set up an buffer for the next frame */
rkcif_assign_new_buffer_pingpong(stream, 1, channel->id);
val = CSI_ENABLE_CAPTURE | channel->fmt_val |
channel->cmd_mode_en << 4 | channel->crop_en << 5 |
channel->id << 8 | channel->data_type << 10 ;
if (mbus_type == V4L2_MBUS_CSI2) {
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;
} else if (mbus_type == V4L2_MBUS_CCP2) {
rkcif_csi_set_lvds_sav_eav(stream, channel);
val = LVDS_ENABLE_CAPTURE | LVDS_MODE(channel->lvds_cfg.mode) |
LVDS_MAIN_LANE(0) | LVDS_FID(0) |
LVDS_LANES_ENABLED(dev->active_sensor->lanes);
if (dev->hdr.mode != NO_HDR)
val |= LVDS_COMPACT;
}
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;
@@ -1229,18 +1427,38 @@ static int rkcif_csi_channel_set(struct rkcif_stream *stream,
static int rkcif_csi_stream_start(struct rkcif_stream *stream)
{
struct rkcif_device *dev = stream->cifdev;
unsigned int flags = dev->active_sensor->mbus.flags;
struct rkcif_sensor_info *active_sensor = dev->active_sensor;
unsigned int flags = active_sensor->mbus.flags;
enum v4l2_mbus_type mbus_type = active_sensor->mbus.type;
struct csi_channel_info *channel;
u32 ret = 0;
stream->frame_idx = 0;
rkcif_csi_get_vc_num(dev, flags);
if (mbus_type == V4L2_MBUS_CSI2) {
rkcif_csi_get_vc_num(dev, flags);
channel = &dev->channels[stream->id];
channel = &dev->channels[stream->id];
channel->id = stream->id;
rkcif_csi_channel_init(stream, channel);
rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CSI2);
} else if (mbus_type == V4L2_MBUS_CCP2) {
rkcif_csi_get_vc_num(dev, flags);
channel->id = stream->id;
rkcif_csi_channel_init(stream, channel);
rkcif_csi_channel_set(stream, channel);
channel = &dev->channels[stream->id];
channel->id = stream->id;
ret = v4l2_subdev_call(dev->terminal_sensor, core,
ioctl, RKMODULE_GET_LVDS_CFG,
&channel->lvds_cfg);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Err: get lvds config failed!!\n");
return ret;
}
rkcif_csi_channel_init(stream, channel);
rkcif_csi_channel_set(stream, channel, V4L2_MBUS_CCP2);
}
stream->state = RKCIF_STATE_STREAMING;
dev->workmode = RKCIF_WORKMODE_PINGPONG;
@@ -1250,11 +1468,13 @@ 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;
struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus;
u32 val;
int id;
struct rkcif_device *cif_dev = stream->cifdev;
if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
if (mbus_cfg->type == V4L2_MBUS_CSI2 ||
mbus_cfg->type == V4L2_MBUS_CCP2) {
id = stream->id;
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),
@@ -1782,6 +2002,12 @@ static int rkcif_sanity_check_fmt(struct rkcif_stream *stream,
return -EINVAL;
}
}
} else if (dev->active_sensor->mbus.type == V4L2_MBUS_CCP2) {
if (crop->left % 4 != 0) {
v4l2_err(v4l2_dev,
"ERROR: lvds crop left must align %d\n", 4);
return -EINVAL;
}
}
return 0;
@@ -1816,9 +2042,9 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
}
}
if (dev->mipi_sensor) {
if (dev->terminal_sensor) {
if (!dev->has_get_hdr) {
ret = v4l2_subdev_call(dev->mipi_sensor,
ret = v4l2_subdev_call(dev->terminal_sensor,
core, ioctl,
RKMODULE_GET_HDR_CFG,
&hdr_cfg);
@@ -1868,7 +2094,8 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
if (dev->chip_id == CHIP_RK1808_CIF ||
dev->chip_id == CHIP_RV1126_CIF) {
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2)
if (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 ||
dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)
ret = rkcif_csi_stream_start(stream);
else
ret = rkcif_stream_start(stream);
@@ -1879,12 +2106,6 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
if (ret < 0)
goto runtime_put;
if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL) {
ret = dev->pipe.set_stream(&dev->pipe, true);
if (ret < 0)
goto stop_stream;
}
ret = media_pipeline_start(&node->vdev.entity, &dev->pipe.pipe);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "start pipeline failed %d\n",
@@ -1892,6 +2113,12 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
goto pipe_stream_off;
}
if (sensor_info->mbus.type != V4L2_MBUS_PARALLEL) {
ret = dev->pipe.set_stream(&dev->pipe, true);
if (ret < 0)
goto stop_stream;
}
if (dev->hdr.mode == HDR_X2) {
if (dev->stream[RKCIF_STREAM_MIPI_ID0].state == RKCIF_STATE_STREAMING &&
dev->stream[RKCIF_STREAM_MIPI_ID1].state == RKCIF_STATE_STREAMING) {
@@ -1910,10 +2137,10 @@ static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
v4l2_info(&dev->v4l2_dev, "%s successfully!\n", __func__);
goto out;
pipe_stream_off:
dev->pipe.set_stream(&dev->pipe, false);
stop_stream:
rkcif_stream_stop(stream);
pipe_stream_off:
dev->pipe.set_stream(&dev->pipe, false);
runtime_put:
pm_runtime_put(dev->dev);
destroy_buf:
@@ -1988,9 +2215,9 @@ 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->terminal_sensor) {
if (!dev->has_get_hdr) {
ret = v4l2_subdev_call(dev->mipi_sensor,
ret = v4l2_subdev_call(dev->terminal_sensor,
core, ioctl,
RKMODULE_GET_HDR_CFG,
&hdr_cfg);
@@ -2484,6 +2711,182 @@ err:
return ret;
}
static struct v4l2_subdev *get_lvds_remote_sensor(struct v4l2_subdev *sd)
{
struct media_pad *local, *remote;
struct media_entity *sensor_me;
local = &sd->entity.pads[RKCIF_LVDS_PAD_SINK];
remote = media_entity_remote_pad(local);
if (!remote) {
v4l2_warn(sd, "No link between dphy and sensor with lvds\n");
return NULL;
}
sensor_me = media_entity_remote_pad(local)->entity;
return media_entity_to_v4l2_subdev(sensor_me);
}
static int rkcif_lvds_subdev_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote,
u32 flags)
{
return 0;
}
static int rkcif_lvds_sd_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd);
/*
* Do not allow format changes and just relay whatever
* set currently in the sensor.
*/
return v4l2_subdev_call(sensor, pad, get_fmt, NULL, fmt);
}
static int rkcif_lvds_sd_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct v4l2_subdev *sensor = get_lvds_remote_sensor(sd);
/*
* Do not allow format changes and just relay whatever
* set currently in the sensor.
*/
return v4l2_subdev_call(sensor, pad, get_fmt, NULL, fmt);
}
static int rkcif_lvds_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *mbus)
{
struct v4l2_subdev *sensor_sd = get_lvds_remote_sensor(sd);
int ret;
ret = v4l2_subdev_call(sensor_sd, video, g_mbus_config, mbus);
if (ret)
return ret;
return 0;
}
static int rkcif_lvds_sd_s_stream(struct v4l2_subdev *sd, int on)
{
return 0;
}
static int rkcif_lvds_sd_s_power(struct v4l2_subdev *sd, int on)
{
return 0;
}
static int rkcif_lvds_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 media_entity_operations rkcif_lvds_sd_media_ops = {
.link_setup = rkcif_lvds_subdev_link_setup,
.link_validate = v4l2_subdev_link_validate,
};
static const struct v4l2_subdev_pad_ops rkcif_lvds_sd_pad_ops = {
.set_fmt = rkcif_lvds_sd_set_fmt,
.get_fmt = rkcif_lvds_sd_get_fmt,
};
static const struct v4l2_subdev_video_ops rkcif_lvds_sd_video_ops = {
.g_mbus_config = rkcif_lvds_g_mbus_config,
.s_stream = rkcif_lvds_sd_s_stream,
};
static const struct v4l2_subdev_core_ops rkcif_lvds_sd_core_ops = {
.s_power = rkcif_lvds_sd_s_power,
.subscribe_event = rkcif_lvds_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static struct v4l2_subdev_ops rkcif_lvds_sd_ops = {
.core = &rkcif_lvds_sd_core_ops,
.video = &rkcif_lvds_sd_video_ops,
.pad = &rkcif_lvds_sd_pad_ops,
};
static void rkcif_lvds_event_inc_sof(struct rkcif_device *dev)
{
struct rkcif_lvds_subdev *subdev = &dev->lvds_subdev;
if (subdev) {
struct v4l2_event event = {
.type = V4L2_EVENT_FRAME_SYNC,
.u.frame_sync.frame_sequence =
atomic_inc_return(&subdev->frm_sync_seq) - 1,
};
v4l2_event_queue(subdev->sd.devnode, &event);
}
}
int rkcif_register_lvds_subdev(struct rkcif_device *dev)
{
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
struct rkcif_lvds_subdev *lvds_subdev = &dev->lvds_subdev;
struct v4l2_subdev *sd;
int ret;
memset(lvds_subdev, 0, sizeof(*lvds_subdev));
lvds_subdev->cifdev = dev;
sd = &lvds_subdev->sd;
lvds_subdev->state = RKCIF_LVDS_STOP;
v4l2_subdev_init(sd, &rkcif_lvds_sd_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.ops = &rkcif_lvds_sd_media_ops;
snprintf(sd->name, sizeof(sd->name), "rkcif-lvds-subdev");
lvds_subdev->pads[RKCIF_LVDS_PAD_SINK].flags =
MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID0].flags = MEDIA_PAD_FL_SOURCE;
lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID1].flags = MEDIA_PAD_FL_SOURCE;
lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID2].flags = MEDIA_PAD_FL_SOURCE;
lvds_subdev->pads[RKCIF_LVDS_PAD_SRC_ID3].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&sd->entity, RKCIF_LVDS_PAD_MAX,
lvds_subdev->pads);
if (ret < 0)
return ret;
sd->owner = THIS_MODULE;
v4l2_set_subdevdata(sd, lvds_subdev);
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret < 0)
goto free_media;
ret = v4l2_device_register_subdev_nodes(v4l2_dev);
if (ret < 0)
goto free_subdev;
return ret;
free_subdev:
v4l2_device_unregister_subdev(sd);
free_media:
media_entity_cleanup(&sd->entity);
v4l2_err(sd, "Failed to register subdev, ret:%d\n", ret);
return ret;
}
void rkcif_unregister_lvds_subdev(struct rkcif_device *dev)
{
struct v4l2_subdev *sd = &dev->lvds_subdev.sd;
v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
}
static void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
struct vb2_v4l2_buffer *vb_done)
{
@@ -2495,7 +2898,10 @@ static void rkcif_vb_done_oneframe(struct rkcif_stream *stream,
vb2_set_plane_payload(&vb_done->vb2_buf, i,
stream->pixm.plane_fmt[i].sizeimage);
}
vb_done->vb2_buf.timestamp = ktime_get_ns();
if (stream->cifdev->hdr.mode == NO_HDR)
vb_done->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -2692,10 +3098,12 @@ 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;
struct v4l2_mbus_config *mbus = &cif_dev->active_sensor->mbus;
void __iomem *base = cif_dev->base_addr;
unsigned int intstat, i = 0xff;
if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CSI2 &&
if ((mbus->type == V4L2_MBUS_CSI2 ||
mbus->type == V4L2_MBUS_CCP2) &&
(cif_dev->chip_id == CHIP_RK1808_CIF ||
cif_dev->chip_id == CHIP_RV1126_CIF)) {
int mipi_id;
@@ -2710,8 +3118,8 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
if (intstat & CSI_FIFO_OVERFLOW) {
v4l2_err(&cif_dev->v4l2_dev,
"ERROR: csi fifo overflow!! intstat: 0x%x\n",
intstat);
"ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n",
intstat, lastline);
return;
}
@@ -2728,11 +3136,19 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
return;
}
if (intstat & CSI_FRAME0_START_ID0)
rkcif_csi2_event_inc_sof();
if (intstat & CSI_FRAME0_START_ID0) {
if (mbus->type == V4L2_MBUS_CSI2)
rkcif_csi2_event_inc_sof();
else if (mbus->type == V4L2_MBUS_CCP2)
rkcif_lvds_event_inc_sof(cif_dev);
}
if (intstat & CSI_FRAME1_START_ID0)
rkcif_csi2_event_inc_sof();
if (intstat & CSI_FRAME1_START_ID0) {
if (mbus->type == V4L2_MBUS_CSI2)
rkcif_csi2_event_inc_sof();
else if (mbus->type == V4L2_MBUS_CCP2)
rkcif_lvds_event_inc_sof(cif_dev);
}
/* if do not reach frame dma end, return irq */
mipi_id = rkcif_csi_g_mipi_id(&cif_dev->v4l2_dev, intstat);
@@ -2799,6 +3215,7 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
if (cif_dev->hdr.mode == NO_HDR) {
if (active_buf)
rkcif_vb_done_oneframe(stream, vb_done);
v4l2_err(&cif_dev->v4l2_dev, "no_hdr vb done\n");
} else if (cif_dev->hdr.mode == HDR_X2) {
if (mipi_id == RKCIF_STREAM_MIPI_ID0) {
if (cif_dev->rdbk_buf[RDBK_L]) {
@@ -2849,7 +3266,6 @@ void rkcif_irq_pingpong(struct rkcif_device *cif_dev)
* - FRAME_END: cif has saved frame to memory,
* a frame ready
*/
if ((intstat & PST_INF_FRAME_END)) {
rkcif_write_register(cif_dev, CIF_REG_DVP_INTSTAT,
PST_INF_FRAME_END_CLR);

View File

@@ -208,20 +208,56 @@ static int rkcif_pipeline_close(struct rkcif_pipeline *p)
*/
static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
{
struct rkcif_device *cif_dev = container_of(p, struct rkcif_device, pipe);
bool can_be_set = false;
int i, ret;
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
if (cif_dev->hdr.mode == NO_HDR) {
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
if (on)
rockchip_set_system_status(SYS_STATUS_CIF0);
if (on)
rockchip_set_system_status(SYS_STATUS_CIF0);
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; i++) {
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; i++) {
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
} else {
if (!on && atomic_dec_return(&p->stream_cnt) > 0)
return 0;
if (on) {
atomic_inc(&p->stream_cnt);
if (cif_dev->hdr.mode == HDR_X2) {
if (atomic_read(&p->stream_cnt) == 1) {
rockchip_set_system_status(SYS_STATUS_CIF0);
can_be_set = false;
} else if (atomic_read(&p->stream_cnt) == 2) {
can_be_set = true;
}
} else if (cif_dev->hdr.mode == HDR_X3) {
if (atomic_read(&p->stream_cnt) == 1) {
rockchip_set_system_status(SYS_STATUS_CIF0);
can_be_set = false;
} else if (atomic_read(&p->stream_cnt) == 3) {
can_be_set = true;
}
}
}
if (on && can_be_set) {
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; i++) {
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
}
}
if (!on)
@@ -252,24 +288,40 @@ static int rkcif_create_links(struct rkcif_device *dev)
/* sensor links(or mipi-phy) */
for (s = 0; s < dev->num_sensors; ++s) {
struct rkcif_sensor_info *sensor = &dev->sensors[s];
struct rkcif_sensor_info linked_sensor;
struct media_entity *source_entity, *sink_entity;
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++) {
if (sensor->sd->entity.pads[pad].flags &
linked_sensor.lanes = sensor->lanes;
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
linked_sensor.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.sd = &dev->lvds_subdev.sd;
dev->lvds_subdev.sensor_self.lanes = sensor->lanes;
memcpy(&dev->lvds_subdev.sensor_self.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
} else {
linked_sensor.sd = sensor->sd;
}
memcpy(&linked_sensor.mbus, &sensor->mbus,
sizeof(struct v4l2_mbus_config));
for (pad = 0; pad < linked_sensor.sd->entity.num_pads; pad++) {
if (linked_sensor.sd->entity.pads[pad].flags &
MEDIA_PAD_FL_SOURCE) {
if (pad == sensor->sd->entity.num_pads) {
if (pad == linked_sensor.sd->entity.num_pads) {
dev_err(dev->dev,
"failed to find src pad for %s\n",
sensor->sd->name);
linked_sensor.sd->name);
break;
}
if ((sensor->mbus.type == V4L2_MBUS_BT656 ||
sensor->mbus.type == V4L2_MBUS_PARALLEL) &&
if ((linked_sensor.mbus.type == V4L2_MBUS_BT656 ||
linked_sensor.mbus.type == V4L2_MBUS_PARALLEL) &&
(dev->chip_id == CHIP_RK1808_CIF ||
dev->chip_id == CHIP_RV1126_CIF)) {
source_entity = &sensor->sd->entity;
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[RKCIF_STREAM_DVP].vnode.vdev.entity;
ret = media_create_pad_link(source_entity,
@@ -279,12 +331,12 @@ static int rkcif_create_links(struct rkcif_device *dev)
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link for %s\n",
sensor->sd->name);
linked_sensor.sd->name);
break;
}
for (id = 0; id < stream_num; id++) {
source_entity = &sensor->sd->entity;
source_entity = &linked_sensor.sd->entity;
sink_entity = &dev->stream[id].vnode.vdev.entity;
if ((dev->chip_id != CHIP_RK1808_CIF &&
@@ -302,12 +354,26 @@ static int rkcif_create_links(struct rkcif_device *dev)
if (ret) {
dev_err(dev->dev,
"failed to create link for %s\n",
sensor->sd->name);
linked_sensor.sd->name);
break;
}
}
}
}
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
source_entity = &sensor->sd->entity;
sink_entity = &linked_sensor.sd->entity;
ret = media_create_pad_link(source_entity,
1,
sink_entity,
0,
MEDIA_LNK_FL_ENABLED);
if (ret)
dev_err(dev->dev, "failed to create link between %s and %s\n",
linked_sensor.sd->name,
sensor->sd->name);
}
}
return 0;
@@ -321,27 +387,41 @@ static int _set_pipeline_default_fmt(struct rkcif_device *dev)
static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct rkcif_device *dev;
int ret;
struct rkcif_sensor_info *sensor;
int ret, index;
dev = container_of(notifier, struct rkcif_device, notifier);
/* mutex_lock(&dev->media_dev.graph_mutex); */
for (index = 0; index < dev->num_sensors; index++) {
sensor = &dev->sensors[index];
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
ret = rkcif_register_lvds_subdev(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"Err: register lvds subdev failed!!!\n");
goto notifier_end;
}
break;
}
}
ret = rkcif_create_links(dev);
if (ret < 0)
goto unlock;
goto unregister_lvds;
ret = v4l2_device_register_subdev_nodes(&dev->v4l2_dev);
if (ret < 0)
goto unlock;
goto unregister_lvds;
ret = _set_pipeline_default_fmt(dev);
if (ret < 0)
goto unlock;
goto unregister_lvds;
v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n");
return ret;
unlock:
/* mutex_unlock(&dev->media_dev.graph_mutex); */
unregister_lvds:
rkcif_unregister_lvds_subdev(dev);
notifier_end:
return ret;
}
@@ -383,7 +463,8 @@ static int rkcif_fwnode_parse(struct device *dev,
if (vep->bus_type != V4L2_MBUS_BT656 &&
vep->bus_type != V4L2_MBUS_PARALLEL &&
vep->bus_type != V4L2_MBUS_CSI2)
vep->bus_type != V4L2_MBUS_CSI2 &&
vep->bus_type != V4L2_MBUS_CCP2)
return 0;
rk_asd->mbus.type = vep->bus_type;
@@ -391,6 +472,8 @@ static int rkcif_fwnode_parse(struct device *dev,
if (vep->bus_type == V4L2_MBUS_CSI2) {
rk_asd->mbus.flags = vep->bus.mipi_csi2.flags;
rk_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
} else if (vep->bus_type == V4L2_MBUS_CCP2) {
rk_asd->lanes = vep->bus.mipi_csi1.data_lane;
} else {
rk_asd->mbus.flags = bus->flags;
}
@@ -1153,6 +1236,9 @@ static int rkcif_plat_remove(struct platform_device *pdev)
if (cif_dev->iommu_en)
rkcif_iommu_cleanup(cif_dev);
if (cif_dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)
rkcif_unregister_lvds_subdev(cif_dev);
media_device_unregister(&cif_dev->media_dev);
v4l2_device_unregister(&cif_dev->v4l2_dev);
if (cif_dev->chip_id == CHIP_RK1808_CIF ||

View File

@@ -100,6 +100,20 @@ enum host_type_t {
RK_DSI_RXHOST
};
enum rkcif_lvds_pad {
RKCIF_LVDS_PAD_SINK = 0x0,
RKCIF_LVDS_PAD_SRC_ID0,
RKCIF_LVDS_PAD_SRC_ID1,
RKCIF_LVDS_PAD_SRC_ID2,
RKCIF_LVDS_PAD_SRC_ID3,
RKCIF_LVDS_PAD_MAX
};
enum rkcif_lvds_state {
RKCIF_LVDS_STOP = 0,
RKCIF_LVDS_START,
};
/*
* struct rkcif_pipeline - An CIF hardware pipeline
*
@@ -200,6 +214,7 @@ struct csi_channel_info {
unsigned int virtual_width;
unsigned int crop_st_x;
unsigned int crop_st_y;
struct rkmodule_lvds_cfg lvds_cfg;
};
struct rkcif_vdev_node {
@@ -264,6 +279,19 @@ struct rkcif_stream {
int crop_enable;
};
struct rkcif_lvds_subdev {
struct rkcif_device *cifdev;
struct v4l2_subdev sd;
struct v4l2_subdev *remote_sd;
struct media_pad pads[RKCIF_LVDS_PAD_MAX];
struct v4l2_mbus_framefmt in_fmt;
const struct cif_output_fmt *cif_fmt_out;
const struct cif_input_fmt *cif_fmt_in;
enum rkcif_lvds_state state;
struct rkcif_sensor_info sensor_self;
atomic_t frm_sync_seq;
};
static inline struct rkcif_buffer *to_rkcif_buffer(struct vb2_v4l2_buffer *vb)
{
return container_of(vb, struct rkcif_buffer, vb);
@@ -319,7 +347,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 v4l2_subdev *terminal_sensor;
struct rkcif_stream stream[RKCIF_MULTI_STREAMS_NUM];
struct rkcif_pipeline pipe;
@@ -336,8 +364,8 @@ struct rkcif_device {
bool can_be_reset;
struct rkcif_hdr hdr;
struct rkcif_buffer *rdbk_buf[RDBK_MAX];
struct rkcif_luma_vdev luma_vdev;
struct rkcif_lvds_subdev lvds_subdev;
};
void rkcif_write_register(struct rkcif_device *dev,
@@ -354,10 +382,11 @@ 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,
bool is_rst_iommu);
bool is_rst_iommu);
int rkcif_register_lvds_subdev(struct rkcif_device *dev);
void rkcif_unregister_lvds_subdev(struct rkcif_device *dev);
#endif

View File

@@ -370,6 +370,37 @@ enum cif_reg_index {
#define CSI_ENABLE_CROP (0x1 << 5)
#define CSI_ENABLE_MIPI_COMPACT (0x1 << 6)
#define LVDS_ENABLE_CAPTURE (0x1 << 16)
#define LVDS_MODE(mode) (((mode) & 0x7) << 17)
#define LVDS_LANES_ENABLED(lanes) \
({ \
unsigned int mask; \
switch (lanes) { \
case 1: \
mask = 0x1 << 20; \
break; \
case 2: \
mask = 0x3 << 20; \
break; \
case 3: \
mask = 0x7 << 20; \
break; \
case 4: \
mask = 0xf << 20; \
break; \
default: \
mask = 0x1 << 20; \
break; \
} \
mask; \
})
#define LVDS_MAIN_LANE(index) (((index) & 0x3) << 24)
#define LVDS_FID(id) (((id) & 0x3) << 26)
#define LVDS_HDR_FRAME_X2 (0x0 << 28)
#define LVDS_HDR_FRAME_X3 (0x1 << 28)
#define LVDS_COMPACT (0x1 << 29)
/* CIF_CSI_INTEN */
#define CSI_FRAME1_START_INTEN(id) (0x1 << ((id) * 2 + 1))
#define CSI_FRAME0_END_INTEN(id) (0x1 << ((id) * 2 + 8))
@@ -433,7 +464,18 @@ enum cif_reg_index {
/* 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_PRESS_ENABLE (0x1 << 12)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_8BITS (0x0 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_10BITS (0x1 << 9)
#define CIF_MIPI_LVDS_SW_LVDS_WIDTH_12BITS (0x2 << 9)
#define CIF_MIPI_LVDS_SW_SEL_LVDS (0x1 << 8)
#define CIF_MIPI_LVDS_SW_HURRY_VALUE(val) (((val) & 0x3) << 5)
#define CIF_MIPI_LVDS_SW_HURRY_ENABLE (0x1 << 4)
#define CIF_MIPI_LVDS_SW_WATER_LINE_75 (0x0 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_50 (0x1 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_25 (0x2 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_00 (0x3 << 1)
#define CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE (0x1 << 0)
/* CSI Host Registers Define */
#define CSIHOST_N_LANES 0x04
@@ -457,4 +499,10 @@ enum cif_reg_index {
#define SW_FRM_END_ID2(x) (((x) & CSI_FRAME_END_ID2) >> 12)
#define SW_FRM_END_ID3(x) (((x) & CSI_FRAME_END_ID3) >> 14)
/* CIF LVDS SAV EAV Define */
#define SW_LVDS_EAV_ACT(code) (((code) & 0xfff) << 16)
#define SW_LVDS_SAV_ACT(code) (((code) & 0xfff) << 0)
#define SW_LVDS_EAV_BLK(code) (((code) & 0xfff) << 16)
#define SW_LVDS_SAV_BLK(code) (((code) & 0xfff) << 0)
#endif

View File

@@ -28,8 +28,10 @@
*2. support vicap + mipi(single) for rv1126
*3. support vicap + mipi hdr for rv1126
*4. add luma device node for rv1126 vicap
*v0.1.4
*1. support vicap-full lvds interface to work in linear and hdr mode for rv1126
*/
#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x3)
#define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x4)
#endif