From ec6859b23f2212275fbd476df14d7a94839c2a35 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:13 -0400 Subject: media: Rename CAMSS driver path Support for camera subsystem on QComm MSM8996/APQ8096 is to be added so remove hardware version from CAMSS driver's path. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-video.c | 859 ++++++++++++++++++++++++ 1 file changed, 859 insertions(+) create mode 100644 drivers/media/platform/qcom/camss/camss-video.c (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c new file mode 100644 index 000000000000..0e7b842854ec --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -0,0 +1,859 @@ +/* + * camss-video.c + * + * Qualcomm MSM Camera Subsystem - V4L2 device node + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2018 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "camss-video.h" +#include "camss.h" + +struct fract { + u8 numerator; + u8 denominator; +}; + +/* + * struct camss_format_info - ISP media bus format information + * @code: V4L2 media bus format code + * @pixelformat: V4L2 pixel format FCC identifier + * @planes: Number of planes + * @hsub: Horizontal subsampling (for each plane) + * @vsub: Vertical subsampling (for each plane) + * @bpp: Bits per pixel when stored in memory (for each plane) + */ +struct camss_format_info { + u32 code; + u32 pixelformat; + u8 planes; + struct fract hsub[3]; + struct fract vsub[3]; + unsigned int bpp[3]; +}; + +static const struct camss_format_info formats_rdi[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, +}; + +static const struct camss_format_info formats_pix[] = { + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, +}; + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static int video_find_format(u32 code, u32 pixelformat, + const struct camss_format_info *formats, + unsigned int nformats) +{ + int i; + + for (i = 0; i < nformats; i++) { + if (formats[i].code == code && + formats[i].pixelformat == pixelformat) + return i; + } + + for (i = 0; i < nformats; i++) + if (formats[i].code == code) + return i; + + WARN_ON(1); + + return -EINVAL; +} + +/* + * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane + * @mbus: v4l2_mbus_framefmt format (input) + * @pix: v4l2_pix_format_mplane format (output) + * @f: a pointer to formats array element to be used for the conversion + * @alignment: bytesperline alignment value + * + * Fill the output pix structure with information from the input mbus format. + * + * Return 0 on success or a negative error code otherwise + */ +static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus, + struct v4l2_pix_format_mplane *pix, + const struct camss_format_info *f, + unsigned int alignment) +{ + unsigned int i; + u32 bytesperline; + + memset(pix, 0, sizeof(*pix)); + v4l2_fill_pix_format_mplane(pix, mbus); + pix->pixelformat = f->pixelformat; + pix->num_planes = f->planes; + for (i = 0; i < pix->num_planes; i++) { + bytesperline = pix->width / f->hsub[i].numerator * + f->hsub[i].denominator * f->bpp[i] / 8; + bytesperline = ALIGN(bytesperline, alignment); + pix->plane_fmt[i].bytesperline = bytesperline; + pix->plane_fmt[i].sizeimage = pix->height / + f->vsub[i].numerator * f->vsub[i].denominator * + bytesperline; + } + + return 0; +} + +static struct v4l2_subdev *video_remote_subdev(struct camss_video *video, + u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(&video->pad); + + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +static int video_get_subdev_format(struct camss_video *video, + struct v4l2_format *format) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + u32 pad; + int ret; + + subdev = video_remote_subdev(video, &pad); + if (subdev == NULL) + return -EPIPE; + + fmt.pad = pad; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret) + return ret; + + ret = video_find_format(fmt.format.code, + format->fmt.pix_mp.pixelformat, + video->formats, video->nformats); + if (ret < 0) + return ret; + + format->type = video->type; + + return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp, + &video->formats[ret], video->bpl_alignment); +} + +/* ----------------------------------------------------------------------------- + * Video queue operations + */ + +static int video_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct camss_video *video = vb2_get_drv_priv(q); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + unsigned int i; + + if (*num_planes) { + if (*num_planes != format->num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) + if (sizes[i] < format->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *num_planes = format->num_planes; + + for (i = 0; i < *num_planes; i++) + sizes[i] = format->plane_fmt[i].sizeimage; + + return 0; +} + +static int video_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, + vb); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + struct sg_table *sgt; + unsigned int i; + + for (i = 0; i < format->num_planes; i++) { + sgt = vb2_dma_sg_plane_desc(vb, i); + if (!sgt) + return -EFAULT; + + buffer->addr[i] = sg_dma_address(sgt->sgl); + } + + if (format->pixelformat == V4L2_PIX_FMT_NV12 || + format->pixelformat == V4L2_PIX_FMT_NV21 || + format->pixelformat == V4L2_PIX_FMT_NV16 || + format->pixelformat == V4L2_PIX_FMT_NV61) + buffer->addr[1] = buffer->addr[0] + + format->plane_fmt[0].bytesperline * + format->height; + + return 0; +} + +static int video_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + unsigned int i; + + for (i = 0; i < format->num_planes; i++) { + if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i)) + return -EINVAL; + + vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage); + } + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static void video_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, + vb); + + video->ops->queue_buffer(video, buffer); +} + +static int video_check_format(struct camss_video *video) +{ + struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp; + struct v4l2_format format; + struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp; + int ret; + + sd_pix->pixelformat = pix->pixelformat; + ret = video_get_subdev_format(video, &format); + if (ret < 0) + return ret; + + if (pix->pixelformat != sd_pix->pixelformat || + pix->height != sd_pix->height || + pix->width != sd_pix->width || + pix->num_planes != sd_pix->num_planes || + pix->field != format.fmt.pix_mp.field) + return -EPIPE; + + return 0; +} + +static int video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct camss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + ret = media_pipeline_start(&vdev->entity, &video->pipe); + if (ret < 0) + return ret; + + ret = video_check_format(video); + if (ret < 0) + goto error; + + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto error; + } + + return 0; + +error: + media_pipeline_stop(&vdev->entity); + + video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void video_stop_streaming(struct vb2_queue *q) +{ + struct camss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + v4l2_subdev_call(subdev, video, s_stream, 0); + } + + media_pipeline_stop(&vdev->entity); + + video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops msm_video_vb2_q_ops = { + .queue_setup = video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = video_buf_init, + .buf_prepare = video_buf_prepare, + .buf_queue = video_buf_queue, + .start_streaming = video_start_streaming, + .stop_streaming = video_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct camss_video *video = video_drvdata(file); + + strlcpy(cap->driver, "qcom-camss", sizeof(cap->driver)); + strlcpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(video->camss->dev)); + + return 0; +} + +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct camss_video *video = video_drvdata(file); + int i, j, k; + + if (f->type != video->type) + return -EINVAL; + + if (f->index >= video->nformats) + return -EINVAL; + + /* find index "i" of "k"th unique pixelformat in formats array */ + k = -1; + for (i = 0; i < video->nformats; i++) { + for (j = 0; j < i; j++) { + if (video->formats[i].pixelformat == + video->formats[j].pixelformat) + break; + } + + if (j == i) + k++; + + if (k == f->index) + break; + } + + if (k < f->index) + return -EINVAL; + + f->pixelformat = video->formats[i].pixelformat; + + return 0; +} + +static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + + *f = video->active_fmt; + + return 0; +} + +static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp; + const struct camss_format_info *fi; + struct v4l2_plane_pix_format *p; + u32 bytesperline[3] = { 0 }; + u32 sizeimage[3] = { 0 }; + u32 width, height; + u32 bpl, lines; + int i, j; + + pix_mp = &f->fmt.pix_mp; + + if (video->line_based) + for (i = 0; i < pix_mp->num_planes && i < 3; i++) { + p = &pix_mp->plane_fmt[i]; + bytesperline[i] = clamp_t(u32, p->bytesperline, + 1, 65528); + sizeimage[i] = clamp_t(u32, p->sizeimage, + bytesperline[i], + bytesperline[i] * 4096); + } + + for (j = 0; j < video->nformats; j++) + if (pix_mp->pixelformat == video->formats[j].pixelformat) + break; + + if (j == video->nformats) + j = 0; /* default format */ + + fi = &video->formats[j]; + width = pix_mp->width; + height = pix_mp->height; + + memset(pix_mp, 0, sizeof(*pix_mp)); + + pix_mp->pixelformat = fi->pixelformat; + pix_mp->width = clamp_t(u32, width, 1, 8191); + pix_mp->height = clamp_t(u32, height, 1, 8191); + pix_mp->num_planes = fi->planes; + for (i = 0; i < pix_mp->num_planes; i++) { + bpl = pix_mp->width / fi->hsub[i].numerator * + fi->hsub[i].denominator * fi->bpp[i] / 8; + bpl = ALIGN(bpl, video->bpl_alignment); + pix_mp->plane_fmt[i].bytesperline = bpl; + pix_mp->plane_fmt[i].sizeimage = pix_mp->height / + fi->vsub[i].numerator * fi->vsub[i].denominator * bpl; + } + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; + pix_mp->flags = 0; + pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace); + pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, + pix_mp->colorspace, pix_mp->ycbcr_enc); + pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace); + + if (video->line_based) + for (i = 0; i < pix_mp->num_planes; i++) { + p = &pix_mp->plane_fmt[i]; + p->bytesperline = clamp_t(u32, p->bytesperline, + 1, 65528); + p->sizeimage = clamp_t(u32, p->sizeimage, + p->bytesperline, + p->bytesperline * 4096); + lines = p->sizeimage / p->bytesperline; + + if (p->bytesperline < bytesperline[i]) + p->bytesperline = ALIGN(bytesperline[i], 8); + + if (p->sizeimage < p->bytesperline * lines) + p->sizeimage = p->bytesperline * lines; + + if (p->sizeimage < sizeimage[i]) + p->sizeimage = sizeimage[i]; + } + + return 0; +} + +static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + + return __video_try_fmt(video, f); +} + +static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + int ret; + + if (vb2_is_busy(&video->vb2_q)) + return -EBUSY; + + ret = __video_try_fmt(video, f); + if (ret < 0) + return ret; + + video->active_fmt = *f; + + return 0; +} + +static int video_enum_input(struct file *file, void *fh, + struct v4l2_input *input) +{ + if (input->index > 0) + return -EINVAL; + + strlcpy(input->name, "camera", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int video_g_input(struct file *file, void *fh, unsigned int *input) +{ + *input = 0; + + return 0; +} + +static int video_s_input(struct file *file, void *fh, unsigned int input) +{ + return input == 0 ? 0 : -EINVAL; +} + +static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { + .vidioc_querycap = video_querycap, + .vidioc_enum_fmt_vid_cap_mplane = video_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, + .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, + .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_input = video_enum_input, + .vidioc_g_input = video_g_input, + .vidioc_s_input = video_s_input, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static int video_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct camss_video *video = video_drvdata(file); + struct v4l2_fh *vfh; + int ret; + + mutex_lock(&video->lock); + + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); + if (vfh == NULL) { + ret = -ENOMEM; + goto error_alloc; + } + + v4l2_fh_init(vfh, vdev); + v4l2_fh_add(vfh); + + file->private_data = vfh; + + ret = v4l2_pipeline_pm_use(&vdev->entity, 1); + if (ret < 0) { + dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", + ret); + goto error_pm_use; + } + + mutex_unlock(&video->lock); + + return 0; + +error_pm_use: + v4l2_fh_release(file); + +error_alloc: + mutex_unlock(&video->lock); + + return ret; +} + +static int video_release(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + + vb2_fop_release(file); + + v4l2_pipeline_pm_use(&vdev->entity, 0); + + file->private_data = NULL; + + return 0; +} + +static const struct v4l2_file_operations msm_vid_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = video_open, + .release = video_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +/* ----------------------------------------------------------------------------- + * CAMSS video core + */ + +static void msm_video_release(struct video_device *vdev) +{ + struct camss_video *video = video_get_drvdata(vdev); + + media_entity_cleanup(&vdev->entity); + + mutex_destroy(&video->q_lock); + mutex_destroy(&video->lock); + + if (atomic_dec_and_test(&video->camss->ref_count)) + camss_delete(video->camss); +} + +/* + * msm_video_init_format - Helper function to initialize format + * @video: struct camss_video + * + * Initialize pad format with default value. + * + * Return 0 on success or a negative error code otherwise + */ +static int msm_video_init_format(struct camss_video *video) +{ + int ret; + struct v4l2_format format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = 1920, + .height = 1080, + .pixelformat = video->formats[0].pixelformat, + }, + }; + + ret = __video_try_fmt(video, &format); + if (ret < 0) + return ret; + + video->active_fmt = format; + + return 0; +} + +/* + * msm_video_register - Register a video device node + * @video: struct camss_video + * @v4l2_dev: V4L2 device + * @name: name to be used for the video device node + * + * Initialize and register a video device node to a V4L2 device. Also + * initialize the vb2 queue. + * + * Return 0 on success or a negative error code otherwise + */ + +int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, + const char *name, int is_pix) +{ + struct media_pad *pad = &video->pad; + struct video_device *vdev; + struct vb2_queue *q; + int ret; + + vdev = &video->vdev; + + mutex_init(&video->q_lock); + + q = &video->vb2_q; + q->drv_priv = video; + q->mem_ops = &vb2_dma_sg_memops; + q->ops = &msm_video_vb2_q_ops; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->buf_struct_size = sizeof(struct camss_buffer); + q->dev = video->camss->dev; + q->lock = &video->q_lock; + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); + goto error_vb2_init; + } + + pad->flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, pad); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", + ret); + goto error_media_init; + } + + mutex_init(&video->lock); + + video->formats = formats_rdi; + video->nformats = ARRAY_SIZE(formats_rdi); + if (is_pix) { + video->formats = formats_pix; + video->nformats = ARRAY_SIZE(formats_pix); + } + + ret = msm_video_init_format(video); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret); + goto error_video_register; + } + + vdev->fops = &msm_vid_fops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + vdev->ioctl_ops = &msm_vid_ioctl_ops; + vdev->release = msm_video_release; + vdev->v4l2_dev = v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = &video->vb2_q; + vdev->lock = &video->lock; + strlcpy(vdev->name, name, sizeof(vdev->name)); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", + ret); + goto error_video_register; + } + + video_set_drvdata(vdev, video); + atomic_inc(&video->camss->ref_count); + + return 0; + +error_video_register: + media_entity_cleanup(&vdev->entity); + mutex_destroy(&video->lock); +error_media_init: + vb2_queue_release(&video->vb2_q); +error_vb2_init: + mutex_destroy(&video->q_lock); + + return ret; +} + +void msm_video_stop_streaming(struct camss_video *video) +{ + if (vb2_is_streaming(&video->vb2_q)) + vb2_queue_release(&video->vb2_q); +} + +void msm_video_unregister(struct camss_video *video) +{ + atomic_inc(&video->camss->ref_count); + video_unregister_device(&video->vdev); + atomic_dec(&video->camss->ref_count); +} -- cgit v1.2.3 From b873663bd85fff5e43bcedb5cc5360f2aa992e05 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:14 -0400 Subject: media: camss: Use SPDX license headers Use SPDX license headers for all files of the Qualcomm CAMSS driver. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 10 +--------- drivers/media/platform/qcom/camss/camss-csid.h | 10 +--------- drivers/media/platform/qcom/camss/camss-csiphy.c | 10 +--------- drivers/media/platform/qcom/camss/camss-csiphy.h | 10 +--------- drivers/media/platform/qcom/camss/camss-ispif.c | 10 +--------- drivers/media/platform/qcom/camss/camss-ispif.h | 10 +--------- drivers/media/platform/qcom/camss/camss-vfe.c | 10 +--------- drivers/media/platform/qcom/camss/camss-vfe.h | 10 +--------- drivers/media/platform/qcom/camss/camss-video.c | 10 +--------- drivers/media/platform/qcom/camss/camss-video.h | 10 +--------- drivers/media/platform/qcom/camss/camss.c | 10 +--------- drivers/media/platform/qcom/camss/camss.h | 10 +--------- 12 files changed, 12 insertions(+), 108 deletions(-) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 39ea27b9da3b..c0fef1787ad4 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss-csid.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 8012222b81ad..ae1d045844fb 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss-csid.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_CSID_H #define QC_MSM_CAMSS_CSID_H diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 642de259dc6b..b37e69161712 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss-csiphy.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2016-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 9a422095b773..76fa2395664c 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss-csiphy.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2016-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_CSIPHY_H #define QC_MSM_CAMSS_CSIPHY_H diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 636d5e712037..5ad719d7e437 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss-ispif.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index c90e1598943a..a5dfb4f27d0e 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss-ispif.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_ISPIF_H #define QC_MSM_CAMSS_ISPIF_H diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 380b90bdd720..256dc2d42411 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss-vfe.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 5aa740741de8..6b4258d8761e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss-vfe.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_VFE_H #define QC_MSM_CAMSS_VFE_H diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 0e7b842854ec..16e74b2448fe 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss-video.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss-video.h b/drivers/media/platform/qcom/camss/camss-video.h index 821c1ef6b5c7..aa35e8cc6fd5 100644 --- a/drivers/media/platform/qcom/camss/camss-video.h +++ b/drivers/media/platform/qcom/camss/camss-video.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss-video.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_VIDEO_H #define QC_MSM_CAMSS_VIDEO_H diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index d1d27fca2958..45285eb6842c 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * camss.c * @@ -5,15 +6,6 @@ * * Copyright (c) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 0e7cfe6bfbe5..fb1c2f946e71 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * camss.h * @@ -5,15 +6,6 @@ * * Copyright (c) 2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef QC_MSM_CAMSS_H #define QC_MSM_CAMSS_H -- cgit v1.2.3 From cba3819d1e93fb77a9323554ccf7b564276c089b Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:35 -0400 Subject: media: camss: Format configuration per hardware version As the 8x16 and 8x96 support different formats, separate the arrays which contain the supported formats. For the VFE also add separate arrays for RDI and PIX subdevices. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 196 +++++++++++++++++++---- drivers/media/platform/qcom/camss/camss-csid.h | 2 + drivers/media/platform/qcom/camss/camss-csiphy.c | 145 ++++++++--------- drivers/media/platform/qcom/camss/camss-csiphy.h | 2 + drivers/media/platform/qcom/camss/camss-ispif.c | 43 ++++- drivers/media/platform/qcom/camss/camss-ispif.h | 2 + drivers/media/platform/qcom/camss/camss-vfe.c | 189 ++++++++++++---------- drivers/media/platform/qcom/camss/camss-vfe.h | 2 + drivers/media/platform/qcom/camss/camss-video.c | 97 ++++++++++- 9 files changed, 467 insertions(+), 211 deletions(-) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 915835ee3271..db960da560c9 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -62,7 +62,7 @@ #define CSID_RESET_TIMEOUT_MS 500 -struct csid_fmts { +struct csid_format { u32 code; u8 data_type; u8 decode_format; @@ -70,7 +70,7 @@ struct csid_fmts { u8 spp; /* bus samples per pixel */ }; -static const struct csid_fmts csid_input_fmts[] = { +static const struct csid_format csid_formats_8x16[] = { { MEDIA_BUS_FMT_UYVY8_2X8, DATA_TYPE_YUV422_8BIT, @@ -185,17 +185,135 @@ static const struct csid_fmts csid_input_fmts[] = { } }; -static const struct csid_fmts *csid_get_fmt_entry(u32 code) +static const struct csid_format csid_formats_8x96[] = { + { + MEDIA_BUS_FMT_UYVY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_VYUY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YUYV8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YVYU8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_SBGGR8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + } +}; + +static const struct csid_format *csid_get_fmt_entry( + const struct csid_format *formats, + unsigned int nformat, + u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) - if (code == csid_input_fmts[i].code) - return &csid_input_fmts[i]; + for (i = 0; i < nformat; i++) + if (code == formats[i].code) + return &formats[i]; WARN(1, "Unknown format\n"); - return &csid_input_fmts[0]; + return &formats[0]; } /* @@ -242,10 +360,13 @@ static int csid_set_clock_rates(struct csid_device *csid) !strcmp(clock->name, "csi1") || !strcmp(clock->name, "csi2") || !strcmp(clock->name, "csi3")) { - u8 bpp = csid_get_fmt_entry( - csid->fmt[MSM_CSIPHY_PAD_SINK].code)->bpp; + const struct csid_format *f = csid_get_fmt_entry( + csid->formats, + csid->nformats, + csid->fmt[MSM_CSIPHY_PAD_SINK].code); u8 num_lanes = csid->phy.lane_cnt; - u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); + u64 min_rate = pixel_clock * f->bpp / + (2 * num_lanes * 4); long rate; camss_add_clock_margin(&min_rate); @@ -408,9 +529,10 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) /* Config Test Generator */ struct v4l2_mbus_framefmt *f = &csid->fmt[MSM_CSID_PAD_SRC]; - u8 bpp = csid_get_fmt_entry(f->code)->bpp; - u8 spp = csid_get_fmt_entry(f->code)->spp; - u32 num_bytes_per_line = f->width * bpp * spp / 8; + const struct csid_format *format = csid_get_fmt_entry( + csid->formats, csid->nformats, f->code); + u32 num_bytes_per_line = + f->width * format->bpp * format->spp / 8; u32 num_lines = f->height; /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ @@ -426,8 +548,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(ver, 0)); - dt = csid_get_fmt_entry( - csid->fmt[MSM_CSID_PAD_SRC].code)->data_type; + dt = format->data_type; /* 5:0 data type */ val = dt; @@ -439,9 +560,12 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(ver, 0)); - df = csid_get_fmt_entry( - csid->fmt[MSM_CSID_PAD_SRC].code)->decode_format; + df = format->decode_format; } else { + struct v4l2_mbus_framefmt *f = + &csid->fmt[MSM_CSID_PAD_SINK]; + const struct csid_format *format = csid_get_fmt_entry( + csid->formats, csid->nformats, f->code); struct csid_phy_config *phy = &csid->phy; val = phy->lane_cnt - 1; @@ -456,10 +580,8 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1); - dt = csid_get_fmt_entry( - csid->fmt[MSM_CSID_PAD_SINK].code)->data_type; - df = csid_get_fmt_entry( - csid->fmt[MSM_CSID_PAD_SINK].code)->decode_format; + dt = format->data_type; + df = format->decode_format; } /* Config LUT */ @@ -534,12 +656,12 @@ static void csid_try_format(struct csid_device *csid, case MSM_CSID_PAD_SINK: /* Set format on sink pad */ - for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) - if (fmt->code == csid_input_fmts[i].code) + for (i = 0; i < csid->nformats; i++) + if (fmt->code == csid->formats[i].code) break; /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(csid_input_fmts)) + if (i >= csid->nformats) fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->width = clamp_t(u32, fmt->width, 1, 8191); @@ -563,12 +685,12 @@ static void csid_try_format(struct csid_device *csid, /* Test generator is enabled, set format on source*/ /* pad to allow test generator usage */ - for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) - if (csid_input_fmts[i].code == fmt->code) + for (i = 0; i < csid->nformats; i++) + if (csid->formats[i].code == fmt->code) break; /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(csid_input_fmts)) + if (i >= csid->nformats) fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->width = clamp_t(u32, fmt->width, 1, 8191); @@ -597,10 +719,10 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; if (code->pad == MSM_CSID_PAD_SINK) { - if (code->index >= ARRAY_SIZE(csid_input_fmts)) + if (code->index >= csid->nformats) return -EINVAL; - code->code = csid_input_fmts[code->index].code; + code->code = csid->formats[code->index].code; } else { if (csid->testgen_mode->cur.val == 0) { if (code->index > 0) @@ -611,10 +733,10 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, code->code = format->code; } else { - if (code->index >= ARRAY_SIZE(csid_input_fmts)) + if (code->index >= csid->nformats) return -EINVAL; - code->code = csid_input_fmts[code->index].code; + code->code = csid->formats[code->index].code; } } @@ -834,6 +956,18 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->camss = camss; csid->id = id; + if (camss->version == CAMSS_8x16) { + csid->formats = csid_formats_8x16; + csid->nformats = + ARRAY_SIZE(csid_formats_8x16); + } else if (camss->version == CAMSS_8x96) { + csid->formats = csid_formats_8x96; + csid->nformats = + ARRAY_SIZE(csid_formats_8x96); + } else { + return -EINVAL; + } + /* Memory */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index ed605fd3bb87..1824b3745e10 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -58,6 +58,8 @@ struct csid_device { struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM]; struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *testgen_mode; + const struct csid_format *formats; + unsigned int nformats; }; struct resources; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 7da705147966..3cdab59d24f9 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -23,93 +23,69 @@ #define MSM_CSIPHY_NAME "msm_csiphy" -static const struct { +struct csiphy_format { u32 code; u8 bpp; -} csiphy_formats[] = { - { - MEDIA_BUS_FMT_UYVY8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_VYUY8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_YUYV8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_YVYU8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_SBGGR8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SGBRG8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SGRBG8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SRGGB8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SBGGR10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SGBRG10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SGRBG10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SRGGB10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SBGGR12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SGBRG12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SGRBG12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SRGGB12_1X12, - 12, - } +}; + +static const struct csiphy_format csiphy_formats_8x16[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, +}; + +static const struct csiphy_format csiphy_formats_8x96[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, }; /* * csiphy_get_bpp - map media bus format to bits per pixel + * @formats: supported media bus formats array + * @nformats: size of @formats array * @code: media bus format code * * Return number of bits per pixel */ -static u8 csiphy_get_bpp(u32 code) +static u8 csiphy_get_bpp(const struct csiphy_format *formats, + unsigned int nformats, u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(csiphy_formats); i++) - if (code == csiphy_formats[i].code) - return csiphy_formats[i].bpp; + for (i = 0; i < nformats; i++) + if (code == formats[i].code) + return formats[i].bpp; WARN(1, "Unknown format\n"); - return csiphy_formats[0].bpp; + return formats[0].bpp; } /* @@ -133,7 +109,8 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy) if (!strcmp(clock->name, "csiphy0_timer") || !strcmp(clock->name, "csiphy1_timer") || !strcmp(clock->name, "csiphy2_timer")) { - u8 bpp = csiphy_get_bpp( + u8 bpp = csiphy_get_bpp(csiphy->formats, + csiphy->nformats, csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); @@ -256,7 +233,8 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) struct csiphy_config *cfg = &csiphy->cfg; u32 pixel_clock; u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg); - u8 bpp = csiphy_get_bpp(csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); + u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, + csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); u8 val; int ret; @@ -361,12 +339,12 @@ static void csiphy_try_format(struct csiphy_device *csiphy, case MSM_CSIPHY_PAD_SINK: /* Set format on sink pad */ - for (i = 0; i < ARRAY_SIZE(csiphy_formats); i++) - if (fmt->code == csiphy_formats[i].code) + for (i = 0; i < csiphy->nformats; i++) + if (fmt->code == csiphy->formats[i].code) break; /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(csiphy_formats)) + if (i >= csiphy->nformats) fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->width = clamp_t(u32, fmt->width, 1, 8191); @@ -402,10 +380,10 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; if (code->pad == MSM_CSIPHY_PAD_SINK) { - if (code->index >= ARRAY_SIZE(csiphy_formats)) + if (code->index >= csiphy->nformats) return -EINVAL; - code->code = csiphy_formats[code->index].code; + code->code = csiphy->formats[code->index].code; } else { if (code->index > 0) return -EINVAL; @@ -563,12 +541,17 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->id = id; csiphy->cfg.combo_mode = 0; - if (camss->version == CAMSS_8x16) + if (camss->version == CAMSS_8x16) { csiphy->ops = &csiphy_ops_2ph_1_0; - else if (camss->version == CAMSS_8x96) + csiphy->formats = csiphy_formats_8x16; + csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); + } else if (camss->version == CAMSS_8x96) { csiphy->ops = &csiphy_ops_3ph_1_0; - else + csiphy->formats = csiphy_formats_8x96; + csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); + } else { return -EINVAL; + } /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 5debe46b6cf1..376f865ad383 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -71,6 +71,8 @@ struct csiphy_device { struct csiphy_config cfg; struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; const struct csiphy_hw_ops *ops; + const struct csiphy_format *formats; + unsigned int nformats; }; struct resources; diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index ae8073274624..146d5d26b3c1 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -96,7 +96,26 @@ enum ispif_intf_cmd { CMD_ALL_NO_CHANGE = 0xffffffff, }; -static const u32 ispif_formats[] = { +static const u32 ispif_formats_8x16[] = { + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, +}; + +static const u32 ispif_formats_8x96[] = { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_YUYV8_2X8, @@ -780,12 +799,12 @@ static void ispif_try_format(struct ispif_line *line, case MSM_ISPIF_PAD_SINK: /* Set format on sink pad */ - for (i = 0; i < ARRAY_SIZE(ispif_formats); i++) - if (fmt->code == ispif_formats[i]) + for (i = 0; i < line->nformats; i++) + if (fmt->code == line->formats[i]) break; /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(ispif_formats)) + if (i >= line->nformats) fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->width = clamp_t(u32, fmt->width, 1, 8191); @@ -823,10 +842,10 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; if (code->pad == MSM_ISPIF_PAD_SINK) { - if (code->index >= ARRAY_SIZE(ispif_formats)) + if (code->index >= line->nformats) return -EINVAL; - code->code = ispif_formats[code->index]; + code->code = line->formats[code->index]; } else { if (code->index > 0) return -EINVAL; @@ -993,6 +1012,18 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, for (i = 0; i < ispif->line_num; i++) { ispif->line[i].ispif = ispif; ispif->line[i].id = i; + + if (to_camss(ispif)->version == CAMSS_8x16) { + ispif->line[i].formats = ispif_formats_8x16; + ispif->line[i].nformats = + ARRAY_SIZE(ispif_formats_8x16); + } else if (to_camss(ispif)->version == CAMSS_8x96) { + ispif->line[i].formats = ispif_formats_8x96; + ispif->line[i].nformats = + ARRAY_SIZE(ispif_formats_8x96); + } else { + return -EINVAL; + } } /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index 9cd51dcb3ede..1a5ba2425a42 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -43,6 +43,8 @@ struct ispif_line { struct v4l2_subdev subdev; struct media_pad pads[MSM_ISPIF_PADS_NUM]; struct v4l2_mbus_framefmt fmt[MSM_ISPIF_PADS_NUM]; + const u32 *formats; + unsigned int nformats; }; struct ispif_device { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index e6f66cfad86d..c27097c440f2 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -45,93 +45,83 @@ #define SCALER_RATIO_MAX 16 -static const struct { +struct vfe_format { u32 code; u8 bpp; -} vfe_formats[] = { - { - MEDIA_BUS_FMT_UYVY8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_VYUY8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_YUYV8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_YVYU8_2X8, - 8, - }, - { - MEDIA_BUS_FMT_SBGGR8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SGBRG8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SGRBG8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SRGGB8_1X8, - 8, - }, - { - MEDIA_BUS_FMT_SBGGR10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SGBRG10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SGRBG10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SRGGB10_1X10, - 10, - }, - { - MEDIA_BUS_FMT_SBGGR12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SGBRG12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SGRBG12_1X12, - 12, - }, - { - MEDIA_BUS_FMT_SRGGB12_1X12, - 12, - } +}; + +static const struct vfe_format formats_rdi_8x16[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, +}; + +static const struct vfe_format formats_pix_8x16[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, +}; + +static const struct vfe_format formats_rdi_8x96[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, +}; + +static const struct vfe_format formats_pix_8x96[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, }; /* * vfe_get_bpp - map media bus format to bits per pixel + * @formats: supported media bus formats array + * @nformats: size of @formats array * @code: media bus format code * * Return number of bits per pixel */ -static u8 vfe_get_bpp(u32 code) +static u8 vfe_get_bpp(const struct vfe_format *formats, + unsigned int nformats, u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vfe_formats); i++) - if (code == vfe_formats[i].code) - return vfe_formats[i].bpp; + for (i = 0; i < nformats; i++) + if (code == formats[i].code) + return formats[i].bpp; WARN(1, "Unknown format\n"); - return vfe_formats[0].bpp; + return formats[0].bpp; } /* @@ -978,8 +968,11 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) if (j == VFE_LINE_PIX) { tmp = pixel_clock[j]; } else { - bpp = vfe_get_bpp(vfe->line[j]. - fmt[MSM_VFE_PAD_SINK].code); + struct vfe_line *l = &vfe->line[j]; + + bpp = vfe_get_bpp(l->formats, + l->nformats, + l->fmt[MSM_VFE_PAD_SINK].code); tmp = pixel_clock[j] * bpp / 64; } @@ -1057,8 +1050,11 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) if (j == VFE_LINE_PIX) { tmp = pixel_clock[j]; } else { - bpp = vfe_get_bpp(vfe->line[j]. - fmt[MSM_VFE_PAD_SINK].code); + struct vfe_line *l = &vfe->line[j]; + + bpp = vfe_get_bpp(l->formats, + l->nformats, + l->fmt[MSM_VFE_PAD_SINK].code); tmp = pixel_clock[j] * bpp / 64; } @@ -1374,12 +1370,12 @@ static void vfe_try_format(struct vfe_line *line, case MSM_VFE_PAD_SINK: /* Set format on sink pad */ - for (i = 0; i < ARRAY_SIZE(vfe_formats); i++) - if (fmt->code == vfe_formats[i].code) + for (i = 0; i < line->nformats; i++) + if (fmt->code == line->formats[i].code) break; /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(vfe_formats)) + if (i >= line->nformats) fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->width = clamp_t(u32, fmt->width, 1, 8191); @@ -1539,10 +1535,10 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; if (code->pad == MSM_VFE_PAD_SINK) { - if (code->index >= ARRAY_SIZE(vfe_formats)) + if (code->index >= line->nformats) return -EINVAL; - code->code = vfe_formats[code->index].code; + code->code = line->formats[code->index].code; } else { if (code->index > 0) return -EINVAL; @@ -1943,12 +1939,33 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, vfe->reg_update = 0; for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { - vfe->line[i].video_out.type = - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - vfe->line[i].video_out.camss = camss; - vfe->line[i].id = i; - init_completion(&vfe->line[i].output.sof); - init_completion(&vfe->line[i].output.reg_update); + struct vfe_line *l = &vfe->line[i]; + + l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + l->video_out.camss = camss; + l->id = i; + init_completion(&l->output.sof); + init_completion(&l->output.reg_update); + + if (camss->version == CAMSS_8x16) { + if (i == VFE_LINE_PIX) { + l->formats = formats_pix_8x16; + l->nformats = ARRAY_SIZE(formats_pix_8x16); + } else { + l->formats = formats_rdi_8x16; + l->nformats = ARRAY_SIZE(formats_rdi_8x16); + } + } else if (camss->version == CAMSS_8x96) { + if (i == VFE_LINE_PIX) { + l->formats = formats_pix_8x96; + l->nformats = ARRAY_SIZE(formats_pix_8x96); + } else { + l->formats = formats_rdi_8x96; + l->nformats = ARRAY_SIZE(formats_rdi_8x96); + } + } else { + return -EINVAL; + } } init_completion(&vfe->reset_complete); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index eaebe833c143..71f6c97b266e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -71,6 +71,8 @@ struct vfe_line { struct v4l2_rect crop; struct camss_video video_out; struct vfe_output output; + const struct vfe_format *formats; + unsigned int nformats; }; struct vfe_device; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 16e74b2448fe..ba7d0c45a8d9 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -41,7 +41,7 @@ struct camss_format_info { unsigned int bpp[3]; }; -static const struct camss_format_info formats_rdi[] = { +static const struct camss_format_info formats_rdi_8x16[] = { { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, @@ -76,7 +76,77 @@ static const struct camss_format_info formats_rdi[] = { { { 1, 1 } }, { { 1, 1 } }, { 12 } }, }; -static const struct camss_format_info formats_pix[] = { +static const struct camss_format_info formats_rdi_8x96[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, +}; + +static const struct camss_format_info formats_pix_8x16[] = { + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, +}; + +static const struct camss_format_info formats_pix_8x96[] = { { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, @@ -790,11 +860,24 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, mutex_init(&video->lock); - video->formats = formats_rdi; - video->nformats = ARRAY_SIZE(formats_rdi); - if (is_pix) { - video->formats = formats_pix; - video->nformats = ARRAY_SIZE(formats_pix); + if (video->camss->version == CAMSS_8x16) { + if (is_pix) { + video->formats = formats_pix_8x16; + video->nformats = ARRAY_SIZE(formats_pix_8x16); + } else { + video->formats = formats_rdi_8x16; + video->nformats = ARRAY_SIZE(formats_rdi_8x16); + } + } else if (video->camss->version == CAMSS_8x96) { + if (is_pix) { + video->formats = formats_pix_8x96; + video->nformats = ARRAY_SIZE(formats_pix_8x96); + } else { + video->formats = formats_rdi_8x96; + video->nformats = ARRAY_SIZE(formats_rdi_8x96); + } + } else { + goto error_video_register; } ret = msm_video_init_format(video); -- cgit v1.2.3 From 312e1c858a0f05e27812cd7de87114801fced508 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:37 -0400 Subject: media: camss: vfe: Add support for UYVY output from VFE on 8x96 Add support to output UYVY formats from the VFE (via the PIX interface). A configuration for the realign module in the VFE is added. As the realign module is present on 8x96 but not on 8x16, this is supported on 8x96 only. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 6 + drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 129 ++++++++++++++++++---- drivers/media/platform/qcom/camss/camss-vfe.c | 31 +++++- drivers/media/platform/qcom/camss/camss-vfe.h | 2 + drivers/media/platform/qcom/camss/camss-video.c | 8 ++ 5 files changed, 152 insertions(+), 24 deletions(-) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 41184dcc33ca..da3a9fed9f2d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -542,6 +542,11 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, } } +static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line, + u8 enable) +{ + /* empty */ +} static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid) { vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), @@ -989,6 +994,7 @@ const struct vfe_hw_ops vfe_ops_4_1 = { .wm_set_subsample = vfe_wm_set_subsample, .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, .set_xbar_cfg = vfe_set_xbar_cfg, + .set_realign_cfg = vfe_set_realign_cfg, .set_rdi_cid = vfe_set_rdi_cid, .reg_update = vfe_reg_update, .reg_update_clear = vfe_reg_update_clear, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 45e6711a346f..4c584bffd179 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -34,6 +34,7 @@ #define VFE_0_MODULE_ZOOM_EN 0x04c #define VFE_0_MODULE_ZOOM_EN_SCALE_ENC BIT(1) #define VFE_0_MODULE_ZOOM_EN_CROP_ENC BIT(2) +#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF BIT(9) #define VFE_0_CORE_CFG 0x050 #define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR 0x4 @@ -87,6 +88,9 @@ #define VFE_0_BUS_XBAR_CFG_x(x) (0x90 + 0x4 * ((x) / 2)) #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN BIT(2) +#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN BIT(3) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA (0x1 << 4) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER (0x2 << 4) #define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA (0x3 << 4) #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT 8 #define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA 0x0 @@ -221,6 +225,11 @@ #define VFE_0_CLAMP_ENC_MIN_CFG_CH1 (0x0 << 8) #define VFE_0_CLAMP_ENC_MIN_CFG_CH2 (0x0 << 16) +#define VFE_0_REALIGN_BUF_CFG 0xaac +#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL BIT(2) +#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL BIT(3) +#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE BIT(4) + #define CAMIF_TIMEOUT_SLEEP_US 1000 #define CAMIF_TIMEOUT_ALL_US 1000000 @@ -311,7 +320,7 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable) #define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N)) -static int vfe_word_per_line(u32 format, u32 pixel_per_line) +static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line) { int val = 0; @@ -333,6 +342,11 @@ static int vfe_word_per_line(u32 format, u32 pixel_per_line) return val; } +static int vfe_word_per_line_by_bytes(u32 bytes_per_line) +{ + return CALC_WORD(bytes_per_line, 1, 8); +} + static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, u16 *width, u16 *height, u16 *bytesperline) { @@ -351,6 +365,15 @@ static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, *height = pix->height; *bytesperline = pix->plane_fmt[0].bytesperline; break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_UYVY: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[plane].bytesperline; + break; + } } @@ -365,7 +388,7 @@ static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm, vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline); - wpl = vfe_word_per_line(pix->pixelformat, width); + wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width); reg = height - 1; reg |= ((wpl + 3) / 4 - 1) << 16; @@ -373,7 +396,7 @@ static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm, writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm)); - wpl = vfe_word_per_line(pix->pixelformat, bytesperline); + wpl = vfe_word_per_line_by_bytes(bytesperline); reg = 0x3; reg |= (height - 1) << 2; @@ -536,32 +559,97 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, struct vfe_line *line = container_of(output, struct vfe_line, output); u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; u32 reg; - unsigned int i; - for (i = 0; i < output->wm_num; i++) { - if (i == 0) { - reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA << - VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; - } else if (i == 1) { - reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; - if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) - reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; - } + switch (p) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + + if (output->wm_idx[0] % 2 == 1) + reg <<= 16; + + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + + reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + + if (output->wm_idx[1] % 2 == 1) + reg <<= 16; - if (output->wm_idx[i] % 2 == 1) + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]), + reg); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_UYVY: + reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN; + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; + + if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU) + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + + if (output->wm_idx[0] % 2 == 1) reg <<= 16; if (enable) vfe_reg_set(vfe, - VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]), + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), reg); else vfe_reg_clr(vfe, - VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]), + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), reg); + break; + default: + break; } } +static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line, + u8 enable) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF; + + if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU && + p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY) + return; + + if (enable) { + vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val); + } else { + vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val); + return; + } + + val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE; + + if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV) + val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL; + else + val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL; + + writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG); +} + static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid) { vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), @@ -911,11 +999,11 @@ static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable) VFE_0_MODULE_ZOOM_EN_CROP_ENC; if (enable) { - writel_relaxed(val_lens, vfe->base + VFE_0_MODULE_LENS_EN); - writel_relaxed(val_zoom, vfe->base + VFE_0_MODULE_ZOOM_EN); + vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens); + vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom); } else { - writel_relaxed(0x0, vfe->base + VFE_0_MODULE_LENS_EN); - writel_relaxed(0x0, vfe->base + VFE_0_MODULE_ZOOM_EN); + vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens); + vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom); } } @@ -1028,6 +1116,7 @@ const struct vfe_hw_ops vfe_ops_4_7 = { .wm_set_subsample = vfe_wm_set_subsample, .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, .set_xbar_cfg = vfe_set_xbar_cfg, + .set_realign_cfg = vfe_set_realign_cfg, .set_rdi_cid = vfe_set_rdi_cid, .reg_update = vfe_reg_update, .reg_update_clear = vfe_reg_update_clear, diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index dc353d624e95..d85d663101f5 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -203,6 +203,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { u32 src_code[] = { MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_YUYV8_1_5X8, }; @@ -213,6 +216,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { u32 src_code[] = { MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_YVYU8_1_5X8, }; @@ -223,6 +229,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { u32 src_code[] = { MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_UYVY8_1_5X8, }; @@ -233,6 +242,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { u32 src_code[] = { MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_1_5X8, }; @@ -308,10 +320,6 @@ static void vfe_init_outputs(struct vfe_device *vfe) output->buf[0] = NULL; output->buf[1] = NULL; INIT_LIST_HEAD(&output->pending_bufs); - - output->wm_num = 1; - if (vfe->line[i].id == VFE_LINE_PIX) - output->wm_num = 2; } } @@ -567,6 +575,7 @@ static int vfe_get_output(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); struct vfe_output *output; + struct v4l2_format *f = &line->video_out.active_fmt; unsigned long flags; int i; int wm_idx; @@ -582,6 +591,18 @@ static int vfe_get_output(struct vfe_line *line) output->active_buf = 0; + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + output->wm_num = 2; + break; + default: + output->wm_num = 1; + break; + } + for (i = 0; i < output->wm_num; i++) { wm_idx = vfe_reserve_wm(vfe, line->id); if (wm_idx < 0) { @@ -712,6 +733,7 @@ static int vfe_enable_output(struct vfe_line *line) ops->enable_irq_pix_line(vfe, 0, line->id, 1); ops->set_module_cfg(vfe, 1); ops->set_camif_cfg(vfe, line); + ops->set_realign_cfg(vfe, line, 1); ops->set_xbar_cfg(vfe, output, 1); ops->set_demux_cfg(vfe, line); ops->set_scale_cfg(vfe, line); @@ -776,6 +798,7 @@ static int vfe_disable_output(struct vfe_line *line) ops->enable_irq_pix_line(vfe, 0, line->id, 0); ops->set_module_cfg(vfe, 0); + ops->set_realign_cfg(vfe, line, 0); ops->set_xbar_cfg(vfe, output, 0); ops->set_camif_cmd(vfe, 0); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 71f6c97b266e..0d10071ae881 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -107,6 +107,8 @@ struct vfe_hw_ops { u8 enable); void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid); + void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, + u8 enable); void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id); void (*reg_update_clear)(struct vfe_device *vfe, enum vfe_line_id line_id); diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index ba7d0c45a8d9..e6e114a62355 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -179,6 +179,14 @@ static const struct camss_format_info formats_pix_8x96[] = { { { 1, 1 } }, { { 1, 2 } }, { 8 } }, { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, }; /* ----------------------------------------------------------------------------- -- cgit v1.2.3 From 5019d7c8209c539226f9e64c38eece7fce732e18 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:39 -0400 Subject: media: camss: csid: MIPI10 to Plain16 format conversion Use the PRDI mode on 8x96 to allow to configure RAW MIPI10 to Plain16 format conversion. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 33 ++++++++++++- drivers/media/platform/qcom/camss/camss-ispif.c | 64 +++++++++++++++++++++++++ drivers/media/platform/qcom/camss/camss-vfe.c | 1 + drivers/media/platform/qcom/camss/camss-video.c | 2 + 4 files changed, 99 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index cf543fa2c497..0715a8e326b1 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -32,6 +32,15 @@ (((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n)) #define CAMSS_CSID_CID_n_CFG(v, n) \ (((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) +#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (0 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (1 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) #define CAMSS_CSID_IRQ_CLEAR_CMD(v) ((v) == CAMSS_8x16 ? 0x060 : 0x064) #define CAMSS_CSID_IRQ_MASK(v) ((v) == CAMSS_8x16 ? 0x064 : 0x068) #define CAMSS_CSID_IRQ_STATUS(v) ((v) == CAMSS_8x16 ? 0x068 : 0x06c) @@ -330,6 +339,16 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, return sink_code; } else if (csid->camss->version == CAMSS_8x96) { switch (sink_code) { + case MEDIA_BUS_FMT_SBGGR10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + index, src_req_code); + } default: if (index > 0) return 0; @@ -636,7 +655,19 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(ver, vc)); - val = (df << 4) | 0x3; + val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; + val |= CAMSS_CSID_CID_n_CFG_RDI_EN; + val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; + if (csid->camss->version == CAMSS_8x96 && + csid->fmt[MSM_CSID_PAD_SINK].code == + MEDIA_BUS_FMT_SBGGR10_1X10 && + csid->fmt[MSM_CSID_PAD_SRC].code == + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) { + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; + } writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(ver, cid)); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 146d5d26b3c1..81d6351c54c6 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -76,6 +76,13 @@ (0x254 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) \ (0x264 + 0x200 * (m) + 0x4 * (n)) +/* PACK_CFG registers are 8x96 only */ +#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(m, n) \ + (0x270 + 0x200 * (m) + 0x4 * (n)) +#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(m, n) \ + (0x27c + 0x200 * (m) + 0x4 * (n)) +#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(c) \ + (1 << ((cid % 8) * 4)) #define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) \ (0x2c0 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) \ @@ -128,6 +135,7 @@ static const u32 ispif_formats_8x96[] = { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, @@ -666,6 +674,54 @@ static void ispif_config_irq(struct ispif_device *ispif, enum ispif_intf intf, writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); } +/* + * ispif_config_pack - Config packing for PRDI mode + * @ispif: ISPIF device + * @code: media bus format code + * @intf: VFE interface + * @cid: desired CID to handle + * @vfe: VFE HW module id + * @enable: enable or disable + */ +static void ispif_config_pack(struct ispif_device *ispif, u32 code, + enum ispif_intf intf, u8 cid, u8 vfe, u8 enable) +{ + u32 addr, val; + + if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) + return; + + switch (intf) { + case RDI0: + if (cid < 8) + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 0); + else + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 0); + break; + case RDI1: + if (cid < 8) + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 1); + else + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 1); + break; + case RDI2: + if (cid < 8) + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 2); + else + addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 2); + break; + default: + return; + } + + if (enable) + val = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(cid); + else + val = 0; + + writel_relaxed(val, ispif->base + addr); +} + /* * ispif_set_intf_cmd - Set command to enable/disable interface * @ispif: ISPIF device @@ -734,6 +790,10 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_csid(ispif, intf, csid, vfe, 1); ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); + if (to_camss(ispif)->version == CAMSS_8x96) + ispif_config_pack(ispif, + line->fmt[MSM_ISPIF_PAD_SINK].code, + intf, cid, vfe, 1); ispif_set_intf_cmd(ispif, CMD_ENABLE_FRAME_BOUNDARY, intf, vfe, vc); } else { @@ -747,6 +807,10 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) return ret; mutex_lock(&ispif->config_lock); + if (to_camss(ispif)->version == CAMSS_8x96) + ispif_config_pack(ispif, + line->fmt[MSM_ISPIF_PAD_SINK].code, + intf, cid, vfe, 0); ispif_config_irq(ispif, intf, vfe, 0); ispif_select_cid(ispif, intf, cid, vfe, 0); ispif_select_csid(ispif, intf, csid, vfe, 0); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index d85d663101f5..11d37b78c3cd 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -89,6 +89,7 @@ static const struct vfe_format formats_rdi_8x96[] = { { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 }, { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index e6e114a62355..28d53bf4c784 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -101,6 +101,8 @@ static const struct camss_format_info formats_rdi_8x96[] = { { { 1, 1 } }, { { 1, 1 } }, { 10 } }, { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, { { 1, 1 } }, { { 1, 1 } }, { 12 } }, { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, -- cgit v1.2.3 From f476fb568f98bb6b2d2499ee7059504bf5203a91 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:40 -0400 Subject: media: camss: Add support for RAW MIPI14 on 8x96 Add support for RAW MIPI14 format for RDI mode on 8x96. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 30 ++++++++++++++++++++++++ drivers/media/platform/qcom/camss/camss-csiphy.c | 4 ++++ drivers/media/platform/qcom/camss/camss-ispif.c | 4 ++++ drivers/media/platform/qcom/camss/camss-vfe.c | 4 ++++ drivers/media/platform/qcom/camss/camss-video.c | 8 +++++++ 5 files changed, 50 insertions(+) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 0715a8e326b1..472884d1546e 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -63,11 +63,13 @@ #define DATA_TYPE_RAW_8BIT 0x2a #define DATA_TYPE_RAW_10BIT 0x2b #define DATA_TYPE_RAW_12BIT 0x2c +#define DATA_TYPE_RAW_14BIT 0x2d #define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 #define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 #define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 #define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 +#define DECODE_FORMAT_UNCOMPRESSED_14_BIT 0x8 #define CSID_RESET_TIMEOUT_MS 500 @@ -306,6 +308,34 @@ static const struct csid_format csid_formats_8x96[] = { DECODE_FORMAT_UNCOMPRESSED_12_BIT, 12, 1, + }, + { + MEDIA_BUS_FMT_SBGGR14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, } }; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 3cdab59d24f9..cae3e8b9ab37 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -64,6 +64,10 @@ static const struct csiphy_format csiphy_formats_8x96[] = { { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14 }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, }; /* diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 81d6351c54c6..3e2f34148977 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -140,6 +140,10 @@ static const u32 ispif_formats_8x96[] = { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR14_1X14, + MEDIA_BUS_FMT_SGBRG14_1X14, + MEDIA_BUS_FMT_SGRBG14_1X14, + MEDIA_BUS_FMT_SRGGB14_1X14, }; /* diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 11d37b78c3cd..96753090e072 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -94,6 +94,10 @@ static const struct vfe_format formats_rdi_8x96[] = { { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14 }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, }; static const struct vfe_format formats_pix_8x96[] = { diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 28d53bf4c784..2e19bc8c4161 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -111,6 +111,14 @@ static const struct camss_format_info formats_rdi_8x96[] = { { { 1, 1 } }, { { 1, 1 } }, { 12 } }, { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, }; static const struct camss_format_info formats_pix_8x16[] = { -- cgit v1.2.3 From cc8fe07398e390d2047c30849f3055d5074ee833 Mon Sep 17 00:00:00 2001 From: Todor Tomov Date: Wed, 25 Jul 2018 12:38:41 -0400 Subject: media: camss: Add support for 10-bit grayscale formats Add support for 10-bit packed V4L2_PIX_FMT_Y10P (on 8x16 and 8x96) and unpacked V4L2_PIX_FMT_Y10 (on 8x96 only) pixel formats. Signed-off-by: Todor Tomov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 50 +++++++++++++++++++----- drivers/media/platform/qcom/camss/camss-csiphy.c | 2 + drivers/media/platform/qcom/camss/camss-ispif.c | 6 ++- drivers/media/platform/qcom/camss/camss-vfe.c | 3 ++ drivers/media/platform/qcom/camss/camss-video.c | 6 +++ 5 files changed, 56 insertions(+), 11 deletions(-) (limited to 'drivers/media/platform/qcom/camss/camss-video.c') diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 472884d1546e..6e141af6b6df 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -193,7 +193,14 @@ static const struct csid_format csid_formats_8x16[] = { DECODE_FORMAT_UNCOMPRESSED_12_BIT, 12, 1, - } + }, + { + MEDIA_BUS_FMT_Y10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, }; static const struct csid_format csid_formats_8x96[] = { @@ -336,7 +343,14 @@ static const struct csid_format csid_formats_8x96[] = { DECODE_FORMAT_UNCOMPRESSED_14_BIT, 14, 1, - } + }, + { + MEDIA_BUS_FMT_Y10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, }; static u32 csid_find_code(u32 *code, unsigned int n_code, @@ -379,6 +393,16 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, return csid_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } + case MEDIA_BUS_FMT_Y10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + index, src_req_code); + } default: if (index > 0) return 0; @@ -689,15 +713,21 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) val |= CAMSS_CSID_CID_n_CFG_RDI_EN; val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; - if (csid->camss->version == CAMSS_8x96 && - csid->fmt[MSM_CSID_PAD_SINK].code == - MEDIA_BUS_FMT_SBGGR10_1X10 && - csid->fmt[MSM_CSID_PAD_SRC].code == - MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) { - val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; - val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; - val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; + + if (csid->camss->version == CAMSS_8x96) { + u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code; + u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code; + + if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 && + src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) || + (sink_code == MEDIA_BUS_FMT_Y10_1X10 && + src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) { + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; + } } + writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(ver, cid)); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index cae3e8b9ab37..4559f3b1b38c 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -45,6 +45,7 @@ static const struct csiphy_format csiphy_formats_8x16[] = { { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, }; static const struct csiphy_format csiphy_formats_8x96[] = { @@ -68,6 +69,7 @@ static const struct csiphy_format csiphy_formats_8x96[] = { { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, }; /* diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 3e2f34148977..7f269021d08c 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -120,6 +120,7 @@ static const u32 ispif_formats_8x16[] = { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_Y10_1X10, }; static const u32 ispif_formats_8x96[] = { @@ -144,6 +145,8 @@ static const u32 ispif_formats_8x96[] = { MEDIA_BUS_FMT_SGBRG14_1X14, MEDIA_BUS_FMT_SGRBG14_1X14, MEDIA_BUS_FMT_SRGGB14_1X14, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, }; /* @@ -692,7 +695,8 @@ static void ispif_config_pack(struct ispif_device *ispif, u32 code, { u32 addr, val; - if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) + if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE && + code != MEDIA_BUS_FMT_Y10_2X8_PADHI_LE) return; switch (intf) { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 96753090e072..ed6a557de65d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -67,6 +67,7 @@ static const struct vfe_format formats_rdi_8x16[] = { { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, }; static const struct vfe_format formats_pix_8x16[] = { @@ -98,6 +99,8 @@ static const struct vfe_format formats_rdi_8x96[] = { { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, + { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 }, }; static const struct vfe_format formats_pix_8x96[] = { diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 2e19bc8c4161..c9bb0d023db4 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -74,6 +74,8 @@ static const struct camss_format_info formats_rdi_8x16[] = { { { 1, 1 } }, { { 1, 1 } }, { 12 } }, { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, }; static const struct camss_format_info formats_rdi_8x96[] = { @@ -119,6 +121,10 @@ static const struct camss_format_info formats_rdi_8x96[] = { { { 1, 1 } }, { { 1, 1 } }, { 14 } }, { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, }; static const struct camss_format_info formats_pix_8x16[] = { -- cgit v1.2.3