mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
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: 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:
parent
cf2552d87a
commit
4c46cb2a7f
@ -15,6 +15,9 @@
|
||||
|
||||
#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 {
|
||||
VIMC_DEBAYER_RED = 0,
|
||||
VIMC_DEBAYER_GREEN = 1,
|
||||
@ -29,19 +32,26 @@ struct vimc_debayer_pix_map {
|
||||
struct vimc_debayer_device {
|
||||
struct vimc_ent_device ved;
|
||||
struct v4l2_subdev sd;
|
||||
/* The active format */
|
||||
struct v4l2_mbus_framefmt sink_fmt;
|
||||
u32 src_code;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct media_pad pads[2];
|
||||
|
||||
u8 *src_frame;
|
||||
|
||||
void (*set_rgb_src)(struct vimc_debayer_device *vdebayer,
|
||||
unsigned int lin, unsigned int col,
|
||||
unsigned int rgb[3]);
|
||||
/* Values calculated when the stream starts */
|
||||
u8 *src_frame;
|
||||
const struct vimc_debayer_pix_map *sink_pix_map;
|
||||
unsigned int sink_bpp;
|
||||
unsigned int mean_win_size;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct media_pad pads[2];
|
||||
|
||||
/*
|
||||
* Virtual "hardware" configuration, filled when the stream starts or
|
||||
* when controls are set.
|
||||
*/
|
||||
struct {
|
||||
const struct vimc_debayer_pix_map *sink_pix_map;
|
||||
unsigned int sink_bpp;
|
||||
struct v4l2_area size;
|
||||
unsigned int mean_win_size;
|
||||
u32 src_code;
|
||||
} hw;
|
||||
};
|
||||
|
||||
static const struct v4l2_mbus_framefmt sink_fmt_default = {
|
||||
@ -153,7 +163,6 @@ static bool vimc_debayer_src_code_is_valid(u32 code)
|
||||
static int vimc_debayer_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state)
|
||||
{
|
||||
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
|
||||
struct v4l2_mbus_framefmt *mf;
|
||||
|
||||
mf = v4l2_subdev_state_get_format(sd_state, 0);
|
||||
@ -161,7 +170,7 @@ static int vimc_debayer_init_state(struct v4l2_subdev *sd,
|
||||
|
||||
mf = v4l2_subdev_state_get_format(sd_state, 1);
|
||||
*mf = sink_fmt_default;
|
||||
mf->code = vdebayer->src_code;
|
||||
mf->code = VIMC_DEBAYER_SOURCE_MBUS_FMT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -210,24 +219,6 @@ static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd,
|
||||
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)
|
||||
{
|
||||
const struct vimc_debayer_pix_map *vpix;
|
||||
@ -253,52 +244,42 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
|
||||
struct v4l2_mbus_framefmt *sink_fmt;
|
||||
u32 *src_code;
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
|
||||
/* Do not change the format while stream is on */
|
||||
if (vdebayer->src_frame)
|
||||
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 while stream is on. */
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vdebayer->src_frame)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Do not change the format of the source pad,
|
||||
* it is propagated from the sink
|
||||
* Do not change the format of the source pad, it is propagated from
|
||||
* the sink.
|
||||
*/
|
||||
if (VIMC_IS_SRC(fmt->pad)) {
|
||||
u32 code = fmt->format.code;
|
||||
if (VIMC_IS_SRC(fmt->pad))
|
||||
return v4l2_subdev_get_fmt(sd, sd_state, fmt);
|
||||
|
||||
fmt->format = *sink_fmt;
|
||||
/* Set the new format in the sink pad. */
|
||||
vimc_debayer_adjust_sink_fmt(&fmt->format);
|
||||
|
||||
if (vimc_debayer_src_code_is_valid(code))
|
||||
*src_code = code;
|
||||
format = v4l2_subdev_state_get_format(sd_state, 0);
|
||||
|
||||
fmt->format.code = *src_code;
|
||||
} else {
|
||||
/* Set the new format in the sink pad */
|
||||
vimc_debayer_adjust_sink_fmt(&fmt->format);
|
||||
dev_dbg(vdebayer->ved.dev, "%s: sink format update: "
|
||||
"old:%dx%d (0x%x, %d, %d, %d, %d) "
|
||||
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name,
|
||||
/* old */
|
||||
format->width, format->height, format->code,
|
||||
format->colorspace, format->quantization,
|
||||
format->xfer_func, format->ycbcr_enc,
|
||||
/* new */
|
||||
fmt->format.width, fmt->format.height, fmt->format.code,
|
||||
fmt->format.colorspace, fmt->format.quantization,
|
||||
fmt->format.xfer_func, fmt->format.ycbcr_enc);
|
||||
|
||||
dev_dbg(vdebayer->ved.dev, "%s: sink format update: "
|
||||
"old:%dx%d (0x%x, %d, %d, %d, %d) "
|
||||
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name,
|
||||
/* old */
|
||||
sink_fmt->width, sink_fmt->height, sink_fmt->code,
|
||||
sink_fmt->colorspace, sink_fmt->quantization,
|
||||
sink_fmt->xfer_func, sink_fmt->ycbcr_enc,
|
||||
/* new */
|
||||
fmt->format.width, fmt->format.height, fmt->format.code,
|
||||
fmt->format.colorspace, fmt->format.quantization,
|
||||
fmt->format.xfer_func, fmt->format.ycbcr_enc);
|
||||
*format = fmt->format;
|
||||
|
||||
*sink_fmt = 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;
|
||||
}
|
||||
@ -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 = {
|
||||
.enum_mbus_code = vimc_debayer_enum_mbus_code,
|
||||
.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,
|
||||
};
|
||||
|
||||
@ -318,8 +299,8 @@ static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer,
|
||||
const struct vimc_pix_map *vpix;
|
||||
unsigned int i, index;
|
||||
|
||||
vpix = vimc_pix_map_by_code(vdebayer->src_code);
|
||||
index = VIMC_FRAME_INDEX(lin, col, vdebayer->sink_fmt.width, 3);
|
||||
vpix = vimc_pix_map_by_code(vdebayer->hw.src_code);
|
||||
index = VIMC_FRAME_INDEX(lin, col, vdebayer->hw.size.width, 3);
|
||||
for (i = 0; i < 3; i++) {
|
||||
switch (vpix->pixelformat) {
|
||||
case V4L2_PIX_FMT_RGB24:
|
||||
@ -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);
|
||||
|
||||
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;
|
||||
unsigned int frame_size;
|
||||
|
||||
if (vdebayer->src_frame)
|
||||
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 */
|
||||
vpix = vimc_pix_map_by_code(vdebayer->src_code);
|
||||
frame_size = vdebayer->sink_fmt.width * vdebayer->sink_fmt.height *
|
||||
vpix->bpp;
|
||||
vpix = vimc_pix_map_by_code(src_fmt->code);
|
||||
frame_size = src_fmt->width * src_fmt->height * vpix->bpp;
|
||||
|
||||
/* Save the bytes per pixel of the sink */
|
||||
vpix = vimc_pix_map_by_code(vdebayer->sink_fmt.code);
|
||||
vdebayer->sink_bpp = vpix->bpp;
|
||||
vpix = vimc_pix_map_by_code(sink_fmt->code);
|
||||
vdebayer->hw.sink_bpp = vpix->bpp;
|
||||
|
||||
/* Get the corresponding pixel map from the table */
|
||||
vdebayer->sink_pix_map =
|
||||
vimc_debayer_pix_map_by_code(vdebayer->sink_fmt.code);
|
||||
vdebayer->hw.sink_pix_map =
|
||||
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
|
||||
@ -363,7 +357,6 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
vdebayer->src_frame = vmalloc(frame_size);
|
||||
if (!vdebayer->src_frame)
|
||||
return -ENOMEM;
|
||||
|
||||
} else {
|
||||
if (!vdebayer->src_frame)
|
||||
return 0;
|
||||
@ -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
|
||||
* 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 */
|
||||
|
||||
dev_dbg(vdebayer->ved.dev,
|
||||
"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
|
||||
@ -439,7 +432,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
|
||||
* frame
|
||||
*/
|
||||
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++) {
|
||||
|
||||
/*
|
||||
@ -449,17 +442,17 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
|
||||
* frame
|
||||
*/
|
||||
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++) {
|
||||
enum vimc_debayer_rgb_colors color;
|
||||
unsigned int index;
|
||||
|
||||
/* 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,
|
||||
vdebayer->sink_fmt.width,
|
||||
vdebayer->sink_bpp);
|
||||
vdebayer->hw.size.width,
|
||||
vdebayer->hw.sink_bpp);
|
||||
|
||||
dev_dbg(vdebayer->ved.dev,
|
||||
"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,
|
||||
/* Get its value */
|
||||
rgb[color] = rgb[color] +
|
||||
vimc_debayer_get_val(&frame[index],
|
||||
vdebayer->sink_bpp);
|
||||
vdebayer->hw.sink_bpp);
|
||||
|
||||
/* Save how many values we already added */
|
||||
n_rgb[color]++;
|
||||
@ -506,8 +499,8 @@ static void *vimc_debayer_process_frame(struct vimc_ent_device *ved,
|
||||
if (!vdebayer->src_frame)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
for (i = 0; i < vdebayer->sink_fmt.height; i++)
|
||||
for (j = 0; j < vdebayer->sink_fmt.width; j++) {
|
||||
for (i = 0; i < vdebayer->hw.size.height; i++)
|
||||
for (j = 0; j < vdebayer->hw.size.width; j++) {
|
||||
vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, 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)
|
||||
|
||||
switch (ctrl->id) {
|
||||
case VIMC_CID_MEAN_WIN_SIZE:
|
||||
vdebayer->mean_win_size = ctrl->val;
|
||||
vdebayer->hw.mean_win_size = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -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.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;
|
||||
|
||||
return &vdebayer->ved;
|
||||
|
Loading…
Reference in New Issue
Block a user