Commit cf2552d8 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Hans Verkuil
Browse files

media: vimc: sensor: Use subdev active state



Store the active formats and crop rectangle in the subdevice active
state. This simplifies implementation of the format and selection
accessors, and allows using the v4l2_subdev_get_fmt() helper to
implement the .get_fmt() operation.

The active configuration that is used in the .process_frame() handler is
still stored in the vimc_sensor_device structure. The driver could
instead access the active state in the .process_frame() handler, but the
required locking could interfere with the real time constraints of the
frame processing. This data would be stored in registers in the
.s_stream() handler for real hardware, storing it in dedicated storage
thus mimics a real driver. To differentiate them from the rest of the
device private data, move the corresponding fields to a sub-structure of
vimc_sensor_device named hw.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarShuah Khan <skhan@linuxfoundation.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent b3f73b21
Loading
Loading
Loading
Loading
+50 −58
Original line number Diff line number Diff line
@@ -24,13 +24,20 @@ struct vimc_sensor_device {
	struct vimc_ent_device ved;
	struct v4l2_subdev sd;
	struct tpg_data tpg;
	struct v4l2_ctrl_handler hdl;
	struct media_pad pad;

	u8 *frame;

	/*
	 * Virtual "hardware" configuration, filled when the stream starts or
	 * when controls are set.
	 */
	struct {
		struct v4l2_area size;
		enum vimc_sensor_osd_mode osd_value;
		u64 start_stream_ts;
	/* The active format */
	struct v4l2_mbus_framefmt mbus_format;
	struct v4l2_ctrl_handler hdl;
	struct media_pad pad;
	} hw;
};

static const struct v4l2_mbus_framefmt fmt_default = {
@@ -88,36 +95,22 @@ static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd,
	return 0;
}

static int vimc_sensor_get_fmt(struct v4l2_subdev *sd,
			       struct v4l2_subdev_state *sd_state,
			       struct v4l2_subdev_format *fmt)
static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor,
				     const struct v4l2_mbus_framefmt *format)
{
	struct vimc_sensor_device *vsensor =
				container_of(sd, struct vimc_sensor_device, sd);

	fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
		      *v4l2_subdev_state_get_format(sd_state, fmt->pad) :
		      vsensor->mbus_format;
	const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code);

	return 0;
}

static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor)
{
	const struct vimc_pix_map *vpix =
				vimc_pix_map_by_code(vsensor->mbus_format.code);

	tpg_reset_source(&vsensor->tpg, vsensor->mbus_format.width,
			 vsensor->mbus_format.height, vsensor->mbus_format.field);
	tpg_s_bytesperline(&vsensor->tpg, 0, vsensor->mbus_format.width * vpix->bpp);
	tpg_s_buf_height(&vsensor->tpg, vsensor->mbus_format.height);
	tpg_reset_source(&vsensor->tpg, format->width, format->height,
			 format->field);
	tpg_s_bytesperline(&vsensor->tpg, 0, format->width * vpix->bpp);
	tpg_s_buf_height(&vsensor->tpg, format->height);
	tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat);
	/* TODO: add support for V4L2_FIELD_ALTERNATE */
	tpg_s_field(&vsensor->tpg, vsensor->mbus_format.field, false);
	tpg_s_colorspace(&vsensor->tpg, vsensor->mbus_format.colorspace);
	tpg_s_ycbcr_enc(&vsensor->tpg, vsensor->mbus_format.ycbcr_enc);
	tpg_s_quantization(&vsensor->tpg, vsensor->mbus_format.quantization);
	tpg_s_xfer_func(&vsensor->tpg, vsensor->mbus_format.xfer_func);
	tpg_s_field(&vsensor->tpg, format->field, false);
	tpg_s_colorspace(&vsensor->tpg, format->colorspace);
	tpg_s_ycbcr_enc(&vsensor->tpg, format->ycbcr_enc);
	tpg_s_quantization(&vsensor->tpg, format->quantization);
	tpg_s_xfer_func(&vsensor->tpg, format->xfer_func);
}

static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
@@ -148,15 +141,11 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
	struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd);
	struct v4l2_mbus_framefmt *mf;

	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
	/* Do not change the format while stream is on */
		if (vsensor->frame)
	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsensor->frame)
		return -EBUSY;

		mf = &vsensor->mbus_format;
	} else {
	mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
	}

	/* Set the new format */
	vimc_sensor_adjust_fmt(&fmt->format);
@@ -181,7 +170,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
	.enum_mbus_code		= vimc_sensor_enum_mbus_code,
	.enum_frame_size	= vimc_sensor_enum_frame_size,
	.get_fmt		= vimc_sensor_get_fmt,
	.get_fmt		= v4l2_subdev_get_fmt,
	.set_fmt		= vimc_sensor_set_fmt,
};

@@ -198,7 +187,7 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,

	tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame);
	tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame);
	switch (vsensor->osd_value) {
	switch (vsensor->hw.osd_value) {
	case VIMC_SENSOR_OSD_SHOW_ALL: {
		const char *order = tpg_g_color_order(&vsensor->tpg);

@@ -212,15 +201,14 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
			 vsensor->tpg.hue);
		tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
		snprintf(str, sizeof(str), "sensor size: %dx%d",
			 vsensor->mbus_format.width,
			 vsensor->mbus_format.height);
			 vsensor->hw.size.width, vsensor->hw.size.height);
		tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
		fallthrough;
	}
	case VIMC_SENSOR_OSD_SHOW_COUNTERS: {
		unsigned int ms;

		ms = div_u64(ktime_get_ns() - vsensor->start_stream_ts, 1000000);
		ms = div_u64(ktime_get_ns() - vsensor->hw.start_stream_ts, 1000000);
		snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d",
			 (ms / (60 * 60 * 1000)) % 24,
			 (ms / (60 * 1000)) % 60,
@@ -243,15 +231,25 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
				container_of(sd, struct vimc_sensor_device, sd);

	if (enable) {
		const struct v4l2_mbus_framefmt *format;
		struct v4l2_subdev_state *state;
		const struct vimc_pix_map *vpix;
		unsigned int frame_size;

		vsensor->start_stream_ts = ktime_get_ns();
		state = v4l2_subdev_lock_and_get_active_state(sd);
		format = v4l2_subdev_state_get_format(state, 0);

		/* Configure the test pattern generator. */
		vimc_sensor_tpg_s_format(vsensor, format);

		/* Calculate the frame size. */
		vpix = vimc_pix_map_by_code(format->code);
		frame_size = format->width * vpix->bpp * format->height;

		/* Calculate the frame size */
		vpix = vimc_pix_map_by_code(vsensor->mbus_format.code);
		frame_size = vsensor->mbus_format.width * vpix->bpp *
			     vsensor->mbus_format.height;
		vsensor->hw.size.width = format->width;
		vsensor->hw.size.height = format->height;

		v4l2_subdev_unlock_state(state);

		/*
		 * Allocate the frame buffer. Use vmalloc to be able to
@@ -261,9 +259,7 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
		if (!vsensor->frame)
			return -ENOMEM;

		/* configure the test pattern generator */
		vimc_sensor_tpg_s_format(vsensor);

		vsensor->hw.start_stream_ts = ktime_get_ns();
	} else {

		vfree(vsensor->frame);
@@ -321,7 +317,7 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
		tpg_s_saturation(&vsensor->tpg, ctrl->val);
		break;
	case VIMC_CID_OSD_TEXT_MODE:
		vsensor->osd_value = ctrl->val;
		vsensor->hw.osd_value = ctrl->val;
		break;
	default:
		return -EINVAL;
@@ -414,8 +410,7 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
	}

	/* Initialize the test pattern generator */
	tpg_init(&vsensor->tpg, vsensor->mbus_format.width,
		 vsensor->mbus_format.height);
	tpg_init(&vsensor->tpg, fmt_default.width, fmt_default.height);
	ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH);
	if (ret)
		goto err_free_hdl;
@@ -432,9 +427,6 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
	vsensor->ved.process_frame = vimc_sensor_process_frame;
	vsensor->ved.dev = vimc->mdev.dev;

	/* Initialize the frame format */
	vsensor->mbus_format = fmt_default;

	return &vsensor->ved;

err_free_tpg: