Commit d3bd039c authored by Bingbu Cao's avatar Bingbu Cao Committed by Hans Verkuil

media: intel/ipu6: support line-based metadata capture support

Some camera sensor can output the embedded data in specific data type.
This patch adds the support for metadata capture in IPU6 ISYS driver.
Signed-off-by: default avatarHongju Wang <hongju.wang@intel.com>
Signed-off-by: default avatarBingbu Cao <bingbu.cao@intel.com>
Co-developed-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent 7c833d20
...@@ -42,6 +42,11 @@ static const u32 csi2_supported_codes[] = { ...@@ -42,6 +42,11 @@ static const u32 csi2_supported_codes[] = {
MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
MEDIA_BUS_FMT_META_8,
MEDIA_BUS_FMT_META_10,
MEDIA_BUS_FMT_META_12,
MEDIA_BUS_FMT_META_16,
MEDIA_BUS_FMT_META_24,
0 0
}; };
......
...@@ -28,7 +28,7 @@ static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, ...@@ -28,7 +28,7 @@ static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q); struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
struct device *dev = &av->isys->adev->auxdev.dev; struct device *dev = &av->isys->adev->auxdev.dev;
u32 size = av->pix_fmt.sizeimage; u32 size = ipu6_isys_get_data_size(av);
/* num_planes == 0: we're being called through VIDIOC_REQBUFS */ /* num_planes == 0: we're being called through VIDIOC_REQBUFS */
if (!*num_planes) { if (!*num_planes) {
...@@ -49,17 +49,17 @@ static int ipu6_isys_buf_prepare(struct vb2_buffer *vb) ...@@ -49,17 +49,17 @@ static int ipu6_isys_buf_prepare(struct vb2_buffer *vb)
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
struct device *dev = &av->isys->adev->auxdev.dev; struct device *dev = &av->isys->adev->auxdev.dev;
u32 bytesperline = ipu6_isys_get_bytes_per_line(av);
u32 height = ipu6_isys_get_frame_height(av);
u32 size = ipu6_isys_get_data_size(av);
dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n", dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",
av->vdev.name, av->pix_fmt.sizeimage, av->vdev.name, size, vb2_plane_size(vb, 0));
vb2_plane_size(vb, 0));
if (av->pix_fmt.sizeimage > vb2_plane_size(vb, 0)) if (size > vb2_plane_size(vb, 0))
return -EINVAL; return -EINVAL;
vb2_set_plane_payload(vb, 0, av->pix_fmt.bytesperline * vb2_set_plane_payload(vb, 0, bytesperline * height);
av->pix_fmt.height);
vb->planes[0].data_offset = 0;
return 0; return 0;
} }
...@@ -328,15 +328,12 @@ static void buf_queue(struct vb2_buffer *vb) ...@@ -328,15 +328,12 @@ static void buf_queue(struct vb2_buffer *vb)
struct isys_fw_msgs *msg; struct isys_fw_msgs *msg;
unsigned long flags; unsigned long flags;
dma_addr_t dma; dma_addr_t dma;
unsigned int i;
int ret; int ret;
dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name); dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);
for (i = 0; i < vb->num_planes; i++) { dma = vb2_dma_contig_plane_dma_addr(vb, 0);
dma = vb2_dma_contig_plane_dma_addr(vb, i); dev_dbg(dev, "iova: iova %pad\n", &dma);
dev_dbg(dev, "iova: plane %u iova %pad\n", i, &dma);
}
spin_lock_irqsave(&aq->lock, flags); spin_lock_irqsave(&aq->lock, flags);
list_add(&ib->head, &aq->incoming); list_add(&ib->head, &aq->incoming);
...@@ -409,7 +406,7 @@ static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq) ...@@ -409,7 +406,7 @@ static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
struct media_pad *remote_pad = struct media_pad *remote_pad =
media_pad_remote_pad_first(av->vdev.entity.pads); media_pad_remote_pad_first(av->vdev.entity.pads);
struct v4l2_subdev *sd; struct v4l2_subdev *sd;
u32 r_stream; u32 r_stream, code;
int ret; int ret;
if (!remote_pad) if (!remote_pad)
...@@ -427,17 +424,19 @@ static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq) ...@@ -427,17 +424,19 @@ static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
return ret; return ret;
} }
if (format.width != av->pix_fmt.width || if (format.width != ipu6_isys_get_frame_width(av) ||
format.height != av->pix_fmt.height) { format.height != ipu6_isys_get_frame_height(av)) {
dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n", dev_err(dev, "wrong width or height %ux%u (%ux%u expected)\n",
av->pix_fmt.width, av->pix_fmt.height, ipu6_isys_get_frame_width(av),
format.width, format.height); ipu6_isys_get_frame_height(av), format.width,
format.height);
return -EINVAL; return -EINVAL;
} }
if (format.code != av->pfmt->code) { code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
if (format.code != code) {
dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n", dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",
av->pfmt->code, format.code); code, format.code);
return -EINVAL; return -EINVAL;
} }
...@@ -509,14 +508,16 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) ...@@ -509,14 +508,16 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q); struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
struct device *dev = &av->isys->adev->auxdev.dev; struct device *dev = &av->isys->adev->auxdev.dev;
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
struct ipu6_isys_buffer_list __bl, *bl = NULL; struct ipu6_isys_buffer_list __bl, *bl = NULL;
struct ipu6_isys_stream *stream; struct ipu6_isys_stream *stream;
struct media_entity *source_entity = NULL; struct media_entity *source_entity = NULL;
int nr_queues, ret; int nr_queues, ret;
dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n", dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
av->vdev.name, av->pix_fmt.width, av->pix_fmt.height, av->vdev.name, ipu6_isys_get_frame_width(av),
av->pfmt->css_pixelformat); ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);
ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues); ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);
if (ret < 0) { if (ret < 0) {
......
...@@ -20,25 +20,30 @@ unsigned int ipu6_isys_mbus_code_to_bpp(u32 code) ...@@ -20,25 +20,30 @@ unsigned int ipu6_isys_mbus_code_to_bpp(u32 code)
{ {
switch (code) { switch (code) {
case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_META_24:
return 24; return 24;
case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_META_16:
return 16; return 16;
case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12:
case MEDIA_BUS_FMT_META_12:
return 12; return 12;
case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10:
case MEDIA_BUS_FMT_META_10:
return 10; return 10;
case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8:
case MEDIA_BUS_FMT_META_8:
return 8; return 8;
default: default:
WARN_ON(1); WARN_ON(1);
......
...@@ -85,6 +85,14 @@ const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = { ...@@ -85,6 +85,14 @@ const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = {
IPU6_FW_ISYS_FRAME_FORMAT_RGB565 }, IPU6_FW_ISYS_FRAME_FORMAT_RGB565 },
{ V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, { V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 }, IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 },
{ V4L2_META_FMT_GENERIC_8, 8, 8, MEDIA_BUS_FMT_META_8,
IPU6_FW_ISYS_FRAME_FORMAT_RAW8, true },
{ V4L2_META_FMT_GENERIC_CSI2_10, 10, 10, MEDIA_BUS_FMT_META_10,
IPU6_FW_ISYS_FRAME_FORMAT_RAW10, true },
{ V4L2_META_FMT_GENERIC_CSI2_12, 12, 12, MEDIA_BUS_FMT_META_12,
IPU6_FW_ISYS_FRAME_FORMAT_RAW12, true },
{ V4L2_META_FMT_GENERIC_CSI2_16, 16, 16, MEDIA_BUS_FMT_META_16,
IPU6_FW_ISYS_FRAME_FORMAT_RAW16, true },
}; };
static int video_open(struct file *file) static int video_open(struct file *file)
...@@ -104,19 +112,31 @@ static int video_open(struct file *file) ...@@ -104,19 +112,31 @@ static int video_open(struct file *file)
return v4l2_fh_open(file); return v4l2_fh_open(file);
} }
static const struct ipu6_isys_pixelformat * const struct ipu6_isys_pixelformat *
ipu6_isys_get_pixelformat(u32 pixelformat) ipu6_isys_get_isys_format(u32 pixelformat, u32 type)
{ {
const struct ipu6_isys_pixelformat *default_pfmt = NULL;
unsigned int i; unsigned int i;
for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) { for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i]; const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i];
if (pfmt->pixelformat == pixelformat) if (type && ((!pfmt->is_meta &&
return pfmt; type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
(pfmt->is_meta &&
type != V4L2_BUF_TYPE_META_CAPTURE)))
continue;
if (!default_pfmt)
default_pfmt = pfmt;
if (pfmt->pixelformat != pixelformat)
continue;
return pfmt;
} }
return &ipu6_isys_pfmts[0]; return default_pfmt;
} }
static int ipu6_isys_vidioc_querycap(struct file *file, void *fh, static int ipu6_isys_vidioc_querycap(struct file *file, void *fh,
...@@ -133,27 +153,27 @@ static int ipu6_isys_vidioc_querycap(struct file *file, void *fh, ...@@ -133,27 +153,27 @@ static int ipu6_isys_vidioc_querycap(struct file *file, void *fh,
static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh, static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh,
struct v4l2_fmtdesc *f) struct v4l2_fmtdesc *f)
{ {
unsigned int i, found = 0; unsigned int i, num_found;
if (f->index >= ARRAY_SIZE(ipu6_isys_pfmts))
return -EINVAL;
if (!f->mbus_code) { for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
f->flags = 0; if ((ipu6_isys_pfmts[i].is_meta &&
f->pixelformat = ipu6_isys_pfmts[f->index].pixelformat; f->type != V4L2_BUF_TYPE_META_CAPTURE) ||
return 0; (!ipu6_isys_pfmts[i].is_meta &&
} f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
continue;
for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) { if (f->mbus_code && f->mbus_code != ipu6_isys_pfmts[i].code)
if (f->mbus_code != ipu6_isys_pfmts[i].code)
continue; continue;
if (f->index == found) { if (num_found < f->index) {
f->flags = 0; num_found++;
f->pixelformat = ipu6_isys_pfmts[i].pixelformat; continue;
return 0;
} }
found++;
f->flags = 0;
f->pixelformat = ipu6_isys_pfmts[i].pixelformat;
return 0;
} }
return -EINVAL; return -EINVAL;
...@@ -185,39 +205,43 @@ static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh, ...@@ -185,39 +205,43 @@ static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh,
return -EINVAL; return -EINVAL;
} }
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, static int ipu6_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *fmt) struct v4l2_format *f)
{ {
struct ipu6_isys_video *av = video_drvdata(file); struct ipu6_isys_video *av = video_drvdata(file);
fmt->fmt.pix = av->pix_fmt; f->fmt.pix = av->pix_fmt;
return 0; return 0;
} }
static const struct ipu6_isys_pixelformat * static int ipu6_isys_vidioc_g_fmt_meta_cap(struct file *file, void *fh,
ipu6_isys_video_try_fmt_vid(struct ipu6_isys_video *av, struct v4l2_format *f)
struct v4l2_pix_format *pix_fmt)
{ {
const struct ipu6_isys_pixelformat *pfmt = struct ipu6_isys_video *av = video_drvdata(file);
ipu6_isys_get_pixelformat(pix_fmt->pixelformat);
f->fmt.meta = av->meta_fmt;
return 0;
}
pix_fmt->pixelformat = pfmt->pixelformat; static void ipu6_isys_try_fmt_cap(struct ipu6_isys_video *av, u32 type,
u32 *format, u32 *width, u32 *height,
u32 *bytesperline, u32 *sizeimage)
{
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(*format, type);
pix_fmt->width = clamp(pix_fmt->width, IPU6_ISYS_MIN_WIDTH, *format = pfmt->pixelformat;
IPU6_ISYS_MAX_WIDTH); *width = clamp(*width, IPU6_ISYS_MIN_WIDTH, IPU6_ISYS_MAX_WIDTH);
pix_fmt->height = clamp(pix_fmt->height, IPU6_ISYS_MIN_HEIGHT, *height = clamp(*height, IPU6_ISYS_MIN_HEIGHT, IPU6_ISYS_MAX_HEIGHT);
IPU6_ISYS_MAX_HEIGHT);
if (pfmt->bpp != pfmt->bpp_packed) if (pfmt->bpp != pfmt->bpp_packed)
pix_fmt->bytesperline = *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
pix_fmt->width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
else else
pix_fmt->bytesperline = *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
DIV_ROUND_UP(pix_fmt->width * pfmt->bpp, BITS_PER_BYTE);
pix_fmt->bytesperline = ALIGN(pix_fmt->bytesperline, *bytesperline = ALIGN(*bytesperline, av->isys->line_align);
av->isys->line_align);
/* /*
* (height + 1) * bytesperline due to a hardware issue: the DMA unit * (height + 1) * bytesperline due to a hardware issue: the DMA unit
...@@ -228,46 +252,116 @@ ipu6_isys_video_try_fmt_vid(struct ipu6_isys_video *av, ...@@ -228,46 +252,116 @@ ipu6_isys_video_try_fmt_vid(struct ipu6_isys_video *av,
* resolution it gives a bigger number. Use larger one to avoid * resolution it gives a bigger number. Use larger one to avoid
* memory corruption. * memory corruption.
*/ */
pix_fmt->sizeimage = *sizeimage = *bytesperline * *height +
max(pix_fmt->sizeimage, max(*bytesperline,
pix_fmt->bytesperline * pix_fmt->height + av->isys->pdata->ipdata->isys_dma_overshoot);
max(pix_fmt->bytesperline, }
av->isys->pdata->ipdata->isys_dma_overshoot));
pix_fmt->field = V4L2_FIELD_NONE;
pix_fmt->colorspace = V4L2_COLORSPACE_RAW;
pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
pix_fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
pix_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
return pfmt; static void __ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video *av,
struct v4l2_format *f)
{
ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
&f->fmt.pix.width, &f->fmt.pix.height,
&f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
} }
static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, static int ipu6_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct ipu6_isys_video *av = video_drvdata(file); struct ipu6_isys_video *av = video_drvdata(file);
if (vb2_is_busy(&av->aq.vbq)) if (vb2_is_busy(&av->aq.vbq))
return -EBUSY; return -EBUSY;
av->pfmt = ipu6_isys_video_try_fmt_vid(av, &f->fmt.pix); __ipu6_isys_vidioc_try_fmt_vid_cap(av, f);
return 0;
}
static int __ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video *av,
struct v4l2_format *f)
{
ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.meta.dataformat,
&f->fmt.meta.width, &f->fmt.meta.height,
&f->fmt.meta.bytesperline,
&f->fmt.meta.buffersize);
return 0;
}
static int ipu6_isys_vidioc_try_fmt_meta_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
struct ipu6_isys_video *av = video_drvdata(file);
__ipu6_isys_vidioc_try_fmt_meta_cap(av, f);
return 0;
}
static int ipu6_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
struct ipu6_isys_video *av = video_drvdata(file);
ipu6_isys_vidioc_try_fmt_vid_cap(file, fh, f);
av->pix_fmt = f->fmt.pix; av->pix_fmt = f->fmt.pix;
return 0; return 0;
} }
static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, static int ipu6_isys_vidioc_s_fmt_meta_cap(struct file *file, void *fh,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct ipu6_isys_video *av = video_drvdata(file); struct ipu6_isys_video *av = video_drvdata(file);
ipu6_isys_video_try_fmt_vid(av, &f->fmt.pix); if (vb2_is_busy(&av->aq.vbq))
return -EBUSY;
ipu6_isys_vidioc_try_fmt_meta_cap(file, fh, f);
av->meta_fmt = f->fmt.meta;
return 0; return 0;
} }
static int ipu6_isys_vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct ipu6_isys_video *av = video_drvdata(file);
int ret;
av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
ret = vb2_queue_change_type(&av->aq.vbq, p->type);
if (ret)
return ret;
return vb2_ioctl_reqbufs(file, priv, p);
}
static int ipu6_isys_vidioc_create_bufs(struct file *file, void *priv,
struct v4l2_create_buffers *p)
{
struct ipu6_isys_video *av = video_drvdata(file);
int ret;
av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
if (ret)
return ret;
return vb2_ioctl_create_bufs(file, priv, p);
}
static int link_validate(struct media_link *link) static int link_validate(struct media_link *link)
{ {
struct ipu6_isys_video *av = struct ipu6_isys_video *av =
...@@ -277,7 +371,7 @@ static int link_validate(struct media_link *link) ...@@ -277,7 +371,7 @@ static int link_validate(struct media_link *link)
struct v4l2_subdev *s_sd; struct v4l2_subdev *s_sd;
struct v4l2_mbus_framefmt *s_fmt; struct v4l2_mbus_framefmt *s_fmt;
struct media_pad *s_pad; struct media_pad *s_pad;
u32 s_stream; u32 s_stream, code;
int ret = -EPIPE; int ret = -EPIPE;
if (!link->source->entity) if (!link->source->entity)
...@@ -303,11 +397,15 @@ static int link_validate(struct media_link *link) ...@@ -303,11 +397,15 @@ static int link_validate(struct media_link *link)
goto unlock; goto unlock;
} }
if (s_fmt->width != av->pix_fmt.width || code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
s_fmt->height != av->pix_fmt.height || s_fmt->code != av->pfmt->code) {
if (s_fmt->width != ipu6_isys_get_frame_width(av) ||
s_fmt->height != ipu6_isys_get_frame_height(av) ||
s_fmt->code != code) {
dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n", dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
s_fmt->width, s_fmt->height, s_fmt->code, s_fmt->width, s_fmt->height, s_fmt->code,
av->pix_fmt.width, av->pix_fmt.height, av->pfmt->code); ipu6_isys_get_frame_width(av),
ipu6_isys_get_frame_height(av), code);
goto unlock; goto unlock;
} }
...@@ -348,6 +446,8 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av, ...@@ -348,6 +446,8 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
struct ipu6_isys_stream *stream = av->stream; struct ipu6_isys_stream *stream = av->stream;
struct ipu6_isys_queue *aq = &av->aq; struct ipu6_isys_queue *aq = &av->aq;
struct v4l2_mbus_framefmt fmt; struct v4l2_mbus_framefmt fmt;
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
struct v4l2_rect v4l2_crop; struct v4l2_rect v4l2_crop;
struct ipu6_isys *isys = av->isys; struct ipu6_isys *isys = av->isys;
struct device *dev = &isys->adev->auxdev.dev; struct device *dev = &isys->adev->auxdev.dev;
...@@ -375,11 +475,11 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av, ...@@ -375,11 +475,11 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
input_pin->input_res.width = fmt.width; input_pin->input_res.width = fmt.width;
input_pin->input_res.height = fmt.height; input_pin->input_res.height = fmt.height;
input_pin->dt = av->dt; input_pin->dt = av->dt;
input_pin->bits_per_pix = av->pfmt->bpp_packed; input_pin->bits_per_pix = pfmt->bpp_packed;
input_pin->mapped_dt = 0x40; /* invalid mipi data type */ input_pin->mapped_dt = 0x40; /* invalid mipi data type */
input_pin->mipi_decompression = 0; input_pin->mipi_decompression = 0;
input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR; input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
input_pin->mipi_store_mode = av->pfmt->bpp == av->pfmt->bpp_packed ? input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER : IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL; IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
input_pin->crop_first_and_last_lines = v4l2_crop.top & 1; input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
...@@ -391,15 +491,15 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av, ...@@ -391,15 +491,15 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
output_pin = &cfg->output_pins[output_pins]; output_pin = &cfg->output_pins[output_pins];
output_pin->input_pin_id = input_pins; output_pin->input_pin_id = input_pins;
output_pin->output_res.width = av->pix_fmt.width; output_pin->output_res.width = ipu6_isys_get_frame_width(av);
output_pin->output_res.height = av->pix_fmt.height; output_pin->output_res.height = ipu6_isys_get_frame_height(av);
output_pin->stride = av->pix_fmt.bytesperline; output_pin->stride = ipu6_isys_get_bytes_per_line(av);
if (av->pfmt->bpp != av->pfmt->bpp_packed) if (pfmt->bpp != pfmt->bpp_packed)
output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC; output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
else else
output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI; output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
output_pin->ft = av->pfmt->css_pixelformat; output_pin->ft = pfmt->css_pixelformat;
output_pin->send_irq = 1; output_pin->send_irq = 1;
memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets)); memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
output_pin->s2m_pixel_soc_pixel_remapping = output_pin->s2m_pixel_soc_pixel_remapping =
...@@ -661,8 +761,8 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av, ...@@ -661,8 +761,8 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
esd = media_entity_to_v4l2_subdev(av->stream->source_entity); esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
av->watermark.width = av->pix_fmt.width; av->watermark.width = ipu6_isys_get_frame_width(av);
av->watermark.height = av->pix_fmt.height; av->watermark.height = ipu6_isys_get_frame_height(av);
av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift; av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size; av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
...@@ -698,7 +798,8 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av, ...@@ -698,7 +798,8 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
static void calculate_stream_datarate(struct ipu6_isys_video *av) static void calculate_stream_datarate(struct ipu6_isys_video *av)
{ {
struct video_stream_watermark *watermark = &av->watermark; struct video_stream_watermark *watermark = &av->watermark;
u32 bpp = av->pfmt->bpp; const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line; u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
u64 line_time_ns, stream_data_rate; u64 line_time_ns, stream_data_rate;
u16 shift, size; u16 shift, size;
...@@ -709,7 +810,7 @@ static void calculate_stream_datarate(struct ipu6_isys_video *av) ...@@ -709,7 +810,7 @@ static void calculate_stream_datarate(struct ipu6_isys_video *av)
pixels_per_line = watermark->width + watermark->hblank; pixels_per_line = watermark->width + watermark->hblank;
line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC, line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC,
watermark->pixel_rate); watermark->pixel_rate);
bytes_per_line = watermark->width * bpp / 8; bytes_per_line = watermark->width * pfmt->bpp / 8;
pages_per_line = DIV_ROUND_UP(bytes_per_line, size); pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
pb_bytes_per_line = pages_per_line << shift; pb_bytes_per_line = pages_per_line << shift;
stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns); stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
...@@ -988,12 +1089,16 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, ...@@ -988,12 +1089,16 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = { static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {
.vidioc_querycap = ipu6_isys_vidioc_querycap, .vidioc_querycap = ipu6_isys_vidioc_querycap,
.vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt, .vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,
.vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,
.vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes, .vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,
.vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,
.vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,
.vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,
.vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,
.vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_qbuf = vb2_ioctl_qbuf,
...@@ -1092,6 +1197,8 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys) ...@@ -1092,6 +1197,8 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
int ipu6_isys_setup_video(struct ipu6_isys_video *av, int ipu6_isys_setup_video(struct ipu6_isys_video *av,
struct media_entity **source_entity, int *nr_queues) struct media_entity **source_entity, int *nr_queues)
{ {
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
struct device *dev = &av->isys->adev->auxdev.dev; struct device *dev = &av->isys->adev->auxdev.dev;
struct v4l2_mbus_frame_desc_entry entry; struct v4l2_mbus_frame_desc_entry entry;
struct v4l2_subdev_route *route = NULL; struct v4l2_subdev_route *route = NULL;
...@@ -1143,7 +1250,7 @@ int ipu6_isys_setup_video(struct ipu6_isys_video *av, ...@@ -1143,7 +1250,7 @@ int ipu6_isys_setup_video(struct ipu6_isys_video *av,
*source_entity, &entry); *source_entity, &entry);
if (ret == -ENOIOCTLCMD) { if (ret == -ENOIOCTLCMD) {
av->vc = 0; av->vc = 0;
av->dt = ipu6_isys_mbus_code_to_mipi(av->pfmt->code); av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
} else if (!ret) { } else if (!ret) {
dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n", dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
entry.stream, entry.length, entry.bus.csi2.vc, entry.stream, entry.length, entry.bus.csi2.vc,
...@@ -1191,11 +1298,18 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av) ...@@ -1191,11 +1298,18 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av)
.height = 1080, .height = 1080,
}, },
}; };
struct v4l2_format format_meta = {
.type = V4L2_BUF_TYPE_META_CAPTURE,
.fmt.meta = {
.width = 1920,
.height = 4,
},
};
int ret; int ret;
mutex_init(&av->mutex); mutex_init(&av->mutex);
av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC | av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
V4L2_CAP_VIDEO_CAPTURE; V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
av->vdev.vfl_dir = VFL_DIR_RX; av->vdev.vfl_dir = VFL_DIR_RX;
ret = ipu6_isys_queue_init(&av->aq); ret = ipu6_isys_queue_init(&av->aq);
...@@ -1216,8 +1330,10 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av) ...@@ -1216,8 +1330,10 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av)
av->vdev.queue = &av->aq.vbq; av->vdev.queue = &av->aq.vbq;
av->vdev.lock = &av->mutex; av->vdev.lock = &av->mutex;
ipu6_isys_video_try_fmt_vid(av, &format.fmt.pix); __ipu6_isys_vidioc_try_fmt_vid_cap(av, &format);
av->pix_fmt = format.fmt.pix; av->pix_fmt = format.fmt.pix;
__ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta);
av->meta_fmt = format_meta.fmt.meta;
set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags); set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
video_set_drvdata(&av->vdev, av); video_set_drvdata(&av->vdev, av);
...@@ -1247,3 +1363,58 @@ void ipu6_isys_video_cleanup(struct ipu6_isys_video *av) ...@@ -1247,3 +1363,58 @@ void ipu6_isys_video_cleanup(struct ipu6_isys_video *av)
media_entity_cleanup(&av->vdev.entity); media_entity_cleanup(&av->vdev.entity);
mutex_destroy(&av->mutex); mutex_destroy(&av->mutex);
} }
u32 ipu6_isys_get_format(struct ipu6_isys_video *av)
{
if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return av->pix_fmt.pixelformat;
if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
return av->meta_fmt.dataformat;
return 0;
}
u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av)
{
if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return av->pix_fmt.sizeimage;
if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
return av->meta_fmt.buffersize;
return 0;
}
u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av)
{
if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return av->pix_fmt.bytesperline;
if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
return av->meta_fmt.bytesperline;
return 0;
}
u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av)
{
if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return av->pix_fmt.width;
if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
return av->meta_fmt.width;
return 0;
}
u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av)
{
if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return av->pix_fmt.height;
if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
return av->meta_fmt.height;
return 0;
}
...@@ -29,6 +29,7 @@ struct ipu6_isys_pixelformat { ...@@ -29,6 +29,7 @@ struct ipu6_isys_pixelformat {
u32 bpp_packed; u32 bpp_packed;
u32 code; u32 code;
u32 css_pixelformat; u32 css_pixelformat;
bool is_meta;
}; };
struct sequence_info { struct sequence_info {
...@@ -91,7 +92,7 @@ struct ipu6_isys_video { ...@@ -91,7 +92,7 @@ struct ipu6_isys_video {
struct media_pad pad; struct media_pad pad;
struct video_device vdev; struct video_device vdev;
struct v4l2_pix_format pix_fmt; struct v4l2_pix_format pix_fmt;
const struct ipu6_isys_pixelformat *pfmt; struct v4l2_meta_format meta_fmt;
struct ipu6_isys *isys; struct ipu6_isys *isys;
struct ipu6_isys_csi2 *csi2; struct ipu6_isys_csi2 *csi2;
struct ipu6_isys_stream *stream; struct ipu6_isys_stream *stream;
...@@ -108,6 +109,8 @@ struct ipu6_isys_video { ...@@ -108,6 +109,8 @@ struct ipu6_isys_video {
extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts[]; extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts[];
extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts_packed[]; extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts_packed[];
const struct ipu6_isys_pixelformat *
ipu6_isys_get_isys_format(u32 pixelformat, u32 code);
int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av, int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
struct media_entity *source_entity, struct media_entity *source_entity,
int nr_queues); int nr_queues);
...@@ -129,4 +132,10 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av, ...@@ -129,4 +132,10 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
bool state); bool state);
void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state); void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state);
u32 ipu6_isys_get_format(struct ipu6_isys_video *av);
u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av);
u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av);
u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av);
u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av);
#endif /* IPU6_ISYS_VIDEO_H */ #endif /* IPU6_ISYS_VIDEO_H */
...@@ -249,7 +249,6 @@ static int isys_register_video_devices(struct ipu6_isys *isys) ...@@ -249,7 +249,6 @@ static int isys_register_video_devices(struct ipu6_isys *isys)
av->isys = isys; av->isys = isys;
av->aq.vbq.buf_struct_size = av->aq.vbq.buf_struct_size =
sizeof(struct ipu6_isys_video_buffer); sizeof(struct ipu6_isys_video_buffer);
av->pfmt = &ipu6_isys_pfmts[0];
ret = ipu6_isys_video_init(av); ret = ipu6_isys_video_init(av);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment