Skip to content

HEVC decoder updates #6990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: rpi-6.12.y
Choose a base branch
from
2 changes: 1 addition & 1 deletion arch/arm/boot/dts/broadcom/bcm2711.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
155 changes: 37 additions & 118 deletions drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "hevc_d_video.h"
#include "hevc_d_hw.h"

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
Expand All @@ -34,54 +38,33 @@ 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[] = {
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,
},
};

Expand Down Expand Up @@ -123,12 +106,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);
Expand All @@ -144,69 +126,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);
Expand All @@ -229,17 +148,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
*/
Expand All @@ -251,9 +170,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);
Expand All @@ -272,11 +190,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);

Expand Down Expand Up @@ -317,7 +236,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,
};

Expand Down Expand Up @@ -439,7 +358,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);
Expand Down
43 changes: 23 additions & 20 deletions drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,36 @@
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>

#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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down
Loading
Loading