From 6998d18820cd3029a4791246daeae85c9c91543f Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:46:02 +0100 Subject: [PATCH 1/9] Revert "media: hevc_dec: Drop the new image formats until we have Mesa 24" This reverts commit 7821b6a1baefd97757142d9c3227b5219e9f4568. --- drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index 274af191d9e65e..cc5e5b888a565f 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -284,8 +284,8 @@ static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, const int index) { static const u32 all_formats[] = { - //V4L2_PIX_FMT_NV12MT_COL128, - //V4L2_PIX_FMT_NV12MT_10_COL128, + V4L2_PIX_FMT_NV12MT_COL128, + V4L2_PIX_FMT_NV12MT_10_COL128, V4L2_PIX_FMT_NV12_COL128, V4L2_PIX_FMT_NV12_10_COL128, }; @@ -298,12 +298,11 @@ static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, pf = all_formats[index]; } else { if (index == 0) { -/* if (sps->bit_depth_luma_minus8 == 0) + if (sps->bit_depth_luma_minus8 == 0) pf = V4L2_PIX_FMT_NV12MT_COL128; else if (sps->bit_depth_luma_minus8 == 2) pf = V4L2_PIX_FMT_NV12MT_10_COL128; } else if (index == 1) { - */ if (sps->bit_depth_luma_minus8 == 0) pf = V4L2_PIX_FMT_NV12_COL128; else if (sps->bit_depth_luma_minus8 == 2) From 3e9706c387c11ab1cc2293721e42ad812802c2b7 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:47:55 +0100 Subject: [PATCH 2/9] Revert "media: hevc_dec: Add module parameter for video_nr" This reverts commit 67b85dd90938f63b00e8c53ddc60357eafece93b. --- drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c index dee978882f82f9..9e90532a3d264c 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -25,15 +25,6 @@ #include "hevc_d_video.h" #include "hevc_d_hw.h" -/* - * Default /dev/videoN node number. - * Deliberately avoid the very low numbers as these are often taken by webcams - * etc, and simple apps tend to only go for /dev/video0. - */ -static int video_nr = 19; -module_param(video_nr, int, 0644); -MODULE_PARM_DESC(video_nr, "decoder video device number"); - static const struct hevc_d_control hevc_d_ctrls[] = { { .cfg = { @@ -382,7 +373,7 @@ static int hevc_d_probe(struct platform_device *pdev) dev->mdev.ops = &hevc_d_m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; - ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr); + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); goto err_m2m; From 048ba4a0b983e217feca982890164b34fc6800a0 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:47:56 +0100 Subject: [PATCH 3/9] Revert "media: hevc_dec: Add in downstream single planar SAND variant" This reverts commit 18d2ec3465dfa8d0175ff87a7ce40430ee97ce36. --- .../raspberrypi/hevc_dec/hevc_d_h265.c | 97 +++++------------ .../raspberrypi/hevc_dec/hevc_d_video.c | 101 ++++-------------- 2 files changed, 47 insertions(+), 151 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c index 6c9a9d6db15a54..477a159815d710 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -1652,27 +1652,12 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) de->cmd_len = 0; de->dpbno_col = ~0U; - switch (ctx->dst_fmt.pixelformat) { - case V4L2_PIX_FMT_NV12MT_COL128: - case V4L2_PIX_FMT_NV12MT_10_COL128: - de->luma_stride = ctx->dst_fmt.height * 128; - de->frame_luma_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); - de->chroma_stride = de->luma_stride / 2; - de->frame_chroma_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1); - break; - case V4L2_PIX_FMT_NV12_COL128: - case V4L2_PIX_FMT_NV12_10_COL128: - de->luma_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128; - de->frame_luma_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); - de->chroma_stride = de->luma_stride; - de->frame_chroma_addr = de->frame_luma_addr + - (ctx->dst_fmt.height * 128); - break; - } - + de->luma_stride = ctx->dst_fmt.height * 128; + de->frame_luma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); + de->chroma_stride = de->luma_stride / 2; + de->frame_chroma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1); de->frame_aux = NULL; if (s->sps.bit_depth_luma_minus8 != @@ -1684,16 +1669,15 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) goto fail; } if (s->sps.bit_depth_luma_minus8 == 0) { - if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) { + if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128) { v4l2_err(&dev->v4l2_dev, "Pixel format %#x != NV12MT_COL128 for 8-bit output", ctx->dst_fmt.pixelformat); goto fail; } } else if (s->sps.bit_depth_luma_minus8 == 2) { - if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128) { + if (ctx->dst_fmt.pixelformat != + V4L2_PIX_FMT_NV12MT_10_COL128) { v4l2_err(&dev->v4l2_dev, "Pixel format %#x != NV12MT_10_COL128 for 10-bit output", ctx->dst_fmt.pixelformat); @@ -1704,40 +1688,20 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) s->sps.bit_depth_luma_minus8 + 8); goto fail; } - switch (ctx->dst_fmt.pixelformat) { - case V4L2_PIX_FMT_NV12MT_COL128: - case V4L2_PIX_FMT_NV12MT_10_COL128: - if (run->dst->vb2_buf.num_planes != 2) { - v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 2\n", - run->dst->vb2_buf.num_planes); - goto fail; - } - if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage || - run->dst->planes[1].length < ctx->dst_fmt.plane_fmt[1].sizeimage) { - v4l2_warn(&dev->v4l2_dev, - "Capture planes length (%d/%d) < sizeimage (%d/%d)\n", - run->dst->planes[0].length, - run->dst->planes[1].length, - ctx->dst_fmt.plane_fmt[0].sizeimage, - ctx->dst_fmt.plane_fmt[1].sizeimage); - goto fail; - } - break; - case V4L2_PIX_FMT_NV12_COL128: - case V4L2_PIX_FMT_NV12_10_COL128: - if (run->dst->vb2_buf.num_planes != 1) { - v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 1\n", - run->dst->vb2_buf.num_planes); - goto fail; - } - if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage) { - v4l2_warn(&dev->v4l2_dev, - "Capture planes length (%d) < sizeimage (%d)\n", - run->dst->planes[0].length, - ctx->dst_fmt.plane_fmt[0].sizeimage); - goto fail; - } - break; + if (run->dst->vb2_buf.num_planes != 2) { + v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 2\n", + run->dst->vb2_buf.num_planes); + goto fail; + } + if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage || + run->dst->planes[1].length < ctx->dst_fmt.plane_fmt[1].sizeimage) { + v4l2_warn(&dev->v4l2_dev, + "Capture planes length (%d/%d) < sizeimage (%d/%d)\n", + run->dst->planes[0].length, + run->dst->planes[1].length, + ctx->dst_fmt.plane_fmt[0].sizeimage, + ctx->dst_fmt.plane_fmt[1].sizeimage); + goto fail; } /* @@ -1897,13 +1861,8 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) de->ref_addrs[i][0] = vb2_dma_contig_plane_dma_addr(buf, 0); - if (ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || - ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) - de->ref_addrs[i][1] = - vb2_dma_contig_plane_dma_addr(buf, 1); - else - de->ref_addrs[i][1] = de->ref_addrs[i][0] + - (ctx->dst_fmt.height * 128); + de->ref_addrs[i][1] = + vb2_dma_contig_plane_dma_addr(buf, 1); } /* Move DPB from temp */ @@ -2455,11 +2414,9 @@ static int try_ctrl_sps(struct v4l2_ctrl *ctrl) return 0; if ((sps->bit_depth_luma_minus8 == 0 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) || + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128) || (sps->bit_depth_luma_minus8 == 2 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128)) { + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128)) { v4l2_warn(&dev->v4l2_dev, "SPS luma depth %d does not match capture format\n", sps->bit_depth_luma_minus8 + 8); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index cc5e5b888a565f..8155f89f4c340b 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -150,55 +150,17 @@ static void hevc_d_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) bytesperline = width * 4 / 3; sizeimage = bytesperline * height; break; - - case V4L2_PIX_FMT_NV12_COL128: - /* Width rounds up to columns */ - width = ALIGN(width, 128); - height = ALIGN(height, 8); - - /* column height - * Accept suggested shape if at least min & < 2 * min - */ - bytesperline = constrain2x(bytesperline, height * 3 / 2); - sizeimage = bytesperline * width; - break; - - case V4L2_PIX_FMT_NV12_10_COL128: - /* width in pixels (3 pels = 4 bytes) rounded to 128 byte - * columns - */ - width = ALIGN(((width + 2) / 3), 32) * 3; - height = ALIGN(height, 8); - - /* column height - * Accept suggested shape if at least min & < 2 * min - */ - bytesperline = constrain2x(bytesperline, height * 3 / 2); - sizeimage = bytesperline * width * 4 / 3; - break; } pix_fmt->width = width; pix_fmt->height = height; pix_fmt->field = V4L2_FIELD_NONE; - switch (pix_fmt->pixelformat) { - default: - case V4L2_PIX_FMT_NV12MT_COL128: - case V4L2_PIX_FMT_NV12MT_10_COL128: - pix_fmt->plane_fmt[0].bytesperline = bytesperline; - pix_fmt->plane_fmt[0].sizeimage = sizeimage; - pix_fmt->plane_fmt[1].bytesperline = bytesperline; - pix_fmt->plane_fmt[1].sizeimage = sizeimage / 2; - pix_fmt->num_planes = 2; - break; - case V4L2_PIX_FMT_NV12_COL128: - case V4L2_PIX_FMT_NV12_10_COL128: - pix_fmt->plane_fmt[0].bytesperline = bytesperline; - pix_fmt->plane_fmt[0].sizeimage = sizeimage; - pix_fmt->num_planes = 1; - break; - } + pix_fmt->plane_fmt[0].bytesperline = bytesperline; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; + pix_fmt->plane_fmt[1].bytesperline = bytesperline; + pix_fmt->plane_fmt[1].sizeimage = sizeimage / 2; + pix_fmt->num_planes = 2; } static int hevc_d_querycap(struct file *file, void *priv, @@ -283,31 +245,19 @@ static int hevc_d_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps) static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, const int index) { - static const u32 all_formats[] = { - V4L2_PIX_FMT_NV12MT_COL128, - V4L2_PIX_FMT_NV12MT_10_COL128, - V4L2_PIX_FMT_NV12_COL128, - V4L2_PIX_FMT_NV12_10_COL128, - }; u32 pf = 0; if (!is_sps_set(sps) || !hevc_d_hevc_validate_sps(sps)) { /* Treat this as an error? For now return both */ - - if (index < ARRAY_SIZE(all_formats)) - pf = all_formats[index]; - } else { - if (index == 0) { - if (sps->bit_depth_luma_minus8 == 0) - pf = V4L2_PIX_FMT_NV12MT_COL128; - else if (sps->bit_depth_luma_minus8 == 2) - pf = V4L2_PIX_FMT_NV12MT_10_COL128; - } else if (index == 1) { - if (sps->bit_depth_luma_minus8 == 0) - pf = V4L2_PIX_FMT_NV12_COL128; - else if (sps->bit_depth_luma_minus8 == 2) - pf = V4L2_PIX_FMT_NV12_10_COL128; - } + if (index == 0) + pf = V4L2_PIX_FMT_NV12MT_COL128; + else if (index == 1) + pf = V4L2_PIX_FMT_NV12MT_10_COL128; + } else if (index == 0) { + if (sps->bit_depth_luma_minus8 == 0) + pf = V4L2_PIX_FMT_NV12MT_COL128; + else if (sps->bit_depth_luma_minus8 == 2) + pf = V4L2_PIX_FMT_NV12MT_10_COL128; } return pf; @@ -519,28 +469,17 @@ static int hevc_d_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, } if (*nplanes) { - if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || - pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { - if (*nplanes != expected_nplanes || - sizes[0] < pix_fmt->plane_fmt[0].sizeimage || - sizes[1] < pix_fmt->plane_fmt[1].sizeimage) - return -EINVAL; - } else { - if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage) - return -EINVAL; - } + if (*nplanes != expected_nplanes || + sizes[0] < pix_fmt->plane_fmt[0].sizeimage || + sizes[1] < pix_fmt->plane_fmt[1].sizeimage) + return -EINVAL; } else { sizes[0] = pix_fmt->plane_fmt[0].sizeimage; if (V4L2_TYPE_IS_OUTPUT(vq->type)) { *nplanes = 1; } else { - if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || - pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { - sizes[1] = pix_fmt->plane_fmt[1].sizeimage; - *nplanes = 2; - } else { - *nplanes = 1; - } + sizes[1] = pix_fmt->plane_fmt[1].sizeimage; + *nplanes = 2; } } From a81d680363ed8fde300c89a99ed79d1734f5ba8b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:50:05 +0100 Subject: [PATCH 4/9] media: hevc_dec: Update driver to latest version from upstreaming Signed-off-by: Dave Stevenson --- .../platform/raspberrypi/hevc_dec/hevc_d.c | 155 +++++------------- .../platform/raspberrypi/hevc_dec/hevc_d.h | 43 ++--- .../raspberrypi/hevc_dec/hevc_d_h265.c | 104 ++++++------ .../platform/raspberrypi/hevc_dec/hevc_d_hw.h | 11 ++ .../raspberrypi/hevc_dec/hevc_d_video.c | 46 ++---- 5 files changed, 145 insertions(+), 214 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c index 9e90532a3d264c..3c76d0e165d7ed 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -25,54 +25,37 @@ #include "hevc_d_video.h" #include "hevc_d_hw.h" -static const struct hevc_d_control hevc_d_ctrls[] = { +int hevc_d_v4l2_debug; +module_param_named(debug, hevc_d_v4l2_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-2"); + +static const struct v4l2_ctrl_config hevc_d_ctrls[] = { { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_SPS, - .ops = &hevc_d_hevc_sps_ctrl_ops, - }, - .required = false, + .id = V4L2_CID_STATELESS_HEVC_SPS, + .ops = &hevc_d_hevc_sps_ctrl_ops, }, { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_PPS, - .ops = &hevc_d_hevc_pps_ctrl_ops, - }, - .required = false, + .id = V4L2_CID_STATELESS_HEVC_PPS, + .ops = &hevc_d_hevc_pps_ctrl_ops, }, { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, - }, - .required = false, + .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, }, { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, - }, - .required = true, + .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, { - .cfg = { - .name = "Slice param array", - .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, - .type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, - .flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, - .dims = { 0x1000 }, - }, - .required = true, + .name = "Slice param array", + .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, + .type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, + .flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, + .dims = { 0x1000 }, }, { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, - .min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, - .max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, - .def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, - }, - .required = false, + .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, + .min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, }, { - .cfg = { - .id = V4L2_CID_STATELESS_HEVC_START_CODE, - .min = V4L2_STATELESS_HEVC_START_CODE_NONE, - .max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, - .def = V4L2_STATELESS_HEVC_START_CODE_NONE, - }, - .required = false, + .id = V4L2_CID_STATELESS_HEVC_START_CODE, + .min = V4L2_STATELESS_HEVC_START_CODE_NONE, + .max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_HEVC_START_CODE_NONE, }, }; @@ -114,12 +97,11 @@ static int hevc_d_init_ctrls(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) return -ENOMEM; for (i = 0; i < HEVC_D_CTRLS_COUNT; i++) { - ctrl = v4l2_ctrl_new_custom(hdl, &hevc_d_ctrls[i].cfg, - ctx); + ctrl = v4l2_ctrl_new_custom(hdl, &hevc_d_ctrls[i], ctx); if (hdl->error) { v4l2_err(&dev->v4l2_dev, "Failed to create new custom control id=%#x\n", - hevc_d_ctrls[i].cfg.id); + hevc_d_ctrls[i].id); v4l2_ctrl_handler_free(hdl); kfree(ctx->ctrls); @@ -135,69 +117,6 @@ static int hevc_d_init_ctrls(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) return 0; } -static int hevc_d_request_validate(struct media_request *req) -{ - struct media_request_object *obj; - struct v4l2_ctrl_handler *parent_hdl, *hdl; - struct hevc_d_ctx *ctx = NULL; - struct v4l2_ctrl *ctrl_test; - unsigned int count; - unsigned int i; - - list_for_each_entry(obj, &req->objects, list) { - struct vb2_buffer *vb; - - if (vb2_request_object_is_buffer(obj)) { - vb = container_of(obj, struct vb2_buffer, req_obj); - ctx = vb2_get_drv_priv(vb->vb2_queue); - - break; - } - } - - if (!ctx) - return -ENOENT; - - count = vb2_request_buffer_cnt(req); - if (!count) { - v4l2_info(&ctx->dev->v4l2_dev, - "No buffer was provided with the request\n"); - return -ENOENT; - } else if (count > 1) { - v4l2_info(&ctx->dev->v4l2_dev, - "More than one buffer was provided with the request\n"); - return -EINVAL; - } - - parent_hdl = &ctx->hdl; - - hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); - if (!hdl) { - v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n"); - return -ENOENT; - } - - for (i = 0; i < HEVC_D_CTRLS_COUNT; i++) { - if (!hevc_d_ctrls[i].required) - continue; - - ctrl_test = - v4l2_ctrl_request_hdl_ctrl_find(hdl, - hevc_d_ctrls[i].cfg.id); - if (!ctrl_test) { - v4l2_info(&ctx->dev->v4l2_dev, - "Missing required codec control %d: id=%#x\n", - i, hevc_d_ctrls[i].cfg.id); - v4l2_ctrl_request_hdl_put(hdl); - return -ENOENT; - } - } - - v4l2_ctrl_request_hdl_put(hdl); - - return vb2_request_validate(req); -} - static int hevc_d_open(struct file *file) { struct hevc_d_dev *dev = video_drvdata(file); @@ -220,17 +139,17 @@ static int hevc_d_open(struct file *file) file->private_data = &ctx->fh; ctx->dev = dev; - ret = hevc_d_init_ctrls(dev, ctx); - if (ret) - goto err_free; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &hevc_d_queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); - goto err_ctrls; + goto err_free; } + ret = hevc_d_init_ctrls(dev, ctx); + if (ret) + goto err_ctx; + /* The only bit of format info that we can guess now is H265 src * Everything else we need more info for */ @@ -242,9 +161,8 @@ static int hevc_d_open(struct file *file) return 0; -err_ctrls: - v4l2_ctrl_handler_free(&ctx->hdl); - kfree(ctx->ctrls); +err_ctx: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); err_free: mutex_destroy(&ctx->ctx_mutex); kfree(ctx); @@ -263,11 +181,12 @@ static int hevc_d_release(struct file *file) mutex_lock(&dev->dev_mutex); v4l2_fh_del(&ctx->fh); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->hdl); kfree(ctx->ctrls); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_exit(&ctx->fh); mutex_destroy(&ctx->ctx_mutex); @@ -308,7 +227,7 @@ static const struct v4l2_m2m_ops hevc_d_m2m_ops = { }; static const struct media_device_ops hevc_d_m2m_media_ops = { - .req_validate = hevc_d_request_validate, + .req_validate = vb2_request_validate, .req_queue = hevc_d_media_req_queue, }; @@ -430,7 +349,7 @@ static void hevc_d_remove(struct platform_device *pdev) } static const struct of_device_id hevc_d_dt_match[] = { - { .compatible = "raspberrypi,hevc-dec", }, + { .compatible = "brcm,bcm2711-hevc-dec", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, hevc_d_dt_match); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h index 37c2d1612d2a4b..f3ae7d3b5cc17e 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h @@ -22,28 +22,36 @@ #include #include -#define HEVC_D_DEC_ENV_COUNT 6 +/* + * Q sizes of 3 give one entry being prepared, one waiting and + * one processing. Testing shows no advantage to greater Q depths + */ + +/* + * Max processing Q size Phase 0 -> Phase 1 + * This is per open context + */ #define HEVC_D_P1BUF_COUNT 3 +/* + * Max processing Q size Phase 1 -> Phase 2 + * This is per device + */ #define HEVC_D_P2BUF_COUNT 3 +/* + * Number of decode environments a context has + * There is no independent flow control on this number so it must be + * capable of holding P1 + P2 entries. + */ +#define HEVC_D_DEC_ENV_COUNT (HEVC_D_P1BUF_COUNT + HEVC_D_P2BUF_COUNT) #define HEVC_D_NAME "rpi-hevc-dec" -#define HEVC_D_CAPABILITY_UNTILED BIT(0) -#define HEVC_D_CAPABILITY_H265_DEC BIT(1) - -#define HEVC_D_QUIRK_NO_DMA_OFFSET BIT(0) - enum hevc_d_irq_status { HEVC_D_IRQ_NONE, HEVC_D_IRQ_ERROR, HEVC_D_IRQ_OK, }; -struct hevc_d_control { - struct v4l2_ctrl_config cfg; - unsigned char required:1; -}; - struct hevc_d_h265_run { u32 slice_ents; const struct v4l2_ctrl_hevc_sps *sps; @@ -88,9 +96,6 @@ struct hevc_d_ctx { struct v4l2_pix_format_mplane dst_fmt; int dst_fmt_set; - int src_stream_on; - int dst_stream_on; - /* * fatal_err is set if an error has occurred s.t. decode cannot * continue (such as running out of CMA) @@ -133,12 +138,6 @@ struct hevc_d_ctx { unsigned int colmv_picsize; }; -struct hevc_d_variant { - unsigned int capabilities; - unsigned int quirks; - unsigned int mod_rate; -}; - struct hevc_d_hw_irq_ent; #define HEVC_D_ICTL_ENABLE_UNLIMITED (-1) @@ -183,6 +182,10 @@ struct hevc_d_dev { struct hevc_d_hw_irq_ctrl ic_active2; }; +extern int hevc_d_v4l2_debug; +#define hevc_d_dbg(level, dev, fmt, arg...)\ + v4l2_dbg((level), hevc_d_v4l2_debug, (dev), fmt, ## arg) + struct v4l2_ctrl *hevc_d_find_ctrl(struct hevc_d_ctx *ctx, u32 id); void *hevc_d_find_control_data(struct hevc_d_ctx *ctx, u32 id); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c index 477a159815d710..ea86f26ace7909 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -21,6 +21,9 @@ #include "hevc_d_hw.h" #include "hevc_d_video.h" +/* Maximum length of command buffer before we rate it an error */ +#define CMD_BUFFER_SIZE_MAX 0x100000 + enum hevc_slice_type { HEVC_SLICE_B = 0, HEVC_SLICE_P = 1, @@ -206,6 +209,7 @@ struct hevc_d_dec_state { /* Slice vars */ unsigned int slice_idx; + unsigned int idx_inuse; bool slice_temporal_mvp; /* Slice flag but constant for frame */ bool use_aux; bool mk_aux; @@ -216,7 +220,7 @@ struct hevc_d_dec_state { const struct v4l2_ctrl_hevc_decode_params *dec; unsigned int nb_refs[2]; unsigned int slice_qp; - unsigned int max_num_merge_cand; // 0 if I-slice + unsigned int max_num_merge_cand; /* 0 if I-slice */ bool dependent_slice_segment_flag; unsigned int start_ts; /* slice_segment_addr -> ts */ @@ -226,18 +230,13 @@ struct hevc_d_dec_state { unsigned int prev_ctb_y; }; -static inline int clip_int(const int x, const int lo, const int hi) -{ - return x < lo ? lo : x > hi ? hi : x; -} - /* Phase 1 command and bit FIFOs */ static int cmds_check_space(struct hevc_d_dec_env *const de, unsigned int n) { struct rpi_cmd *a; unsigned int newmax; - if (n > 0x100000) { + if (n > CMD_BUFFER_SIZE_MAX) { v4l2_err(&de->ctx->dev->v4l2_dev, "%s: n %u implausible\n", __func__, n); return -ENOMEM; @@ -256,15 +255,14 @@ static int cmds_check_space(struct hevc_d_dec_env *const de, unsigned int n) de->cmd_max, newmax); return -ENOMEM; } - v4l2_info(&de->ctx->dev->v4l2_dev, - "cmd buffer realloc from %u to %u\n", de->cmd_max, newmax); + hevc_d_dbg(1, &de->ctx->dev->v4l2_dev, + "cmd buffer realloc from %u to %u\n", de->cmd_max, newmax); de->cmd_fifo = a; de->cmd_max = newmax; return 0; } -// ???? u16 addr - put in u32 static void p1_apb_write(struct hevc_d_dec_env *const de, const u16 addr, const u32 data) { @@ -506,7 +504,7 @@ static void write_prob(struct hevc_d_dec_env *const de, s->sh->slice_type != HEVC_SLICE_I) ? s->sh->slice_type + 1 : 2 - s->sh->slice_type; - const int q = clip_int(s->slice_qp, 0, 51); + const int q = clamp((int)s->slice_qp, 0, 51); const u8 *p = prob_init[init_type]; u8 dst[RPI_PROB_ARRAY_SIZE]; unsigned int i; @@ -560,21 +558,20 @@ static inline __u32 dma_to_axi_addr(dma_addr_t a) static int write_bitstream(struct hevc_d_dec_env *const de, const struct hevc_d_dec_state *const s) { - // FIXME!!!! - // Note that FFmpeg V4L2 does not remove emulation prevention bytes, - // so this is matched in the configuration here. - // Whether that is the correct behaviour or not is not clear in the - // spec. + /* V4L2 always has emulation prevention bytes in the stream */ const int rpi_use_emu = 1; unsigned int offset = s->sh->data_byte_offset; - const unsigned int len = (s->sh->bit_size + 7) / 8 - offset; + /* BFNUM includes the byte with rbsp_stop_one_bit which is not part + * of slice_segment_data + */ + const unsigned int len = s->sh->bit_size / 8 + 1; dma_addr_t addr = s->src_addr + offset; offset = addr & 63; p1_apb_write(de, RPI_BFBASE, dma_to_axi_addr(addr)); p1_apb_write(de, RPI_BFNUM, len); - p1_apb_write(de, RPI_BFCONTROL, offset + (1 << 7)); // Stop + p1_apb_write(de, RPI_BFCONTROL, offset + (1 << 7)); /* Stop */ p1_apb_write(de, RPI_BFCONTROL, offset + (rpi_use_emu << 6)); return 0; } @@ -698,7 +695,10 @@ static void program_slicecmds(struct hevc_d_dec_env *const de, p1_apb_write(de, 0x4000 + 4 * i, de->slice_msgs[i] & 0xffff); } -/* NoBackwardPredictionFlag 8.3.5 - Simply checks POCs */ +/* NoBackwardPredictionFlag 8.3.5 - Simply checks POCs of the frames referenced + * by the idx array against cur_poc. Needs to be called twice (with L0 & L1) to + * get NoBackwardPredictionFlag. + */ static int has_backward(const struct v4l2_hevc_dpb_entry *const dpb, const __u8 *const idx, const unsigned int n, const s32 cur_poc) @@ -1106,7 +1106,7 @@ static int tile_entry_fill(struct hevc_d_dec_env *const de, 2 | (last_x << 5) | (last_y << 18)); p1_apb_write(de, RPI_TRANSFER, PROB_RELOAD); - // Inc tile + /* Inc tile */ if (++t_x >= s->tile_width) { t_x = 0; ++t_y; @@ -1760,22 +1760,19 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) /* Pre calc parameters */ s->dec = dec; + s->idx_inuse = 0; for (i = 0; i != run->h265.slice_ents; ++i) { const struct v4l2_ctrl_hevc_slice_params *const sh = sh0 + i; const bool last_slice = i + 1 == run->h265.slice_ents; + u32 last_offset = sh->data_byte_offset + DIV_ROUND_UP(sh->bit_size, 8); + unsigned int j; s->sh = sh; - if (run->src->planes[0].bytesused < (sh->bit_size + 7) / 8) { - v4l2_warn(&dev->v4l2_dev, - "Bit size %d > bytesused %d\n", - sh->bit_size, run->src->planes[0].bytesused); - goto fail; - } - if (sh->data_byte_offset >= sh->bit_size / 8) { + if (run->src->planes[0].bytesused < last_offset) { v4l2_warn(&dev->v4l2_dev, - "Bit size %u < Byte offset %u * 8\n", - sh->bit_size, sh->data_byte_offset); + "Last byte offset %d > bytesused %d\n", + last_offset, run->src->planes[0].bytesused); goto fail; } @@ -1794,6 +1791,11 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 0 : sh->num_ref_idx_l1_active_minus1 + 1; + for (j = 0; j != s->nb_refs[0]; ++j) + s->idx_inuse |= 1 << sh->ref_idx_l0[j]; + for (j = 0; j != s->nb_refs[1]; ++j) + s->idx_inuse |= 1 << sh->ref_idx_l1[j]; + if (s->sps.flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) populate_scaling_factors(run, de, s); @@ -1824,7 +1826,6 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) * Locate ref frames * At least in the current implementation this is constant across all * slices. If this changes we will need idx mapping code. - * Uses sh so here rather than trigger */ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, @@ -1842,9 +1843,14 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) struct vb2_buffer *buf = vb2_find_buffer(vq, dec->dpb[i].timestamp); if (!buf) { - v4l2_warn(&dev->v4l2_dev, - "Missing DPB ent %d, timestamp=%lld\n", - i, (long long)dec->dpb[i].timestamp); + if (!(s->idx_inuse & (1 << i))) + hevc_d_dbg(2, &dev->v4l2_dev, + "Missing unused DPB ent %d, timestamp=%lld\n", + i, (long long)dec->dpb[i].timestamp); + else + v4l2_warn(&dev->v4l2_dev, + "Missing inuse DPB ent %d, timestamp=%lld\n", + i, (long long)dec->dpb[i].timestamp); continue; } @@ -1918,7 +1924,7 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) fail: if (de) - // Actual error reporting happens in Trigger + /* Actual error reporting happens in Trigger */ de->state = HEVC_D_DECODE_ERROR_DONE; } @@ -1987,11 +1993,17 @@ static void phase2_claimed(struct hevc_d_dev *const dev, void *v) apb_write_vc_len(dev, RPI_OUTCSTRIDE, de->chroma_stride); for (i = 0; i < 16; i++) { - // Strides are in fact unused but fill in anyway - apb_write_vc_addr(dev, 0x9000 + 16 * i, de->ref_addrs[i][0]); - apb_write_vc_len(dev, 0x9004 + 16 * i, de->luma_stride); - apb_write_vc_addr(dev, 0x9008 + 16 * i, de->ref_addrs[i][1]); - apb_write_vc_len(dev, 0x900C + 16 * i, de->chroma_stride); + /* Strides are in fact unused but fill in anyway */ + unsigned int roff = i * RPI_REFREGS_SIZE; + + apb_write_vc_addr(dev, RPI_REFYBASE0 + roff, + de->ref_addrs[i][0]); + apb_write_vc_len(dev, RPI_REFYSTRIDE0 + roff, + de->luma_stride); + apb_write_vc_addr(dev, RPI_REFCBASE0 + roff, + de->ref_addrs[i][1]); + apb_write_vc_len(dev, RPI_REFCSTRIDE0 + roff, + de->chroma_stride); } apb_write(dev, RPI_CONFIG2, de->rpi_config2); @@ -2017,7 +2029,7 @@ static void phase1_claimed(struct hevc_d_dev *const dev, void *v); /* release any and all objects associated with de and reenable phase 1 if * required - */// 1 if required + */ static void phase1_err_fin(struct hevc_d_dev *const dev, struct hevc_d_ctx *const ctx, struct hevc_d_dec_env *const de) @@ -2059,8 +2071,8 @@ static void phase1_thread(struct hevc_d_dev *const dev, void *v) __func__, pu_gptr->size); goto fail; } - v4l2_info(&dev->v4l2_dev, "%s: PU realloc (%zx) OK\n", - __func__, pu_gptr->size); + hevc_d_dbg(1, &dev->v4l2_dev, "%s: PU realloc (%zx) OK\n", + __func__, pu_gptr->size); } if (de->p1_status & STATUS_COEFF_EXHAUSTED) { @@ -2071,8 +2083,8 @@ static void phase1_thread(struct hevc_d_dev *const dev, void *v) __func__, coeff_gptr->size); goto fail; } - v4l2_info(&dev->v4l2_dev, "%s: Coeff realloc (%zx) OK\n", - __func__, coeff_gptr->size); + hevc_d_dbg(1, &dev->v4l2_dev, "%s: Coeff realloc (%zx) OK\n", + __func__, coeff_gptr->size); } phase1_claimed(dev, de); @@ -2097,8 +2109,8 @@ static void phase1_cb(struct hevc_d_dev *const dev, void *v) de->p1_status = check_status(dev); if (de->p1_status != 0) { - v4l2_info(&dev->v4l2_dev, "%s: Post wait: %#x\n", - __func__, de->p1_status); + hevc_d_dbg(2, &dev->v4l2_dev, "%s: Post wait: %#x\n", + __func__, de->p1_status); if (de->p1_status < 0) goto fail; diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h index 8d91931aadf207..e573d3149cff07 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h @@ -73,6 +73,17 @@ struct hevc_d_hw_irq_ent { #define RPI_COLSTRIDE 0x803C #define RPI_CURRPOC 0x8040 +/* + * Reference frame register values + * There are 16 of these arranged sequentially + */ +#define RPI_REFYBASE0 0x9000 +#define RPI_REFYSTRIDE0 0x9004 +#define RPI_REFCBASE0 0x9008 +#define RPI_REFCSTRIDE0 0x900c +/* Offset to get from REFYBASEn to REFYBASEn+1 */ +#define RPI_REFREGS_SIZE 16 + /* * Write a general register value * Order is unimportant diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index 8155f89f4c340b..06d7da70437826 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -535,14 +535,13 @@ static int hevc_d_buf_prepare(struct vb2_buffer *vb) return 0; } -/* Only stops the clock if streaom off on both output & capture */ +/* + * Stop the clock for this context + * clk_disable_unprepare does ref counting so this will not actually + * disable the clock if there are other running contexts + */ static void stop_clock(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) { - if (ctx->src_stream_on || - ctx->dst_stream_on) - return; - - clk_set_min_rate(dev->clock, 0); clk_disable_unprepare(dev->clock); } @@ -572,29 +571,18 @@ static int hevc_d_start_streaming(struct vb2_queue *vq, unsigned int count) struct hevc_d_dev *dev = ctx->dev; int ret = 0; - if (!V4L2_TYPE_IS_OUTPUT(vq->type)) { - ctx->dst_stream_on = 1; - goto ok; - } - - if (ctx->src_fmt.pixelformat != V4L2_PIX_FMT_HEVC_SLICE) { - ret = -EINVAL; - goto fail_cleanup; - } - - if (ctx->src_stream_on) - goto ok; + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, vq); - ret = start_clock(dev, ctx); - if (ret) - goto fail_cleanup; + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + ret = start_clock(dev, ctx); + if (ret) + goto fail_cleanup; - ret = hevc_d_h265_start(ctx); - if (ret) - goto fail_stop_clock; + ret = hevc_d_h265_start(ctx); + if (ret) + goto fail_stop_clock; + } - ctx->src_stream_on = 1; -ok: return 0; fail_stop_clock: @@ -611,17 +599,15 @@ static void hevc_d_stop_streaming(struct vb2_queue *vq) struct hevc_d_dev *dev = ctx->dev; if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - ctx->src_stream_on = 0; hevc_d_h265_stop(ctx); - } else { - ctx->dst_stream_on = 0; + stop_clock(dev, ctx); } hevc_d_queue_cleanup(vq, VB2_BUF_STATE_ERROR); vb2_wait_for_all_buffers(vq); - stop_clock(dev, ctx); + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, vq); } static void hevc_d_buf_queue(struct vb2_buffer *vb) From 4a9bfa6a456e68fd2d874e38975d8d816244e964 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:44:49 +0100 Subject: [PATCH 5/9] arm: dt: Update BCM2711 HEVC decoder compatible string to match upstream Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/broadcom/bcm2711.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi index bb137d8da1a821..3c76cb28fd0e78 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi @@ -614,7 +614,7 @@ }; hevc_dec: codec@7eb10000 { - compatible = "brcm,bcm2711-hevc-dec", "raspberrypi,hevc-dec"; + compatible = "brcm,bcm2711-hevc-dec"; reg = <0x0 0x7eb00000 0x10000>, /* HEVC */ <0x0 0x7eb10000 0x1000>; /* INTC */ reg-names = "hevc", From dadfa1002fea888fc202398470863a8ffdd7edf3 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 6 Aug 2025 17:45:26 +0100 Subject: [PATCH 6/9] arm64: dt: Update HEVC decoder compatible string for upstream Signed-off-by: Dave Stevenson --- arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi index 95482c40a9eb57..3574a6c4b9c3b8 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi @@ -369,7 +369,7 @@ }; hevc_dec: codec@800000 { - compatible = "brcm,bcm2712-hevc-dec", "raspberrypi,hevc-dec"; + compatible = "brcm,bcm2712-hevc-dec", "brcm,bcm2711-hevc-dec"; reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ <0x10 0x00840000 0x0 0x1000>; /* INTC */ reg-names = "hevc", From f3a1b7f895b8a9c2e26645a3aa4ad485573ff4d8 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 11 Feb 2025 16:09:27 +0000 Subject: [PATCH 7/9] media: hevc_dec: Add in downstream single planar SAND variant Upstream will take the multi-planar SAND format, but add back in the downstream single planar variant for backwards compatibility Signed-off-by: Dave Stevenson --- .../raspberrypi/hevc_dec/hevc_d_h265.c | 97 ++++++++++++----- .../raspberrypi/hevc_dec/hevc_d_video.c | 101 ++++++++++++++---- 2 files changed, 151 insertions(+), 47 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c index ea86f26ace7909..ef8c01feb0840c 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -1652,12 +1652,27 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) de->cmd_len = 0; de->dpbno_col = ~0U; - de->luma_stride = ctx->dst_fmt.height * 128; - de->frame_luma_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); - de->chroma_stride = de->luma_stride / 2; - de->frame_chroma_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1); + switch (ctx->dst_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + de->luma_stride = ctx->dst_fmt.height * 128; + de->frame_luma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); + de->chroma_stride = de->luma_stride / 2; + de->frame_chroma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1); + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: + de->luma_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128; + de->frame_luma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); + de->chroma_stride = de->luma_stride; + de->frame_chroma_addr = de->frame_luma_addr + + (ctx->dst_fmt.height * 128); + break; + } + de->frame_aux = NULL; if (s->sps.bit_depth_luma_minus8 != @@ -1669,15 +1684,16 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) goto fail; } if (s->sps.bit_depth_luma_minus8 == 0) { - if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128) { + if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) { v4l2_err(&dev->v4l2_dev, "Pixel format %#x != NV12MT_COL128 for 8-bit output", ctx->dst_fmt.pixelformat); goto fail; } } else if (s->sps.bit_depth_luma_minus8 == 2) { - if (ctx->dst_fmt.pixelformat != - V4L2_PIX_FMT_NV12MT_10_COL128) { + if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128) { v4l2_err(&dev->v4l2_dev, "Pixel format %#x != NV12MT_10_COL128 for 10-bit output", ctx->dst_fmt.pixelformat); @@ -1688,20 +1704,40 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) s->sps.bit_depth_luma_minus8 + 8); goto fail; } - if (run->dst->vb2_buf.num_planes != 2) { - v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 2\n", - run->dst->vb2_buf.num_planes); - goto fail; - } - if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage || - run->dst->planes[1].length < ctx->dst_fmt.plane_fmt[1].sizeimage) { - v4l2_warn(&dev->v4l2_dev, - "Capture planes length (%d/%d) < sizeimage (%d/%d)\n", - run->dst->planes[0].length, - run->dst->planes[1].length, - ctx->dst_fmt.plane_fmt[0].sizeimage, - ctx->dst_fmt.plane_fmt[1].sizeimage); - goto fail; + switch (ctx->dst_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + if (run->dst->vb2_buf.num_planes != 2) { + v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 2\n", + run->dst->vb2_buf.num_planes); + goto fail; + } + if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage || + run->dst->planes[1].length < ctx->dst_fmt.plane_fmt[1].sizeimage) { + v4l2_warn(&dev->v4l2_dev, + "Capture planes length (%d/%d) < sizeimage (%d/%d)\n", + run->dst->planes[0].length, + run->dst->planes[1].length, + ctx->dst_fmt.plane_fmt[0].sizeimage, + ctx->dst_fmt.plane_fmt[1].sizeimage); + goto fail; + } + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: + if (run->dst->vb2_buf.num_planes != 1) { + v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 1\n", + run->dst->vb2_buf.num_planes); + goto fail; + } + if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage) { + v4l2_warn(&dev->v4l2_dev, + "Capture planes length (%d) < sizeimage (%d)\n", + run->dst->planes[0].length, + ctx->dst_fmt.plane_fmt[0].sizeimage); + goto fail; + } + break; } /* @@ -1867,8 +1903,13 @@ void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) de->ref_addrs[i][0] = vb2_dma_contig_plane_dma_addr(buf, 0); - de->ref_addrs[i][1] = - vb2_dma_contig_plane_dma_addr(buf, 1); + if (ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) + de->ref_addrs[i][1] = + vb2_dma_contig_plane_dma_addr(buf, 1); + else + de->ref_addrs[i][1] = de->ref_addrs[i][0] + + (ctx->dst_fmt.height * 128); } /* Move DPB from temp */ @@ -2426,9 +2467,11 @@ static int try_ctrl_sps(struct v4l2_ctrl *ctrl) return 0; if ((sps->bit_depth_luma_minus8 == 0 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128) || + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) || (sps->bit_depth_luma_minus8 == 2 && - ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128)) { + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128)) { v4l2_warn(&dev->v4l2_dev, "SPS luma depth %d does not match capture format\n", sps->bit_depth_luma_minus8 + 8); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index 06d7da70437826..8968ebf1135b9e 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -150,17 +150,55 @@ static void hevc_d_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) bytesperline = width * 4 / 3; sizeimage = bytesperline * height; break; + + case V4L2_PIX_FMT_NV12_COL128: + /* Width rounds up to columns */ + width = ALIGN(width, 128); + height = ALIGN(height, 8); + + /* column height + * Accept suggested shape if at least min & < 2 * min + */ + bytesperline = constrain2x(bytesperline, height * 3 / 2); + sizeimage = bytesperline * width; + break; + + case V4L2_PIX_FMT_NV12_10_COL128: + /* width in pixels (3 pels = 4 bytes) rounded to 128 byte + * columns + */ + width = ALIGN(((width + 2) / 3), 32) * 3; + height = ALIGN(height, 8); + + /* column height + * Accept suggested shape if at least min & < 2 * min + */ + bytesperline = constrain2x(bytesperline, height * 3 / 2); + sizeimage = bytesperline * width * 4 / 3; + break; } pix_fmt->width = width; pix_fmt->height = height; pix_fmt->field = V4L2_FIELD_NONE; - pix_fmt->plane_fmt[0].bytesperline = bytesperline; - pix_fmt->plane_fmt[0].sizeimage = sizeimage; - pix_fmt->plane_fmt[1].bytesperline = bytesperline; - pix_fmt->plane_fmt[1].sizeimage = sizeimage / 2; - pix_fmt->num_planes = 2; + switch (pix_fmt->pixelformat) { + default: + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + pix_fmt->plane_fmt[0].bytesperline = bytesperline; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; + pix_fmt->plane_fmt[1].bytesperline = bytesperline; + pix_fmt->plane_fmt[1].sizeimage = sizeimage / 2; + pix_fmt->num_planes = 2; + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: + pix_fmt->plane_fmt[0].bytesperline = bytesperline; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; + pix_fmt->num_planes = 1; + break; + } } static int hevc_d_querycap(struct file *file, void *priv, @@ -245,19 +283,31 @@ static int hevc_d_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps) static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, const int index) { + static const u32 all_formats[] = { + V4L2_PIX_FMT_NV12MT_COL128, + V4L2_PIX_FMT_NV12MT_10_COL128, + V4L2_PIX_FMT_NV12_COL128, + V4L2_PIX_FMT_NV12_10_COL128, + }; u32 pf = 0; if (!is_sps_set(sps) || !hevc_d_hevc_validate_sps(sps)) { /* Treat this as an error? For now return both */ - if (index == 0) - pf = V4L2_PIX_FMT_NV12MT_COL128; - else if (index == 1) - pf = V4L2_PIX_FMT_NV12MT_10_COL128; - } else if (index == 0) { - if (sps->bit_depth_luma_minus8 == 0) - pf = V4L2_PIX_FMT_NV12MT_COL128; - else if (sps->bit_depth_luma_minus8 == 2) - pf = V4L2_PIX_FMT_NV12MT_10_COL128; + + if (index < ARRAY_SIZE(all_formats)) + pf = all_formats[index]; + } else { + if (index == 0) { + if (sps->bit_depth_luma_minus8 == 0) + pf = V4L2_PIX_FMT_NV12MT_COL128; + else if (sps->bit_depth_luma_minus8 == 2) + pf = V4L2_PIX_FMT_NV12MT_10_COL128; + } else if (index == 1) { + if (sps->bit_depth_luma_minus8 == 0) + pf = V4L2_PIX_FMT_NV12_COL128; + else if (sps->bit_depth_luma_minus8 == 2) + pf = V4L2_PIX_FMT_NV12_10_COL128; + } } return pf; @@ -469,17 +519,28 @@ static int hevc_d_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, } if (*nplanes) { - if (*nplanes != expected_nplanes || - sizes[0] < pix_fmt->plane_fmt[0].sizeimage || - sizes[1] < pix_fmt->plane_fmt[1].sizeimage) - return -EINVAL; + if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { + if (*nplanes != expected_nplanes || + sizes[0] < pix_fmt->plane_fmt[0].sizeimage || + sizes[1] < pix_fmt->plane_fmt[1].sizeimage) + return -EINVAL; + } else { + if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage) + return -EINVAL; + } } else { sizes[0] = pix_fmt->plane_fmt[0].sizeimage; if (V4L2_TYPE_IS_OUTPUT(vq->type)) { *nplanes = 1; } else { - sizes[1] = pix_fmt->plane_fmt[1].sizeimage; - *nplanes = 2; + if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { + sizes[1] = pix_fmt->plane_fmt[1].sizeimage; + *nplanes = 2; + } else { + *nplanes = 1; + } } } From f417c826106716d1c37056c2f187164f9bb2c06c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 16 Jan 2025 18:24:17 +0000 Subject: [PATCH 8/9] media: hevc_dec: Add module parameter for video_nr To avoid user complaints that /dev/video0 isn't their USB webcam, add downstream patch that allows setting the preferred video device number. Signed-off-by: Dave Stevenson --- drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c index 3c76d0e165d7ed..30a382b65c0a57 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -29,6 +29,15 @@ int hevc_d_v4l2_debug; module_param_named(debug, hevc_d_v4l2_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-2"); +/* + * Default /dev/videoN node number. + * Deliberately avoid the very low numbers as these are often taken by webcams + * etc, and simple apps tend to only go for /dev/video0. + */ +static int video_nr = 19; +module_param(video_nr, int, 0644); +MODULE_PARM_DESC(video_nr, "decoder video device number"); + static const struct v4l2_ctrl_config hevc_d_ctrls[] = { { .id = V4L2_CID_STATELESS_HEVC_SPS, @@ -292,7 +301,7 @@ static int hevc_d_probe(struct platform_device *pdev) dev->mdev.ops = &hevc_d_m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; - ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); + ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); goto err_m2m; From f5cd42af9b0fb23b0bf66dbb9ee61d57e81005d9 Mon Sep 17 00:00:00 2001 From: John Cox Date: Thu, 31 Jul 2025 15:13:54 +0100 Subject: [PATCH 9/9] hevc_d: Do not map OUTPUT or CAPTURE buffers to kernel Decoder does not need OUTPUT or CAPTURE buffers mapped into memory. Set the queue dma_attrs to indicate this. Signed-off-by: John Cox --- drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index 8968ebf1135b9e..f02c238711c4e7 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -706,6 +706,7 @@ int hevc_d_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct hevc_d_buffer); src_vq->ops = &hevc_d_qops; @@ -722,6 +723,7 @@ int hevc_d_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct hevc_d_buffer); dst_vq->min_queued_buffers = 1;