* [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling
@ 2026-11-12 8:31 Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 1/7] media: verisilicon: Keep the encoder CAPTURE format while buffers exist Arun Iyengar via B4 Relay
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar, stable
This series fixes the format handling of the Hantro JPEG encoders, found
with v4l2-ctl, v4l2-compliance and GStreamer on the RK3588 VEPU121.
The encoder accepted a CAPTURE sizeimage far too small for the selected
resolution, and setting the OUTPUT format never updated the coded size,
so the sequence mandated by the stateful encoder specification (CAPTURE
format first, then OUTPUT) left a 96x32 coded format under a 1920x1088
raw one. The JPEG encoders program the hardware from the OUTPUT size and
use the difference as the crop inside the last macroblock, so this ended
in IOMMU page faults, a frame processing timeout and a wedged encoder.
Patches 2 and 3 fix the two ioctl paths, patch 4 refuses a job whose
geometry or CAPTURE buffer the hardware can't be programmed with, as a
last line of defence, and patch 5 reports the fixed colorimetry of JPEG
instead of propagating whatever the application set, which also fixes a
v4l2-compliance failure on the encoder.
Patch 1 keeps the CAPTURE (coded) format while CAPTURE buffers exist:
the encoder sizes its CAPTURE buffers for the coded format, so changing
it under allocated buffers would leave them the wrong size. Patch 6
keeps the raw OUTPUT format while OUTPUT buffers exist, which also fixes
a CAPTURE S_FMT that v4l2-ctl --stream-mmap issues after the OUTPUT queue
is set up: it succeeded but left the raw format descriptor reset
to the default (three planes) under a negotiated two-plane format, so the
next job read a plane from IOVA 0.
Patch 7 limits the advertised frame size to 8176x8176: both Rockchip
encoder register layouts hold the size in 9-bit macroblock counts, so
8192 was programmed as 0 macroblocks.
Patch 2 changes the same branch of hantro_try_fmt() as patch 3 of
"media: verisilicon: fix VEPU1 JPEG encoder writes past the CAPTURE
buffer" v2 from Sergei Khomenkov [1], which raises a small JPEG
sizeimage to the header plus 64 bytes. The minimum set here is always
above that one, so the two don't contradict each other, but the one
that is applied second needs a rebase of that branch.
[1] https://lore.kernel.org/r/20261110-hantro-buflimit-v2-0-ff7790def9fc@gmail.com
Tested on an Orange Pi 5 (RK3588S, VEPU121): with patches 2-6, an
explicit CAPTURE 1920x1080 JPEG plus OUTPUT NM12 stream gives 8
decodable 1920x1088 frames, a requested sizeimage of 1000 is raised to
4178544 and a larger one is kept, G_FMT on CAPTURE follows the OUTPUT
format, v4l2-compliance passes 49/49 (58/58 with streaming) with sRGB /
ITU-R 601 / full range on both queues, nine GStreamer v4l2jpegenc
pipelines reach EOS, and v4l2-ctl --stream-mmap no longer faults. Patch
4's checks are not reachable from userspace once the format ioctls are
fixed; no run printed them. With patch 7, NV12, I420, YUYV and UYVY
encodes from 96x96 up to 8176x8176 (including 8176x1080, 1920x8176 and a
cropped 8168x8164) decode back at 53 dB PSNR, 8192 wide or high is
refused at S_FMT, and a probe with the reserved bit above each field set
showed the hardware does not take a 512 macroblock count.
The new CAPTURE busy check of patch 1 was tested on the board with v2:
S_FMT on the CAPTURE queue succeeds before buffers are allocated,
returns -EBUSY while one is, and succeeds again after they are freed.
On that kernel v4l2-compliance still passes 49/49 (58/58 with
streaming), and v4l2-ctl --stream-mmap encodes eight 1920x1088 frames
with no fault or timeout.
This series was developed with Claude (Anthropic) as a coding assistant:
it wrote the code and the commit messages, and I reviewed and tested
every change as described above.
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
Changes in v2:
- New patch 1: keep the CAPTURE (coded) format while CAPTURE buffers
exist, returning -EBUSY from S_FMT, so the coded buffers
can't be left sized for a different format (Sashiko: hantro_set_fmt_cap()
was missing the CAPTURE busy check)
- Patches 2, 3 and 5 (the sizeimage, coded-size and colorimetry
patches) now carry a Fixes tag (Sashiko)
- Patch 2: the commit message and the comment no longer call the
default size the worst case; no functional change
- Patch 4: complete the controls of the request when the job is refused
by the geometry check, so the media request doesn't hang (Sashiko: the
early return left the request uncompleted)
- Patch 5: the commit message names the mtk-jpeg and imx-jpeg drivers,
so the series no longer goes to the MediaTek maintainers and list
(matched by a keyword only); no code change
- Patch 6: commit message corrected, the CAPTURE S_FMT succeeds (the
-EBUSY from hantro_set_fmt_out() is ignored) and leaves the raw format
descriptor out of sync, and the Fixes tags now name the commits
that introduced the reset and the mismatch (Sashiko); no code change
- Patch 7 (the size limit) unchanged
- Cover letter: note the overlap with Sergei Khomenkov's series
- Link to v1: https://patch.msgid.link/20261110-hantro-jpeg-enc-fixes-v1-0-fc4dc7e985d2@gmail.com
---
Arun Iyengar (7):
media: verisilicon: Keep the encoder CAPTURE format while buffers exist
media: verisilicon: Enforce a minimum CAPTURE sizeimage for the encoder
media: verisilicon: Keep the encoder coded size in sync with OUTPUT
media: verisilicon: Refuse JPEG encode jobs with inconsistent geometry
media: verisilicon: Report fixed JPEG colorimetry on the encoder
media: verisilicon: Don't reset the encoder raw format while OUTPUT buffers exist
media: verisilicon: rockchip: Limit the JPEG encoder to 8176x8176
.../platform/verisilicon/hantro_h1_jpeg_enc.c | 9 ++
drivers/media/platform/verisilicon/hantro_jpeg.c | 37 +++++++++
drivers/media/platform/verisilicon/hantro_jpeg.h | 5 ++
drivers/media/platform/verisilicon/hantro_v4l2.c | 97 +++++++++++++++++++---
.../verisilicon/rockchip_vpu2_hw_jpeg_enc.c | 9 ++
.../media/platform/verisilicon/rockchip_vpu_hw.c | 11 ++-
6 files changed, 155 insertions(+), 13 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261110-hantro-jpeg-enc-fixes-9ff8bf6a491f
Best regards,
--
Arun Iyengar <aiyengar1990@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/7] media: verisilicon: Keep the encoder CAPTURE format while buffers exist
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 2/7] media: verisilicon: Enforce a minimum CAPTURE sizeimage for the encoder Arun Iyengar via B4 Relay
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar, stable
From: Arun Iyengar <aiyengar1990@gmail.com>
Commit bbd267daf4fc ("media: verisilicon: vp9: Allow to change
resolution while streaming") dropped the busy check of the CAPTURE queue
in hantro_set_fmt_cap() to let the decoder change resolutions. On the
encoder, CAPTURE is the coded queue, and its format can now be changed
while buffers are allocated, prepared or queued: the new sizeimage, and
the size of the OUTPUT format reset along with it, no longer match the
buffers.
Return -EBUSY again for the encoder when the CAPTURE queue is busy, as
before that commit.
Fixes: bbd267daf4fc ("media: verisilicon: vp9: Allow to change resolution while streaming")
Cc: stable@vger.kernel.org
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/hantro_v4l2.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 83af9fa1ce94..d033fe0ecef6 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -596,7 +596,13 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
int ret;
if (ctx->is_encoder) {
- struct vb2_queue *peer_vq;
+ struct vb2_queue *vq, *peer_vq;
+
+ /* The CAPTURE buffers are sized for the current coded format. */
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
/*
* Since format change on the CAPTURE queue will reset
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/7] media: verisilicon: Enforce a minimum CAPTURE sizeimage for the encoder
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 1/7] media: verisilicon: Keep the encoder CAPTURE format while buffers exist Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 3/7] media: verisilicon: Keep the encoder coded size in sync with OUTPUT Arun Iyengar via B4 Relay
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
For coded formats hantro_try_fmt() only computes sizeimage when the
application passes 0, and otherwise accepts any value. On the encoder
that lets the CAPTURE buffers be far too small for the selected
resolution.
This is easy to hit: "v4l2-ctl --set-fmt-video=width=1920,height=1080,
pixelformat=JPEG" does G_FMT, modifies the size and calls S_FMT, so it
passes back the 6768 byte sizeimage of the 96x32 default format. The
driver accepts it for 1920x1088, the hardware runs out of stream buffer
on every frame and the encoder only produces empty buffers.
The stateful encoder specification lets the encoder adjust sizeimage to
match hardware requirements. For the encoder, clamp the requested
sizeimage up to the size already used as the default, while still
allowing applications to ask for larger buffers. The decoder behaviour
is unchanged.
Fixes: 775fec69008d ("media: add Rockchip VPU JPEG encoder driver")
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/hantro_v4l2.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index d033fe0ecef6..c4e36a79eecc 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -386,14 +386,25 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
pix_mp->plane_fmt[0].sizeimage +=
hantro_av1_mv_size(pix_mp->width,
pix_mp->height);
- } else if (!pix_mp->plane_fmt[0].sizeimage) {
+ } else {
+ u32 max_size = fmt->header_size +
+ pix_mp->width * pix_mp->height * fmt->max_depth;
+ u32 *sizeimage = &pix_mp->plane_fmt[0].sizeimage;
+
/*
* For coded formats the application can specify
* sizeimage. If the application passes a zero sizeimage,
* let's default to the maximum frame size.
+ *
+ * On the encoder, a buffer that is too small for the
+ * current resolution only gives failed frames, so never
+ * let the application go below that default. Larger
+ * values are kept.
*/
- pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
- pix_mp->width * pix_mp->height * fmt->max_depth;
+ if (ctx->is_encoder)
+ *sizeimage = max(*sizeimage, max_size);
+ else if (!*sizeimage)
+ *sizeimage = max_size;
}
return 0;
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/7] media: verisilicon: Keep the encoder coded size in sync with OUTPUT
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 1/7] media: verisilicon: Keep the encoder CAPTURE format while buffers exist Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 2/7] media: verisilicon: Enforce a minimum CAPTURE sizeimage for the encoder Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 4/7] media: verisilicon: Refuse JPEG encode jobs with inconsistent geometry Arun Iyengar via B4 Relay
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
On the encoder, setting the CAPTURE (coded) format resets the OUTPUT
(raw) format to the same size, but setting the OUTPUT format never
updates the CAPTURE format. Following the order mandated by the
stateful encoder specification (CAPTURE first, then OUTPUT) therefore
leaves the coded size at whatever it was before, e.g. the 96x32
default:
v4l2-ctl --set-fmt-video-out=width=1920,height=1080,pixelformat=NM12 \
--set-fmt-video=pixelformat=JPEG --stream-out-mmap ...
ends up with a 1920x1088 OUTPUT format and a 96x32 CAPTURE format with
a 96x32 sized buffer. The JPEG encoders treat the difference between
the two as the crop inside the last macroblock, which is expected to be
below 16 pixels, and program the hardware with the full OUTPUT frame
size. On RK3588 this results in IOMMU page faults, a frame processing
timeout and a wedged encoder.
The specification says that the CAPTURE width and height are set by the
encoder from the OUTPUT format and selection rectangles, and that
setting the OUTPUT format resets the crop rectangle to the full frame.
Do that in hantro_set_fmt_out(): derive the coded format from the new
OUTPUT size, re-applying the CAPTURE constraints, including the minimum
sizeimage. As the coded format can now change from an OUTPUT S_FMT,
return -EBUSY if this would require bigger CAPTURE buffers than the
ones already allocated.
With this, the coded size can only differ from the OUTPUT size by the
crop set through VIDIOC_S_SELECTION, which is restricted to the last
macroblock.
Fixes: 953aaa1492c5 ("media: rockchip/vpu: Prepare things to support decoders")
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/hantro_v4l2.c | 26 ++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index c4e36a79eecc..e9d91504fab2 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -542,6 +542,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp,
bool need_postproc)
{
+ struct v4l2_pix_format_mplane coded_fmt;
struct vb2_queue *vq;
int ret;
@@ -561,16 +562,41 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
return -EBUSY;
}
} else {
+ struct vb2_queue *peer_vq;
+
/*
* The encoder doesn't admit a format change if
* there are OUTPUT buffers allocated.
*/
if (vb2_is_busy(vq))
return -EBUSY;
+
+ /*
+ * Setting the OUTPUT format resets the crop rectangle to
+ * the full frame, so the coded size becomes the OUTPUT
+ * size. Refuse the change if it would need bigger
+ * CAPTURE buffers than the ones already allocated.
+ */
+ coded_fmt = ctx->dst_fmt;
+ coded_fmt.width = pix_mp->width;
+ coded_fmt.height = pix_mp->height;
+ ret = hantro_try_fmt(ctx, &coded_fmt,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (ret)
+ return ret;
+
+ peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(peer_vq) &&
+ coded_fmt.plane_fmt[0].sizeimage >
+ ctx->dst_fmt.plane_fmt[0].sizeimage)
+ return -EBUSY;
}
ctx->vpu_src_fmt = hantro_find_format(ctx, pix_mp->pixelformat);
ctx->src_fmt = *pix_mp;
+ if (ctx->is_encoder)
+ ctx->dst_fmt = coded_fmt;
/*
* Current raw format might have become invalid with newly
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 4/7] media: verisilicon: Refuse JPEG encode jobs with inconsistent geometry
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
` (2 preceding siblings ...)
2026-11-12 8:31 ` [PATCH v2 3/7] media: verisilicon: Keep the encoder coded size in sync with OUTPUT Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 5/7] media: verisilicon: Report fixed JPEG colorimetry on the encoder Arun Iyengar via B4 Relay
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
The JPEG encoders program the hardware with the macroblock count of the
OUTPUT format and treat the difference between the OUTPUT and CAPTURE
sizes as the crop inside the last macroblock, which is written into
narrow register fields. They also write the JPEG header into the
CAPTURE buffer without checking its size.
When the two formats disagree beyond that, as could happen before the
coded size was kept in sync with the OUTPUT format, the encoder on
RK3588 generated IOMMU page faults close to address 0, timed out, and
left the IOMMU unable to stall, requiring a reboot.
The format ioctls are now expected to keep the formats consistent, but
as getting this wrong takes down the whole encoder, check the geometry
and the CAPTURE buffer size before programming the hardware and fail
the job instead.
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
.../platform/verisilicon/hantro_h1_jpeg_enc.c | 9 ++++++
drivers/media/platform/verisilicon/hantro_jpeg.c | 37 ++++++++++++++++++++++
drivers/media/platform/verisilicon/hantro_jpeg.h | 5 +++
.../verisilicon/rockchip_vpu2_hw_jpeg_enc.c | 9 ++++++
4 files changed, 60 insertions(+)
diff --git a/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c b/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c
index 86cc1a07026f..b2f97f45e0ac 100644
--- a/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c
+++ b/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c
@@ -109,10 +109,19 @@ int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
struct vb2_v4l2_buffer *src_buf, *dst_buf;
struct hantro_jpeg_ctx jpeg_ctx;
u32 reg;
+ int ret;
src_buf = hantro_get_src_buf(ctx);
dst_buf = hantro_get_dst_buf(ctx);
+ ret = hantro_jpeg_enc_check_job(ctx, &dst_buf->vb2_buf);
+ if (ret) {
+ /* Complete the controls of the request, the job is not run */
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+ return ret;
+ }
+
hantro_start_prepare_run(ctx);
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
diff --git a/drivers/media/platform/verisilicon/hantro_jpeg.c b/drivers/media/platform/verisilicon/hantro_jpeg.c
index 13a60638e43f..2f2afd632c1b 100644
--- a/drivers/media/platform/verisilicon/hantro_jpeg.c
+++ b/drivers/media/platform/verisilicon/hantro_jpeg.c
@@ -14,6 +14,7 @@
#include <media/v4l2-jpeg.h>
#include "hantro_jpeg.h"
#include "hantro.h"
+#include "hantro_hw.h"
#define LUMA_QUANT_OFF 25
#define CHROMA_QUANT_OFF 90
@@ -243,3 +244,39 @@ void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
jpeg_set_quality(ctx);
}
+
+/*
+ * Check that the formats describe a frame the JPEG encoders can be
+ * programmed with: the coded size may only crop the OUTPUT frame inside
+ * the right-most and bottom-most macroblocks, and the CAPTURE buffer
+ * must have room for the header and some payload. The V4L2 ioctls are
+ * expected to guarantee this, but programming the hardware with
+ * anything else makes it access memory outside the buffers, so refuse
+ * the job instead.
+ */
+int hantro_jpeg_enc_check_job(struct hantro_ctx *ctx,
+ struct vb2_buffer *dst_buf)
+{
+ const struct v4l2_pix_format_mplane *src = &ctx->src_fmt;
+ const struct v4l2_pix_format_mplane *dst = &ctx->dst_fmt;
+
+ if (!dst->width || !dst->height ||
+ !IS_ALIGNED(src->width, MB_DIM) ||
+ !IS_ALIGNED(src->height, MB_DIM) ||
+ dst->width > src->width || dst->height > src->height ||
+ src->width - dst->width >= MB_DIM ||
+ src->height - dst->height >= MB_DIM ||
+ !IS_ALIGNED(src->width - dst->width, 4)) {
+ vpu_err("inconsistent geometry: OUTPUT %ux%u, CAPTURE %ux%u\n",
+ src->width, src->height, dst->width, dst->height);
+ return -EINVAL;
+ }
+
+ if (vb2_plane_size(dst_buf, 0) <= ctx->vpu_dst_fmt->header_size) {
+ vpu_err("CAPTURE buffer too small: %lu bytes\n",
+ vb2_plane_size(dst_buf, 0));
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/verisilicon/hantro_jpeg.h b/drivers/media/platform/verisilicon/hantro_jpeg.h
index 0b49d0b82caa..296ad1e821c7 100644
--- a/drivers/media/platform/verisilicon/hantro_jpeg.h
+++ b/drivers/media/platform/verisilicon/hantro_jpeg.h
@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0+ */
+struct hantro_ctx;
+struct vb2_buffer;
+
#define JPEG_HEADER_SIZE 624
#define JPEG_QUANT_SIZE 64
@@ -13,3 +16,5 @@ struct hantro_jpeg_ctx {
};
void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx);
+int hantro_jpeg_enc_check_job(struct hantro_ctx *ctx,
+ struct vb2_buffer *dst_buf);
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c
index 61621b1be8a2..c7a1323506f5 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c
@@ -135,10 +135,19 @@ int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx)
struct vb2_v4l2_buffer *src_buf, *dst_buf;
struct hantro_jpeg_ctx jpeg_ctx;
u32 reg;
+ int ret;
src_buf = hantro_get_src_buf(ctx);
dst_buf = hantro_get_dst_buf(ctx);
+ ret = hantro_jpeg_enc_check_job(ctx, &dst_buf->vb2_buf);
+ if (ret) {
+ /* Complete the controls of the request, the job is not run */
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+ return ret;
+ }
+
hantro_start_prepare_run(ctx);
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 5/7] media: verisilicon: Report fixed JPEG colorimetry on the encoder
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
` (3 preceding siblings ...)
2026-11-12 8:31 ` [PATCH v2 4/7] media: verisilicon: Refuse JPEG encode jobs with inconsistent geometry Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 6/7] media: verisilicon: Don't reset the encoder raw format while OUTPUT buffers exist Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 7/7] media: verisilicon: rockchip: Limit the JPEG encoder to 8176x8176 Arun Iyengar via B4 Relay
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
The driver reports V4L2_COLORSPACE_JPEG with default encoding,
quantization and transfer function on both queues, and lets the
application set any colorimetry, which is then copied to the other
queue. For the JPEG encoder this is wrong on the raw side:
V4L2_COLORSPACE_JPEG is only a shorthand for the colorimetry of the
JPEG data, and the raw frames should describe the actual samples. It
also makes v4l2-compliance fail on the encoder:
fail: v4l2-test-formats.cpp(892): fmt_raw.g_colorspace() != V4L2_COLORSPACE_SRGB
test VIDIOC_S_FMT: FAIL
The colorimetry of JPEG is fixed and the hardware doesn't convert the
samples. When the coded format is JPEG, report sRGB primaries and
transfer function with full range BT.601 Y'CbCr on both queues, as the
mtk-jpeg and imx-jpeg drivers do, and ignore what the application asks
for. Other coded formats keep propagating the colorimetry set by
the application, which they signal in the bitstream.
Fixes: 775fec69008d ("media: add Rockchip VPU JPEG encoder driver")
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/hantro_v4l2.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index e9d91504fab2..11bce0cdf4b3 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -407,6 +407,19 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
*sizeimage = max_size;
}
+ if (ctx->is_encoder && vpu_fmt->codec_mode == HANTRO_MODE_JPEG_ENC) {
+ /*
+ * The colorimetry of JPEG is fixed: full range BT.601
+ * Y'CbCr with sRGB primaries and transfer function. The
+ * hardware doesn't convert the samples, so the raw frames
+ * must use it too.
+ */
+ pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
+ pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB;
+ pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ }
+
return 0;
}
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 6/7] media: verisilicon: Don't reset the encoder raw format while OUTPUT buffers exist
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
` (4 preceding siblings ...)
2026-11-12 8:31 ` [PATCH v2 5/7] media: verisilicon: Report fixed JPEG colorimetry on the encoder Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 7/7] media: verisilicon: rockchip: Limit the JPEG encoder to 8176x8176 Arun Iyengar via B4 Relay
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
For an encoder, hantro_set_fmt_cap() allows S_FMT on the CAPTURE queue
while the OUTPUT queue has buffers as long as the coded pixel format and
size don't change, and then unconditionally resets the raw format through
hantro_reset_raw_fmt(). That helper sets ctx->vpu_src_fmt to the default
raw format before hantro_set_fmt_out() refuses the change with -EBUSY
(the OUTPUT queue is busy). hantro_set_fmt_cap() ignores that error, so
the ioctl succeeds but leaves the context inconsistent: ctx->src_fmt
still describes the negotiated raw format (e.g. NM12, two planes) while
ctx->vpu_src_fmt describes the default one (YM12, three planes).
The next job then programs the hardware with the wrong input format: on
the RK3588 VEPU121 JPEG encoder the third plane address is never written,
the encoder reads the V plane from IOVA 0 and the job ends in an IOMMU
page fault and a watchdog timeout. v4l2-ctl triggers this on every
--stream-mmap run, because it re-applies the CAPTURE format after the
OUTPUT queue has been set up:
rk_iommu fdba0800.iommu: Page fault at 0x0000000000000000 of type read
rk_iommu fdba0800.iommu: Page fault at 0x00000000000003c0 of type read
...
hantro_watchdog:208: frame processing timed out!
Skip the raw format reset when OUTPUT buffers exist: the coded format is
unchanged in that case, so the raw format stays valid, and the S_FMT is
accepted as the busy check intends. Also restore ctx->vpu_src_fmt in
hantro_reset_raw_fmt() when hantro_set_fmt_out() fails, so that no other
caller can leave the two descriptors out of sync.
The raw format has been reset under allocated OUTPUT buffers since the
encoder was added. Since commit 14b4bd01f8e5 ("media: verisilicon:
Additional fix for the crash when opening the driver") only the
descriptor is reset, which gives the mismatch described above.
Fixes: 775fec69008d ("media: add Rockchip VPU JPEG encoder driver")
Fixes: 14b4bd01f8e5 ("media: verisilicon: Additional fix for the crash when opening the driver")
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/hantro_v4l2.c | 33 +++++++++++++++++++-----
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 11bce0cdf4b3..a40abe2c459f 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -471,7 +471,7 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx)
int
hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth, bool need_postproc)
{
- const struct hantro_fmt *raw_vpu_fmt;
+ const struct hantro_fmt *raw_vpu_fmt, *old_vpu_src_fmt = NULL;
struct v4l2_pix_format_mplane raw_fmt, *encoded_fmt;
int ret;
@@ -481,6 +481,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth, bool need_postproc)
if (ctx->is_encoder) {
encoded_fmt = &ctx->dst_fmt;
+ old_vpu_src_fmt = ctx->vpu_src_fmt;
ctx->vpu_src_fmt = raw_vpu_fmt;
} else {
encoded_fmt = &ctx->src_fmt;
@@ -497,6 +498,12 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth, bool need_postproc)
if (!ret) {
ctx->bit_depth = bit_depth;
ctx->need_postproc = need_postproc;
+ } else if (ctx->is_encoder) {
+ /*
+ * hantro_set_fmt_out() refused the new raw format, so the
+ * OUTPUT format is unchanged: keep its descriptor in sync.
+ */
+ ctx->vpu_src_fmt = old_vpu_src_fmt;
}
return ret;
@@ -643,6 +650,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
+ bool reset_raw_fmt = ctx->is_encoder;
int ret;
if (ctx->is_encoder) {
@@ -661,11 +669,22 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
*/
peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
- if (vb2_is_busy(peer_vq) &&
- (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
- pix_mp->height != ctx->dst_fmt.height ||
- pix_mp->width != ctx->dst_fmt.width))
- return -EBUSY;
+ if (vb2_is_busy(peer_vq)) {
+ if (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
+ pix_mp->height != ctx->dst_fmt.height ||
+ pix_mp->width != ctx->dst_fmt.width)
+ return -EBUSY;
+
+ /*
+ * The coded format is unchanged, so the raw format
+ * stays valid. It couldn't be reset anyway while
+ * OUTPUT buffers exist (hantro_set_fmt_out() would
+ * refuse), and failing here after the coded format
+ * has been updated would leave the context
+ * inconsistent.
+ */
+ reset_raw_fmt = false;
+ }
}
ret = hantro_try_fmt(ctx, pix_mp, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
@@ -687,7 +706,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
* Note that hantro_reset_raw_fmt() also propagates size
* changes to the raw format.
*/
- if (ctx->is_encoder)
+ if (reset_raw_fmt)
hantro_reset_raw_fmt(ctx, HANTRO_DEFAULT_BIT_DEPTH, HANTRO_AUTO_POSTPROC);
/* Colorimetry information are always propagated. */
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 7/7] media: verisilicon: rockchip: Limit the JPEG encoder to 8176x8176
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
` (5 preceding siblings ...)
2026-11-12 8:31 ` [PATCH v2 6/7] media: verisilicon: Don't reset the encoder raw format while OUTPUT buffers exist Arun Iyengar via B4 Relay
@ 2026-11-12 8:31 ` Arun Iyengar via B4 Relay
6 siblings, 0 replies; 8+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-12 8:31 UTC (permalink / raw)
To: Nicolas Dufresne, Benjamin Gaignard, Philipp Zabel,
Mauro Carvalho Chehab, Heiko Stuebner, Ezequiel Garcia,
Hans Verkuil, Boris Brezillon, Andrzej Pietrasiewicz
Cc: linux-media, linux-rockchip, linux-kernel, linux-arm-kernel,
Sergei Khomenkov, Arun Iyengar
From: Arun Iyengar <aiyengar1990@gmail.com>
The Rockchip JPEG encoders advertise frame sizes up to 8192x8192, but
both register layouts take the picture size in 9-bit macroblock counts:
- VEPU2 (RK3399, RK3568, PX30, RK3588 VEPU121): enc_width is bits 16:8
and enc_height bits 28:20 of the encoder start register.
rockchip_vpu2_jpeg_enc_run() masks the counts with 0x1ff, so an 8192
pixel (512 macroblock) dimension is programmed as 0 macroblocks.
Setting the bit above each field on an RK3588 VEPU121 did not give a
512 macroblock picture either, so the fields really are 9 bits wide.
- H1 (RK3066, RK3288): the height count starts at bit 10 and the width
count at bit 19, so a 512 macroblock height runs into the width field.
Limit the shared format table to 511 macroblocks, 8176 pixels, so
userspace gets the largest size the hardware can encode instead of a
corrupt or timed out frame.
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/platform/verisilicon/rockchip_vpu_hw.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 02673be9878e..f8079f96c398 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -20,6 +20,13 @@
#define ROCKCHIP_VPU981_MIN_SIZE 64
+/*
+ * The H1 and VEPU2 JPEG encoders take the picture size in macroblocks in
+ * 9-bit register fields, so 511 macroblocks (8176 pixels) is the largest
+ * width and height they can encode.
+ */
+#define ROCKCHIP_VPU_JPEG_ENC_MAX_SIZE (511 * MB_DIM)
+
/*
* Supported formats.
*/
@@ -52,10 +59,10 @@ static const struct hantro_fmt rockchip_vpu_enc_fmts[] = {
.header_size = JPEG_HEADER_SIZE,
.frmsize = {
.min_width = 96,
- .max_width = 8192,
+ .max_width = ROCKCHIP_VPU_JPEG_ENC_MAX_SIZE,
.step_width = MB_DIM,
.min_height = 32,
- .max_height = 8192,
+ .max_height = ROCKCHIP_VPU_JPEG_ENC_MAX_SIZE,
.step_height = MB_DIM,
},
},
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-12 8:31 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-12 8:31 [PATCH v2 0/7] media: verisilicon: Fix the JPEG encoder format handling Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 1/7] media: verisilicon: Keep the encoder CAPTURE format while buffers exist Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 2/7] media: verisilicon: Enforce a minimum CAPTURE sizeimage for the encoder Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 3/7] media: verisilicon: Keep the encoder coded size in sync with OUTPUT Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 4/7] media: verisilicon: Refuse JPEG encode jobs with inconsistent geometry Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 5/7] media: verisilicon: Report fixed JPEG colorimetry on the encoder Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 6/7] media: verisilicon: Don't reset the encoder raw format while OUTPUT buffers exist Arun Iyengar via B4 Relay
2026-11-12 8:31 ` [PATCH v2 7/7] media: verisilicon: rockchip: Limit the JPEG encoder to 8176x8176 Arun Iyengar via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®