summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/imx8/mxc-isi-cap.c41
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2.c24
-rw-r--r--drivers/media/platform/imx8/ov5640_mipi_v3.c171
3 files changed, 186 insertions, 50 deletions
diff --git a/drivers/media/platform/imx8/mxc-isi-cap.c b/drivers/media/platform/imx8/mxc-isi-cap.c
index 0eaa1fc03c11..cf86e9968f6a 100644
--- a/drivers/media/platform/imx8/mxc-isi-cap.c
+++ b/drivers/media/platform/imx8/mxc-isi-cap.c
@@ -840,6 +840,7 @@ static int mxc_isi_cap_try_fmt_mplane(struct file *file, void *fh,
static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
{
struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
struct v4l2_subdev_format src_fmt;
struct media_pad *source_pad;
struct v4l2_subdev *src_sd;
@@ -861,9 +862,20 @@ static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
src_fmt.pad = source_pad->index;
src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ src_fmt.format.width = dst_f->width;
+ src_fmt.format.height = dst_f->height;
+ ret = v4l2_subdev_call(src_sd, pad, set_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, set remote fmt fail!\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&src_fmt, 0, sizeof(src_fmt));
+ src_fmt.pad = source_pad->index;
+ src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(src_sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD) {
- v4l2_err(mxc_isi->v4l2_dev, "%s, get remote fmt faile!\n", __func__);
+ v4l2_err(mxc_isi->v4l2_dev, "%s, get remote fmt fail!\n", __func__);
return -EINVAL;
}
@@ -872,6 +884,14 @@ static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
set_frame_bounds(src_f, src_fmt.format.width, src_fmt.format.height);
+ if (dst_f->width > src_f->width || dst_f->height > src_f->height) {
+ dev_err(&mxc_isi->pdev->dev,
+ "%s: src:(%d,%d), dst:(%d,%d) Not support upscale\n", __func__,
+ src_f->width, src_f->height,
+ dst_f->width, dst_f->height);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -881,7 +901,6 @@ static int mxc_isi_cap_s_fmt_mplane(struct file *file, void *priv,
struct mxc_isi_dev *mxc_isi = video_drvdata(file);
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
- struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
struct mxc_isi_fmt *fmt;
int bpl;
int i;
@@ -954,16 +973,18 @@ static int mxc_isi_cap_s_fmt_mplane(struct file *file, void *priv,
set_frame_bounds(dst_f, pix->width, pix->height);
- mxc_isi_source_fmt_init(mxc_isi);
+ return 0;
+}
+
+static int mxc_isi_config_parm(struct mxc_isi_dev *mxc_isi)
+{
+ int ret;
- if ((dst_f->width > src_f->width) ||
- (dst_f->height > src_f->height)) {
- dev_err(&mxc_isi->pdev->dev, "%s: Not support upscale\n", __func__);
+ ret = mxc_isi_source_fmt_init(mxc_isi);
+ if (ret < 0)
return -EINVAL;
- }
mxc_isi_channel_init(mxc_isi);
- /* configure mxc isi channel */
mxc_isi_channel_config(mxc_isi);
return 0;
@@ -977,6 +998,10 @@ static int mxc_isi_cap_streamon(struct file *file, void *priv,
dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+ ret = mxc_isi_config_parm(mxc_isi);
+ if (ret < 0)
+ return -EINVAL;
+
ret = vb2_ioctl_streamon(file, priv, type);
mxc_isi_channel_enable(mxc_isi);
mxc_isi_pipeline_enable(mxc_isi, 1);
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2.c b/drivers/media/platform/imx8/mxc-mipi-csi2.c
index 7bdd8a05973f..313ec77cd2cf 100644
--- a/drivers/media/platform/imx8/mxc-mipi-csi2.c
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2.c
@@ -603,6 +603,30 @@ static int mipi_csi2_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *fmt)
{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sen_sd;
+ struct media_pad *source_pad;
+ int ret;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ fmt->pad = source_pad->index;
+ ret = v4l2_subdev_call(sen_sd, pad, set_fmt, NULL, fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return -EINVAL;
+
return 0;
}
diff --git a/drivers/media/platform/imx8/ov5640_mipi_v3.c b/drivers/media/platform/imx8/ov5640_mipi_v3.c
index 7aed344bf7d7..a3a2d2e198e4 100644
--- a/drivers/media/platform/imx8/ov5640_mipi_v3.c
+++ b/drivers/media/platform/imx8/ov5640_mipi_v3.c
@@ -44,12 +44,12 @@
enum ov5640_mode {
ov5640_mode_MIN = 0,
- ov5640_mode_VGA_640_480 = 0,
- ov5640_mode_NTSC_720_480 = 1,
- ov5640_mode_720P_1280_720 = 2,
- ov5640_mode_1080P_1920_1080 = 3,
+ ov5640_mode_1080P_1920_1080 = 0,
+ ov5640_mode_720P_1280_720 = 1,
+ ov5640_mode_NTSC_720_480 = 2,
+ ov5640_mode_VGA_640_480 = 3,
ov5640_mode_QSXGA_2592_1944 = 4,
- ov5640_mode_MAX = 5,
+ ov5640_mode_MAX = 4,
ov5640_mode_INIT = 0xff, /*only for sensor init*/
};
@@ -355,27 +355,27 @@ static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
{
- {ov5640_mode_VGA_640_480, -1, 0, 0, NULL, 0},
- {ov5640_mode_NTSC_720_480, -1, 0, 0, NULL, 0},
- {ov5640_mode_720P_1280_720, -1, 0, 0, NULL, 0},
{ov5640_mode_1080P_1920_1080, -1, 0, 0, NULL, 0},
+ {ov5640_mode_720P_1280_720, -1, 0, 0, NULL, 0},
+ {ov5640_mode_NTSC_720_480, -1, 0, 0, NULL, 0},
+ {ov5640_mode_VGA_640_480, -1, 0, 0, NULL, 0},
{ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
ov5640_setting_15fps_QSXGA_2592_1944,
ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
},
{
- {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480,
- ov5640_setting_30fps_VGA_640_480,
- ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
- {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
- ov5640_setting_30fps_NTSC_720_480,
- ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
- {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
- ov5640_setting_30fps_720P_1280_720,
- ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
{ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
ov5640_setting_30fps_1080P_1920_1080,
ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
+ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+ ov5640_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+ ov5640_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480,
+ ov5640_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
{ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
},
};
@@ -438,6 +438,23 @@ static struct ov5640 *to_ov5640(const struct i2c_client *client)
return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
}
+static enum ov5640_frame_rate to_ov5640_frame_rate(struct v4l2_fract *timeperframe)
+{
+ enum ov5640_frame_rate rate;
+ u32 tgt_fps; /* target frames per secound */
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ if (tgt_fps == 30)
+ rate = ov5640_30_fps;
+ else if (tgt_fps == 15)
+ rate = ov5640_15_fps;
+ else
+ rate = -EINVAL;
+
+ return rate;
+}
+
static uint16_t find_hs_configure(struct ov5640 *sensor)
{
struct device *dev = &sensor->i2c_client->dev;
@@ -683,10 +700,12 @@ static void ov5640_start(struct ov5640 *sensor)
udelay(1000);
}
-static int ov5640_change_mode(struct ov5640 *sensor,
- enum ov5640_frame_rate frame_rate, enum ov5640_mode mode)
+static int ov5640_change_mode(struct ov5640 *sensor)
{
struct reg_value *pModeSetting = NULL;
+ enum ov5640_mode mode = sensor->streamcap.capturemode;
+ enum ov5640_frame_rate frame_rate =
+ to_ov5640_frame_rate(&sensor->streamcap.timeperframe);
int ArySize = 0, retval = 0;
if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
@@ -813,10 +832,10 @@ static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
struct ov5640 *sensor = to_ov5640(client);
struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
u32 tgt_fps; /* target frames per secound */
- enum ov5640_frame_rate frame_rate;
enum ov5640_mode mode = a->parm.capture.capturemode;
int ret = 0;
+
switch (a->type) {
/* This is the only case currently handled. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -839,28 +858,13 @@ static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
timeperframe->numerator = 1;
}
- /* Actual frame rate we use */
- tgt_fps = timeperframe->denominator /
- timeperframe->numerator;
-
- if (tgt_fps == 30)
- frame_rate = ov5640_30_fps;
- else if (tgt_fps == 15)
- frame_rate = ov5640_15_fps;
- else {
- pr_err(" The camera frame rate is not supported!\n");
- goto error;
+ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+ pr_err("The camera mode[%d] is not supported!\n", mode);
+ return -EINVAL;
}
- ret = ov5640_change_mode(sensor, frame_rate, mode);
- if (ret < 0)
- goto error;
-
- sensor->streamcap.timeperframe = *timeperframe;
sensor->streamcap.capturemode = mode;
- sensor->pix.width = ov5640_mode_info_data[frame_rate][mode].width;
- sensor->pix.height = ov5640_mode_info_data[frame_rate][mode].height;
-
+ sensor->streamcap.timeperframe = *timeperframe;
break;
/* These are all the possible cases. */
@@ -881,7 +885,6 @@ static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
break;
}
-error:
return ret;
}
@@ -899,6 +902,88 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+static struct ov5640_mode_info *get_max_resolution(enum ov5640_frame_rate rate)
+{
+ u32 max_width;
+ enum ov5640_mode mode;
+ int i;
+
+ mode = 0;
+ max_width = ov5640_mode_info_data[rate][0].width;
+
+ for (i = 0; i < (ov5640_mode_MAX + 1); i++) {
+ if (ov5640_mode_info_data[rate][i].width > max_width) {
+ max_width = ov5640_mode_info_data[rate][i].width;
+ mode = i;
+ }
+ }
+ return &ov5640_mode_info_data[rate][mode];
+}
+
+static struct ov5640_mode_info *match(struct v4l2_mbus_framefmt *fmt,
+ enum ov5640_frame_rate rate)
+{
+ struct ov5640_mode_info *info;
+ int i;
+
+ for (i = 0; i < (ov5640_mode_MAX + 1); i++) {
+ if (fmt->width == ov5640_mode_info_data[rate][i].width &&
+ fmt->height == ov5640_mode_info_data[rate][i].height) {
+ info = &ov5640_mode_info_data[rate][i];
+ break;
+ }
+ }
+ if (i == ov5640_mode_MAX + 1)
+ info = NULL;
+
+ return info;
+}
+
+static void try_to_find_resolution(struct ov5640 *sensor,
+ struct v4l2_mbus_framefmt *mf)
+{
+ enum ov5640_mode mode = sensor->streamcap.capturemode;
+ struct v4l2_fract *timeperframe = &sensor->streamcap.timeperframe;
+ enum ov5640_frame_rate frame_rate = to_ov5640_frame_rate(timeperframe);
+ struct device *dev = &sensor->i2c_client->dev;
+ struct ov5640_mode_info *info;
+ bool found = false;
+
+ if ((mf->width == ov5640_mode_info_data[frame_rate][mode].width) &&
+ (mf->height == ov5640_mode_info_data[frame_rate][mode].height)) {
+ info = &ov5640_mode_info_data[frame_rate][mode];
+ found = true;
+ } else {
+ /* get mode info according to frame user's width and height */
+ info = match(mf, frame_rate);
+ if (info == NULL) {
+ frame_rate ^= 0x1;
+ info = match(mf, frame_rate);
+ if (info) {
+ sensor->streamcap.capturemode = -1;
+ dev_err(dev, "%s %dx%d only support %s(fps)\n", __func__,
+ info->width, info->height,
+ (frame_rate == 0) ? "15fps" : "30fps");
+ return;
+ }
+ goto max_resolution;
+ }
+ found = true;
+ }
+
+ /* get max resolution to resize */
+max_resolution:
+ if (!found) {
+ frame_rate ^= 0x1;
+ info = get_max_resolution(frame_rate);
+ }
+
+ sensor->streamcap.capturemode = info->mode;
+ sensor->streamcap.timeperframe.denominator = (frame_rate) ? 30 : 15;
+ sensor->pix.width = info->width;
+ sensor->pix.height = info->height;
+}
+
static int ov5640_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -907,6 +992,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov5640 *sensor = to_ov5640(client);
+ int ret;
if (format->pad)
return -EINVAL;
@@ -917,13 +1003,15 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
}
mf->field = V4L2_FIELD_NONE;
+ try_to_find_resolution(sensor, mf);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
+ ret = ov5640_change_mode(sensor);
sensor->fmt = fmt;
- return 0;
+ return ret;
}
static int ov5640_get_fmt(struct v4l2_subdev *sd,
@@ -933,7 +1021,6 @@ static int ov5640_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf = &format->format;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov5640 *sensor = to_ov5640(client);
- /*const struct ov5640_datafmt *fmt = sensor->fmt;*/
if (format->pad)
return -EINVAL;