diff mbox series

[03/19] media: adv748x: Use V4L2 streams

Message ID 20240430103956.60190-4-jacopo.mondi@ideasonboard.com
State New
Headers show
Series [01/19] media: adv748x: Add support for active state | expand

Commit Message

Jacopo Mondi April 30, 2024, 10:39 a.m. UTC
Initialize the CSI-2 subdevice with the V4L2_SUBDEV_FL_STREAMS flag
and initialize a simple routing table by implementing the .init_state()
operation.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c | 28 ++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

Comments

Laurent Pinchart May 2, 2024, 5:40 p.m. UTC | #1
Hi Jacopo,

Thank you for the patch.

On Tue, Apr 30, 2024 at 12:39:39PM +0200, Jacopo Mondi wrote:
> Initialize the CSI-2 subdevice with the V4L2_SUBDEV_FL_STREAMS flag
> and initialize a simple routing table by implementing the .init_state()
> operation.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  drivers/media/i2c/adv748x/adv748x-csi2.c | 28 ++++++++++++++++++++++--
>  1 file changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> index 60bf1dc0f58b..d929db7e8ef2 100644
> --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> @@ -59,7 +59,30 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
>  
>  /* -----------------------------------------------------------------------------
>   * v4l2_subdev_internal_ops
> - *
> + */
> +
> +static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_state *state)
> +{
> +	struct v4l2_subdev_route routes[] = {
> +		{
> +			.sink_pad = ADV748X_CSI2_SINK,
> +			.sink_stream = 0,
> +			.source_pad = ADV748X_CSI2_SOURCE,
> +			.source_stream = 0,
> +			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
> +		},
> +	};
> +
> +	struct v4l2_subdev_krouting routing = {
> +		.num_routes = ARRAY_SIZE(routes),
> +		.routes = routes,
> +	};
> +
> +	return v4l2_subdev_set_routing(sd, state, &routing);

You need to initialize formats too.

> +}
> +
> +/*
>   * We use the internal registered operation to be able to ensure that our
>   * incremental subdevices (not connected in the forward path) can be registered
>   * against the resulting video path and media device.
> @@ -109,6 +132,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
>  }
>  
>  static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
> +	.init_state = adv748x_csi2_init_state,

The .init_state() operation needs to be provided along with the call to
v4l2_subdev_init_finalize() in patch 01/19.

>  	.registered = adv748x_csi2_registered,
>  };
>  
> @@ -245,7 +269,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  		return 0;
>  
>  	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
> -			    MEDIA_ENT_F_VID_IF_BRIDGE, 0,
> +			    MEDIA_ENT_F_VID_IF_BRIDGE, V4L2_SUBDEV_FL_STREAMS,
>  			    is_txa(tx) ? "txa" : "txb");
>  
>  	/* Register internal ops for incremental subdev registration */
> -- 
> 2.44.0
>
Jacopo Mondi May 3, 2024, 7:59 a.m. UTC | #2
Hi Laurent

On Thu, May 02, 2024 at 08:40:51PM GMT, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Tue, Apr 30, 2024 at 12:39:39PM +0200, Jacopo Mondi wrote:
> > Initialize the CSI-2 subdevice with the V4L2_SUBDEV_FL_STREAMS flag
> > and initialize a simple routing table by implementing the .init_state()
> > operation.
> >
> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> > ---
> >  drivers/media/i2c/adv748x/adv748x-csi2.c | 28 ++++++++++++++++++++++--
> >  1 file changed, 26 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > index 60bf1dc0f58b..d929db7e8ef2 100644
> > --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> > +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > @@ -59,7 +59,30 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
> >
> >  /* -----------------------------------------------------------------------------
> >   * v4l2_subdev_internal_ops
> > - *
> > + */
> > +
> > +static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
> > +				   struct v4l2_subdev_state *state)
> > +{
> > +	struct v4l2_subdev_route routes[] = {
> > +		{
> > +			.sink_pad = ADV748X_CSI2_SINK,
> > +			.sink_stream = 0,
> > +			.source_pad = ADV748X_CSI2_SOURCE,
> > +			.source_stream = 0,
> > +			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
> > +		},
> > +	};
> > +
> > +	struct v4l2_subdev_krouting routing = {
> > +		.num_routes = ARRAY_SIZE(routes),
> > +		.routes = routes,
> > +	};
> > +
> > +	return v4l2_subdev_set_routing(sd, state, &routing);
>
> You need to initialize formats too.
>

The adv748x driver handles formats very poorly, doesn't implement
enum_mbus_codes and does not allow userspace to change the format
(while at the same time it doesn't check that the format is the
expected one in set_format()).

This is from a freshly booted renesas-drivers/main

- entity 30: adv748x 4-0070 txa (2 pads, 3 links, 0 routes)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev5
        pad0: Sink
                [stream:0 fmt:unknown/0x0]
                <- "adv748x 4-0070 afe":8 []
                <- "adv748x 4-0070 hdmi":1 [ENABLED]
        pad1: Source
                [stream:0 fmt:unknown/0x0]
                -> "rcar_csi2 feaa0000.csi2":0 [ENABLED,IMMUTABLE]

It would probably be better to handle the formats properly and the
introduce streams or use the introduction of streams to also fix the
format handling ?

> > +}
> > +
> > +/*
> >   * We use the internal registered operation to be able to ensure that our
> >   * incremental subdevices (not connected in the forward path) can be registered
> >   * against the resulting video path and media device.
> > @@ -109,6 +132,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
> >  }
> >
> >  static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
> > +	.init_state = adv748x_csi2_init_state,
>
> The .init_state() operation needs to be provided along with the call to
> v4l2_subdev_init_finalize() in patch 01/19.
>

I'll squash, however even if it might be a requirement for having a
fully working implementation, not having init_state() will not lead to
any crash and maybe smaller incremental patches are easier to handle.

	if (sd->internal_ops && sd->internal_ops->init_state) {
		/*
		 * There can be no race at this point, but we lock the state
		 * anyway to satisfy lockdep checks.
		 */
		v4l2_subdev_lock_state(state);
		ret = sd->internal_ops->init_state(sd, state);
		v4l2_subdev_unlock_state(state);


> >  	.registered = adv748x_csi2_registered,
> >  };
> >
> > @@ -245,7 +269,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
> >  		return 0;
> >
> >  	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
> > -			    MEDIA_ENT_F_VID_IF_BRIDGE, 0,
> > +			    MEDIA_ENT_F_VID_IF_BRIDGE, V4L2_SUBDEV_FL_STREAMS,
> >  			    is_txa(tx) ? "txa" : "txb");
> >
> >  	/* Register internal ops for incremental subdev registration */
> > --
> > 2.44.0
> >
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart May 3, 2024, 8:31 a.m. UTC | #3
Hi Jacopo,

On Fri, May 03, 2024 at 09:59:55AM +0200, Jacopo Mondi wrote:
> On Thu, May 02, 2024 at 08:40:51PM GMT, Laurent Pinchart wrote:
> > On Tue, Apr 30, 2024 at 12:39:39PM +0200, Jacopo Mondi wrote:
> > > Initialize the CSI-2 subdevice with the V4L2_SUBDEV_FL_STREAMS flag
> > > and initialize a simple routing table by implementing the .init_state()
> > > operation.
> > >
> > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> > > ---
> > >  drivers/media/i2c/adv748x/adv748x-csi2.c | 28 ++++++++++++++++++++++--
> > >  1 file changed, 26 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > index 60bf1dc0f58b..d929db7e8ef2 100644
> > > --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > @@ -59,7 +59,30 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
> > >
> > >  /* -----------------------------------------------------------------------------
> > >   * v4l2_subdev_internal_ops
> > > - *
> > > + */
> > > +
> > > +static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
> > > +				   struct v4l2_subdev_state *state)
> > > +{
> > > +	struct v4l2_subdev_route routes[] = {
> > > +		{
> > > +			.sink_pad = ADV748X_CSI2_SINK,
> > > +			.sink_stream = 0,
> > > +			.source_pad = ADV748X_CSI2_SOURCE,
> > > +			.source_stream = 0,
> > > +			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
> > > +		},
> > > +	};
> > > +
> > > +	struct v4l2_subdev_krouting routing = {
> > > +		.num_routes = ARRAY_SIZE(routes),
> > > +		.routes = routes,
> > > +	};
> > > +
> > > +	return v4l2_subdev_set_routing(sd, state, &routing);
> >
> > You need to initialize formats too.
> >
> 
> The adv748x driver handles formats very poorly, doesn't implement
> enum_mbus_codes and does not allow userspace to change the format
> (while at the same time it doesn't check that the format is the
> expected one in set_format()).
> 
> This is from a freshly booted renesas-drivers/main
> 
> - entity 30: adv748x 4-0070 txa (2 pads, 3 links, 0 routes)
>              type V4L2 subdev subtype Unknown flags 0
>              device node name /dev/v4l-subdev5
>         pad0: Sink
>                 [stream:0 fmt:unknown/0x0]
>                 <- "adv748x 4-0070 afe":8 []
>                 <- "adv748x 4-0070 hdmi":1 [ENABLED]
>         pad1: Source
>                 [stream:0 fmt:unknown/0x0]
>                 -> "rcar_csi2 feaa0000.csi2":0 [ENABLED,IMMUTABLE]
> 
> It would probably be better to handle the formats properly and the
> introduce streams or use the introduction of streams to also fix the
> format handling ?

As Niklas pointed out in the review of some patches, fixing issues
first, and moving to the active subdev state, would be better done
before adding streams in my opinion. At least if those fixes are not too
difficult without streams.

For this specific patch, the addition of the .init_state() operation
should be squashed with 01/19, without routing, and routing should be
added on top.

> > > +}
> > > +
> > > +/*
> > >   * We use the internal registered operation to be able to ensure that our
> > >   * incremental subdevices (not connected in the forward path) can be registered
> > >   * against the resulting video path and media device.
> > > @@ -109,6 +132,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
> > >  }
> > >
> > >  static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
> > > +	.init_state = adv748x_csi2_init_state,
> >
> > The .init_state() operation needs to be provided along with the call to
> > v4l2_subdev_init_finalize() in patch 01/19.
> 
> I'll squash, however even if it might be a requirement for having a
> fully working implementation, not having init_state() will not lead to
> any crash and maybe smaller incremental patches are easier to handle.
> 
> 	if (sd->internal_ops && sd->internal_ops->init_state) {
> 		/*
> 		 * There can be no race at this point, but we lock the state
> 		 * anyway to satisfy lockdep checks.
> 		 */
> 		v4l2_subdev_lock_state(state);
> 		ret = sd->internal_ops->init_state(sd, state);
> 		v4l2_subdev_unlock_state(state);

I think it's a mistake in the core to not require .init_state() for
subdevs using the active state. Tomi, what do you think ?

> > >  	.registered = adv748x_csi2_registered,
> > >  };
> > >
> > > @@ -245,7 +269,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
> > >  		return 0;
> > >
> > >  	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
> > > -			    MEDIA_ENT_F_VID_IF_BRIDGE, 0,
> > > +			    MEDIA_ENT_F_VID_IF_BRIDGE, V4L2_SUBDEV_FL_STREAMS,
> > >  			    is_txa(tx) ? "txa" : "txb");
> > >
> > >  	/* Register internal ops for incremental subdev registration */
Tomi Valkeinen May 3, 2024, 8:46 a.m. UTC | #4
On 03/05/2024 11:31, Laurent Pinchart wrote:

>>>> +}
>>>> +
>>>> +/*
>>>>    * We use the internal registered operation to be able to ensure that our
>>>>    * incremental subdevices (not connected in the forward path) can be registered
>>>>    * against the resulting video path and media device.
>>>> @@ -109,6 +132,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
>>>>   }
>>>>
>>>>   static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
>>>> +	.init_state = adv748x_csi2_init_state,
>>>
>>> The .init_state() operation needs to be provided along with the call to
>>> v4l2_subdev_init_finalize() in patch 01/19.
>>
>> I'll squash, however even if it might be a requirement for having a
>> fully working implementation, not having init_state() will not lead to
>> any crash and maybe smaller incremental patches are easier to handle.
>>
>> 	if (sd->internal_ops && sd->internal_ops->init_state) {
>> 		/*
>> 		 * There can be no race at this point, but we lock the state
>> 		 * anyway to satisfy lockdep checks.
>> 		 */
>> 		v4l2_subdev_lock_state(state);
>> 		ret = sd->internal_ops->init_state(sd, state);
>> 		v4l2_subdev_unlock_state(state);
> 
> I think it's a mistake in the core to not require .init_state() for
> subdevs using the active state. Tomi, what do you think ?

If I'm not mistaken, the v4l2 rules say that a subdev configuration 
should always be a valid one (for that specific device). To fulfill 
that, you need .init_state().

So yes, I agree. This is probably one more thing that can be added to 
the "[PATCH v6 03/11] media: subdev: Add checks for subdev features".

  Tomi
diff mbox series

Patch

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 60bf1dc0f58b..d929db7e8ef2 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -59,7 +59,30 @@  static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
 
 /* -----------------------------------------------------------------------------
  * v4l2_subdev_internal_ops
- *
+ */
+
+static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_state *state)
+{
+	struct v4l2_subdev_route routes[] = {
+		{
+			.sink_pad = ADV748X_CSI2_SINK,
+			.sink_stream = 0,
+			.source_pad = ADV748X_CSI2_SOURCE,
+			.source_stream = 0,
+			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+		},
+	};
+
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = ARRAY_SIZE(routes),
+		.routes = routes,
+	};
+
+	return v4l2_subdev_set_routing(sd, state, &routing);
+}
+
+/*
  * We use the internal registered operation to be able to ensure that our
  * incremental subdevices (not connected in the forward path) can be registered
  * against the resulting video path and media device.
@@ -109,6 +132,7 @@  static int adv748x_csi2_registered(struct v4l2_subdev *sd)
 }
 
 static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
+	.init_state = adv748x_csi2_init_state,
 	.registered = adv748x_csi2_registered,
 };
 
@@ -245,7 +269,7 @@  int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
 		return 0;
 
 	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
-			    MEDIA_ENT_F_VID_IF_BRIDGE, 0,
+			    MEDIA_ENT_F_VID_IF_BRIDGE, V4L2_SUBDEV_FL_STREAMS,
 			    is_txa(tx) ? "txa" : "txb");
 
 	/* Register internal ops for incremental subdev registration */