media: mgb4: Add support for YUV image formats
Recent mgb4 firmwares support YUV in addition to the RGB image format. Enable YUV in the driver when the FW supports it. Signed-off-by: Martin Tůma <martin.tuma@digiteqautomotive.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
committed by
Hans Verkuil
parent
044fcf738a
commit
a5972ea0fb
@@ -30,4 +30,11 @@ static inline struct mgb4_frame_buffer *to_frame_buffer(struct vb2_v4l2_buffer *
|
||||
return container_of(vbuf, struct mgb4_frame_buffer, vb);
|
||||
}
|
||||
|
||||
static inline bool has_yuv(struct mgb4_regs *video)
|
||||
{
|
||||
u32 status = mgb4_read_reg(video, 0xD0);
|
||||
|
||||
return (status & (1U << 8));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -186,8 +186,11 @@ static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers,
|
||||
struct device *alloc_devs[])
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = vb2_get_drv_priv(q);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
u32 config = mgb4_read_reg(video, vindev->config->regs.config);
|
||||
u32 pixelsize = (config & (1U << 16)) ? 2 : 4;
|
||||
unsigned int size = (vindev->timings.bt.width + vindev->padding)
|
||||
* vindev->timings.bt.height * 4;
|
||||
* vindev->timings.bt.height * pixelsize;
|
||||
|
||||
/*
|
||||
* If I/O reconfiguration is in process, do not allow to start
|
||||
@@ -220,9 +223,12 @@ static int buffer_init(struct vb2_buffer *vb)
|
||||
static int buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
struct device *dev = &vindev->mgbdev->pdev->dev;
|
||||
u32 config = mgb4_read_reg(video, vindev->config->regs.config);
|
||||
u32 pixelsize = (config & (1U << 16)) ? 2 : 4;
|
||||
unsigned int size = (vindev->timings.bt.width + vindev->padding)
|
||||
* vindev->timings.bt.height * 4;
|
||||
* vindev->timings.bt.height * pixelsize;
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size) {
|
||||
dev_err(dev, "buffer too small (%lu < %u)\n",
|
||||
@@ -359,22 +365,30 @@ static int vidioc_querycap(struct file *file, void *priv,
|
||||
static int vidioc_enum_fmt(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
if (f->index != 0)
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
|
||||
if (f->index == 0) {
|
||||
f->pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
return 0;
|
||||
} else if (f->index == 1 && has_yuv(video)) {
|
||||
f->pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
f->pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int vidioc_enum_frameintervals(struct file *file, void *priv,
|
||||
struct v4l2_frmivalenum *ival)
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
|
||||
if (ival->index != 0)
|
||||
return -EINVAL;
|
||||
if (ival->pixel_format != V4L2_PIX_FMT_ABGR32)
|
||||
if (!(ival->pixel_format == V4L2_PIX_FMT_ABGR32 ||
|
||||
((has_yuv(video) && ival->pixel_format == V4L2_PIX_FMT_YUYV))))
|
||||
return -EINVAL;
|
||||
if (ival->width != vindev->timings.bt.width ||
|
||||
ival->height != vindev->timings.bt.height)
|
||||
@@ -393,13 +407,29 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
|
||||
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
u32 config = mgb4_read_reg(video, vindev->config->regs.config);
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.width = vindev->timings.bt.width;
|
||||
f->fmt.pix.height = vindev->timings.bt.height;
|
||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + vindev->padding) * 4;
|
||||
|
||||
if (config & (1U << 16)) {
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
if (config & (1U << 20)) {
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
|
||||
} else {
|
||||
if (config & (1U << 19))
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
else
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
}
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + vindev->padding) * 2;
|
||||
} else {
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + vindev->padding) * 4;
|
||||
}
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
|
||||
|
||||
return 0;
|
||||
@@ -408,14 +438,30 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
u32 pixelsize;
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.width = vindev->timings.bt.width;
|
||||
f->fmt.pix.height = vindev->timings.bt.height;
|
||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4,
|
||||
ALIGN_DOWN(f->fmt.pix.bytesperline, 4));
|
||||
|
||||
if (has_yuv(video) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
pixelsize = 2;
|
||||
if (!(f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709 ||
|
||||
f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M))
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
} else {
|
||||
pixelsize = 4;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
}
|
||||
|
||||
if (f->fmt.pix.bytesperline > f->fmt.pix.width * pixelsize &&
|
||||
f->fmt.pix.bytesperline < f->fmt.pix.width * pixelsize * 2)
|
||||
f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline,
|
||||
pixelsize);
|
||||
else
|
||||
f->fmt.pix.bytesperline = f->fmt.pix.width * pixelsize;
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
|
||||
|
||||
return 0;
|
||||
@@ -425,13 +471,36 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &vindev->mgbdev->video;
|
||||
u32 config, pixelsize;
|
||||
|
||||
if (vb2_is_busy(&vindev->queue))
|
||||
return -EBUSY;
|
||||
|
||||
vidioc_try_fmt(file, priv, f);
|
||||
|
||||
vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4;
|
||||
config = mgb4_read_reg(video, vindev->config->regs.config);
|
||||
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
pixelsize = 2;
|
||||
config |= 1U << 16;
|
||||
|
||||
if (f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709) {
|
||||
config |= 1U << 20;
|
||||
config |= 1U << 19;
|
||||
} else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M) {
|
||||
config &= ~(1U << 20);
|
||||
config |= 1U << 19;
|
||||
} else {
|
||||
config &= ~(1U << 20);
|
||||
config &= ~(1U << 19);
|
||||
}
|
||||
} else {
|
||||
pixelsize = 4;
|
||||
config &= ~(1U << 16);
|
||||
}
|
||||
mgb4_write_reg(video, vindev->config->regs.config, config);
|
||||
|
||||
vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width
|
||||
* pixelsize)) / pixelsize;
|
||||
mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding);
|
||||
set_loopback_padding(vindev, vindev->padding);
|
||||
|
||||
@@ -467,7 +536,8 @@ static int vidioc_enum_framesizes(struct file *file, void *fh,
|
||||
{
|
||||
struct mgb4_vin_dev *vindev = video_drvdata(file);
|
||||
|
||||
if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_ABGR32)
|
||||
if (fsize->index != 0 || !(fsize->pixel_format == V4L2_PIX_FMT_ABGR32 ||
|
||||
fsize->pixel_format == V4L2_PIX_FMT_YUYV))
|
||||
return -EINVAL;
|
||||
|
||||
fsize->discrete.width = vindev->timings.bt.width;
|
||||
@@ -499,9 +569,6 @@ static int vidioc_parm(struct file *file, void *priv,
|
||||
.denominator = 125000000,
|
||||
};
|
||||
|
||||
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
parm->parm.capture.readbuffers = 2;
|
||||
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
|
||||
parm->parm.capture.timeperframe = timeperframe;
|
||||
|
||||
@@ -59,7 +59,11 @@ static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers,
|
||||
struct device *alloc_devs[])
|
||||
{
|
||||
struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(q);
|
||||
unsigned int size;
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
u32 config = mgb4_read_reg(video, voutdev->config->regs.config);
|
||||
u32 pixelsize = (config & (1U << 16)) ? 2 : 4;
|
||||
unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height
|
||||
* pixelsize;
|
||||
|
||||
/*
|
||||
* If I/O reconfiguration is in process, do not allow to start
|
||||
@@ -69,8 +73,6 @@ static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers,
|
||||
if (test_bit(0, &voutdev->mgbdev->io_reconfig))
|
||||
return -EBUSY;
|
||||
|
||||
size = (voutdev->width + voutdev->padding) * voutdev->height * 4;
|
||||
|
||||
if (*nplanes)
|
||||
return sizes[0] < size ? -EINVAL : 0;
|
||||
*nplanes = 1;
|
||||
@@ -93,9 +95,11 @@ static int buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct device *dev = &voutdev->mgbdev->pdev->dev;
|
||||
unsigned int size;
|
||||
|
||||
size = (voutdev->width + voutdev->padding) * voutdev->height * 4;
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
u32 config = mgb4_read_reg(video, voutdev->config->regs.config);
|
||||
u32 pixelsize = (config & (1U << 16)) ? 2 : 4;
|
||||
unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height
|
||||
* pixelsize;
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size) {
|
||||
dev_err(dev, "buffer too small (%lu < %u)\n",
|
||||
@@ -194,24 +198,47 @@ static int vidioc_querycap(struct file *file, void *priv,
|
||||
static int vidioc_enum_fmt(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
if (f->index != 0)
|
||||
struct mgb4_vin_dev *voutdev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
|
||||
if (f->index == 0) {
|
||||
f->pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
return 0;
|
||||
} else if (f->index == 1 && has_yuv(video)) {
|
||||
f->pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
f->pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vout_dev *voutdev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
u32 config = mgb4_read_reg(video, voutdev->config->regs.config);
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.width = voutdev->width;
|
||||
f->fmt.pix.height = voutdev->height;
|
||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4;
|
||||
|
||||
if (config & (1U << 16)) {
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
if (config & (1U << 20)) {
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
|
||||
} else {
|
||||
if (config & (1U << 19))
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
else
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
}
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 2;
|
||||
} else {
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4;
|
||||
}
|
||||
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
|
||||
|
||||
return 0;
|
||||
@@ -220,14 +247,30 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vout_dev *voutdev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
u32 pixelsize;
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.width = voutdev->width;
|
||||
f->fmt.pix.height = voutdev->height;
|
||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4,
|
||||
ALIGN_DOWN(f->fmt.pix.bytesperline, 4));
|
||||
|
||||
if (has_yuv(video) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
pixelsize = 2;
|
||||
if (!(f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709 ||
|
||||
f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M))
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
} else {
|
||||
pixelsize = 4;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
|
||||
}
|
||||
|
||||
if (f->fmt.pix.bytesperline > f->fmt.pix.width * pixelsize &&
|
||||
f->fmt.pix.bytesperline < f->fmt.pix.width * pixelsize * 2)
|
||||
f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline,
|
||||
pixelsize);
|
||||
else
|
||||
f->fmt.pix.bytesperline = f->fmt.pix.width * pixelsize;
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
|
||||
|
||||
return 0;
|
||||
@@ -237,13 +280,39 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
||||
{
|
||||
struct mgb4_vout_dev *voutdev = video_drvdata(file);
|
||||
struct mgb4_regs *video = &voutdev->mgbdev->video;
|
||||
u32 config, pixelsize;
|
||||
int ret;
|
||||
|
||||
if (vb2_is_busy(&voutdev->queue))
|
||||
return -EBUSY;
|
||||
|
||||
vidioc_try_fmt(file, priv, f);
|
||||
ret = vidioc_try_fmt(file, priv, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4;
|
||||
config = mgb4_read_reg(video, voutdev->config->regs.config);
|
||||
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
pixelsize = 2;
|
||||
config |= 1U << 16;
|
||||
|
||||
if (f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709) {
|
||||
config |= 1U << 20;
|
||||
config |= 1U << 19;
|
||||
} else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M) {
|
||||
config &= ~(1U << 20);
|
||||
config |= 1U << 19;
|
||||
} else {
|
||||
config &= ~(1U << 20);
|
||||
config &= ~(1U << 19);
|
||||
}
|
||||
} else {
|
||||
pixelsize = 4;
|
||||
config &= ~(1U << 16);
|
||||
}
|
||||
mgb4_write_reg(video, voutdev->config->regs.config, config);
|
||||
|
||||
voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width
|
||||
* pixelsize)) / pixelsize;
|
||||
mgb4_write_reg(video, voutdev->config->regs.padding, voutdev->padding);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user