mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
media: ipu6: Rework CSI-2 sub-device streaming control
CSI-2 sub-device streaming control should use {enable,disable}_streams pad
ops and not s_stream video ops as the sub-device supports streams. Fix
this by removing driver-implemented stream management and moving sensor
streaming control to the CSI-2 sub-device sub-driver.
Fixes: a11a5570a0
("media: intel/ipu6: add IPU6 CSI2 receiver v4l2 sub-device")
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
parent
ce44dc1fea
commit
3a5c59ad92
4 changed files with 49 additions and 97 deletions
|
@ -345,42 +345,61 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int set_stream(struct v4l2_subdev *sd, int enable)
|
||||
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
|
||||
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
|
||||
struct device *dev = &csi2->isys->adev->auxdev.dev;
|
||||
struct ipu6_isys_csi2_timing timing = { };
|
||||
unsigned int nlanes;
|
||||
struct v4l2_subdev *remote_sd;
|
||||
struct media_pad *remote_pad;
|
||||
u64 sink_streams;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off");
|
||||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
if (!enable) {
|
||||
csi2->stream_count--;
|
||||
if (csi2->stream_count)
|
||||
return 0;
|
||||
|
||||
ipu6_isys_csi2_set_stream(sd, &timing, 0, enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (csi2->stream_count) {
|
||||
csi2->stream_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlanes = csi2->nlanes;
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ipu6_isys_csi2_set_stream(sd, &timing, nlanes, enable);
|
||||
ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csi2->stream_count++;
|
||||
ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
|
||||
sink_streams);
|
||||
if (ret) {
|
||||
ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state,
|
||||
u32 pad, u64 streams_mask)
|
||||
{
|
||||
struct v4l2_subdev *remote_sd;
|
||||
struct media_pad *remote_pad;
|
||||
u64 sink_streams;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
|
||||
|
||||
v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -475,10 +494,6 @@ static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
|
||||
.s_stream = set_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = ipu6_isys_subdev_set_fmt,
|
||||
|
@ -486,11 +501,12 @@ static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
|
|||
.set_selection = ipu6_isys_csi2_set_sel,
|
||||
.enum_mbus_code = ipu6_isys_subdev_enum_mbus_code,
|
||||
.set_routing = ipu6_isys_subdev_set_routing,
|
||||
.enable_streams = ipu6_isys_csi2_enable_streams,
|
||||
.disable_streams = ipu6_isys_csi2_disable_streams,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops csi2_sd_ops = {
|
||||
.core = &csi2_sd_core_ops,
|
||||
.video = &csi2_sd_video_ops,
|
||||
.pad = &csi2_sd_pad_ops,
|
||||
};
|
||||
|
||||
|
@ -631,33 +647,3 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status)
|
||||
{
|
||||
struct ipu6_isys_stream *stream = av->stream;
|
||||
struct v4l2_subdev *sd = &stream->asd->sd;
|
||||
struct v4l2_subdev_state *state;
|
||||
struct media_pad *r_pad;
|
||||
unsigned int i;
|
||||
u32 r_stream;
|
||||
|
||||
r_pad = media_pad_remote_pad_first(&av->pad);
|
||||
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
|
||||
|
||||
state = v4l2_subdev_lock_and_get_active_state(sd);
|
||||
|
||||
for (i = 0; i < state->stream_configs.num_configs; i++) {
|
||||
struct v4l2_subdev_stream_config *cfg =
|
||||
&state->stream_configs.configs[i];
|
||||
|
||||
if (cfg->pad == r_pad->index && r_stream == cfg->stream) {
|
||||
dev_dbg(&av->isys->adev->auxdev.dev,
|
||||
"%s: pad:%u, stream:%u, status:%u\n",
|
||||
sd->entity.name, r_pad->index, r_stream,
|
||||
status);
|
||||
cfg->enabled = status;
|
||||
}
|
||||
}
|
||||
|
||||
v4l2_subdev_unlock_state(state);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ struct ipu6_isys_csi2 {
|
|||
u32 receiver_errors;
|
||||
unsigned int nlanes;
|
||||
unsigned int port;
|
||||
unsigned int stream_count;
|
||||
};
|
||||
|
||||
struct ipu6_isys_csi2_timing {
|
||||
|
@ -77,6 +76,5 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
|
|||
struct ipu6_isys_csi2 *csi2,
|
||||
struct media_entity *source_entity,
|
||||
struct v4l2_mbus_frame_desc_entry *entry);
|
||||
void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status);
|
||||
|
||||
#endif /* IPU6_ISYS_CSI2_H */
|
||||
|
|
|
@ -551,7 +551,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
|
|||
stream->nr_queues);
|
||||
|
||||
list_add(&aq->node, &stream->queues);
|
||||
ipu6_isys_set_csi2_streams_status(av, true);
|
||||
ipu6_isys_configure_stream_watermark(av, true);
|
||||
ipu6_isys_update_stream_watermark(av, true);
|
||||
|
||||
|
@ -598,8 +597,6 @@ static void stop_streaming(struct vb2_queue *q)
|
|||
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
|
||||
struct ipu6_isys_stream *stream = av->stream;
|
||||
|
||||
ipu6_isys_set_csi2_streams_status(av, false);
|
||||
|
||||
mutex_lock(&stream->mutex);
|
||||
|
||||
ipu6_isys_update_stream_watermark(av, false);
|
||||
|
|
|
@ -990,9 +990,7 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
|||
struct v4l2_subdev_state *subdev_state;
|
||||
struct device *dev = &av->isys->adev->auxdev.dev;
|
||||
struct v4l2_subdev *sd;
|
||||
struct v4l2_subdev *ssd;
|
||||
struct media_pad *r_pad;
|
||||
struct media_pad *s_pad;
|
||||
u32 sink_pad, sink_stream;
|
||||
u64 r_stream;
|
||||
u64 stream_mask = 0;
|
||||
|
@ -1003,7 +1001,6 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
|||
if (WARN(!stream->source_entity, "No source entity for stream\n"))
|
||||
return -ENODEV;
|
||||
|
||||
ssd = media_entity_to_v4l2_subdev(stream->source_entity);
|
||||
sd = &stream->asd->sd;
|
||||
r_pad = media_pad_remote_pad_first(&av->pad);
|
||||
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
|
||||
|
@ -1017,27 +1014,15 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]);
|
||||
|
||||
stream_mask = get_stream_mask_by_pipeline(av);
|
||||
if (!state) {
|
||||
stop_streaming_firmware(av);
|
||||
|
||||
/* stop external sub-device now. */
|
||||
dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask,
|
||||
ssd->name);
|
||||
ret = v4l2_subdev_disable_streams(ssd, s_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "disable streams of %s failed with %d\n",
|
||||
ssd->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* stop sub-device which connects with video */
|
||||
dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name,
|
||||
r_pad->index);
|
||||
ret = v4l2_subdev_call(sd, video, s_stream, state);
|
||||
dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
|
||||
sd->name, r_pad->index, stream_mask);
|
||||
ret = v4l2_subdev_disable_streams(sd, r_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "stream off %s failed with %d\n", sd->name,
|
||||
ret);
|
||||
|
@ -1052,34 +1037,20 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
|
|||
}
|
||||
|
||||
/* start sub-device which connects with video */
|
||||
dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
|
||||
ret = v4l2_subdev_call(sd, video, s_stream, state);
|
||||
dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
|
||||
r_pad->index, stream_mask);
|
||||
ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev, "stream on %s failed with %d\n", sd->name,
|
||||
ret);
|
||||
goto out_media_entity_stop_streaming_firmware;
|
||||
}
|
||||
|
||||
/* start external sub-device now. */
|
||||
dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask,
|
||||
ssd->name);
|
||||
ret = v4l2_subdev_enable_streams(ssd, s_pad->index,
|
||||
stream_mask);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"enable streams 0x%llx of %s failed with %d\n",
|
||||
stream_mask, stream->source_entity->name, ret);
|
||||
goto out_media_entity_stop_streaming;
|
||||
}
|
||||
}
|
||||
|
||||
av->streaming = state;
|
||||
|
||||
return 0;
|
||||
|
||||
out_media_entity_stop_streaming:
|
||||
v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream));
|
||||
|
||||
out_media_entity_stop_streaming_firmware:
|
||||
stop_streaming_firmware(av);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue