* [PATCH v2 01/10] media: adv748x: Add flags to adv748x_subdev_init()
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 02/10] media: adv748x: Add support for v4l2_subdev_state Jacopo Mondi
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Add a flags parameter to the adv748x_subdev_init() function that
allows to pass additional flags to the v4l2_subdevice.
This will be used to identify the CSI-2 subdevices as multiplexed.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/i2c/adv748x/adv748x-afe.c | 2 +-
drivers/media/i2c/adv748x/adv748x-core.c | 4 ++--
drivers/media/i2c/adv748x/adv748x-csi2.c | 2 +-
drivers/media/i2c/adv748x/adv748x-hdmi.c | 2 +-
drivers/media/i2c/adv748x/adv748x.h | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 02eabe10ab97..0d05e8a8887f 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -510,7 +510,7 @@ int adv748x_afe_init(struct adv748x_afe *afe)
afe->curr_norm = V4L2_STD_NTSC_M;
adv748x_subdev_init(&afe->sd, state, &adv748x_afe_ops,
- MEDIA_ENT_F_ATV_DECODER, "afe");
+ MEDIA_ENT_F_ATV_DECODER, 0, "afe");
/* Identify the first connector found as a default input if set */
for (i = ADV748X_PORT_AIN0; i <= ADV748X_PORT_AIN7; i++) {
diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
index 4e54148147b9..0961b1468465 100644
--- a/drivers/media/i2c/adv748x/adv748x-core.c
+++ b/drivers/media/i2c/adv748x/adv748x-core.c
@@ -583,10 +583,10 @@ static int __maybe_unused adv748x_resume_early(struct device *dev)
void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
const struct v4l2_subdev_ops *ops, u32 function,
- const char *ident)
+ u32 flags, const char *ident)
{
v4l2_subdev_init(sd, ops);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | flags;
/* the owner is the same as the i2c_client's driver owner */
sd->owner = state->dev->driver->owner;
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index bd4f3fe0e309..8c2701e1da0e 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -297,7 +297,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,
+ MEDIA_ENT_F_VID_IF_BRIDGE, 0,
is_txa(tx) ? "txa" : "txb");
/* Ensure that matching is based upon the endpoint fwnodes */
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index 52fa7bd75660..535a21b3c350 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -732,7 +732,7 @@ int adv748x_hdmi_init(struct adv748x_hdmi *hdmi)
hdmi->aspect_ratio.denominator = 9;
adv748x_subdev_init(&hdmi->sd, state, &adv748x_ops_hdmi,
- MEDIA_ENT_F_IO_DTV, "hdmi");
+ MEDIA_ENT_F_IO_DTV, 0, "hdmi");
hdmi->pads[ADV748X_HDMI_SINK].flags = MEDIA_PAD_FL_SINK;
hdmi->pads[ADV748X_HDMI_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 31bac06d46b5..92c8caee6a42 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -426,7 +426,7 @@ static inline struct v4l2_subdev *adv748x_get_remote_sd(struct media_pad *pad)
void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
const struct v4l2_subdev_ops *ops, u32 function,
- const char *ident);
+ u32 flags, const char *ident);
int adv748x_register_subdevs(struct adv748x_state *state,
struct v4l2_device *v4l2_dev);
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 02/10] media: adv748x: Add support for v4l2_subdev_state
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 01/10] media: adv748x: Add flags to adv748x_subdev_init() Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 03/10] media: adv748x: Move format to subdev state Jacopo Mondi
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Create and initialize the v4l2_subdev_state for the adv748x CSI-2
subdevice in order to prepare to support routing of the video stream.
Create the subdevice state with v4l2_subdev_init_finalize() and
implement the init_cfg() operation to guarantee the state is initialized
correctly with the default routing set.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/i2c/adv748x/adv748x-csi2.c | 52 +++++++++++++++++++++++-
drivers/media/i2c/adv748x/adv748x.h | 3 ++
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 8c2701e1da0e..9e0957501d70 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -139,6 +139,45 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
* But we must support setting the pad formats for format propagation.
*/
+static int adv748x_csi2_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ /* One route for each virtual channel. Route 0 enabled by default. */
+ struct v4l2_subdev_route routes[ADV748X_CSI2_STREAMS] = {
+ {
+ .sink_pad = ADV748X_CSI2_SINK,
+ .sink_stream = 0,
+ .source_pad = ADV748X_CSI2_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ {
+ .sink_pad = ADV748X_CSI2_SINK,
+ .sink_stream = 0,
+ .source_pad = ADV748X_CSI2_SOURCE,
+ .source_stream = 1,
+ },
+ {
+ .sink_pad = ADV748X_CSI2_SINK,
+ .sink_stream = 0,
+ .source_pad = ADV748X_CSI2_SOURCE,
+ .source_stream = 2,
+ },
+ {
+ .sink_pad = ADV748X_CSI2_SINK,
+ .sink_stream = 0,
+ .source_pad = ADV748X_CSI2_SOURCE,
+ .source_stream = 3,
+ },
+ };
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ADV748X_CSI2_STREAMS,
+ .routes = routes,
+ };
+
+ return v4l2_subdev_set_routing(sd, state, &routing);
+}
+
static struct v4l2_mbus_framefmt *
adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
@@ -228,6 +267,7 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
}
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
+ .init_cfg = adv748x_csi2_init_cfg,
.get_fmt = adv748x_csi2_get_format,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
@@ -297,7 +337,8 @@ 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_MULTIPLEXED,
is_txa(tx) ? "txa" : "txb");
/* Ensure that matching is based upon the endpoint fwnodes */
@@ -314,10 +355,14 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
if (ret)
return ret;
- ret = adv748x_csi2_init_controls(tx);
+ ret = v4l2_subdev_init_finalize(&tx->sd);
if (ret)
goto err_free_media;
+ ret = adv748x_csi2_init_controls(tx);
+ if (ret)
+ goto err_free_state;
+
ret = v4l2_async_register_subdev(&tx->sd);
if (ret)
goto err_free_ctrl;
@@ -326,6 +371,8 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
err_free_ctrl:
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
+err_free_state:
+ v4l2_subdev_cleanup(&tx->sd);
err_free_media:
media_entity_cleanup(&tx->sd.entity);
@@ -338,6 +385,7 @@ void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
return;
v4l2_async_unregister_subdev(&tx->sd);
+ v4l2_subdev_cleanup(&tx->sd);
media_entity_cleanup(&tx->sd.entity);
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
}
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 92c8caee6a42..d651c8390e6f 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -73,6 +73,9 @@ enum adv748x_csi2_pads {
/* CSI2 transmitters can have 2 internal connections, HDMI/AFE */
#define ADV748X_CSI2_MAX_SUBDEVS 2
+/* CSI2 number of streams: 1 for each CSI-2 Virtual channel output. */
+#define ADV748X_CSI2_STREAMS 4
+
struct adv748x_csi2 {
struct adv748x_state *state;
struct v4l2_mbus_framefmt format;
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 03/10] media: adv748x: Move format to subdev state
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 01/10] media: adv748x: Add flags to adv748x_subdev_init() Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 02/10] media: adv748x: Add support for v4l2_subdev_state Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 04/10] media: adv748x: Implement .get_frame_desc() Jacopo Mondi
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Move format handling to the v4l2_subdev state and store it per
(pad, stream) combination.
Now that the image format is stored in the subdev state, it can be
accessed through v4l2_subdev_get_fmt() instead of open-coding it.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/i2c/adv748x/adv748x-csi2.c | 77 +++++-------------------
drivers/media/i2c/adv748x/adv748x.h | 1 -
2 files changed, 16 insertions(+), 62 deletions(-)
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 9e0957501d70..8326cfe6192a 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -178,78 +178,33 @@ static int adv748x_csi2_init_cfg(struct v4l2_subdev *sd,
return v4l2_subdev_set_routing(sd, state, &routing);
}
-static struct v4l2_mbus_framefmt *
-adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
-{
- struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
-
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, sd_state, pad);
-
- return &tx->format;
-}
-
-static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
- struct v4l2_mbus_framefmt *mbusformat;
-
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
- return -EINVAL;
-
- mutex_lock(&state->mutex);
-
- sdformat->format = *mbusformat;
-
- mutex_unlock(&state->mutex);
-
- return 0;
-}
-
static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
- struct v4l2_mbus_framefmt *mbusformat;
+ struct v4l2_mbus_framefmt *fmt;
int ret = 0;
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
+ /* Do not allow to set format on the multiplexed source pad. */
+ if (sdformat->pad == ADV748X_CSI2_SOURCE)
return -EINVAL;
- mutex_lock(&state->mutex);
-
- if (sdformat->pad == ADV748X_CSI2_SOURCE) {
- const struct v4l2_mbus_framefmt *sink_fmt;
-
- sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
- ADV748X_CSI2_SINK,
- sdformat->which);
-
- if (!sink_fmt) {
- ret = -EINVAL;
- goto unlock;
- }
+ fmt = v4l2_subdev_state_get_stream_format(sd_state, sdformat->pad,
+ sdformat->stream);
+ if (!fmt)
+ return -EINVAL;
- sdformat->format = *sink_fmt;
- }
+ *fmt = sdformat->format;
- *mbusformat = sdformat->format;
+ /* Propagate format to the other end of the route. */
+ fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
+ sdformat->stream);
+ if (!fmt)
+ return ret;
-unlock:
- mutex_unlock(&state->mutex);
+ *fmt = sdformat->format;
- return ret;
+ return 0;
}
static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
@@ -268,7 +223,7 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.init_cfg = adv748x_csi2_init_cfg,
- .get_fmt = adv748x_csi2_get_format,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
};
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index d651c8390e6f..98a3b3e0642a 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -78,7 +78,6 @@ enum adv748x_csi2_pads {
struct adv748x_csi2 {
struct adv748x_state *state;
- struct v4l2_mbus_framefmt format;
unsigned int page;
unsigned int port;
unsigned int num_lanes;
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 04/10] media: adv748x: Implement .get_frame_desc()
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (2 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 03/10] media: adv748x: Move format to subdev state Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 05/10] media: adv748x: Implement set_routing Jacopo Mondi
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Implement the get_frame_desc subdev pad operation.
Implement the get_frame_desc pad operation to allow retrieving the
stream configuration of the adv748x csi2 subdevice.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/i2c/adv748x/adv748x-csi2.c | 94 ++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 8326cfe6192a..91cd70739e9d 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -14,6 +14,50 @@
#include "adv748x.h"
+/* Describes a format bit depth and CSI-2 defined Data Type. */
+struct adv748x_csi2_format_info {
+ u8 dt;
+ u8 bpp;
+};
+
+static int adv748x_csi2_get_format_info(struct adv748x_csi2 *tx,
+ u32 mbus_code,
+ struct adv748x_csi2_format_info *fmt)
+{
+ switch (mbus_code) {
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ fmt->dt = 0x1e;
+ fmt->bpp = 16;
+ break;
+ case MEDIA_BUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ fmt->dt = 0x1f;
+ fmt->bpp = 20;
+ break;
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ fmt->dt = 0x22;
+ fmt->bpp = 16;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ fmt->dt = 0x23;
+ fmt->bpp = 18;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ fmt->dt = 0x24;
+ fmt->bpp = 24;
+ break;
+ default:
+ dev_err(tx->state->dev,
+ "Unsupported media bus code: %u\n", mbus_code);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
{
return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
@@ -221,11 +265,61 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
return 0;
}
+static int adv748x_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+ struct adv748x_csi2_format_info info = {};
+ struct v4l2_mbus_frame_desc_entry *entry;
+ struct v4l2_subdev_route *route;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+
+ if (pad != ADV748X_CSI2_SOURCE)
+ return -EINVAL;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ /* A single route is available. */
+ route = &state->routing.routes[0];
+ fmt = v4l2_subdev_state_get_stream_format(state, pad,
+ route->source_stream);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = adv748x_csi2_get_format_info(tx, fmt->code, &info);
+ if (ret)
+ goto out;
+
+ memset(fd, 0, sizeof(*fd));
+
+ /* A single stream is available. */
+ fd->num_entries = 1;
+ fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+ entry = &fd->entry[0];
+ entry->stream = 0;
+ entry->flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
+ entry->length = fmt->width * fmt->height * info.bpp / 8;
+ entry->pixelcode = fmt->code;
+ entry->bus.csi2.vc = route->source_stream;
+ entry->bus.csi2.dt = info.dt;
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.init_cfg = adv748x_csi2_init_cfg,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
+ .get_frame_desc = adv748x_csi2_get_frame_desc,
};
/* -----------------------------------------------------------------------------
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 05/10] media: adv748x: Implement set_routing
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (3 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 04/10] media: adv748x: Implement .get_frame_desc() Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 06/10] media: rcar-csi2: Add support for multiplexed streams Jacopo Mondi
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Add the set_routing() subdev operation to allow userspace to configure
the CSI-2 virtual channel.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/i2c/adv748x/adv748x-csi2.c | 66 ++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 91cd70739e9d..af1c2469900c 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -314,12 +314,78 @@ static int adv748x_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
return ret;
}
+static int adv748x_csi2_routing_validate(struct adv748x_csi2 *tx,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct v4l2_subdev_route *route;
+
+ if (routing->num_routes != 1) {
+ dev_err(tx->state->dev, "Unsupported number of routes %u",
+ routing->num_routes);
+ return -EINVAL;
+ }
+
+ route = &routing->routes[0];
+
+ if (route->sink_pad != ADV748X_CSI2_SINK ||
+ route->source_pad != ADV748X_CSI2_SOURCE) {
+ dev_err(tx->state->dev,
+ "Routes should go from the sink to the source pads.\n");
+ return -EINVAL;
+ }
+
+ if (route->source_stream > 4) {
+ dev_err(tx->state->dev, "Unsupported source stream %u\n",
+ route->source_stream);
+ return -EINVAL;
+ }
+
+ if (route->sink_stream != 0) {
+ dev_err(tx->state->dev, "Unsupported sink stream %u\n",
+ route->sink_stream);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int adv748x_csi2_set_vc_with_routing(struct adv748x_csi2 *tx,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct v4l2_subdev_route *route = &routing->routes[0];
+
+ return adv748x_csi2_set_virtual_channel(tx, route->source_stream);
+}
+
+static int adv748x_csi2_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+ int ret;
+
+ ret = adv748x_csi2_routing_validate(tx, routing);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_set_routing(sd, state, routing);
+ if (ret)
+ return ret;
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ return adv748x_csi2_set_vc_with_routing(tx, routing);
+}
+
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.init_cfg = adv748x_csi2_init_cfg,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
.get_frame_desc = adv748x_csi2_get_frame_desc,
+ .set_routing = adv748x_csi2_set_routing,
};
/* -----------------------------------------------------------------------------
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 06/10] media: rcar-csi2: Add support for multiplexed streams
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (4 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 05/10] media: adv748x: Implement set_routing Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 07/10] media: rcar-csi2: Move format to subdev state Jacopo Mondi
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Create and initialize the v4l2_subdev_state for the R-Car CSI-2 receiver
in order to prepare to support multiplexed transmitters.
Create the subdevice state with v4l2_subdev_init_finalize() and
implement the init_cfg() operation to guarantee the state is initialized
correctly with a set of default routes.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 66 ++++++++++++++++++++-
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index d48356d99590..f4786081e3a0 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -911,11 +911,65 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
return 0;
}
+static int rcsi2_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ /*
+ * Routing is fixed for this device: which stream goes to the next
+ * processing block (VIN) is controlled by link enablement between the
+ * CSI-2 and the VIN itself.
+ *
+ * In example, to route VC 3 to VIN1, as an example: "csi2:3 -> vin1:0"
+ *
+ * The routing table is then fixed as streams transmitted on VC x will
+ * be directed to csi:0/x and will be transmitted to VINs on media link
+ * csi2:x->vin:0.
+ */
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = RCAR_CSI2_SINK,
+ .sink_stream = 0,
+ .source_pad = RCAR_CSI2_SOURCE_VC0,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ {
+ .sink_pad = RCAR_CSI2_SINK,
+ .sink_stream = 1,
+ .source_pad = RCAR_CSI2_SOURCE_VC1,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ {
+ .sink_pad = RCAR_CSI2_SINK,
+ .sink_stream = 2,
+ .source_pad = RCAR_CSI2_SOURCE_VC2,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ {
+ .sink_pad = RCAR_CSI2_SINK,
+ .sink_stream = 3,
+ .source_pad = RCAR_CSI2_SOURCE_VC3,
+ .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);
+}
+
static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
.s_stream = rcsi2_s_stream,
};
static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
+ .init_cfg = rcsi2_init_cfg,
.set_fmt = rcsi2_set_pad_format,
.get_fmt = rcsi2_get_pad_format,
};
@@ -1537,7 +1591,8 @@ static int rcsi2_probe(struct platform_device *pdev)
v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s",
KBUILD_MODNAME, dev_name(&pdev->dev));
- priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_MULTIPLEXED;
priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
priv->subdev.entity.ops = &rcar_csi2_entity_ops;
@@ -1558,14 +1613,20 @@ static int rcsi2_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
+ ret = v4l2_subdev_init_finalize(&priv->subdev);
+ if (ret)
+ goto error_async;
+
ret = v4l2_async_register_subdev(&priv->subdev);
if (ret < 0)
- goto error_async;
+ goto error_subdev;
dev_info(priv->dev, "%d lanes found\n", priv->lanes);
return 0;
+error_subdev:
+ v4l2_subdev_cleanup(&priv->subdev);
error_async:
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
@@ -1582,6 +1643,7 @@ static int rcsi2_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_subdev_cleanup(&priv->subdev);
pm_runtime_disable(&pdev->dev);
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 07/10] media: rcar-csi2: Move format to subdev state
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (5 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 06/10] media: rcar-csi2: Add support for multiplexed streams Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 08/10] media: rcar-csi2: Config by using the remote frame_desc Jacopo Mondi
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Move format handling to the v4l2_subdev state and store it per
(pad, stream) combination.
Now that the image format is stored in the subdev state, it can be
accessed through v4l2_subdev_get_fmt() instead of open-coding it.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 48 +++++++++------------
1 file changed, 20 insertions(+), 28 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index f4786081e3a0..b06af1080b04 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -870,43 +870,35 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
}
static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- struct rcar_csi2 *priv = sd_to_csi2(sd);
- struct v4l2_mbus_framefmt *framefmt;
+ struct v4l2_mbus_framefmt *fmt;
- mutex_lock(&priv->lock);
+ /*
+ * Format is propagated from sink streams to source streams, so
+ * disallow setting format on the source pads.
+ */
+ if (format->pad > RCAR_CSI2_SINK)
+ return -EINVAL;
if (!rcsi2_code_to_fmt(format->format.code))
format->format.code = rcar_csi2_formats[0].code;
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- priv->mf = format->format;
- } else {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
- *framefmt = format->format;
- }
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct rcar_csi2 *priv = sd_to_csi2(sd);
+ fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
- mutex_lock(&priv->lock);
+ *fmt = format->format;
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- format->format = priv->mf;
- else
- format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ /* Propagate format to the other end of the route. */
+ fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
- mutex_unlock(&priv->lock);
+ *fmt = format->format;
return 0;
}
@@ -971,7 +963,7 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
.init_cfg = rcsi2_init_cfg,
.set_fmt = rcsi2_set_pad_format,
- .get_fmt = rcsi2_get_pad_format,
+ .get_fmt = v4l2_subdev_get_fmt,
};
static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 08/10] media: rcar-csi2: Config by using the remote frame_desc
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (6 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 07/10] media: rcar-csi2: Move format to subdev state Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 09/10] media: rcar-csi2: Implement set_routing Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 10/10] media: rcar-vin: Support state-aware transmitters Jacopo Mondi
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc,
Niklas Söderlund
Configure the CSI-2 receiver by inspecting the remote subdev frame_desc.
Configure the link clock rate, field handling and CSI-2 Virtual Channel
and DT filtering using the frame descriptor retrieved from the
transmitter.
This change also makes mandatory for any subdevice that operates with
the R-Car CSI-2 receiver to implement the .get_frame_desc() operation.
[based on a patch from]
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
[rework based on lates multistream support]
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 138 +++++++++++++++-----
1 file changed, 105 insertions(+), 33 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index b06af1080b04..39545e631e42 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -70,10 +70,7 @@ struct rcar_csi2;
#define FLD_REG 0x1c
#define FLD_FLD_NUM(n) (((n) & 0xff) << 16)
#define FLD_DET_SEL(n) (((n) & 0x3) << 4)
-#define FLD_FLD_EN4 BIT(3)
-#define FLD_FLD_EN3 BIT(2)
-#define FLD_FLD_EN2 BIT(1)
-#define FLD_FLD_EN BIT(0)
+#define FLD_FLD_EN(n) BIT((n) & 0xf)
/* Automatic Standby Control */
#define ASTBY_REG 0x20
@@ -471,6 +468,17 @@ static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
return NULL;
}
+static const struct rcar_csi2_format *rcsi2_datatype_to_fmt(unsigned int dt)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++)
+ if (rcar_csi2_formats[i].datatype == dt)
+ return &rcar_csi2_formats[i];
+
+ return NULL;
+}
+
enum rcar_csi2_pads {
RCAR_CSI2_SINK,
RCAR_CSI2_SOURCE_VC0,
@@ -506,7 +514,6 @@ struct rcar_csi2 {
int channel_vc[4];
struct mutex lock; /* Protects mf and stream_count. */
- struct v4l2_mbus_framefmt mf;
int stream_count;
unsigned short lanes;
@@ -555,6 +562,32 @@ static int rcsi2_exit_standby(struct rcar_csi2 *priv)
return 0;
}
+static int rcsi2_get_remote_frame_desc(struct rcar_csi2 *priv,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct media_pad *pad;
+ int ret;
+
+ if (!priv->remote)
+ return -ENODEV;
+
+ pad = media_entity_remote_pad(&priv->pads[RCAR_CSI2_SINK]);
+ if (!pad)
+ return -ENODEV;
+
+ ret = v4l2_subdev_call(priv->remote, pad, get_frame_desc,
+ pad->index, fd);
+ if (ret)
+ return ret;
+
+ if (fd->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ dev_err(priv->dev, "Frame desc do not describe CSI-2 link");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
unsigned int lanes)
{
@@ -605,11 +638,14 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
return 0;
}
-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
- unsigned int lanes)
+static int rcsi2_calc_mbps(struct rcar_csi2 *priv,
+ struct v4l2_mbus_frame_desc *fd, unsigned int lanes)
{
+ const struct v4l2_mbus_frame_desc_entry_csi2 *csi2_desc;
+ const struct rcar_csi2_format *format;
struct v4l2_subdev *source;
struct v4l2_ctrl *ctrl;
+ unsigned int i;
u64 mbps;
if (!priv->remote)
@@ -625,12 +661,30 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
return -EINVAL;
}
+ /* Verify that all remote streams send the same datatype. */
+ csi2_desc = NULL;
+ for (i = 0; i < fd->num_entries; i++) {
+ struct v4l2_mbus_frame_desc_entry_csi2 *stream_desc;
+
+ stream_desc = &fd->entry[i].bus.csi2;
+ if (!csi2_desc)
+ csi2_desc = stream_desc;
+
+ if (csi2_desc->dt != stream_desc->dt) {
+ dev_err(priv->dev,
+ "Remote streams with different DT: %u - %u\n",
+ csi2_desc->dt, stream_desc->dt);
+ return -EINVAL;
+ }
+ }
+ format = rcsi2_datatype_to_fmt(csi2_desc->dt);
+
/*
* Calculate the phypll in mbps.
* link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes)
* bps = link_freq * 2
*/
- mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
+ mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * format->bpp;
do_div(mbps, lanes * 1000000);
return mbps;
@@ -676,54 +730,65 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
static int rcsi2_start_receiver(struct rcar_csi2 *priv)
{
- const struct rcar_csi2_format *format;
+ const struct v4l2_subdev_stream_configs *configs;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_frame_desc fd;
unsigned int lanes;
unsigned int i;
int mbps, ret;
- dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
- priv->mf.width, priv->mf.height,
- priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
-
- /* Code is validated in set_fmt. */
- format = rcsi2_code_to_fmt(priv->mf.code);
- if (!format)
- return -EINVAL;
+ /* Get information about multiplexed link. */
+ ret = rcsi2_get_remote_frame_desc(priv, &fd);
+ if (ret)
+ return ret;
- /*
- * Enable all supported CSI-2 channels with virtual channel and
- * data type matching.
- *
- * NOTE: It's not possible to get individual datatype for each
- * source virtual channel. Once this is possible in V4L2
- * it should be used here.
- */
- for (i = 0; i < priv->info->num_channels; i++) {
+ for (i = 0; i < fd.num_entries; i++) {
+ struct v4l2_mbus_frame_desc_entry *entry = &fd.entry[i];
u32 vcdt_part;
if (priv->channel_vc[i] < 0)
continue;
- vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN |
- VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype);
+ vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) |
+ VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
+ VCDT_SEL_DT(entry->bus.csi2.dt);
/* Store in correct reg and offset. */
if (i < 2)
vcdt |= vcdt_part << ((i % 2) * 16);
else
vcdt2 |= vcdt_part << ((i % 2) * 16);
+
+ dev_dbg(priv->dev, "channel %u: VC = %d, datatype = 0x%x\n",
+ i, priv->channel_vc[i], entry->bus.csi2.dt);
}
- if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
- fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
- | FLD_FLD_EN;
+ /*
+ * Configure field handling inspecting the formats of the
+ * sink pad streams.
+ */
+ state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
+ configs = &state->stream_configs;
+ for (i = 0; i < configs->num_configs; ++i) {
+ const struct v4l2_subdev_stream_config *config = configs->configs;
- if (priv->mf.height == 240)
+ if (config->pad != RCAR_CSI2_SINK)
+ continue;
+
+ if (config->fmt.field != V4L2_FIELD_ALTERNATE)
+ continue;
+
+ fld |= FLD_DET_SEL(1);
+ fld |= FLD_FLD_EN(config->stream);
+
+ /* PAL vs NTSC. */
+ if (config->fmt.height == 240)
fld |= FLD_FLD_NUM(0);
else
fld |= FLD_FLD_NUM(1);
}
+ v4l2_subdev_unlock_state(state);
/*
* Get the number of active data lanes inspecting the remote mbus
@@ -736,7 +801,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
phycnt = PHYCNT_ENABLECLK;
phycnt |= (1 << lanes) - 1;
- mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
+ mbps = rcsi2_calc_mbps(priv, &fd, lanes);
if (mbps < 0)
return mbps;
@@ -1019,6 +1084,13 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
struct rcar_csi2 *priv = notifier_to_csi2(notifier);
int pad;
+ if (!v4l2_subdev_has_op(subdev, pad, get_frame_desc)) {
+ dev_err(priv->dev,
+ "Subdev %s bound failed: missing get_frame_desc()\n",
+ subdev->name);
+ return -EINVAL;
+ }
+
pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
MEDIA_PAD_FL_SOURCE);
if (pad < 0) {
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 09/10] media: rcar-csi2: Implement set_routing
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (7 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 08/10] media: rcar-csi2: Config by using the remote frame_desc Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
2022-03-16 15:46 ` [PATCH v2 10/10] media: rcar-vin: Support state-aware transmitters Jacopo Mondi
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
Add the set_routing() subdev operation to allow userspace to activate
routes on the R-Car CSI-2 receiver.
Routing for this device is fixed. Validate that the provided route
respects it.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 37 +++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 39545e631e42..0f1f667a7aee 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -968,6 +968,42 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
return 0;
}
+static int rcsi2_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ unsigned int i;
+ int ret = 0;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+ if (ret)
+ return ret;
+
+ /*
+ * Routing is fixed for this device.
+ *
+ * Only routes in the form of CSI2:0/x->CSI2:x+1/0 are allowed.
+ *
+ * We have anyway to implement set_routing to mark the route as active.
+ */
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+ unsigned int vc = route->sink_stream;
+ unsigned int pad = vc + 1;
+
+ if (route->sink_pad != 0)
+ return -EINVAL;
+
+ if (route->source_pad != pad ||
+ route->source_stream != 0)
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_set_routing(sd, state, routing);
+}
+
static int rcsi2_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
@@ -1029,6 +1065,7 @@ static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
.init_cfg = rcsi2_init_cfg,
.set_fmt = rcsi2_set_pad_format,
.get_fmt = v4l2_subdev_get_fmt,
+ .set_routing = rcsi2_set_routing,
};
static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 10/10] media: rcar-vin: Support state-aware transmitters
2022-03-16 15:46 [PATCH v2 00/10] media: Multiplexed streams for R-Car CSI-2 and ADV748x Jacopo Mondi
` (8 preceding siblings ...)
2022-03-16 15:46 ` [PATCH v2 09/10] media: rcar-csi2: Implement set_routing Jacopo Mondi
@ 2022-03-16 15:46 ` Jacopo Mondi
9 siblings, 0 replies; 11+ messages in thread
From: Jacopo Mondi @ 2022-03-16 15:46 UTC (permalink / raw)
To: niklas.soderlund, laurent.pinchart
Cc: Jacopo Mondi, tomi.valkeinen, linux-media, linux-renesas-soc
The VIN driver calls get_fmt() on the remove subdev to validate its
format. Now that the R-Car CSI-2 driver are moved to be state-aware
subdevices they need their active state when calling operations.
Use the newly introduced v4l2_subdev_call_state_active() from
v4l2-subdev-legacy.h.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
drivers/media/platform/rcar-vin/rcar-dma.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index e08d4ca28725..68c192ea7cb5 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <media/v4l2-subdev-legacy.h>
#include <media/videobuf2-dma-contig.h>
#include "rcar-vin.h"
@@ -1140,7 +1141,7 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
};
fmt.pad = pad->index;
- if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt))
+ if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt))
return -EPIPE;
switch (fmt.format.code) {
--
2.35.1
^ permalink raw reply related [flat|nested] 11+ messages in thread