media: rockchip: rkcif support RKCIF_MASTER_MASTER/RKCIF_MASTER_SLAVE sync mode

Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
Change-Id: I71270f1e0e3ba309683092f1ae1d01122bc4b613
This commit is contained in:
Zefa Chen
2021-11-06 18:41:37 +08:00
committed by Tao Huang
parent 08b6f9fdcf
commit d79447a5e8
5 changed files with 212 additions and 1 deletions

View File

@@ -2930,6 +2930,47 @@ static void rkcif_release_rdbk_buf(struct rkcif_stream *stream)
}
static void rkcif_detach_sync_mode(struct rkcif_device *cif_dev)
{
int i = 0;
struct rkcif_hw *hw = cif_dev->hw_dev;
struct rkcif_device *tmp_dev;
if ((!cif_dev->sync_type) ||
(atomic_read(&cif_dev->pipe.stream_cnt) != 0))
return;
hw->sync_config.streaming_cnt--;
if (cif_dev->sync_type == EXTERNAL_MASTER_MODE) {
for (i = 0; i < hw->sync_config.ext_master.count; i++) {
tmp_dev = hw->sync_config.ext_master.cif_dev[i];
if (tmp_dev == cif_dev) {
hw->sync_config.ext_master.is_streaming[i] = false;
break;
}
}
}
if (cif_dev->sync_type == INTERNAL_MASTER_MODE)
hw->sync_config.int_master.is_streaming[0] = false;
if (cif_dev->sync_type == SLAVE_MODE) {
for (i = 0; i < hw->sync_config.slave.count; i++) {
tmp_dev = hw->sync_config.slave.cif_dev[i];
if (tmp_dev == cif_dev) {
hw->sync_config.slave.is_streaming[i] = false;
break;
}
}
}
if (!hw->sync_config.streaming_cnt && hw->sync_config.is_attach) {
hw->sync_config.is_attach = false;
hw->sync_config.mode = RKCIF_NOSYNC_MODE;
hw->sync_config.dev_cnt = 0;
for (i = 0; i < hw->dev_num; i++)
hw->cif_dev[i]->sync_type = NO_SYNC_MODE;
}
}
void rkcif_do_stop_stream(struct rkcif_stream *stream,
unsigned int mode)
{
@@ -3046,7 +3087,7 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream,
rkcif_destroy_dummy_buf(stream);
v4l2_info(&dev->v4l2_dev, "stream[%d] stopping finished\n", stream->id);
rkcif_detach_sync_mode(dev);
mutex_unlock(&dev->stream_lock);
}
@@ -3799,6 +3840,68 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode)
return 0;
}
static void rkcif_attach_sync_mode(struct rkcif_hw *hw)
{
struct rkcif_device *dev;
int i = 0;
int ret = 0;
int sync_type = 0;
int count = 0;
if (hw->sync_config.is_attach)
return;
memset(&hw->sync_config, 0, sizeof(struct rkcif_multi_sync_config));
for (i = 0; i < hw->dev_num; i++) {
dev = hw->cif_dev[i];
ret = v4l2_subdev_call(dev->terminal_sensor.sd,
core, ioctl,
RKMODULE_GET_SYNC_MODE,
&sync_type);
if (!ret) {
if (sync_type == EXTERNAL_MASTER_MODE) {
count = hw->sync_config.ext_master.count;
hw->sync_config.ext_master.cif_dev[count] = dev;
hw->sync_config.ext_master.count++;
hw->sync_config.dev_cnt++;
dev->sync_type = EXTERNAL_MASTER_MODE;
} else if (sync_type == INTERNAL_MASTER_MODE) {
count = hw->sync_config.int_master.count;
hw->sync_config.int_master.cif_dev[count] = dev;
hw->sync_config.int_master.count++;
hw->sync_config.dev_cnt++;
dev->sync_type = INTERNAL_MASTER_MODE;
} else if (sync_type == SLAVE_MODE) {
count = hw->sync_config.slave.count;
hw->sync_config.slave.cif_dev[count] = dev;
hw->sync_config.slave.count++;
hw->sync_config.dev_cnt++;
dev->sync_type = SLAVE_MODE;
}
}
}
if (hw->sync_config.int_master.count == 1) {
if (hw->sync_config.ext_master.count) {
hw->sync_config.mode = RKCIF_MASTER_MASTER;
hw->sync_config.is_attach = true;
} else if (hw->sync_config.slave.count) {
hw->sync_config.mode = RKCIF_MASTER_SLAVE;
hw->sync_config.is_attach = true;
} else {
dev_info(hw->dev,
"Missing slave device, do not use sync mode\n");
}
if (hw->sync_config.ext_master.count &&
hw->sync_config.slave.count)
dev_info(hw->dev,
"There are two types of slave devices, it may cause problems\n");
} else {
dev_info(hw->dev,
"Only support one master device, master device count %d\n",
hw->sync_config.int_master.count);
}
}
int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
{
struct rkcif_vdev_node *node = &stream->vnode;
@@ -3813,6 +3916,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode)
v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id);
mutex_lock(&dev->stream_lock);
rkcif_attach_sync_mode(dev->hw_dev);
if ((stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) == mode) {
ret = -EBUSY;
v4l2_err(v4l2_dev, "stream in busy state\n");

View File

@@ -814,6 +814,71 @@ static int rkcif_pipeline_close(struct rkcif_pipeline *p)
return 0;
}
static void rkcif_set_sensor_streamon_in_sync_mode(struct rkcif_device *cif_dev)
{
struct rkcif_hw *hw = cif_dev->hw_dev;
struct rkcif_device *dev = NULL;
int i = 0;
int on = 1;
int ret = 0;
bool is_streaming = false;
if (cif_dev->sync_type) {
hw->sync_config.streaming_cnt++;
if (hw->sync_config.streaming_cnt < hw->sync_config.dev_cnt)
return;
} else {
return;
}
if (hw->sync_config.mode == RKCIF_MASTER_MASTER ||
hw->sync_config.mode == RKCIF_MASTER_SLAVE) {
for (i = 0; i < hw->sync_config.slave.count; i++) {
dev = hw->sync_config.slave.cif_dev[i];
is_streaming = hw->sync_config.slave.is_streaming[i];
if (!is_streaming) {
ret = v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl,
RKMODULE_SET_QUICK_STREAM, &on);
if (!ret)
dev_info(dev->dev,
"set RKMODULE_SET_QUICK_STREAM failed\n");
hw->sync_config.slave.is_streaming[i] = true;
}
v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
"quick stream in sync mode, slave_dev[%d]\n", i);
}
for (i = 0; i < hw->sync_config.ext_master.count; i++) {
dev = hw->sync_config.ext_master.cif_dev[i];
is_streaming = hw->sync_config.ext_master.is_streaming[i];
if (!is_streaming) {
ret = v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl,
RKMODULE_SET_QUICK_STREAM, &on);
if (!ret)
dev_info(dev->dev,
"set RKMODULE_SET_QUICK_STREAM failed\n");
hw->sync_config.ext_master.is_streaming[i] = true;
}
v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
"quick stream in sync mode, ext_master_dev[%d]\n", i);
}
for (i = 0; i < hw->sync_config.int_master.count; i++) {
dev = hw->sync_config.int_master.cif_dev[i];
is_streaming = hw->sync_config.int_master.is_streaming[i];
if (!is_streaming) {
ret = v4l2_subdev_call(dev->terminal_sensor.sd, core, ioctl,
RKMODULE_SET_QUICK_STREAM, &on);
if (!ret)
dev_info(hw->dev,
"set RKMODULE_SET_QUICK_STREAM failed\n");
hw->sync_config.int_master.is_streaming[i] = true;
}
v4l2_dbg(3, rkcif_debug, &dev->v4l2_dev,
"quick stream in sync mode, int_master_dev[%d]\n", i);
}
}
}
/*
* stream-on order: isp_subdev, mipi dphy, sensor
* stream-off order: mipi dphy, sensor, isp_subdev
@@ -855,6 +920,8 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
if (on)
rkcif_set_sensor_streamon_in_sync_mode(cif_dev);
} else {
if (!on && atomic_dec_return(&p->stream_cnt) > 0)
return 0;
@@ -906,6 +973,9 @@ static int rkcif_pipeline_set_stream(struct rkcif_pipeline *p, bool on)
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
if (on)
rkcif_set_sensor_streamon_in_sync_mode(cif_dev);
}
}
@@ -1553,6 +1623,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
cif_dev->pipe.set_stream = rkcif_pipeline_set_stream;
cif_dev->isr_hdl = rkcif_irq_handler;
cif_dev->id_use_cnt = 0;
cif_dev->sync_type = NO_SYNC_MODE;
if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE)
cif_dev->isr_hdl = rkcif_irq_lite_handler;

View File

@@ -709,6 +709,7 @@ struct rkcif_device {
bool reset_work_cancel;
bool iommu_en;
bool is_use_dummybuf;
int sync_type;
};
extern struct platform_driver rkcif_plat_drv;

View File

@@ -994,6 +994,8 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
cif_hw->irq = irq;
cif_hw->match_data = data;
cif_hw->chip_id = data->chip_id;
cif_hw->sync_config.is_attach = false;
cif_hw->sync_config.mode = RKCIF_NOSYNC_MODE;
if (data->chip_id >= CHIP_RK1808_CIF) {
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM,

View File

@@ -33,6 +33,38 @@
#define write_cif_reg_and(base, addr, val) \
writel(readl((addr) + (base)) & (val), (addr) + (base))
/*
* multi sensor sync mode
* RKCIF_NOSYNC_MODE: not used sync mode
* RKCIF_MASTER_MASTER: internal master->external master
* RKCIF_MASTER_SLAVE: internal master->slave
* RKCIF_MASTER_MASTER: pwm/gpio->external master
* RKCIF_MASTER_MASTER: pwm/gpio->slave
*/
enum rkcif_sync_mode {
RKCIF_NOSYNC_MODE,
RKCIF_MASTER_MASTER,
RKCIF_MASTER_SLAVE,
RKCIF_EXT_MASTER,
RKCIF_EXT_SLAVE,
};
struct rkcif_sync_dev {
struct rkcif_device *cif_dev[RKCIF_DEV_MAX];
int count;
bool is_streaming[RKCIF_DEV_MAX];
};
struct rkcif_multi_sync_config {
struct rkcif_sync_dev int_master;
struct rkcif_sync_dev ext_master;
struct rkcif_sync_dev slave;
enum rkcif_sync_mode mode;
int dev_cnt;
int streaming_cnt;
bool is_attach;
};
/*
* add new chip id in tail in time order
* by increasing to distinguish cif version
@@ -88,6 +120,7 @@ struct rkcif_hw {
atomic_t power_cnt;
const struct rkcif_hw_match_data *match_data;
struct mutex dev_lock;
struct rkcif_multi_sync_config sync_config;
};
void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu);