media: renesas: vsp1: Allow setting encoding and quantization

The RPF and WPF support different encodings and quantizations when
converting between RGB and YUV formats. Allow setting the corresponding
format parameters from userspace, and configure the hardware
accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Link: https://lore.kernel.org/r/20250429232904.26413-7-laurent.pinchart+renesas@ideasonboard.com
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
Laurent Pinchart 2025-04-30 02:29:01 +03:00 committed by Hans Verkuil
parent d5e3bc24d5
commit e6c9597e5f
5 changed files with 121 additions and 16 deletions

View File

@ -359,33 +359,42 @@ vsp1_get_format_info_by_index(struct vsp1_device *vsp1, unsigned int index,
* space and limitations of the VSP1. It should be used in the video device and
* subdev set format handlers.
*
* For now, simply hardcode the color space fields to the VSP1 defaults based
* on the media bus code.
* The colorspace and xfer_func fields are freely configurable, as they are out
* of scope for VSP processing. The encoding and quantization is hardcoded for
* non-YUV formats, and can be configured for YUV formats.
*/
void vsp1_adjust_color_space(u32 code, u32 *colorspace, u8 *xfer_func,
u8 *encoding, u8 *quantization)
{
if (*colorspace == V4L2_COLORSPACE_DEFAULT ||
*colorspace >= V4L2_COLORSPACE_LAST)
*colorspace = code == MEDIA_BUS_FMT_AYUV8_1X32
? V4L2_COLORSPACE_SMPTE170M
: V4L2_COLORSPACE_SRGB;
if (*xfer_func == V4L2_XFER_FUNC_DEFAULT ||
*xfer_func >= V4L2_XFER_FUNC_LAST)
*xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(*colorspace);
switch (code) {
case MEDIA_BUS_FMT_ARGB8888_1X32:
default:
*colorspace = V4L2_COLORSPACE_SRGB;
*xfer_func = V4L2_XFER_FUNC_SRGB;
*encoding = V4L2_YCBCR_ENC_601;
*quantization = V4L2_QUANTIZATION_FULL_RANGE;
break;
case MEDIA_BUS_FMT_AHSV8888_1X32:
*colorspace = V4L2_COLORSPACE_SRGB;
*xfer_func = V4L2_XFER_FUNC_SRGB;
*encoding = V4L2_HSV_ENC_256;
*quantization = V4L2_QUANTIZATION_FULL_RANGE;
break;
case MEDIA_BUS_FMT_AYUV8_1X32:
*colorspace = V4L2_COLORSPACE_SMPTE170M;
*xfer_func = V4L2_XFER_FUNC_709;
*encoding = V4L2_YCBCR_ENC_601;
*quantization = V4L2_QUANTIZATION_LIM_RANGE;
if (*encoding != V4L2_YCBCR_ENC_601 &&
*encoding != V4L2_YCBCR_ENC_709)
*encoding = V4L2_YCBCR_ENC_601;
if (*quantization != V4L2_QUANTIZATION_FULL_RANGE &&
*quantization != V4L2_QUANTIZATION_LIM_RANGE)
*quantization = V4L2_QUANTIZATION_LIM_RANGE;
break;
}
}

View File

@ -92,8 +92,33 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
if (fmtinfo->swap_uv)
infmt |= VI6_RPF_INFMT_SPUVS;
if (sink_format->code != source_format->code)
infmt |= VI6_RPF_INFMT_CSC;
if (sink_format->code != source_format->code) {
u16 ycbcr_enc;
u16 quantization;
u32 rdtm;
if (sink_format->code == MEDIA_BUS_FMT_AYUV8_1X32) {
ycbcr_enc = sink_format->ycbcr_enc;
quantization = sink_format->quantization;
} else {
ycbcr_enc = source_format->ycbcr_enc;
quantization = source_format->quantization;
}
if (ycbcr_enc == V4L2_YCBCR_ENC_601 &&
quantization == V4L2_QUANTIZATION_LIM_RANGE)
rdtm = VI6_RPF_INFMT_RDTM_BT601;
else if (ycbcr_enc == V4L2_YCBCR_ENC_601 &&
quantization == V4L2_QUANTIZATION_FULL_RANGE)
rdtm = VI6_RPF_INFMT_RDTM_BT601_EXT;
else if (ycbcr_enc == V4L2_YCBCR_ENC_709 &&
quantization == V4L2_QUANTIZATION_LIM_RANGE)
rdtm = VI6_RPF_INFMT_RDTM_BT709;
else
rdtm = VI6_RPF_INFMT_RDTM_BT709_EXT;
infmt |= VI6_RPF_INFMT_CSC | rdtm;
}
vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt);
vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap);

View File

@ -36,6 +36,11 @@ static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
code->code = codes[code->index];
if (code->pad == RWPF_PAD_SOURCE &&
code->code == MEDIA_BUS_FMT_AYUV8_1X32)
code->flags = V4L2_SUBDEV_MBUS_CODE_CSC_YCBCR_ENC
| V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION;
return 0;
}
@ -79,11 +84,13 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
if (fmt->pad == RWPF_PAD_SOURCE) {
const struct v4l2_mbus_framefmt *sink_format =
v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
u16 flags = fmt->format.flags & V4L2_MBUS_FRAMEFMT_SET_CSC;
bool csc;
/*
* The RWPF performs format conversion but can't scale, only the
* format code can be changed on the source pad when converting
* between RGB and YUV.
* format code, encoding and quantization can be changed on the
* source pad when converting between RGB and YUV.
*/
if (sink_format->code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32)
@ -91,9 +98,29 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
else
format->code = sink_format->code;
/*
* Encoding and quantization can only be configured when YCbCr
* <-> RGB is enabled. The V4L2 API requires userspace to set
* the V4L2_MBUS_FRAMEFMT_SET_CSC flag. If either of these
* conditions is not met, use the encoding and quantization
* values from the sink pad.
*/
csc = (format->code == MEDIA_BUS_FMT_AYUV8_1X32) !=
(sink_format->code == MEDIA_BUS_FMT_AYUV8_1X32);
if (csc && (flags & V4L2_MBUS_FRAMEFMT_SET_CSC)) {
format->ycbcr_enc = fmt->format.ycbcr_enc;
format->quantization = fmt->format.quantization;
} else {
format->ycbcr_enc = sink_format->ycbcr_enc;
format->quantization = sink_format->quantization;
}
vsp1_entity_adjust_color_space(format);
fmt->format = *format;
fmt->format.flags = flags;
goto done;
}

View File

@ -129,6 +129,20 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
pix->pixelformat = info->fourcc;
pix->field = V4L2_FIELD_NONE;
/*
* Adjust the colour space fields. On capture devices, userspace needs
* to set the V4L2_PIX_FMT_FLAG_SET_CSC to override the defaults. Reset
* all fields to *_DEFAULT if the flag isn't set, to then handle
* capture and output devices in the same way.
*/
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
!(pix->flags & V4L2_PIX_FMT_FLAG_SET_CSC)) {
pix->colorspace = V4L2_COLORSPACE_DEFAULT;
pix->xfer_func = V4L2_XFER_FUNC_DEFAULT;
pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
pix->quantization = V4L2_QUANTIZATION_DEFAULT;
}
vsp1_adjust_color_space(info->mbus, &pix->colorspace, &pix->xfer_func,
&pix->ycbcr_enc, &pix->quantization);
@ -908,6 +922,11 @@ static int vsp1_video_enum_format(struct file *file, void *fh,
f->pixelformat = info->fourcc;
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
info->mbus == MEDIA_BUS_FMT_AYUV8_1X32)
f->flags = V4L2_FMT_FLAG_CSC_YCBCR_ENC
| V4L2_FMT_FLAG_CSC_QUANTIZATION;
return 0;
}

View File

@ -282,8 +282,33 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
(256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
}
if (sink_format->code != source_format->code)
outfmt |= VI6_WPF_OUTFMT_CSC;
if (sink_format->code != source_format->code) {
u16 ycbcr_enc;
u16 quantization;
u32 wrtm;
if (sink_format->code == MEDIA_BUS_FMT_AYUV8_1X32) {
ycbcr_enc = sink_format->ycbcr_enc;
quantization = sink_format->quantization;
} else {
ycbcr_enc = source_format->ycbcr_enc;
quantization = source_format->quantization;
}
if (ycbcr_enc == V4L2_YCBCR_ENC_601 &&
quantization == V4L2_QUANTIZATION_LIM_RANGE)
wrtm = VI6_WPF_OUTFMT_WRTM_BT601;
else if (ycbcr_enc == V4L2_YCBCR_ENC_601 &&
quantization == V4L2_QUANTIZATION_FULL_RANGE)
wrtm = VI6_WPF_OUTFMT_WRTM_BT601_EXT;
else if (ycbcr_enc == V4L2_YCBCR_ENC_709 &&
quantization == V4L2_QUANTIZATION_LIM_RANGE)
wrtm = VI6_WPF_OUTFMT_WRTM_BT709;
else
wrtm = VI6_WPF_OUTFMT_WRTM_BT709_EXT;
outfmt |= VI6_WPF_OUTFMT_CSC | wrtm;
}
wpf->outfmt = outfmt;