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

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
...@@ -24,13 +24,20 @@ struct vimc_sensor_device { ...@@ -24,13 +24,20 @@ struct vimc_sensor_device {
struct vimc_ent_device ved; struct vimc_ent_device ved;
struct v4l2_subdev sd; struct v4l2_subdev sd;
struct tpg_data tpg; struct tpg_data tpg;
u8 *frame;
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 v4l2_ctrl_handler hdl;
struct media_pad pad; 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;
} hw;
}; };
static const struct v4l2_mbus_framefmt fmt_default = { static const struct v4l2_mbus_framefmt fmt_default = {
...@@ -88,36 +95,22 @@ static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd, ...@@ -88,36 +95,22 @@ static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd,
return 0; return 0;
} }
static int vimc_sensor_get_fmt(struct v4l2_subdev *sd, static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor,
struct v4l2_subdev_state *sd_state, const struct v4l2_mbus_framefmt *format)
struct v4l2_subdev_format *fmt)
{ {
struct vimc_sensor_device *vsensor = const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code);
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;
return 0; tpg_reset_source(&vsensor->tpg, format->width, format->height,
} format->field);
tpg_s_bytesperline(&vsensor->tpg, 0, format->width * vpix->bpp);
static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor) tpg_s_buf_height(&vsensor->tpg, format->height);
{
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_s_fourcc(&vsensor->tpg, vpix->pixelformat); tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat);
/* TODO: add support for V4L2_FIELD_ALTERNATE */ /* TODO: add support for V4L2_FIELD_ALTERNATE */
tpg_s_field(&vsensor->tpg, vsensor->mbus_format.field, false); tpg_s_field(&vsensor->tpg, format->field, false);
tpg_s_colorspace(&vsensor->tpg, vsensor->mbus_format.colorspace); tpg_s_colorspace(&vsensor->tpg, format->colorspace);
tpg_s_ycbcr_enc(&vsensor->tpg, vsensor->mbus_format.ycbcr_enc); tpg_s_ycbcr_enc(&vsensor->tpg, format->ycbcr_enc);
tpg_s_quantization(&vsensor->tpg, vsensor->mbus_format.quantization); tpg_s_quantization(&vsensor->tpg, format->quantization);
tpg_s_xfer_func(&vsensor->tpg, vsensor->mbus_format.xfer_func); tpg_s_xfer_func(&vsensor->tpg, format->xfer_func);
} }
static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) 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, ...@@ -148,15 +141,11 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd); struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf; struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */
/* Do not change the format while stream is on */ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsensor->frame)
if (vsensor->frame) return -EBUSY;
return -EBUSY;
mf = &vsensor->mbus_format; mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
} else {
mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
}
/* Set the new format */ /* Set the new format */
vimc_sensor_adjust_fmt(&fmt->format); vimc_sensor_adjust_fmt(&fmt->format);
...@@ -181,7 +170,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, ...@@ -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 = { static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
.enum_mbus_code = vimc_sensor_enum_mbus_code, .enum_mbus_code = vimc_sensor_enum_mbus_code,
.enum_frame_size = vimc_sensor_enum_frame_size, .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, .set_fmt = vimc_sensor_set_fmt,
}; };
...@@ -198,7 +187,7 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved, ...@@ -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_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame);
tpg_calc_text_basep(&vsensor->tpg, basep, 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: { case VIMC_SENSOR_OSD_SHOW_ALL: {
const char *order = tpg_g_color_order(&vsensor->tpg); const char *order = tpg_g_color_order(&vsensor->tpg);
...@@ -212,15 +201,14 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved, ...@@ -212,15 +201,14 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
vsensor->tpg.hue); vsensor->tpg.hue);
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), "sensor size: %dx%d", snprintf(str, sizeof(str), "sensor size: %dx%d",
vsensor->mbus_format.width, vsensor->hw.size.width, vsensor->hw.size.height);
vsensor->mbus_format.height);
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
fallthrough; fallthrough;
} }
case VIMC_SENSOR_OSD_SHOW_COUNTERS: { case VIMC_SENSOR_OSD_SHOW_COUNTERS: {
unsigned int ms; 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", snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d",
(ms / (60 * 60 * 1000)) % 24, (ms / (60 * 60 * 1000)) % 24,
(ms / (60 * 1000)) % 60, (ms / (60 * 1000)) % 60,
...@@ -243,15 +231,25 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -243,15 +231,25 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
container_of(sd, struct vimc_sensor_device, sd); container_of(sd, struct vimc_sensor_device, sd);
if (enable) { if (enable) {
const struct v4l2_mbus_framefmt *format;
struct v4l2_subdev_state *state;
const struct vimc_pix_map *vpix; const struct vimc_pix_map *vpix;
unsigned int frame_size; 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);
/* Calculate the frame size */ /* Configure the test pattern generator. */
vpix = vimc_pix_map_by_code(vsensor->mbus_format.code); vimc_sensor_tpg_s_format(vsensor, format);
frame_size = vsensor->mbus_format.width * vpix->bpp *
vsensor->mbus_format.height; /* Calculate the frame size. */
vpix = vimc_pix_map_by_code(format->code);
frame_size = format->width * vpix->bpp * 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 * 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) ...@@ -261,9 +259,7 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
if (!vsensor->frame) if (!vsensor->frame)
return -ENOMEM; return -ENOMEM;
/* configure the test pattern generator */ vsensor->hw.start_stream_ts = ktime_get_ns();
vimc_sensor_tpg_s_format(vsensor);
} else { } else {
vfree(vsensor->frame); vfree(vsensor->frame);
...@@ -321,7 +317,7 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -321,7 +317,7 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
tpg_s_saturation(&vsensor->tpg, ctrl->val); tpg_s_saturation(&vsensor->tpg, ctrl->val);
break; break;
case VIMC_CID_OSD_TEXT_MODE: case VIMC_CID_OSD_TEXT_MODE:
vsensor->osd_value = ctrl->val; vsensor->hw.osd_value = ctrl->val;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -414,8 +410,7 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, ...@@ -414,8 +410,7 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
} }
/* Initialize the test pattern generator */ /* Initialize the test pattern generator */
tpg_init(&vsensor->tpg, vsensor->mbus_format.width, tpg_init(&vsensor->tpg, fmt_default.width, fmt_default.height);
vsensor->mbus_format.height);
ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH); ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH);
if (ret) if (ret)
goto err_free_hdl; goto err_free_hdl;
...@@ -432,9 +427,6 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, ...@@ -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.process_frame = vimc_sensor_process_frame;
vsensor->ved.dev = vimc->mdev.dev; vsensor->ved.dev = vimc->mdev.dev;
/* Initialize the frame format */
vsensor->mbus_format = fmt_default;
return &vsensor->ved; return &vsensor->ved;
err_free_tpg: err_free_tpg:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment