Commit 113ac3e2 authored by Hans Verkuil's avatar Hans Verkuil
Browse files

Merge tag 'tags/next-media-renesas-20240619' of...

Merge tag 'tags/next-media-renesas-20240619' of git://git.kernel.org/pub/scm/linux/kernel/git/pinchartl/linux.git



- Conversion of max9286 and adv748x to V4L2 subdev active state
- Cleanups and fixes for the Renesas R-Car VSP and VIN drivers
- Miscellaneous cleanups to V4L2 core

Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parents bf9817d2 1b9fd2f0
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -199,7 +199,6 @@ module_param(debug, int, 0644);
})

static void __vb2_queue_cancel(struct vb2_queue *q);
static void __enqueue_in_driver(struct vb2_buffer *vb);

static const char *vb2_state_name(enum vb2_buffer_state s)
{
+2 −2
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe,
{
	memset(fmt, 0, sizeof(*fmt));

	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
	fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
	fmt->field = V4L2_FIELD_ALTERNATE;

@@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
	if (code->index != 0)
		return -EINVAL;

	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
	code->code = MEDIA_BUS_FMT_UYVY8_1X16;

	return 0;
}
+95 −50
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
 */

#include <linux/module.h>
#include <linux/mutex.h>

#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -14,6 +13,15 @@

#include "adv748x.h"

static const unsigned int adv748x_csi2_txa_fmts[] = {
	MEDIA_BUS_FMT_UYVY8_1X16,
	MEDIA_BUS_FMT_RGB888_1X24,
};

static const unsigned int adv748x_csi2_txb_fmts[] = {
	MEDIA_BUS_FMT_UYVY8_1X16,
};

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);
@@ -59,7 +67,33 @@ 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)
{
	static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = {
		.width		= 1280,
		.height		= 720,
		.code		= MEDIA_BUS_FMT_UYVY8_1X16,
		.colorspace	= V4L2_COLORSPACE_SRGB,
		.field		= V4L2_FIELD_NONE,
		.ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT,
		.quantization	= V4L2_QUANTIZATION_DEFAULT,
		.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
	};
	struct v4l2_mbus_framefmt *fmt;

	fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK);
	*fmt = adv748x_csi2_default_fmt;

	fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE);
	*fmt = adv748x_csi2_default_fmt;

	return 0;
}

/*
 * 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 +143,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,
};

@@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
 * But we must support setting the pad formats for format propagation.
 */

static struct v4l2_mbus_framefmt *
adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd,
				       struct v4l2_subdev_state *sd_state,
			    unsigned int pad, u32 which)
				       struct v4l2_subdev_mbus_code_enum *code)
{
	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
	const unsigned int *codes = is_txa(tx) ?
				    adv748x_csi2_txa_fmts :
				    adv748x_csi2_txb_fmts;
	size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
				     : ARRAY_SIZE(adv748x_csi2_txb_fmts);

	if (which == V4L2_SUBDEV_FORMAT_TRY)
		return v4l2_subdev_state_get_format(sd_state, pad);
	/*
	 * The format available on the source pad is the one applied on the sink
	 * pad.
	 */
	if (code->pad == ADV748X_CSI2_SOURCE) {
		struct v4l2_mbus_framefmt *fmt;

	return &tx->format;
}
		if (code->index)
			return -EINVAL;

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;
		fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK);
		code->code = fmt->code;

		return 0;
	}

	mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
						 sdformat->which);
	if (!mbusformat)
	if (code->index >= num_fmts)
		return -EINVAL;

	mutex_lock(&state->mutex);
	code->code = codes[code->index];

	sdformat->format = *mbusformat;
	return 0;
}

	mutex_unlock(&state->mutex);
static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code)
{
	const unsigned int *codes = is_txa(tx) ?
				    adv748x_csi2_txa_fmts :
				    adv748x_csi2_txb_fmts;
	size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
				     : ARRAY_SIZE(adv748x_csi2_txb_fmts);

	for (unsigned int i = 0; i < num_fmts; i++) {
		if (codes[i] == code)
			return true;
	}

	return 0;
	return false;
}

static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
@@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
				   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;
	int ret = 0;

	mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
						 sdformat->which);
	if (!mbusformat)
		return -EINVAL;

	mutex_lock(&state->mutex);

	if (sdformat->pad == ADV748X_CSI2_SOURCE) {
		const struct v4l2_mbus_framefmt *sink_fmt;
	if (sdformat->pad == ADV748X_CSI2_SOURCE)
		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);

		sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
						       ADV748X_CSI2_SINK,
						       sdformat->which);

		if (!sink_fmt) {
			ret = -EINVAL;
			goto unlock;
		}

		sdformat->format = *sink_fmt;
	}
	/*
	 * Make sure the format is supported, if not default it to
	 * UYVY8 as it's supported by both TXes.
	 */
	if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code))
		sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16;

	mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
	*mbusformat = sdformat->format;

unlock:
	mutex_unlock(&state->mutex);
	/* Propagate format to the source pad. */
	mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE);
	*mbusformat = sdformat->format;

	return ret;
	return 0;
}

static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
@@ -228,7 +267,8 @@ 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 = {
	.get_fmt = adv748x_csi2_get_format,
	.enum_mbus_code = adv748x_csi2_enum_mbus_code,
	.get_fmt = v4l2_subdev_get_fmt,
	.set_fmt = adv748x_csi2_set_format,
	.get_mbus_config = adv748x_csi2_get_mbus_config,
};
@@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
	if (ret)
		goto err_cleanup_subdev;

	tx->sd.state_lock = &state->mutex;
	ret = v4l2_subdev_init_finalize(&tx->sd);
	if (ret)
		goto err_free_ctrl;

	ret = v4l2_async_register_subdev(&tx->sd);
	if (ret)
		goto err_free_ctrl;
+0 −1
Original line number Diff line number Diff line
@@ -75,7 +75,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;
+68 −113
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -198,12 +197,6 @@ struct max9286_priv {
	struct v4l2_ctrl *pixelrate_ctrl;
	unsigned int pixelrate;

	struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
	struct v4l2_fract interval;

	/* Protects controls and fmt structures */
	struct mutex mutex;

	unsigned int nsources;
	unsigned int source_mask;
	unsigned int route_mask;
@@ -576,11 +569,14 @@ static void max9286_set_video_format(struct max9286_priv *priv,
		      MAX9286_INVVS | MAX9286_HVSRC_D14);
}

static void max9286_set_fsync_period(struct max9286_priv *priv)
static void max9286_set_fsync_period(struct max9286_priv *priv,
				     struct v4l2_subdev_state *state)
{
	const struct v4l2_fract *interval;
	u32 fsync;

	if (!priv->interval.numerator || !priv->interval.denominator) {
	interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
	if (!interval->numerator || !interval->denominator) {
		/*
		 * Special case, a null interval enables automatic FRAMESYNC
		 * mode. FRAMESYNC is taken from the slowest link.
@@ -596,8 +592,8 @@ static void max9286_set_fsync_period(struct max9286_priv *priv)
	 * The FRAMESYNC generator is configured with a period expressed as a
	 * number of PCLK periods.
	 */
	fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
			priv->interval.denominator);
	fsync = div_u64((u64)priv->pixelrate * interval->numerator,
			interval->denominator);

	dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
		priv->pixelrate);
@@ -788,22 +784,25 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv)
static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct max9286_priv *priv = sd_to_max9286(sd);
	struct v4l2_subdev_state *state;
	struct max9286_source *source;
	unsigned int i;
	bool sync = false;
	int ret;
	int ret = 0;

	state = v4l2_subdev_lock_and_get_active_state(sd);

	if (enable) {
		const struct v4l2_mbus_framefmt *format;

		/*
		 * Get the format from the first used sink pad, as all sink
		 * formats must be identical.
		 * Get the format from the source pad, as all formats must be
		 * identical.
		 */
		format = &priv->fmt[__ffs(priv->bound_sources)];
		format = v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD);

		max9286_set_video_format(priv, format);
		max9286_set_fsync_period(priv);
		max9286_set_fsync_period(priv, state);

		/*
		 * The frame sync between cameras is transmitted across the
@@ -816,12 +815,12 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
		for_each_source(priv, source) {
			ret = v4l2_subdev_call(source->sd, video, s_stream, 1);
			if (ret)
				return ret;
				goto unlock;
		}

		ret = max9286_check_video_links(priv);
		if (ret)
			return ret;
			goto unlock;

		/*
		 * Wait until frame synchronization is locked.
@@ -842,7 +841,8 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
		if (!sync) {
			dev_err(&priv->client->dev,
				"Failed to get frame synchronization\n");
			return -EXDEV; /* Invalid cross-device link */
			ret = -EXDEV; /* Invalid cross-device link */
			goto unlock;
		}

		/*
@@ -865,26 +865,21 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
		max9286_i2c_mux_close(priv);
	}

	return 0;
unlock:
	v4l2_subdev_unlock_state(state);

	return ret;
}

static int max9286_get_frame_interval(struct v4l2_subdev *sd,
				      struct v4l2_subdev_state *sd_state,
				      struct v4l2_subdev_frame_interval *interval)
{
	struct max9286_priv *priv = sd_to_max9286(sd);

	/*
	 * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
	 * subdev active state API.
	 */
	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
		return -EINVAL;

	if (interval->pad != MAX9286_SRC_PAD)
		return -EINVAL;

	interval->interval = priv->interval;
	interval->interval = *v4l2_subdev_state_get_interval(sd_state,
							     interval->pad);

	return 0;
}
@@ -893,19 +888,11 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd,
				      struct v4l2_subdev_state *sd_state,
				      struct v4l2_subdev_frame_interval *interval)
{
	struct max9286_priv *priv = sd_to_max9286(sd);

	/*
	 * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
	 * subdev active state API.
	 */
	if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
		return -EINVAL;

	if (interval->pad != MAX9286_SRC_PAD)
		return -EINVAL;

	priv->interval = interval->interval;
	*v4l2_subdev_state_get_interval(sd_state,
					interval->pad) = interval->interval;

	return 0;
}
@@ -914,39 +901,28 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
				  struct v4l2_subdev_state *sd_state,
				  struct v4l2_subdev_mbus_code_enum *code)
{
	if (code->pad || code->index > 0)
	if (code->pad || code->index >= ARRAY_SIZE(max9286_formats))
		return -EINVAL;

	code->code = MEDIA_BUS_FMT_UYVY8_1X16;
	code->code = max9286_formats[code->index].code;

	return 0;
}

static struct v4l2_mbus_framefmt *
max9286_get_pad_format(struct max9286_priv *priv,
		       struct v4l2_subdev_state *sd_state,
		       unsigned int pad, u32 which)
{
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
		return v4l2_subdev_state_get_format(sd_state, pad);
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return &priv->fmt[pad];
	default:
		return NULL;
	}
}

static int max9286_set_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_state *state,
			   struct v4l2_subdev_format *format)
{
	struct max9286_priv *priv = sd_to_max9286(sd);
	struct v4l2_mbus_framefmt *cfg_fmt;
	struct max9286_source *source;
	unsigned int i;

	/*
	 * Disable setting format on the source pad: format is propagated
	 * from the sinks.
	 */
	if (format->pad == MAX9286_SRC_PAD)
		return -EINVAL;
		return v4l2_subdev_get_fmt(sd, state, format);

	/* Validate the format. */
	for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
@@ -957,42 +933,17 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
	if (i == ARRAY_SIZE(max9286_formats))
		format->format.code = max9286_formats[0].code;

	cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
					 format->which);
	if (!cfg_fmt)
		return -EINVAL;

	mutex_lock(&priv->mutex);
	*cfg_fmt = format->format;
	mutex_unlock(&priv->mutex);

	return 0;
}

static int max9286_get_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *format)
{
	struct max9286_priv *priv = sd_to_max9286(sd);
	struct v4l2_mbus_framefmt *cfg_fmt;
	unsigned int pad = format->pad;

	/*
	 * Multiplexed Stream Support: Support link validation by returning the
	 * format of the first bound link. All links must have the same format,
	 * as we do not support mixing and matching of cameras connected to the
	 * max9286.
	 * Apply the same format on all the other pad as all links must have the
	 * same format.
	 */
	if (pad == MAX9286_SRC_PAD)
		pad = __ffs(priv->bound_sources);
	for_each_source(priv, source) {
		unsigned int index = to_index(priv, source);

	cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
	if (!cfg_fmt)
		return -EINVAL;
		*v4l2_subdev_state_get_format(state, index) = format->format;
	}

	mutex_lock(&priv->mutex);
	format->format = *cfg_fmt;
	mutex_unlock(&priv->mutex);
	*v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD) = format->format;

	return 0;
}
@@ -1003,7 +954,7 @@ static const struct v4l2_subdev_video_ops max9286_video_ops = {

static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
	.enum_mbus_code = max9286_enum_mbus_code,
	.get_fmt	= max9286_get_fmt,
	.get_fmt	= v4l2_subdev_get_fmt,
	.set_fmt	= max9286_set_fmt,
	.get_frame_interval = max9286_get_frame_interval,
	.set_frame_interval = max9286_set_frame_interval,
@@ -1025,26 +976,29 @@ static const struct v4l2_mbus_framefmt max9286_default_format = {
	.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
};

static void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
static int max9286_init_state(struct v4l2_subdev *sd,
			      struct v4l2_subdev_state *state)
{
	*fmt = max9286_default_format;
}
	struct v4l2_fract *interval;

static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
	struct v4l2_mbus_framefmt *format;
	unsigned int i;
	for (unsigned int i = 0; i < MAX9286_N_PADS; i++)
		*v4l2_subdev_state_get_format(state, i) = max9286_default_format;

	for (i = 0; i < MAX9286_N_SINKS; i++) {
		format = v4l2_subdev_state_get_format(fh->state, i);
		max9286_init_format(format);
	}
	/*
	 * Special case: a null interval enables automatic FRAMESYNC mode.
	 *
	 * FRAMESYNC is taken from the slowest link. See register 0x01
	 * configuration.
	 */
	interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
	interval->numerator = 0;
	interval->denominator = 0;

	return 0;
}

static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = {
	.open = max9286_open,
	.init_state = max9286_init_state,
};

static const struct media_entity_operations max9286_media_ops = {
@@ -1079,10 +1033,6 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
	}

	/* Configure V4L2 for the MAX9286 itself */

	for (i = 0; i < MAX9286_N_SINKS; i++)
		max9286_init_format(&priv->fmt[i]);

	v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops);
	priv->sd.internal_ops = &max9286_subdev_internal_ops;
	priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1109,14 +1059,21 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
	if (ret)
		goto err_async;

	priv->sd.state_lock = priv->ctrls.lock;
	ret = v4l2_subdev_init_finalize(&priv->sd);
	if (ret)
		goto err_async;

	ret = v4l2_async_register_subdev(&priv->sd);
	if (ret < 0) {
		dev_err(dev, "Unable to register subdevice\n");
		goto err_async;
		goto err_subdev;
	}

	return 0;

err_subdev:
	v4l2_subdev_cleanup(&priv->sd);
err_async:
	v4l2_ctrl_handler_free(&priv->ctrls);
	max9286_v4l2_notifier_unregister(priv);
@@ -1126,6 +1083,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv)

static void max9286_v4l2_unregister(struct max9286_priv *priv)
{
	v4l2_subdev_cleanup(&priv->sd);
	v4l2_ctrl_handler_free(&priv->ctrls);
	v4l2_async_unregister_subdev(&priv->sd);
	max9286_v4l2_notifier_unregister(priv);
@@ -1182,7 +1140,6 @@ static int max9286_setup(struct max9286_priv *priv)
	max9286_write(priv, 0x69, (0xf & ~priv->route_mask));

	max9286_set_video_format(priv, &max9286_default_format);
	max9286_set_fsync_period(priv);

	cfg = max9286_read(priv, 0x1c);
	if (cfg < 0)
@@ -1629,8 +1586,6 @@ static int max9286_probe(struct i2c_client *client)
	if (!priv)
		return -ENOMEM;

	mutex_init(&priv->mutex);

	priv->client = client;

	/* GPIO values default to high */
Loading