Commit 4c46cb2a authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Hans Verkuil

media: vimc: debayer: 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_debayer_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_debayer_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 cf2552d8
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include "vimc-common.h" #include "vimc-common.h"
/* TODO: Add support for more output formats, we only support RGB888 for now. */
#define VIMC_DEBAYER_SOURCE_MBUS_FMT MEDIA_BUS_FMT_RGB888_1X24
enum vimc_debayer_rgb_colors { enum vimc_debayer_rgb_colors {
VIMC_DEBAYER_RED = 0, VIMC_DEBAYER_RED = 0,
VIMC_DEBAYER_GREEN = 1, VIMC_DEBAYER_GREEN = 1,
...@@ -29,19 +32,26 @@ struct vimc_debayer_pix_map { ...@@ -29,19 +32,26 @@ struct vimc_debayer_pix_map {
struct vimc_debayer_device { struct vimc_debayer_device {
struct vimc_ent_device ved; struct vimc_ent_device ved;
struct v4l2_subdev sd; struct v4l2_subdev sd;
/* The active format */ struct v4l2_ctrl_handler hdl;
struct v4l2_mbus_framefmt sink_fmt; struct media_pad pads[2];
u32 src_code;
u8 *src_frame;
void (*set_rgb_src)(struct vimc_debayer_device *vdebayer, void (*set_rgb_src)(struct vimc_debayer_device *vdebayer,
unsigned int lin, unsigned int col, unsigned int lin, unsigned int col,
unsigned int rgb[3]); unsigned int rgb[3]);
/* Values calculated when the stream starts */
u8 *src_frame; /*
* Virtual "hardware" configuration, filled when the stream starts or
* when controls are set.
*/
struct {
const struct vimc_debayer_pix_map *sink_pix_map; const struct vimc_debayer_pix_map *sink_pix_map;
unsigned int sink_bpp; unsigned int sink_bpp;
struct v4l2_area size;
unsigned int mean_win_size; unsigned int mean_win_size;
struct v4l2_ctrl_handler hdl; u32 src_code;
struct media_pad pads[2]; } hw;
}; };
static const struct v4l2_mbus_framefmt sink_fmt_default = { static const struct v4l2_mbus_framefmt sink_fmt_default = {
...@@ -153,7 +163,6 @@ static bool vimc_debayer_src_code_is_valid(u32 code) ...@@ -153,7 +163,6 @@ static bool vimc_debayer_src_code_is_valid(u32 code)
static int vimc_debayer_init_state(struct v4l2_subdev *sd, static int vimc_debayer_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state) struct v4l2_subdev_state *sd_state)
{ {
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf; struct v4l2_mbus_framefmt *mf;
mf = v4l2_subdev_state_get_format(sd_state, 0); mf = v4l2_subdev_state_get_format(sd_state, 0);
...@@ -161,7 +170,7 @@ static int vimc_debayer_init_state(struct v4l2_subdev *sd, ...@@ -161,7 +170,7 @@ static int vimc_debayer_init_state(struct v4l2_subdev *sd,
mf = v4l2_subdev_state_get_format(sd_state, 1); mf = v4l2_subdev_state_get_format(sd_state, 1);
*mf = sink_fmt_default; *mf = sink_fmt_default;
mf->code = vdebayer->src_code; mf->code = VIMC_DEBAYER_SOURCE_MBUS_FMT;
return 0; return 0;
} }
...@@ -210,24 +219,6 @@ static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd, ...@@ -210,24 +219,6 @@ static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd,
return 0; return 0;
} }
static int vimc_debayer_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
/* Get the current sink format */
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
*v4l2_subdev_state_get_format(sd_state, 0) :
vdebayer->sink_fmt;
/* Set the right code for the source pad */
if (VIMC_IS_SRC(fmt->pad))
fmt->format.code = vdebayer->src_code;
return 0;
}
static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
{ {
const struct vimc_debayer_pix_map *vpix; const struct vimc_debayer_pix_map *vpix;
...@@ -253,52 +244,42 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, ...@@ -253,52 +244,42 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt) struct v4l2_subdev_format *fmt)
{ {
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_mbus_framefmt *format;
u32 *src_code;
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 && vdebayer->src_frame)
if (vdebayer->src_frame)
return -EBUSY; return -EBUSY;
sink_fmt = &vdebayer->sink_fmt;
src_code = &vdebayer->src_code;
} else {
sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
src_code = &v4l2_subdev_state_get_format(sd_state, 1)->code;
}
/* /*
* Do not change the format of the source pad, * Do not change the format of the source pad, it is propagated from
* it is propagated from the sink * the sink.
*/ */
if (VIMC_IS_SRC(fmt->pad)) { if (VIMC_IS_SRC(fmt->pad))
u32 code = fmt->format.code; return v4l2_subdev_get_fmt(sd, sd_state, fmt);
fmt->format = *sink_fmt;
if (vimc_debayer_src_code_is_valid(code))
*src_code = code;
fmt->format.code = *src_code; /* Set the new format in the sink pad. */
} else {
/* Set the new format in the sink pad */
vimc_debayer_adjust_sink_fmt(&fmt->format); vimc_debayer_adjust_sink_fmt(&fmt->format);
format = v4l2_subdev_state_get_format(sd_state, 0);
dev_dbg(vdebayer->ved.dev, "%s: sink format update: " dev_dbg(vdebayer->ved.dev, "%s: sink format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) " "old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name, "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name,
/* old */ /* old */
sink_fmt->width, sink_fmt->height, sink_fmt->code, format->width, format->height, format->code,
sink_fmt->colorspace, sink_fmt->quantization, format->colorspace, format->quantization,
sink_fmt->xfer_func, sink_fmt->ycbcr_enc, format->xfer_func, format->ycbcr_enc,
/* new */ /* new */
fmt->format.width, fmt->format.height, fmt->format.code, fmt->format.width, fmt->format.height, fmt->format.code,
fmt->format.colorspace, fmt->format.quantization, fmt->format.colorspace, fmt->format.quantization,
fmt->format.xfer_func, fmt->format.ycbcr_enc); fmt->format.xfer_func, fmt->format.ycbcr_enc);
*sink_fmt = fmt->format; *format = fmt->format;
}
/* Propagate the format to the source pad. */
format = v4l2_subdev_state_get_format(sd_state, 1);
*format = fmt->format;
format->code = VIMC_DEBAYER_SOURCE_MBUS_FMT;
return 0; return 0;
} }
...@@ -306,7 +287,7 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, ...@@ -306,7 +287,7 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = { static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = {
.enum_mbus_code = vimc_debayer_enum_mbus_code, .enum_mbus_code = vimc_debayer_enum_mbus_code,
.enum_frame_size = vimc_debayer_enum_frame_size, .enum_frame_size = vimc_debayer_enum_frame_size,
.get_fmt = vimc_debayer_get_fmt, .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = vimc_debayer_set_fmt, .set_fmt = vimc_debayer_set_fmt,
}; };
...@@ -318,8 +299,8 @@ static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer, ...@@ -318,8 +299,8 @@ static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer,
const struct vimc_pix_map *vpix; const struct vimc_pix_map *vpix;
unsigned int i, index; unsigned int i, index;
vpix = vimc_pix_map_by_code(vdebayer->src_code); vpix = vimc_pix_map_by_code(vdebayer->hw.src_code);
index = VIMC_FRAME_INDEX(lin, col, vdebayer->sink_fmt.width, 3); index = VIMC_FRAME_INDEX(lin, col, vdebayer->hw.size.width, 3);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
switch (vpix->pixelformat) { switch (vpix->pixelformat) {
case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_RGB24:
...@@ -337,24 +318,37 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -337,24 +318,37 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
if (enable) { if (enable) {
const struct v4l2_mbus_framefmt *sink_fmt;
const struct v4l2_mbus_framefmt *src_fmt;
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;
if (vdebayer->src_frame) if (vdebayer->src_frame)
return 0; return 0;
state = v4l2_subdev_lock_and_get_active_state(sd);
sink_fmt = v4l2_subdev_state_get_format(state, 0);
src_fmt = v4l2_subdev_state_get_format(state, 1);
/* Calculate the frame size of the source pad */ /* Calculate the frame size of the source pad */
vpix = vimc_pix_map_by_code(vdebayer->src_code); vpix = vimc_pix_map_by_code(src_fmt->code);
frame_size = vdebayer->sink_fmt.width * vdebayer->sink_fmt.height * frame_size = src_fmt->width * src_fmt->height * vpix->bpp;
vpix->bpp;
/* Save the bytes per pixel of the sink */ /* Save the bytes per pixel of the sink */
vpix = vimc_pix_map_by_code(vdebayer->sink_fmt.code); vpix = vimc_pix_map_by_code(sink_fmt->code);
vdebayer->sink_bpp = vpix->bpp; vdebayer->hw.sink_bpp = vpix->bpp;
/* Get the corresponding pixel map from the table */ /* Get the corresponding pixel map from the table */
vdebayer->sink_pix_map = vdebayer->hw.sink_pix_map =
vimc_debayer_pix_map_by_code(vdebayer->sink_fmt.code); vimc_debayer_pix_map_by_code(sink_fmt->code);
vdebayer->hw.size.width = sink_fmt->width;
vdebayer->hw.size.height = sink_fmt->height;
vdebayer->hw.src_code = src_fmt->code;
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
...@@ -363,7 +357,6 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -363,7 +357,6 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
vdebayer->src_frame = vmalloc(frame_size); vdebayer->src_frame = vmalloc(frame_size);
if (!vdebayer->src_frame) if (!vdebayer->src_frame)
return -ENOMEM; return -ENOMEM;
} else { } else {
if (!vdebayer->src_frame) if (!vdebayer->src_frame)
return 0; return 0;
...@@ -424,13 +417,13 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, ...@@ -424,13 +417,13 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* the top left corner of the mean window (considering the current * the top left corner of the mean window (considering the current
* pixel as the center) * pixel as the center)
*/ */
seek = vdebayer->mean_win_size / 2; seek = vdebayer->hw.mean_win_size / 2;
/* Sum the values of the colors in the mean window */ /* Sum the values of the colors in the mean window */
dev_dbg(vdebayer->ved.dev, dev_dbg(vdebayer->ved.dev,
"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
vdebayer->sd.name, lin, col, vdebayer->sink_fmt.height, seek); vdebayer->sd.name, lin, col, vdebayer->hw.size.height, seek);
/* /*
* Iterate through all the lines in the mean window, start * Iterate through all the lines in the mean window, start
...@@ -439,7 +432,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, ...@@ -439,7 +432,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* frame * frame
*/ */
for (wlin = seek > lin ? 0 : lin - seek; for (wlin = seek > lin ? 0 : lin - seek;
wlin < lin + seek + 1 && wlin < vdebayer->sink_fmt.height; wlin < lin + seek + 1 && wlin < vdebayer->hw.size.height;
wlin++) { wlin++) {
/* /*
...@@ -449,17 +442,17 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, ...@@ -449,17 +442,17 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* frame * frame
*/ */
for (wcol = seek > col ? 0 : col - seek; for (wcol = seek > col ? 0 : col - seek;
wcol < col + seek + 1 && wcol < vdebayer->sink_fmt.width; wcol < col + seek + 1 && wcol < vdebayer->hw.size.width;
wcol++) { wcol++) {
enum vimc_debayer_rgb_colors color; enum vimc_debayer_rgb_colors color;
unsigned int index; unsigned int index;
/* Check which color this pixel is */ /* Check which color this pixel is */
color = vdebayer->sink_pix_map->order[wlin % 2][wcol % 2]; color = vdebayer->hw.sink_pix_map->order[wlin % 2][wcol % 2];
index = VIMC_FRAME_INDEX(wlin, wcol, index = VIMC_FRAME_INDEX(wlin, wcol,
vdebayer->sink_fmt.width, vdebayer->hw.size.width,
vdebayer->sink_bpp); vdebayer->hw.sink_bpp);
dev_dbg(vdebayer->ved.dev, dev_dbg(vdebayer->ved.dev,
"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
...@@ -468,7 +461,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, ...@@ -468,7 +461,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
/* Get its value */ /* Get its value */
rgb[color] = rgb[color] + rgb[color] = rgb[color] +
vimc_debayer_get_val(&frame[index], vimc_debayer_get_val(&frame[index],
vdebayer->sink_bpp); vdebayer->hw.sink_bpp);
/* Save how many values we already added */ /* Save how many values we already added */
n_rgb[color]++; n_rgb[color]++;
...@@ -506,8 +499,8 @@ static void *vimc_debayer_process_frame(struct vimc_ent_device *ved, ...@@ -506,8 +499,8 @@ static void *vimc_debayer_process_frame(struct vimc_ent_device *ved,
if (!vdebayer->src_frame) if (!vdebayer->src_frame)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
for (i = 0; i < vdebayer->sink_fmt.height; i++) for (i = 0; i < vdebayer->hw.size.height; i++)
for (j = 0; j < vdebayer->sink_fmt.width; j++) { for (j = 0; j < vdebayer->hw.size.width; j++) {
vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb); vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb);
vdebayer->set_rgb_src(vdebayer, i, j, rgb); vdebayer->set_rgb_src(vdebayer, i, j, rgb);
} }
...@@ -522,7 +515,7 @@ static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -522,7 +515,7 @@ static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) { switch (ctrl->id) {
case VIMC_CID_MEAN_WIN_SIZE: case VIMC_CID_MEAN_WIN_SIZE:
vdebayer->mean_win_size = ctrl->val; vdebayer->hw.mean_win_size = ctrl->val;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -599,17 +592,8 @@ static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc, ...@@ -599,17 +592,8 @@ static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc,
vdebayer->ved.process_frame = vimc_debayer_process_frame; vdebayer->ved.process_frame = vimc_debayer_process_frame;
vdebayer->ved.dev = vimc->mdev.dev; vdebayer->ved.dev = vimc->mdev.dev;
vdebayer->mean_win_size = vimc_debayer_ctrl_mean_win_size.def; vdebayer->hw.mean_win_size = vimc_debayer_ctrl_mean_win_size.def;
/* Initialize the frame format */
vdebayer->sink_fmt = sink_fmt_default;
/*
* TODO: Add support for more output formats, we only support
* RGB888 for now
* NOTE: the src format is always the same as the sink, except
* for the code
*/
vdebayer->src_code = MEDIA_BUS_FMT_RGB888_1X24;
vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame; vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame;
return &vdebayer->ved; return &vdebayer->ved;
......
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