1

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: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
Laurent Pinchart 2024-04-25 02:57:39 +03:00 committed by Hans Verkuil
parent b3f73b2188
commit cf2552d87a

View File

@ -24,13 +24,20 @@ struct vimc_sensor_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
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 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 = {
@ -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);
const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code);
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
*v4l2_subdev_state_get_format(sd_state, fmt->pad) :
vsensor->mbus_format;
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);
/* 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;
/* 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;
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: