media: rockchip: isp: modify input crop

1.for bayer raw, do align order
2.sensor can request isp do input crop
3.user can request isp do input crop

Change-Id: I765145f87d38b2610d94118cba6c9b2c31755acc
Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
Cai YiWei
2020-04-06 20:55:18 +08:00
committed by Tao Huang
parent af5596135a
commit 24a732b843
4 changed files with 322 additions and 255 deletions

View File

@@ -324,63 +324,38 @@ static int _set_pipeline_default_fmt(struct rkisp_device *dev)
struct v4l2_subdev *isp;
struct v4l2_subdev_format fmt;
struct v4l2_subdev_selection sel;
struct v4l2_subdev_pad_config cfg;
u32 width, height;
u32 ori_width, ori_height, ori_code;
u32 width, height, code;
isp = &dev->isp_sdev.sd;
fmt = dev->active_sensor->fmt[0];
code = fmt.format.code;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.pad = RKISP_ISP_PAD_SINK;
/* isp input format information from sensor */
v4l2_subdev_call(isp, pad, set_fmt, NULL, &fmt);
if (dev->isp_ver == ISP_V12) {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V12);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V12);
} else if (dev->isp_ver == ISP_V13) {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V13);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V13);
} else {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX);
}
rkisp_align_sensor_resolution(dev, &sel.r, false);
width = sel.r.width;
height = sel.r.height;
sel.target = V4L2_SEL_TGT_CROP;
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sel.pad = RKISP_ISP_PAD_SINK;
/* image resolution processed by isp */
v4l2_subdev_call(isp, pad, set_selection, NULL, &sel);
/* change fmt&size for RKISP_ISP_PAD_SOURCE_PATH */
if ((code & RKISP_MEDIA_BUS_FMT_MASK) == RKISP_MEDIA_BUS_FMT_BAYER)
fmt.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
sel.r.left = 0;
sel.r.top = 0;
width = fmt.format.width;
height = fmt.format.height;
sel.r.width = fmt.format.width;
sel.r.height = fmt.format.height;
sel.target = V4L2_SEL_TGT_CROP;
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
memset(&cfg, 0, sizeof(cfg));
/* change fmt&size for RKISP_ISP_PAD_SINK */
fmt.pad = RKISP_ISP_PAD_SINK;
sel.pad = RKISP_ISP_PAD_SINK;
v4l2_subdev_call(isp, pad, set_fmt, &cfg, &fmt);
v4l2_subdev_call(isp, pad, set_selection, &cfg, &sel);
/* change fmt&size for RKISP_ISP_PAD_SOURCE_PATH */
if ((fmt.format.code & RKISP_MEDIA_BUS_FMT_MASK) ==
RKISP_MEDIA_BUS_FMT_BAYER)
fmt.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt.format.width = width;
fmt.format.height = height;
fmt.pad = RKISP_ISP_PAD_SOURCE_PATH;
sel.pad = RKISP_ISP_PAD_SOURCE_PATH;
v4l2_subdev_call(isp, pad, set_fmt, &cfg, &fmt);
v4l2_subdev_call(isp, pad, set_selection, &cfg, &sel);
v4l2_subdev_call(isp, pad, set_fmt, NULL, &fmt);
v4l2_subdev_call(isp, pad, set_selection, NULL, &sel);
/* change fmt&size of MP/SP */
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MP,
@@ -392,27 +367,24 @@ static int _set_pipeline_default_fmt(struct rkisp_device *dev)
dev->isp_ver == ISP_V13 ||
dev->isp_ver == ISP_V20) &&
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
ori_width = dev->active_sensor->fmt[1].format.width;
ori_height = dev->active_sensor->fmt[1].format.height;
ori_code = dev->active_sensor->fmt[1].format.code;
width = dev->active_sensor->fmt[1].format.width;
height = dev->active_sensor->fmt[1].format.height;
code = dev->active_sensor->fmt[1].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX0,
ori_width, ori_height,
rkisp_mbus_pixelcode_to_v4l2(ori_code));
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
}
if (dev->isp_ver == ISP_V20 &&
dev->active_sensor->mbus.type == V4L2_MBUS_CSI2) {
ori_width = dev->active_sensor->fmt[2].format.width;
ori_height = dev->active_sensor->fmt[2].format.height;
ori_code = dev->active_sensor->fmt[2].format.code;
width = dev->active_sensor->fmt[2].format.width;
height = dev->active_sensor->fmt[2].format.height;
code = dev->active_sensor->fmt[2].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX1,
ori_width, ori_height,
rkisp_mbus_pixelcode_to_v4l2(ori_code));
ori_width = dev->active_sensor->fmt[3].format.width;
ori_height = dev->active_sensor->fmt[3].format.height;
ori_code = dev->active_sensor->fmt[3].format.code;
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
width = dev->active_sensor->fmt[3].format.width;
height = dev->active_sensor->fmt[3].format.height;
code = dev->active_sensor->fmt[3].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX2,
ori_width, ori_height,
rkisp_mbus_pixelcode_to_v4l2(ori_code));
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
}
return 0;
}

View File

@@ -3992,36 +3992,17 @@ static void rkisp_clear_first_param_v2x(struct rkisp_isp_params_vdev *params_vde
params_vdev->isp2x_params.module_en_update = 0;
}
static int rkisp_get_isp_fmt(struct rkisp_isp_params_vdev *params_vdev,
struct v4l2_subdev_format *fmt)
{
struct rkisp_device *dev = params_vdev->dev;
int ret;
/* get isp in format */
fmt->pad = RKISP_ISP_PAD_SINK;
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(&dev->isp_sdev.sd, pad, get_fmt, NULL, fmt);
return ret;
}
static void
rkisp_get_param_size_v2x(struct rkisp_isp_params_vdev *params_vdev,
unsigned int sizes[])
{
struct rkisp_device *dev = params_vdev->dev;
struct rkisp_isp_params_val_v2x *priv_val;
struct v4l2_subdev_format fmt;
u32 width, height;
int i, ret;
ret = rkisp_get_isp_fmt(params_vdev, &fmt);
if (ret) {
dev_err(dev->dev, "get format fail\n");
return;
}
width = (fmt.format.width + 15) / 16 + 1;
height = (fmt.format.height + 7) / 8 + 1;
width = (dev->isp_sdev.in_crop.width + 15) / 16 + 1;
height = (dev->isp_sdev.in_crop.height + 7) / 8 + 1;
sizes[0] = sizeof(struct isp2x_isp_params_cfg) + 2 * width * height;

View File

@@ -63,17 +63,17 @@
* Cropping regions of ISP
*
* +---------------------------------------------------------+
* | Sensor image |
* | Sensor image/ISP in_frm |
* | +---------------------------------------------------+ |
* | | ISP_ACQ (for black level) | |
* | | in_frm | |
* | | in_crop | |
* | | +--------------------------------------------+ | |
* | | | ISP_OUT | | |
* | | | in_crop | | |
* | | | +---------------------------------+ | | |
* | | | | ISP_IS | | | |
* | | | | rkisp_isp_subdev: out_crop | | | |
* | | | +---------------------------------+ | | |
* | | | ISP_IS | | |
* | | | rkisp_isp_subdev: out_crop | | |
* | | | | | |
* | | | | | |
* | | | | | |
* | | | | | |
* | | +--------------------------------------------+ | |
* | +---------------------------------------------------+ |
* +---------------------------------------------------------+
@@ -164,6 +164,127 @@ static struct rkisp_sensor_info *sd_to_sensor(struct rkisp_device *dev,
return NULL;
}
int rkisp_align_sensor_resolution(struct rkisp_device *dev,
struct v4l2_rect *crop, bool user)
{
struct v4l2_subdev *sensor = NULL;
struct v4l2_subdev_selection sel;
u32 code = dev->isp_sdev.in_frm.code;
u32 src_w = dev->isp_sdev.in_frm.width;
u32 src_h = dev->isp_sdev.in_frm.height;
u32 dest_w, dest_h, w, h;
int ret = 0;
if (!crop)
return -EINVAL;
if (dev->isp_ver == ISP_V12) {
w = clamp_t(u32, src_w,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V12);
h = clamp_t(u32, src_h,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V12);
} else if (dev->isp_ver == ISP_V13) {
w = clamp_t(u32, src_w,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V13);
h = clamp_t(u32, src_h,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V13);
} else {
w = clamp_t(u32, src_w,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX);
h = clamp_t(u32, src_h,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX);
}
if (dev->active_sensor)
sensor = dev->active_sensor->sd;
if (sensor) {
/* crop info from sensor */
sel.pad = 0;
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sel.target = V4L2_SEL_TGT_CROP;
/* crop by sensor, isp don't input crop */
ret = v4l2_subdev_call(sensor, pad, get_selection, NULL, &sel);
if (!ret && !user) {
crop->left = 0;
crop->top = 0;
crop->width = clamp_t(u32, sel.r.width,
CIF_ISP_INPUT_W_MIN, w);
crop->height = clamp_t(u32, sel.r.height,
CIF_ISP_INPUT_H_MIN, h);
return 0;
}
if (ret) {
sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
/* only crop bounds, want to isp to do input crop */
ret = v4l2_subdev_call(sensor, pad, get_selection, NULL, &sel);
if (!ret) {
crop->left = ALIGN(sel.r.left, 2);
crop->width = ALIGN(sel.r.width, 2);
crop->left = clamp_t(u32, crop->left, 0, w);
crop->top = clamp_t(u32, sel.r.top, 0, h);
crop->width = clamp_t(u32, crop->width,
CIF_ISP_INPUT_W_MIN, w - crop->left);
crop->height = clamp_t(u32, sel.r.height,
CIF_ISP_INPUT_H_MIN, h - crop->top);
return 0;
}
}
}
/* crop from user */
if (user) {
crop->left = clamp_t(u32, crop->left, 0, w);
crop->top = clamp_t(u32, crop->top, 0, h);
crop->width = clamp_t(u32, crop->width,
CIF_ISP_INPUT_W_MIN, w - crop->left);
crop->height = clamp_t(u32, crop->height,
CIF_ISP_INPUT_H_MIN, h - crop->top);
if ((code & RKISP_MEDIA_BUS_FMT_MASK) == RKISP_MEDIA_BUS_FMT_BAYER &&
(ALIGN_DOWN(crop->width, 16) != crop->width ||
ALIGN_DOWN(crop->height, 8) != crop->height))
v4l2_warn(&dev->v4l2_dev,
"Note: bayer raw need width 16 align, height 8 align!\n"
"suggest (%d,%d)/%dx%d, specical requirements, Ignore!\n",
ALIGN_DOWN(crop->left, 4), crop->top,
ALIGN_DOWN(crop->width, 16), ALIGN_DOWN(crop->height, 8));
return 0;
}
/* yuv format */
if ((code & RKISP_MEDIA_BUS_FMT_MASK) != RKISP_MEDIA_BUS_FMT_BAYER) {
crop->left = 0;
crop->top = 0;
crop->width = min_t(u32, src_w, CIF_ISP_INPUT_W_MAX);
crop->height = min_t(u32, src_h, CIF_ISP_INPUT_H_MAX);
return 0;
}
/* bayer raw processed by isp need:
* width 16 align
* height 8 align
* width and height no exceeding the max limit
*/
dest_w = ALIGN_DOWN(w, 16);
dest_h = ALIGN_DOWN(h, 8);
/* try to center of crop
*4 align to no change bayer raw format
*/
crop->left = ALIGN_DOWN((src_w - dest_w) >> 1, 4);
crop->top = (src_h - dest_h) >> 1;
crop->width = dest_w;
crop->height = dest_h;
return 0;
}
struct media_pad *rkisp_media_entity_remote_pad(struct media_pad *pad)
{
struct media_link *link;
@@ -386,7 +507,6 @@ static int rkisp_config_isp(struct rkisp_device *dev)
{
struct ispsd_in_fmt *in_fmt;
struct ispsd_out_fmt *out_fmt;
struct v4l2_mbus_framefmt *in_frm;
struct v4l2_rect *in_crop;
struct rkisp_sensor_info *sensor;
void __iomem *base = dev->base_addr;
@@ -397,7 +517,6 @@ static int rkisp_config_isp(struct rkisp_device *dev)
u32 acq_prop = 0;
sensor = dev->active_sensor;
in_frm = &dev->isp_sdev.in_frm;
in_fmt = &dev->isp_sdev.in_fmt;
out_fmt = &dev->isp_sdev.out_fmt;
in_crop = &dev->isp_sdev.in_crop;
@@ -482,20 +601,20 @@ static int rkisp_config_isp(struct rkisp_device *dev)
writel(0, base + CIF_ISP_ACQ_NR_FRAMES);
/* Acquisition Size */
writel(0, base + CIF_ISP_ACQ_H_OFFS);
writel(0, base + CIF_ISP_ACQ_V_OFFS);
writel(acq_mult * in_frm->width, base + CIF_ISP_ACQ_H_SIZE);
writel(acq_mult * in_crop->left, base + CIF_ISP_ACQ_H_OFFS);
writel(in_crop->top, base + CIF_ISP_ACQ_V_OFFS);
writel(acq_mult * in_crop->width, base + CIF_ISP_ACQ_H_SIZE);
/* ISP Out Area */
writel(in_crop->left, base + CIF_ISP_OUT_H_OFFS);
writel(in_crop->top, base + CIF_ISP_OUT_V_OFFS);
/* ISP Out Area differ with ACQ is only FIFO, so don't crop in this */
writel(0, base + CIF_ISP_OUT_H_OFFS);
writel(0, base + CIF_ISP_OUT_V_OFFS);
writel(in_crop->width, base + CIF_ISP_OUT_H_SIZE);
if (dev->cap_dev.stream[RKISP_STREAM_SP].interlaced) {
writel(in_frm->height / 2, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height / 2, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height / 2, base + CIF_ISP_OUT_V_SIZE);
} else {
writel(in_frm->height, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height, base + CIF_ISP_ACQ_V_SIZE);
writel(in_crop->height, base + CIF_ISP_OUT_V_SIZE);
}
@@ -1103,17 +1222,21 @@ static int rkisp_isp_sd_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct v4l2_mbus_framefmt *mf;
struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
if (!fmt)
goto err;
if (fmt->pad != RKISP_ISP_PAD_SINK &&
fmt->pad != RKISP_ISP_PAD_SOURCE_PATH)
return -EINVAL;
mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
if (!cfg)
goto err;
mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
if (fmt->pad == RKISP_ISP_PAD_SINK) {
@@ -1129,64 +1252,8 @@ static int rkisp_isp_sd_get_fmt(struct v4l2_subdev *sd,
mf->field = V4L2_FIELD_NONE;
return 0;
}
static void rkisp_isp_sd_try_fmt(struct v4l2_subdev *sd,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt)
{
struct rkisp_device *isp_dev = sd_to_isp_dev(sd);
struct rkisp_isp_subdev *isp_sd = &isp_dev->isp_sdev;
const struct ispsd_in_fmt *in_fmt;
const struct ispsd_out_fmt *out_fmt;
switch (pad) {
case RKISP_ISP_PAD_SINK:
in_fmt = find_in_fmt(fmt->code);
if (in_fmt)
fmt->code = in_fmt->mbus_code;
else
fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
if (isp_dev->isp_ver == ISP_V12) {
fmt->width = clamp_t(u32, fmt->width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V12);
fmt->height = clamp_t(u32, fmt->height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V12);
} else if (isp_dev->isp_ver == ISP_V13) {
fmt->width = clamp_t(u32, fmt->width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V13);
fmt->height = clamp_t(u32, fmt->height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V13);
} else {
fmt->width = clamp_t(u32, fmt->width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX);
fmt->height = clamp_t(u32, fmt->height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX);
}
break;
case RKISP_ISP_PAD_SOURCE_PATH:
out_fmt = find_out_fmt(fmt->code);
if (out_fmt)
fmt->code = out_fmt->mbus_code;
else
fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
/* window size is set in s_selection */
fmt->width = isp_sd->out_crop.width;
fmt->height = isp_sd->out_crop.height;
/* full range by default */
if (!fmt->quantization)
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
break;
}
fmt->field = V4L2_FIELD_NONE;
err:
return -EINVAL;
}
static int rkisp_isp_sd_set_fmt(struct v4l2_subdev *sd,
@@ -1195,32 +1262,46 @@ static int rkisp_isp_sd_set_fmt(struct v4l2_subdev *sd,
{
struct rkisp_device *isp_dev = sd_to_isp_dev(sd);
struct rkisp_isp_subdev *isp_sd = &isp_dev->isp_sdev;
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct v4l2_mbus_framefmt *mf;
if (!fmt)
goto err;
if (fmt->pad != RKISP_ISP_PAD_SINK &&
fmt->pad != RKISP_ISP_PAD_SOURCE_PATH)
return -EINVAL;
rkisp_isp_sd_try_fmt(sd, fmt->pad, mf);
goto err;
mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
if (!cfg)
goto err;
mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
fmt->format = *mf;
return 0;
}
if (fmt->pad == RKISP_ISP_PAD_SINK) {
const struct ispsd_in_fmt *in_fmt;
in_fmt = find_in_fmt(mf->code);
if (!in_fmt ||
mf->width < CIF_ISP_INPUT_W_MIN ||
mf->height < CIF_ISP_INPUT_H_MIN)
goto err;
isp_sd->in_fmt = *in_fmt;
isp_sd->in_frm = *mf;
} else if (fmt->pad == RKISP_ISP_PAD_SOURCE_PATH) {
const struct ispsd_out_fmt *out_fmt;
/* Ignore width/height */
out_fmt = find_out_fmt(mf->code);
if (!out_fmt)
goto err;
isp_sd->out_fmt = *out_fmt;
/* window size is set in s_selection */
mf->width = isp_sd->out_crop.width;
mf->height = isp_sd->out_crop.height;
/* full range by default */
if (!mf->quantization)
mf->quantization = V4L2_QUANTIZATION_FULL_RANGE;
/*
* It is quantization for output,
* isp use bt601 limit-range in internal
@@ -1228,118 +1309,148 @@ static int rkisp_isp_sd_set_fmt(struct v4l2_subdev *sd,
isp_sd->quantization = mf->quantization;
}
mf->field = V4L2_FIELD_NONE;
return 0;
err:
return -EINVAL;
}
static void rkisp_isp_sd_try_crop(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
struct v4l2_rect *crop,
u32 pad)
{
struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
struct v4l2_mbus_framefmt in_frm = isp_sd->in_frm;
struct rkisp_device *dev = sd_to_isp_dev(sd);
struct v4l2_rect in_crop = isp_sd->in_crop;
struct v4l2_rect *input = &sel->r;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
in_frm = *v4l2_subdev_get_try_format(sd, cfg, RKISP_ISP_PAD_SINK);
in_crop = *v4l2_subdev_get_try_crop(sd, cfg, RKISP_ISP_PAD_SINK);
}
crop->left = ALIGN(crop->left, 2);
crop->width = ALIGN(crop->width, 2);
input->left = ALIGN(input->left, 2);
input->width = ALIGN(input->width, 2);
if (sel->pad == RKISP_ISP_PAD_SINK) {
input->left = clamp_t(u32, input->left, 0, in_frm.width);
input->top = clamp_t(u32, input->top, 0, in_frm.height);
input->width = clamp_t(u32, input->width, CIF_ISP_INPUT_W_MIN,
in_frm.width - input->left);
input->height = clamp_t(u32, input->height,
CIF_ISP_INPUT_H_MIN,
in_frm.height - input->top);
} else if (sel->pad == RKISP_ISP_PAD_SOURCE_PATH) {
input->left = clamp_t(u32, input->left, 0, in_crop.width);
input->top = clamp_t(u32, input->top, 0, in_crop.height);
input->width = clamp_t(u32, input->width, CIF_ISP_OUTPUT_W_MIN,
in_crop.width - input->left);
input->height = clamp_t(u32, input->height, CIF_ISP_OUTPUT_H_MIN,
in_crop.height - input->top);
if (pad == RKISP_ISP_PAD_SINK) {
/* update sensor info if sensor link be changed */
rkisp_update_sensor_info(dev);
rkisp_align_sensor_resolution(dev, crop, true);
} else if (pad == RKISP_ISP_PAD_SOURCE_PATH) {
crop->left = clamp_t(u32, crop->left, 0, in_crop.width);
crop->top = clamp_t(u32, crop->top, 0, in_crop.height);
crop->width = clamp_t(u32, crop->width, CIF_ISP_OUTPUT_W_MIN,
in_crop.width - crop->left);
crop->height = clamp_t(u32, crop->height, CIF_ISP_OUTPUT_H_MIN,
in_crop.height - crop->top);
}
}
static int rkisp_isp_sd_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
if (sel->pad != RKISP_ISP_PAD_SOURCE_PATH &&
sel->pad != RKISP_ISP_PAD_SINK)
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_rect *try_sel;
try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
sel->r = *try_sel;
return 0;
}
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
if (sel->pad == RKISP_ISP_PAD_SINK) {
sel->r.height = isp_sd->in_frm.height;
sel->r.width = isp_sd->in_frm.width;
sel->r.left = 0;
sel->r.top = 0;
} else {
sel->r = isp_sd->in_crop;
}
break;
case V4L2_SEL_TGT_CROP:
if (sel->pad == RKISP_ISP_PAD_SINK)
sel->r = isp_sd->in_crop;
else
sel->r = isp_sd->out_crop;
break;
default:
return -EINVAL;
}
return 0;
}
static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
struct rkisp_device *dev = sd_to_isp_dev(sd);
struct v4l2_rect *crop;
u32 max_w, max_h;
if (!sel)
goto err;
if (sel->pad != RKISP_ISP_PAD_SOURCE_PATH &&
sel->pad != RKISP_ISP_PAD_SINK)
return -EINVAL;
goto err;
crop = &sel->r;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
if (!cfg)
goto err;
crop = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
}
*crop = isp_sd->in_crop;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
crop->left = 0;
crop->top = 0;
if (sel->pad == RKISP_ISP_PAD_SINK) {
if (dev->isp_ver == ISP_V12) {
max_w = CIF_ISP_INPUT_W_MAX_V12;
max_h = CIF_ISP_INPUT_H_MAX_V12;
} else if (dev->isp_ver == ISP_V13) {
max_w = CIF_ISP_INPUT_W_MAX_V13;
max_h = CIF_ISP_INPUT_H_MAX_V13;
} else {
max_w = CIF_ISP_INPUT_W_MAX;
max_h = CIF_ISP_INPUT_H_MAX;
}
crop->width = min_t(u32, isp_sd->in_frm.width, max_w);
crop->height = min_t(u32, isp_sd->in_frm.height, max_h);
}
break;
case V4L2_SEL_TGT_CROP:
if (sel->pad == RKISP_ISP_PAD_SOURCE_PATH)
*crop = isp_sd->out_crop;
break;
default:
goto err;
}
return 0;
err:
return -EINVAL;
}
static int rkisp_isp_sd_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
{
struct rkisp_isp_subdev *isp_sd = sd_to_isp_sd(sd);
struct rkisp_device *dev = sd_to_isp_dev(sd);
struct v4l2_rect *crop;
if (!sel)
goto err;
if (sel->pad != RKISP_ISP_PAD_SOURCE_PATH &&
sel->pad != RKISP_ISP_PAD_SINK)
goto err;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
goto err;
crop = &sel->r;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
if (!cfg)
goto err;
crop = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
}
rkisp_isp_sd_try_crop(sd, crop, sel->pad);
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad,
sel->r.left, sel->r.top, sel->r.width, sel->r.height);
rkisp_isp_sd_try_crop(sd, cfg, sel);
crop->left, crop->top, crop->width, crop->height);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_rect *try_sel;
try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
sel->r = *try_sel;
return 0;
if (sel->pad == RKISP_ISP_PAD_SINK) {
isp_sd->in_crop = *crop;
/* ISP20 don't have out crop */
if (dev->isp_ver == ISP_V20) {
isp_sd->out_crop = *crop;
isp_sd->out_crop.left = 0;
isp_sd->out_crop.top = 0;
}
} else {
if (dev->isp_ver == ISP_V20)
*crop = isp_sd->out_crop;
isp_sd->out_crop = *crop;
}
if (sel->pad == RKISP_ISP_PAD_SINK)
isp_sd->in_crop = sel->r;
else
isp_sd->out_crop = sel->r;
/* change fmt&size of MP/SP */
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MP,
isp_sd->out_crop.width,
isp_sd->out_crop.height,
V4L2_PIX_FMT_YUYV);
if (dev->isp_ver != ISP_V10_1)
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_SP,
isp_sd->out_crop.width,
isp_sd->out_crop.height,
V4L2_PIX_FMT_YUYV);
return 0;
err:
return -EINVAL;
}
static void rkisp_isp_read_add_fifo_data(struct rkisp_device *dev)

View File

@@ -94,7 +94,7 @@ enum rkisp_isp_pad {
* struct rkisp_isp_subdev - ISP sub-device
*
* See Cropping regions of ISP in rkisp.c for details
* @in_frm: input size, don't have to be equal to sensor size
* @in_frm: input size, equal to sensor size
* @in_fmt: intput format
* @in_crop: crop for sink pad
* @out_fmt: output format
@@ -143,6 +143,9 @@ void rkisp_isp_isr(unsigned int isp_mis, unsigned int isp3a_mis,
irqreturn_t rkisp_vs_isr_handler(int irq, void *ctx);
int rkisp_align_sensor_resolution(struct rkisp_device *dev,
struct v4l2_rect *crop, bool user);
struct media_pad *rkisp_media_entity_remote_pad(struct media_pad *pad);
int rkisp_update_sensor_info(struct rkisp_device *dev);