From nobody Fri Dec 19 16:07:59 2025 Received: from mx.gpxsee.org (mx.gpxsee.org [37.205.14.76]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8712148848; Fri, 26 Apr 2024 14:25:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=37.205.14.76 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714141536; cv=none; b=JycwZJ980bezTAAxFXCRhRRVAVPb55mKADwMhq33xgb6q+9M1Al0EDd9ZyJGx98SmAcuBn25XU4Lto9GeDlEMp4sd/6eM9U7qYWJYKj99d4DuIx2ACB5tT7nr0S5herrvoANexR1RGgBNSPp/cwmQkjIl+3w9Qd8wHDfFvsF/Qg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714141536; c=relaxed/simple; bh=ccRpWXTBYy4x2pBc2wBVCQ8YO4UdS6e31f0367Lm588=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=B+8eO2Fi6ToclME6RFsDDndb0V33eQwJVHfZvYLieoxga1c6zdCcchdLuHEjYLHT/a0JQb37xtqypoO7kUQsLQ5foPkEoBUY/gv8YZFO97K/lhCIZdxqdTm3FnhUQzgrCrc1W2BhJAchVFfR44iFB1ZEuYf/FVOQS0D43TnHtUw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gpxsee.org; spf=pass smtp.mailfrom=gpxsee.org; arc=none smtp.client-ip=37.205.14.76 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gpxsee.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gpxsee.org Received: from mgb4.. (unknown [62.77.71.229]) by mx.gpxsee.org (Postfix) with ESMTPSA id 581FD4260D; Fri, 26 Apr 2024 16:16:26 +0200 (CEST) From: tumic@gpxsee.org To: Mauro Carvalho Chehab , Hans Verkuil Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Martin=20T=C5=AFma?= Subject: [PATCH v5 1/4] media: mgb4: Add support for YUV image formats Date: Fri, 26 Apr 2024 16:16:16 +0200 Message-ID: <20240426141619.8866-2-tumic@gpxsee.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240426141619.8866-1-tumic@gpxsee.org> References: <20240426141619.8866-1-tumic@gpxsee.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Martin T=C5=AFma Recent mgb4 firmwares support YUV in addition to the RGB image format. Enab= le YUV in the driver when the FW supports it. Signed-off-by: Martin T=C5=AFma --- drivers/media/pci/mgb4/mgb4_io.h | 7 ++ drivers/media/pci/mgb4/mgb4_vin.c | 107 ++++++++++++++++++++++------ drivers/media/pci/mgb4/mgb4_vout.c | 109 +++++++++++++++++++++++------ 3 files changed, 183 insertions(+), 40 deletions(-) diff --git a/drivers/media/pci/mgb4/mgb4_io.h b/drivers/media/pci/mgb4/mgb4= _io.h index 8698db1be4a9..204613a6685c 100644 --- a/drivers/media/pci/mgb4/mgb4_io.h +++ b/drivers/media/pci/mgb4/mgb4_io.h @@ -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); } =20 +static inline bool has_yuv(struct mgb4_regs *video) +{ + u32 status =3D mgb4_read_reg(video, 0xD0); + + return (status & (1U << 8)); +} + #endif diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb= 4_vin.c index 2cd78c539889..7fb14e867e8d 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.c +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -186,8 +186,11 @@ static int queue_setup(struct vb2_queue *q, unsigned i= nt *nbuffers, struct device *alloc_devs[]) { struct mgb4_vin_dev *vindev =3D vb2_get_drv_priv(q); + struct mgb4_regs *video =3D &vindev->mgbdev->video; + u32 config =3D mgb4_read_reg(video, vindev->config->regs.config); + u32 pixelsize =3D (config & (1U << 16)) ? 2 : 4; unsigned int size =3D (vindev->timings.bt.width + vindev->padding) - * vindev->timings.bt.height * 4; + * vindev->timings.bt.height * pixelsize; =20 /* * 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 =3D vb2_get_drv_priv(vb->vb2_queue); + struct mgb4_regs *video =3D &vindev->mgbdev->video; struct device *dev =3D &vindev->mgbdev->pdev->dev; + u32 config =3D mgb4_read_reg(video, vindev->config->regs.config); + u32 pixelsize =3D (config & (1U << 16)) ? 2 : 4; unsigned int size =3D (vindev->timings.bt.width + vindev->padding) - * vindev->timings.bt.height * 4; + * vindev->timings.bt.height * pixelsize; =20 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 *p= riv, static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index !=3D 0) - return -EINVAL; - - f->pixelformat =3D V4L2_PIX_FMT_ABGR32; + struct mgb4_vin_dev *vindev =3D video_drvdata(file); + struct mgb4_regs *video =3D &vindev->mgbdev->video; =20 - return 0; + if (f->index =3D=3D 0) { + f->pixelformat =3D V4L2_PIX_FMT_ABGR32; + return 0; + } else if (f->index =3D=3D 1 && has_yuv(video)) { + f->pixelformat =3D V4L2_PIX_FMT_YUYV; + return 0; + } else { + return -EINVAL; + } } =20 static int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *ival) { struct mgb4_vin_dev *vindev =3D video_drvdata(file); + struct mgb4_regs *video =3D &vindev->mgbdev->video; =20 if (ival->index !=3D 0) return -EINVAL; - if (ival->pixel_format !=3D V4L2_PIX_FMT_ABGR32) + if (!(ival->pixel_format =3D=3D V4L2_PIX_FMT_ABGR32 || + ((has_yuv(video) && ival->pixel_format =3D=3D V4L2_PIX_FMT_YUYV)))) return -EINVAL; if (ival->width !=3D vindev->timings.bt.width || ival->height !=3D vindev->timings.bt.height) @@ -393,13 +407,29 @@ static int vidioc_enum_frameintervals(struct file *fi= le, void *priv, static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format = *f) { struct mgb4_vin_dev *vindev =3D video_drvdata(file); + struct mgb4_regs *video =3D &vindev->mgbdev->video; + u32 config =3D mgb4_read_reg(video, vindev->config->regs.config); =20 - f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; f->fmt.pix.width =3D vindev->timings.bt.width; f->fmt.pix.height =3D vindev->timings.bt.height; f->fmt.pix.field =3D V4L2_FIELD_NONE; - f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; - f->fmt.pix.bytesperline =3D (f->fmt.pix.width + vindev->padding) * 4; + + if (config & (1U << 16)) { + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_YUYV; + if (config & (1U << 20)) { + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_REC709; + } else { + if (config & (1U << 19)) + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SRGB; + } + f->fmt.pix.bytesperline =3D (f->fmt.pix.width + vindev->padding) * 2; + } else { + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline =3D (f->fmt.pix.width + vindev->padding) * 4; + } f->fmt.pix.sizeimage =3D f->fmt.pix.bytesperline * f->fmt.pix.height; =20 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_forma= t *f) { struct mgb4_vin_dev *vindev =3D video_drvdata(file); + struct mgb4_regs *video =3D &vindev->mgbdev->video; + u32 pixelsize; =20 - f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; f->fmt.pix.width =3D vindev->timings.bt.width; f->fmt.pix.height =3D vindev->timings.bt.height; f->fmt.pix.field =3D V4L2_FIELD_NONE; - f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; - f->fmt.pix.bytesperline =3D max(f->fmt.pix.width * 4, - ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + + if (has_yuv(video) && f->fmt.pix.pixelformat =3D=3D V4L2_PIX_FMT_YUYV) { + pixelsize =3D 2; + if (!(f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_REC709 || + f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_SMPTE170M)) + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SRGB; + } else { + pixelsize =3D 4; + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; + f->fmt.pix.colorspace =3D 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 =3D ALIGN(f->fmt.pix.bytesperline, + pixelsize); + else + f->fmt.pix.bytesperline =3D f->fmt.pix.width * pixelsize; f->fmt.pix.sizeimage =3D f->fmt.pix.bytesperline * f->fmt.pix.height; =20 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 =3D video_drvdata(file); struct mgb4_regs *video =3D &vindev->mgbdev->video; + u32 config, pixelsize; =20 if (vb2_is_busy(&vindev->queue)) return -EBUSY; =20 vidioc_try_fmt(file, priv, f); =20 - vindev->padding =3D (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / = 4; + config =3D mgb4_read_reg(video, vindev->config->regs.config); + if (f->fmt.pix.pixelformat =3D=3D V4L2_PIX_FMT_YUYV) { + pixelsize =3D 2; + config |=3D 1U << 16; + + if (f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_REC709) { + config |=3D 1U << 20; + config |=3D 1U << 19; + } else if (f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_SMPTE170M) { + config &=3D ~(1U << 20); + config |=3D 1U << 19; + } else { + config &=3D ~(1U << 20); + config &=3D ~(1U << 19); + } + } else { + pixelsize =3D 4; + config &=3D ~(1U << 16); + } + mgb4_write_reg(video, vindev->config->regs.config, config); + + vindev->padding =3D (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); =20 @@ -467,7 +536,8 @@ static int vidioc_enum_framesizes(struct file *file, vo= id *fh, { struct mgb4_vin_dev *vindev =3D video_drvdata(file); =20 - if (fsize->index !=3D 0 || fsize->pixel_format !=3D V4L2_PIX_FMT_ABGR32) + if (fsize->index !=3D 0 || !(fsize->pixel_format =3D=3D V4L2_PIX_FMT_ABGR= 32 || + fsize->pixel_format =3D=3D V4L2_PIX_FMT_YUYV)) return -EINVAL; =20 fsize->discrete.width =3D vindev->timings.bt.width; @@ -499,9 +569,6 @@ static int vidioc_parm(struct file *file, void *priv, .denominator =3D 125000000, }; =20 - if (parm->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - parm->parm.capture.readbuffers =3D 2; parm->parm.capture.capability =3D V4L2_CAP_TIMEPERFRAME; parm->parm.capture.timeperframe =3D timeperframe; diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mg= b4_vout.c index 241353ee77a5..2ee9606d9072 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.c +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -59,7 +59,11 @@ static int queue_setup(struct vb2_queue *q, unsigned int= *nbuffers, struct device *alloc_devs[]) { struct mgb4_vout_dev *voutdev =3D vb2_get_drv_priv(q); - unsigned int size; + struct mgb4_regs *video =3D &voutdev->mgbdev->video; + u32 config =3D mgb4_read_reg(video, voutdev->config->regs.config); + u32 pixelsize =3D (config & (1U << 16)) ? 2 : 4; + unsigned int size =3D (voutdev->width + voutdev->padding) * voutdev->heig= ht + * pixelsize; =20 /* * 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; =20 - size =3D (voutdev->width + voutdev->padding) * voutdev->height * 4; - if (*nplanes) return sizes[0] < size ? -EINVAL : 0; *nplanes =3D 1; @@ -93,9 +95,11 @@ static int buffer_prepare(struct vb2_buffer *vb) { struct mgb4_vout_dev *voutdev =3D vb2_get_drv_priv(vb->vb2_queue); struct device *dev =3D &voutdev->mgbdev->pdev->dev; - unsigned int size; - - size =3D (voutdev->width + voutdev->padding) * voutdev->height * 4; + struct mgb4_regs *video =3D &voutdev->mgbdev->video; + u32 config =3D mgb4_read_reg(video, voutdev->config->regs.config); + u32 pixelsize =3D (config & (1U << 16)) ? 2 : 4; + unsigned int size =3D (voutdev->width + voutdev->padding) * voutdev->heig= ht + * pixelsize; =20 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 *p= riv, static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index !=3D 0) - return -EINVAL; - - f->pixelformat =3D V4L2_PIX_FMT_ABGR32; + struct mgb4_vin_dev *voutdev =3D video_drvdata(file); + struct mgb4_regs *video =3D &voutdev->mgbdev->video; =20 - return 0; + if (f->index =3D=3D 0) { + f->pixelformat =3D V4L2_PIX_FMT_ABGR32; + return 0; + } else if (f->index =3D=3D 1 && has_yuv(video)) { + f->pixelformat =3D V4L2_PIX_FMT_YUYV; + return 0; + } else { + return -EINVAL; + } } =20 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format = *f) { struct mgb4_vout_dev *voutdev =3D video_drvdata(file); + struct mgb4_regs *video =3D &voutdev->mgbdev->video; + u32 config =3D mgb4_read_reg(video, voutdev->config->regs.config); =20 - f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; f->fmt.pix.width =3D voutdev->width; f->fmt.pix.height =3D voutdev->height; f->fmt.pix.field =3D V4L2_FIELD_NONE; - f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; - f->fmt.pix.bytesperline =3D (f->fmt.pix.width + voutdev->padding) * 4; + + if (config & (1U << 16)) { + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_YUYV; + if (config & (1U << 20)) { + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_REC709; + } else { + if (config & (1U << 19)) + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SRGB; + } + f->fmt.pix.bytesperline =3D (f->fmt.pix.width + voutdev->padding) * 2; + } else { + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline =3D (f->fmt.pix.width + voutdev->padding) * 4; + } + f->fmt.pix.sizeimage =3D f->fmt.pix.bytesperline * f->fmt.pix.height; =20 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_forma= t *f) { struct mgb4_vout_dev *voutdev =3D video_drvdata(file); + struct mgb4_regs *video =3D &voutdev->mgbdev->video; + u32 pixelsize; =20 - f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; f->fmt.pix.width =3D voutdev->width; f->fmt.pix.height =3D voutdev->height; f->fmt.pix.field =3D V4L2_FIELD_NONE; - f->fmt.pix.colorspace =3D V4L2_COLORSPACE_RAW; - f->fmt.pix.bytesperline =3D max(f->fmt.pix.width * 4, - ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + + if (has_yuv(video) && f->fmt.pix.pixelformat =3D=3D V4L2_PIX_FMT_YUYV) { + pixelsize =3D 2; + if (!(f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_REC709 || + f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_SMPTE170M)) + f->fmt.pix.colorspace =3D V4L2_COLORSPACE_SRGB; + } else { + pixelsize =3D 4; + f->fmt.pix.pixelformat =3D V4L2_PIX_FMT_ABGR32; + f->fmt.pix.colorspace =3D 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 =3D ALIGN(f->fmt.pix.bytesperline, + pixelsize); + else + f->fmt.pix.bytesperline =3D f->fmt.pix.width * pixelsize; f->fmt.pix.sizeimage =3D f->fmt.pix.bytesperline * f->fmt.pix.height; =20 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 =3D video_drvdata(file); struct mgb4_regs *video =3D &voutdev->mgbdev->video; + u32 config, pixelsize; + int ret; =20 if (vb2_is_busy(&voutdev->queue)) return -EBUSY; =20 - vidioc_try_fmt(file, priv, f); + ret =3D vidioc_try_fmt(file, priv, f); + if (ret < 0) + return ret; + + config =3D mgb4_read_reg(video, voutdev->config->regs.config); + if (f->fmt.pix.pixelformat =3D=3D V4L2_PIX_FMT_YUYV) { + pixelsize =3D 2; + config |=3D 1U << 16; + + if (f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_REC709) { + config |=3D 1U << 20; + config |=3D 1U << 19; + } else if (f->fmt.pix.colorspace =3D=3D V4L2_COLORSPACE_SMPTE170M) { + config &=3D ~(1U << 20); + config |=3D 1U << 19; + } else { + config &=3D ~(1U << 20); + config &=3D ~(1U << 19); + } + } else { + pixelsize =3D 4; + config &=3D ~(1U << 16); + } + mgb4_write_reg(video, voutdev->config->regs.config, config); =20 - voutdev->padding =3D (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) /= 4; + voutdev->padding =3D (f->fmt.pix.bytesperline - (f->fmt.pix.width + * pixelsize)) / pixelsize; mgb4_write_reg(video, voutdev->config->regs.padding, voutdev->padding); =20 return 0; --=20 2.44.0