From 469ed478f494f5f89319dfbfe7f2dba648f312f3 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 8 Jul 2026 17:38:06 +0100 Subject: [PATCH 1/7] Revert "media/hevc_d: Fix height rounding for old sand formats" This reverts commit 970a68f63bf77fe173006ecc8bfdd7eef676f00e. --- drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 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 9c33ca8cba9622..cff997f74d6413 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -144,7 +144,7 @@ static void hevc_d_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) case V4L2_PIX_FMT_NV12_COL128: /* Width rounds up to columns */ width = ALIGN(width, 128); - height = ALIGN(height, 16); + height = ALIGN(height, 8); /* column height * Accept suggested shape if at least min & < 2 * min @@ -158,7 +158,7 @@ static void hevc_d_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) * columns */ width = ALIGN(((width + 2) / 3), 32) * 3; - height = ALIGN(height, 16); + height = ALIGN(height, 8); /* column height * Accept suggested shape if at least min & < 2 * min From 65d3c0a485e70f3e5190ef5599fd8ba9996ef6e2 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 8 Jul 2026 17:38:08 +0100 Subject: [PATCH 2/7] Revert "media/hevc_d: Fix old-style bit_size handling support" This reverts commit 7a41407d9a255b4e36b2e7710bbe7f3e1092fa2e. --- .../raspberrypi/hevc_dec/hevc_d_h265.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 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 e1fc9f69a5f3cd..b86c935e8b3ae9 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -1578,8 +1578,6 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) bool slice_temporal_mvp; unsigned int ctb_size_y; bool sps_changed = false; - /* Old (downstream only) bit size meanings */ - bool old_bits = false; de = dec_env_new(ctx); if (!de) { @@ -1648,7 +1646,6 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) de->chroma_stride = de->luma_stride; de->frame_chroma_addr = de->frame_luma_addr + (ctx->dst_fmt.height * 128); - old_bits = true; break; } @@ -1779,24 +1776,15 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 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; - unsigned int bit_size = old_bits ? sh->bit_size - 8 * sh->data_byte_offset : - sh->bit_size; - const u32 byte_size = DIV_ROUND_UP(bit_size, 8); + const u32 byte_size = DIV_ROUND_UP(sh->bit_size, 8); unsigned int j; s->sh = sh; - if (old_bits && sh->bit_size <= 8 * sh->data_byte_offset) { - v4l2_warn(&dev->v4l2_dev, - "data_byte_offset %d * 8 >= bits %d\n", - sh->data_byte_offset, sh->bit_size); - goto fail; - } - if (sh->data_byte_offset + byte_size > run->src->planes[0].bytesused) { v4l2_warn(&dev->v4l2_dev, "data_byte_offset %d + bits %d (= %d bytes) > bytesused %d\n", - sh->data_byte_offset, bit_size, byte_size, + sh->data_byte_offset, sh->bit_size, byte_size, run->src->planes[0].bytesused); goto fail; } @@ -1806,7 +1794,7 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) * actual size of the buffer (which may well be what is used to set * bit_size if the caller isn't being very pedantic). */ - s->data_len = min(bit_size / 8 + 1, + s->data_len = min(sh->bit_size / 8 + 1, run->src->planes[0].bytesused - sh->data_byte_offset); s->slice_qp = 26 + s->pps.init_qp_minus26 + sh->slice_qp_delta; From 63f69f241cf54c983fe27ed4370e405d19aa31ea Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 8 Jul 2026 17:38:09 +0100 Subject: [PATCH 3/7] Revert "media: hevc_dec: Add module parameter for video_nr" This reverts commit dace498f77992ab7f1aaadcddd08689b4becab10. --- 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 78ff5de9798051..fcd45e6f8d08a2 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -29,15 +29,6 @@ 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, @@ -261,7 +252,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 e09c413cf14eb81c1736f437eae3fca5cfb4ed52 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 8 Jul 2026 17:38:10 +0100 Subject: [PATCH 4/7] Revert "media: hevc_dec: Add in downstream single planar SAND variant" This reverts commit a9731ff75336f472eca7a94e661d5bbcb1382ae2. --- .../raspberrypi/hevc_dec/hevc_d_h265.c | 79 ++------------ .../raspberrypi/hevc_dec/hevc_d_video.c | 101 ++++-------------- 2 files changed, 31 insertions(+), 149 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 b86c935e8b3ae9..04688b9bee5730 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -1628,40 +1628,24 @@ static int 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 == 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 (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); @@ -1680,42 +1664,6 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 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; - } - /* * Fill in ref planes with our address s.t. if we mess up refs * somehow then we still have a valid address entry @@ -1885,13 +1833,8 @@ static int 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 */ 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 cff997f74d6413..8c5aa64df93c77 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -140,55 +140,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, @@ -273,31 +235,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; @@ -509,28 +459,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 c59b8f114f5ac76754c8e7468ba99ea34c4efc4f Mon Sep 17 00:00:00 2001 From: John Cox Date: Mon, 9 Mar 2026 15:44:14 +0000 Subject: [PATCH 5/7] hevc_d: Pick the fixes from the latest upstreaming reviews Does NOT include the clock and IRQ changes. Signed-off-by: John Cox --- .../platform/raspberrypi/hevc_dec/hevc_d.c | 8 +- .../platform/raspberrypi/hevc_dec/hevc_d.h | 11 +- .../raspberrypi/hevc_dec/hevc_d_h265.c | 236 +++++++++--------- .../platform/raspberrypi/hevc_dec/hevc_d_hw.c | 10 +- .../platform/raspberrypi/hevc_dec/hevc_d_hw.h | 8 +- .../raspberrypi/hevc_dec/hevc_d_video.c | 94 +++---- .../raspberrypi/hevc_dec/hevc_d_video.h | 1 - 7 files changed, 172 insertions(+), 196 deletions(-) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c index fcd45e6f8d08a2..cdec2b54361a87 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -11,9 +11,9 @@ * Copyright (C) 2018 Bootlin */ +#include #include #include -#include #include #include @@ -208,7 +208,7 @@ static int hevc_d_probe(struct platform_device *pdev) ret = hevc_d_hw_probe(dev); if (ret) { - dev_err(&pdev->dev, "Failed to probe hardware - %d\n", ret); + dev_err_probe(&pdev->dev, ret, "Failed to probe hardware\n"); return ret; } @@ -216,7 +216,7 @@ static int hevc_d_probe(struct platform_device *pdev) ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) { - dev_err(&pdev->dev, "Failed to register V4L2 device\n"); + dev_err_probe(&pdev->dev, ret, "Failed to register V4L2 device\n"); return ret; } @@ -318,7 +318,7 @@ static struct platform_driver hevc_d_driver = { .remove = hevc_d_remove, .driver = { .name = HEVC_D_NAME, - .of_match_table = of_match_ptr(hevc_d_dt_match), + .of_match_table = hevc_d_dt_match, }, }; module_platform_driver(hevc_d_driver); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h index 61446165d5e58e..367c9624c63d38 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h @@ -134,12 +134,17 @@ struct hevc_d_ctx { struct hevc_d_hwbuf pu_bufs[HEVC_D_P2BUF_COUNT]; struct hevc_d_hwbuf coeff_bufs[HEVC_D_P2BUF_COUNT]; - /* Spinlock protecting aux_free */ - spinlock_t aux_lock; + /* Aux structures only used in setup so no locking needed */ struct hevc_d_q_aux *aux_free; - struct hevc_d_q_aux *aux_ents[HEVC_D_AUX_ENT_COUNT]; + struct hevc_d_slot { + u32 refybase; + u32 refcbase; + u32 colbase; + u32 poc; + } slots[HEVC_D_AUX_ENT_COUNT]; + unsigned int colmv_stride; unsigned int colmv_picsize; }; 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 04688b9bee5730..eb99747e588e9d 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -11,7 +11,8 @@ * Copyright (C) 2018 Bootlin */ -#include +//#include +#include #include #include @@ -136,6 +137,8 @@ static size_t next_size(const size_t x) struct hevc_d_q_aux { unsigned int refcount; unsigned int q_index; + /* Is this aux entry set correctly? Only set on release or in P2 */ + bool good; struct hevc_d_q_aux *next; struct hevc_d_hwbuf col; }; @@ -191,12 +194,13 @@ struct hevc_d_dec_env { unsigned int luma_stride; dma_addr_t frame_chroma_addr; unsigned int chroma_stride; - dma_addr_t ref_addrs[16][2]; - struct hevc_d_q_aux *frame_aux; - struct hevc_d_q_aux *col_aux; + u32 mvbase; + + unsigned int frame_slot; + unsigned int ref_slots[16]; - dma_addr_t pu_base_vc; - dma_addr_t coeff_base_vc; + dma_addr_t pu_base_addr; + dma_addr_t coeff_base_addr; u32 pu_stride; u32 coeff_stride; @@ -337,10 +341,6 @@ static struct hevc_d_q_aux *aux_q_alloc(struct hevc_d_ctx *const ctx, DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING)) goto fail; - /* - * Spinlock not required as called in P0 only and - * aux checks done by _new - */ aq->refcount = 1; aq->q_index = q_index; ctx->aux_ents[q_index] = aq; @@ -355,9 +355,7 @@ static struct hevc_d_q_aux *aux_q_new(struct hevc_d_ctx *const ctx, const unsigned int q_index) { struct hevc_d_q_aux *aq; - unsigned long lockflags; - spin_lock_irqsave(&ctx->aux_lock, lockflags); /* * If we already have this allocated to a slot then use that * and assume that it will all work itself out in the pipeline @@ -375,7 +373,6 @@ static struct hevc_d_q_aux *aux_q_new(struct hevc_d_ctx *const ctx, ctx->aux_ents[q_index] = aq; } } - spin_unlock_irqrestore(&ctx->aux_lock, lockflags); if (!aq) aq = aux_q_alloc(ctx, q_index); @@ -384,57 +381,38 @@ static struct hevc_d_q_aux *aux_q_new(struct hevc_d_ctx *const ctx, } static struct hevc_d_q_aux *aux_q_ref_idx(struct hevc_d_ctx *const ctx, - const int q_index) + const unsigned int q_index) { - unsigned long lockflags; struct hevc_d_q_aux *aq; - spin_lock_irqsave(&ctx->aux_lock, lockflags); aq = ctx->aux_ents[q_index]; if (aq) ++aq->refcount; - spin_unlock_irqrestore(&ctx->aux_lock, lockflags); return aq; } -static struct hevc_d_q_aux *aux_q_ref(struct hevc_d_ctx *const ctx, - struct hevc_d_q_aux *const aq) -{ - unsigned long lockflags; - - if (aq) { - spin_lock_irqsave(&ctx->aux_lock, lockflags); - ++aq->refcount; - spin_unlock_irqrestore(&ctx->aux_lock, lockflags); - } - return aq; -} - static void aux_q_release(struct hevc_d_ctx *const ctx, struct hevc_d_q_aux **const paq) { struct hevc_d_q_aux *const aq = *paq; - unsigned long lockflags; if (!aq) return; *paq = NULL; - spin_lock_irqsave(&ctx->aux_lock, lockflags); if (--aq->refcount == 0) { aq->next = ctx->aux_free; ctx->aux_free = aq; ctx->aux_ents[aq->q_index] = NULL; aq->q_index = ~0U; + aq->good = false; } - spin_unlock_irqrestore(&ctx->aux_lock, lockflags); } static void aux_q_init(struct hevc_d_ctx *const ctx) { - spin_lock_init(&ctx->aux_lock); ctx->aux_free = NULL; } @@ -761,9 +739,12 @@ static void pre_slice_decode(struct hevc_d_dec_env *const de, msg_slice(de, cmd_slice); if (s->slice_temporal_mvp) { - const __u8 *const rpl = collocated_from_l0_flag ? + const u8 *const rpl = collocated_from_l0_flag ? sh->ref_idx_l0 : sh->ref_idx_l1; - de->dpbno_col = rpl[sh->collocated_ref_idx]; + if (sh->collocated_ref_idx >= dec->num_active_dpb_entries) + de->dpbno_col = rpl[0]; + else + de->dpbno_col = rpl[sh->collocated_ref_idx]; } /* Write reference picture descriptions */ @@ -1453,9 +1434,6 @@ static void dec_env_delete(struct hevc_d_dec_env *const de) struct hevc_d_ctx * const ctx = de->ctx; unsigned long lock_flags; - aux_q_release(ctx, &de->frame_aux); - aux_q_release(ctx, &de->col_aux); - spin_lock_irqsave(&ctx->dec_lock, lock_flags); de->state = HEVC_D_DECODE_END; @@ -1487,7 +1465,7 @@ static int dec_env_init(struct hevc_d_ctx *const ctx) ctx->dec_pool = kzalloc(sizeof(*ctx->dec_pool) * HEVC_D_DEC_ENV_COUNT, GFP_KERNEL); if (!ctx->dec_pool) - return -1; + return -ENOMEM; spin_lock_init(&ctx->dec_lock); @@ -1510,7 +1488,7 @@ static int dec_env_init(struct hevc_d_ctx *const ctx) fail: dec_env_uninit(ctx); - return -1; + return -ENOMEM; } /* @@ -1575,9 +1553,9 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) unsigned int prev_rs; unsigned int i; int rv; - bool slice_temporal_mvp; unsigned int ctb_size_y; bool sps_changed = false; + unsigned int lkg_slot; de = dec_env_new(ctx); if (!de) { @@ -1588,7 +1566,7 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) s->sh = NULL; /* Avoid use until in the slice loop */ - slice_temporal_mvp = (sh0->flags & + s->slice_temporal_mvp = (sh0->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED); /* Frame start */ @@ -1634,7 +1612,8 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 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; + de->mvbase = 0; + de->frame_slot = run->dst->vb2_buf.index; if (s->sps.bit_depth_luma_minus8 == 0) { if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128) { @@ -1664,21 +1643,6 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) goto fail; } - /* - * Fill in ref planes with our address s.t. if we mess up refs - * somehow then we still have a valid address entry - */ - for (i = 0; i != 16; ++i) { - de->ref_addrs[i][0] = de->frame_luma_addr; - de->ref_addrs[i][1] = de->frame_chroma_addr; - } - - /* - * Stash initial temporal_mvp flag - * This must be the same for all pic slices (7.4.7.1) - */ - s->slice_temporal_mvp = slice_temporal_mvp; - /* * Need Aux ents for all (ref) DPB ents if temporal MV could * be enabled for any pic @@ -1738,7 +1702,7 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) } /* BFNUM (data_len) includes the byte with rbsp_stop_one_bit which is not * part of slice_segment_data but is all but certain to be in the input - * stream so add that when calulating the value we need, but limit to the + * stream so add that when calculating the value we need, but limit to the * actual size of the buffer (which may well be what is used to set * bit_size if the caller isn't being very pedantic). */ @@ -1805,6 +1769,13 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) goto fail; } + /* + * Find all the references. If any are missing the fill with the + * nearest valid entry. If nothing valid then use the buffer we + * are decoding into as a last resort. Ensure everything contains + * something valid so no checking is required in P2 + */ + lkg_slot = de->frame_slot; for (i = 0; i < dec->num_active_dpb_entries; ++i) { struct vb2_buffer *buf = vb2_find_buffer(vq, dec->dpb[i].timestamp); @@ -1817,25 +1788,30 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) v4l2_warn(&dev->v4l2_dev, "Missing inuse DPB ent %d, timestamp=%lld\n", i, (long long)dec->dpb[i].timestamp); + de->ref_slots[i] = lkg_slot; continue; } if (s->use_aux) { - int buffer_index = buf->index; - - dpb_q_aux[i] = aux_q_ref_idx(ctx, buffer_index); + dpb_q_aux[i] = aux_q_ref_idx(ctx, buf->index); if (!dpb_q_aux[i]) v4l2_warn(&dev->v4l2_dev, "Missing DPB AUX ent %d, timestamp=%lld, index=%d\n", i, (long long)dec->dpb[i].timestamp, - buffer_index); + buf->index); } - 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); + de->ref_slots[i] = buf->index; + if (lkg_slot == de->frame_slot) { + unsigned int j; + + for (j = 0; j != i; ++j) + de->ref_slots[j] = buf->index; + } + lkg_slot = buf->index; } + for (; i != 16; ++i) + de->ref_slots[i] = lkg_slot; /* Move DPB from temp */ for (i = 0; i != V4L2_HEVC_DPB_ENTRIES_NUM_MAX; ++i) { @@ -1855,34 +1831,7 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) goto fail; } - de->frame_aux = aux_q_ref(ctx, s->frame_aux); - } - - if (de->dpbno_col != ~0U) { - if (de->dpbno_col >= dec->num_active_dpb_entries) { - v4l2_err(&dev->v4l2_dev, - "Col ref index %d >= %d\n", - de->dpbno_col, - dec->num_active_dpb_entries); - } else { - /* Standard requires that the col pic is constant for - * the duration of the pic (text of collocated_ref_idx - * in H265-2 2018 7.4.7.1) - */ - - /* Spot the collocated ref in passing */ - de->col_aux = aux_q_ref(ctx, - dpb_q_aux[de->dpbno_col]); - - if (!de->col_aux) { - v4l2_warn(&dev->v4l2_dev, - "Missing DPB ent for col\n"); - /* Need to abort if this fails as P2 may - * explode on bad data - */ - goto fail; - } - } + de->mvbase = VC_ADDR(s->frame_aux->col.addr); } de->state = HEVC_D_DECODE_PHASE1; @@ -1948,31 +1897,82 @@ static void phase2_cb(struct hevc_d_dev *const dev, void *v) phase2_done(dev, v, VB2_BUF_STATE_DONE); } +static void phase2_err_claimed(struct hevc_d_dev *const dev, void *v) +{ + struct hevc_d_dec_env *const de = v; + struct hevc_d_ctx *const ctx = de->ctx; + struct hevc_d_slot *const slot = ctx->slots + de->frame_slot; + + slot->refybase = 0; + slot->refcbase = 0; + slot->colbase = 0; + slot->poc = de->rpi_currpoc; + + phase2_done(dev, de, VB2_BUF_STATE_ERROR); +} + +static const struct hevc_d_slot *find_slot(struct hevc_d_dec_env *const de, + const struct hevc_d_ctx *ctx, + unsigned int dpb_no) +{ + const struct hevc_d_slot *slot = ctx->slots + de->ref_slots[dpb_no]; + const u32 poc = slot->poc; + u32 pocdiff = 0xffffffff; + unsigned int i; + + if (likely(slot->refybase)) + return slot; + + slot = NULL; + for (i = 0; i != 16; ++i) { + const struct hevc_d_slot *t = ctx->slots + de->ref_slots[i]; + u32 d = abs((s32)(poc - t->poc)); + + if (t->refybase && d < pocdiff) { + slot = t; + pocdiff = d; + } + } + return slot; +} + static void phase2_claimed(struct hevc_d_dev *const dev, void *v) { struct hevc_d_dec_env *const de = v; + struct hevc_d_ctx *const ctx = de->ctx; + struct hevc_d_slot *const slot = ctx->slots + de->frame_slot; + u32 colbase = 0; unsigned int i; - apb_write_vc_addr(dev, RPI_PURBASE, de->pu_base_vc); + slot->refybase = VC_ADDR(de->frame_luma_addr); + slot->refcbase = VC_ADDR(de->frame_chroma_addr); + slot->colbase = de->mvbase; + slot->poc = de->rpi_currpoc; + + apb_write_vc_addr(dev, RPI_PURBASE, de->pu_base_addr); apb_write_vc_len(dev, RPI_PURSTRIDE, de->pu_stride); - apb_write_vc_addr(dev, RPI_COEFFRBASE, de->coeff_base_vc); + apb_write_vc_addr(dev, RPI_COEFFRBASE, de->coeff_base_addr); apb_write_vc_len(dev, RPI_COEFFRSTRIDE, de->coeff_stride); apb_write_vc_addr(dev, RPI_OUTYBASE, de->frame_luma_addr); - apb_write_vc_addr(dev, RPI_OUTCBASE, de->frame_chroma_addr); apb_write_vc_len(dev, RPI_OUTYSTRIDE, de->luma_stride); + apb_write_vc_addr(dev, RPI_OUTCBASE, de->frame_chroma_addr); 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 */ unsigned int roff = i * RPI_REFREGS_SIZE; + const struct hevc_d_slot *ref = find_slot(de, ctx, i); - apb_write_vc_addr(dev, RPI_REFYBASE0 + roff, - de->ref_addrs[i][0]); + if (!ref) + goto fail; + if (i == de->dpbno_col) + colbase = ref->colbase; + + apb_write(dev, RPI_REFYBASE0 + roff, ref->refybase); 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(dev, RPI_REFCBASE0 + roff, ref->refcbase); apb_write_vc_len(dev, RPI_REFCSTRIDE0 + roff, de->chroma_stride); } @@ -1982,23 +1982,21 @@ static void phase2_claimed(struct hevc_d_dev *const dev, void *v) apb_write(dev, RPI_CURRPOC, de->rpi_currpoc); /* collocated reads/writes */ - apb_write_vc_len(dev, RPI_COLSTRIDE, - de->ctx->colmv_stride); - apb_write_vc_len(dev, RPI_MVSTRIDE, - de->ctx->colmv_stride); - apb_write_vc_addr(dev, RPI_MVBASE, - !de->frame_aux ? 0 : de->frame_aux->col.addr); - apb_write_vc_addr(dev, RPI_COLBASE, - !de->col_aux ? 0 : de->col_aux->col.addr); + if (!colbase && de->dpbno_col != ~0U) + goto fail; + + apb_write_vc_len(dev, RPI_COLSTRIDE, ctx->colmv_stride); + apb_write(dev, RPI_COLBASE, colbase); + apb_write_vc_len(dev, RPI_MVSTRIDE, ctx->colmv_stride); + apb_write(dev, RPI_MVBASE, de->mvbase); hevc_d_hw_irq_active2_irq(dev, &de->irq_ent, phase2_cb, de); apb_write_final(dev, RPI_NUMROWS, de->pic_height_in_ctbs_y); -} + return; -static void phase2_err_claimed(struct hevc_d_dev *const dev, void *v) -{ - phase2_done(dev, v, VB2_BUF_STATE_ERROR); +fail: + phase2_err_claimed(dev, de); } static void phase1_claimed(struct hevc_d_dev *const dev, void *v); @@ -2108,11 +2106,11 @@ static void phase1_claimed(struct hevc_d_dev *const dev, void *v) if (ctx->fatal_err) goto fail; - de->pu_base_vc = pu_hwbuf->addr; + de->pu_base_addr = pu_hwbuf->addr; de->pu_stride = ALIGN_DOWN(pu_hwbuf->size / de->pic_height_in_ctbs_y, 64); - de->coeff_base_vc = coeff_hwbuf->addr; + de->coeff_base_addr = coeff_hwbuf->addr; de->coeff_stride = ALIGN_DOWN(coeff_hwbuf->size / de->pic_height_in_ctbs_y, 64); @@ -2120,9 +2118,9 @@ static void phase1_claimed(struct hevc_d_dev *const dev, void *v) * in cb_phase1 after error detection */ - apb_write_vc_addr(dev, RPI_PUWBASE, de->pu_base_vc); + apb_write_vc_addr(dev, RPI_PUWBASE, de->pu_base_addr); apb_write_vc_len(dev, RPI_PUWSTRIDE, de->pu_stride); - apb_write_vc_addr(dev, RPI_COEFFWBASE, de->coeff_base_vc); + apb_write_vc_addr(dev, RPI_COEFFWBASE, de->coeff_base_addr); apb_write_vc_len(dev, RPI_COEFFWSTRIDE, de->coeff_stride); /* Trigger command FIFO */ diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c index 1b9ffcd4df3d81..8564b332f8d2af 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c @@ -11,16 +11,8 @@ * Copyright (C) 2018 Bootlin */ #include -#include -#include #include -#include -#include -#include -#include #include -#include -#include #include #include @@ -405,7 +397,7 @@ int hevc_d_hw_probe(struct hevc_d_dev *dev) return ret; irq_dec = platform_get_irq(dev->pdev, 0); - if (irq_dec <= 0) + if (irq_dec < 0) return irq_dec; ret = devm_request_threaded_irq(dev->dev, irq_dec, hevc_d_irq_irq, 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 765b27ab161bad..85fe96fc13d4c5 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h @@ -14,6 +14,8 @@ #ifndef _HEVC_D_HW_H_ #define _HEVC_D_HW_H_ +#include + struct hevc_d_hw_irq_ent { struct hevc_d_hw_irq_ent *next; hevc_d_irq_callback cb; @@ -84,6 +86,8 @@ struct hevc_d_hw_irq_ent { /* Offset to get from REFYBASEn to REFYBASEn+1 */ #define RPI_REFREGS_SIZE 16 +#define VC_ADDR(x) ((u32)((x) >> 6)) + /* * Write a general register value * Order is unimportant @@ -123,14 +127,14 @@ static inline void apb_write_vc_addr(const struct hevc_d_dev * const dev, const unsigned int offset, const dma_addr_t a) { - apb_write(dev, offset, (u32)(a >> 6)); + apb_write(dev, offset, VC_ADDR(a)); } static inline void apb_write_vc_addr_final(const struct hevc_d_dev * const dev, const unsigned int offset, const dma_addr_t a) { - apb_write_final(dev, offset, (u32)(a >> 6)); + apb_write_final(dev, offset, VC_ADDR(a)); } static inline void apb_write_vc_len(const struct hevc_d_dev * const dev, 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 8c5aa64df93c77..b7f0b6ac9f7263 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -11,7 +11,6 @@ * Copyright (C) 2018 Bootlin */ -#include #include #include #include @@ -27,14 +26,6 @@ static inline struct hevc_d_ctx *hevc_d_file2ctx(struct file *file) return container_of(file->private_data, struct hevc_d_ctx, fh); } -/* constrain x to y,y*2 */ -static inline unsigned int constrain2x(unsigned int x, unsigned int y) -{ - return (x < y) ? - y : - (x > y * 2) ? y : x; -} - size_t hevc_d_round_up_size(const size_t x) { /* Admit no size < 256 */ @@ -43,7 +34,7 @@ size_t hevc_d_round_up_size(const size_t x) return x >= (3 << n) ? 4 << n : (3 << n); } -size_t hevc_d_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8) +static u32 bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8) { const size_t wxh = w * h; size_t bits_alloc; @@ -59,42 +50,39 @@ size_t hevc_d_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_min wxh * 3 / 8; /* Allow for bit depth */ bits_alloc += (bits_alloc * bits_minus8) / 8; - return hevc_d_round_up_size(bits_alloc); + return (u32)hevc_d_round_up_size(bits_alloc); } void hevc_d_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt) { - size_t size; - u32 w; - u32 h; - - w = pix_fmt->width; - h = pix_fmt->height; - if (!w || !h) { - w = HEVC_D_DEFAULT_WIDTH; - h = HEVC_D_DEFAULT_HEIGHT; - } - if (w > HEVC_D_MAX_WIDTH) - w = HEVC_D_MAX_WIDTH; - if (h > HEVC_D_MAX_HEIGHT) - h = HEVC_D_MAX_HEIGHT; - - if (!pix_fmt->plane_fmt[0].sizeimage || - pix_fmt->plane_fmt[0].sizeimage > SZ_32M) { - /* Unspecified or way too big - pick max for size */ - size = hevc_d_bit_buf_size(w, h, 2); - } + unsigned int width = pix_fmt->width; + unsigned int height = pix_fmt->height; + unsigned int sizeimage = pix_fmt->plane_fmt[0].sizeimage; + + if (!width) + width = HEVC_D_DEFAULT_WIDTH; + else + width = clamp(width, HEVC_D_MIN_WIDTH, HEVC_D_MAX_WIDTH); + if (!height) + height = HEVC_D_DEFAULT_HEIGHT; + else + height = clamp(height, HEVC_D_MIN_HEIGHT, HEVC_D_MAX_HEIGHT); + + /* If unspecified or way too big - pick max for size */ + if (!sizeimage || sizeimage > SZ_32M) + sizeimage = bit_buf_size(width, height, 2); + /* Set a minimum */ - size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage); + sizeimage = max(SZ_4K, sizeimage); pix_fmt->pixelformat = V4L2_PIX_FMT_HEVC_SLICE; - pix_fmt->width = w; - pix_fmt->height = h; + pix_fmt->width = width; + pix_fmt->height = height; pix_fmt->num_planes = 1; pix_fmt->field = V4L2_FIELD_NONE; /* Zero bytes per line for encoded source. */ pix_fmt->plane_fmt[0].bytesperline = 0; - pix_fmt->plane_fmt[0].sizeimage = size; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; } /* Take any pix_format and make it valid */ @@ -447,30 +435,21 @@ static int hevc_d_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, struct device *alloc_devs[]) { struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *pix_fmt; - int expected_nplanes; + const struct v4l2_pix_format_mplane *pix_fmt; + unsigned int i; - if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - pix_fmt = &ctx->src_fmt; - expected_nplanes = 1; - } else { - pix_fmt = get_dst_fmt(ctx); - expected_nplanes = 2; - } + pix_fmt = V4L2_TYPE_IS_OUTPUT(vq->type) ? &ctx->src_fmt : get_dst_fmt(ctx); if (*nplanes) { - if (*nplanes != expected_nplanes || - sizes[0] < pix_fmt->plane_fmt[0].sizeimage || - sizes[1] < pix_fmt->plane_fmt[1].sizeimage) + if (*nplanes != pix_fmt->num_planes) return -EINVAL; + for (i = 0; i != pix_fmt->num_planes; ++i) + if (sizes[i] < pix_fmt->plane_fmt[i].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; - } + *nplanes = pix_fmt->num_planes; + for (i = 0; i != pix_fmt->num_planes; ++i) + sizes[i] = pix_fmt->plane_fmt[i].sizeimage; } return 0; @@ -508,12 +487,11 @@ static int hevc_d_buf_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *pix_fmt; + struct v4l2_pix_format_mplane *pix_fmt = &ctx->dst_fmt; + /* If OUTPUT then we don't care about actual buffer size */ if (V4L2_TYPE_IS_OUTPUT(vq->type)) - pix_fmt = &ctx->src_fmt; - else - pix_fmt = &ctx->dst_fmt; + return 0; if (vb2_plane_size(vb, 0) < pix_fmt->plane_fmt[0].sizeimage || vb2_plane_size(vb, 1) < pix_fmt->plane_fmt[1].sizeimage) diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h index fb894bc9c813c2..e7952937ed865e 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h @@ -30,7 +30,6 @@ extern const struct v4l2_ioctl_ops hevc_d_ioctl_ops; int hevc_d_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); -size_t hevc_d_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8); size_t hevc_d_round_up_size(const size_t x); void hevc_d_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt); From 5524a0369f2f495e810a2a23249d02150906022c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 16 Jan 2025 18:24:17 +0000 Subject: [PATCH 6/7] 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 cdec2b54361a87..0d06bab61af23c 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, @@ -252,7 +261,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 cb5f28e96df77d804d2b1be21e09f99b46b99b39 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 11 Feb 2025 16:09:27 +0000 Subject: [PATCH 7/7] 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 This includes the fixups that were present as separate patches in earlier versions. Signed-off-by: Dave Stevenson --- .../raspberrypi/hevc_dec/hevc_d_h265.c | 93 ++++++++++++++++--- .../raspberrypi/hevc_dec/hevc_d_video.c | 72 +++++++++++--- 2 files changed, 137 insertions(+), 28 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 eb99747e588e9d..1d4a7fbd9d4aaa 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -1556,6 +1556,8 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) unsigned int ctb_size_y; bool sps_changed = false; unsigned int lkg_slot; + /* Old (downstream only) bit size meanings */ + bool old_bits = false; de = dec_env_new(ctx); if (!de) { @@ -1606,25 +1608,43 @@ static int 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); - de->mvbase = 0; - de->frame_slot = run->dst->vb2_buf.index; + 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); + de->mvbase = 0; + de->frame_slot = run->dst->vb2_buf.index; + 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); + de->mvbase = 0; + de->frame_slot = run->dst->vb2_buf.index; + old_bits = true; + break; + } 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 (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); @@ -1643,6 +1663,42 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 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; + } + /* * Need Aux ents for all (ref) DPB ents if temporal MV could * be enabled for any pic @@ -1688,15 +1744,24 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) 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; - const u32 byte_size = DIV_ROUND_UP(sh->bit_size, 8); + unsigned int bit_size = old_bits ? sh->bit_size - 8 * sh->data_byte_offset : + sh->bit_size; + const u32 byte_size = DIV_ROUND_UP(bit_size, 8); unsigned int j; s->sh = sh; + if (old_bits && sh->bit_size <= 8 * sh->data_byte_offset) { + v4l2_warn(&dev->v4l2_dev, + "data_byte_offset %d * 8 >= bits %d\n", + sh->data_byte_offset, sh->bit_size); + goto fail; + } + if (sh->data_byte_offset + byte_size > run->src->planes[0].bytesused) { v4l2_warn(&dev->v4l2_dev, "data_byte_offset %d + bits %d (= %d bytes) > bytesused %d\n", - sh->data_byte_offset, sh->bit_size, byte_size, + sh->data_byte_offset, bit_size, byte_size, run->src->planes[0].bytesused); goto fail; } @@ -1706,7 +1771,7 @@ static int hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) * actual size of the buffer (which may well be what is used to set * bit_size if the caller isn't being very pedantic). */ - s->data_len = min(sh->bit_size / 8 + 1, + s->data_len = min(bit_size / 8 + 1, run->src->planes[0].bytesused - sh->data_byte_offset); s->slice_qp = 26 + s->pps.init_qp_minus26 + sh->slice_qp_delta; 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 b7f0b6ac9f7263..9758d7310ec74f 100644 --- a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -128,17 +128,49 @@ 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, 16); + + 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, 16); + + 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, @@ -223,19 +255,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;