diff options
-rw-r--r-- | drivers/media/platform/imx8/mxc-isi-cap.c | 41 | ||||
-rw-r--r-- | drivers/media/platform/imx8/mxc-mipi-csi2.c | 24 | ||||
-rw-r--r-- | drivers/media/platform/imx8/ov5640_mipi_v3.c | 171 |
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; |