mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
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:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user