rockchip64: fixes for v4l2, add rkvdec hevc decoder

This commit is contained in:
Paolo Sabatino 2023-12-14 22:26:33 +01:00 committed by Igor
parent cabb8aaf27
commit fbfa2aa9ad
8 changed files with 8756 additions and 0 deletions

View File

@ -0,0 +1,659 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:35 +0000
Subject: [PATCH] media: v4l2-common: Add helpers to calculate bytesperline and
sizeimage
Add helper functions to calculate plane bytesperline and sizeimage, these
new helpers consider block width and height when calculating plane
bytesperline and sizeimage.
This prepare support for new pixel formats added in next patch that make
use of block width and height.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/media/v4l2-core/v4l2-common.c | 77 +++++++++++++--------------
1 file changed, 38 insertions(+), 39 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index e0fbe6ba4b6c..cb2f1acab7cf 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -338,6 +338,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
return info->block_h[plane];
}
+static inline unsigned int v4l2_format_plane_width(const struct v4l2_format_info *info, int plane,
+ unsigned int width)
+{
+ unsigned int hdiv = plane ? info->hdiv : 1;
+ unsigned int bytes = DIV_ROUND_UP(width * info->bpp[plane],
+ v4l2_format_block_width(info, plane) *
+ v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(bytes, hdiv);
+}
+
+static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane,
+ unsigned int height)
+{
+ unsigned int vdiv = plane ? info->vdiv : 1;
+ unsigned int lines = ALIGN(height, v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(lines, vdiv);
+}
+
+static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
+ unsigned int width, unsigned int height)
+{
+ return v4l2_format_plane_width(info, plane, width) *
+ v4l2_format_plane_height(info, plane, height);
+}
+
void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
const struct v4l2_frmsize_stepwise *frmsize)
{
@@ -373,37 +400,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
if (info->mem_planes == 1) {
plane = &pixfmt->plane_fmt[0];
- plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
+ plane->bytesperline = v4l2_format_plane_width(info, 0, width);
plane->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- plane->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv);
- }
+ for (i = 0; i < info->comp_planes; i++)
+ plane->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
} else {
for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
plane = &pixfmt->plane_fmt[i];
plane->bytesperline =
- info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv);
- plane->sizeimage =
- plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
+ v4l2_format_plane_width(info, i, width);
+ plane->sizeimage = plane->bytesperline *
+ v4l2_format_plane_height(info, i, height);
}
}
return 0;
@@ -427,22 +436,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
pixfmt->width = width;
pixfmt->height = height;
pixfmt->pixelformat = pixelformat;
- pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
+ pixfmt->bytesperline = v4l2_format_plane_width(info, 0, width);
pixfmt->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- pixfmt->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv);
- }
+ for (i = 0; i < info->comp_planes; i++)
+ pixfmt->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: v4l2: Add NV15 and NV20 pixel formats
Add NV15 and NV20 pixel formats used by the Rockchip Video Decoder for
10-bit buffers.
NV15 and NV20 is a packed 10-bit 4:2:0/4:2:2 semi-planar Y/CbCr format
similar to P010 and P210 but has no padding between components. Instead,
luminance and chrominance samples are grouped into 4s so that each group is
packed into an integer number of bytes:
YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes
The '15' and '20' suffix refers to the optimum effective bits per pixel
which is achieved when the total number of luminance samples is a multiple
of 8 for NV15 and 4 for NV20.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/media/v4l2-core/v4l2-common.c | 3 +++
drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
include/uapi/linux/videodev2.h | 3 +++
3 files changed, 8 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index cb2f1acab7cf..8446a1deffd8 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -268,6 +268,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 2, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+ { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 1, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index e6fd355a2e92..24771edaa4f2 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1354,6 +1354,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV24: descr = "Y/UV 4:4:4"; break;
case V4L2_PIX_FMT_NV42: descr = "Y/UV 4:4:4"; break;
case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_NV15: descr = "10-bit Y/UV 4:2:0 (Packed)"; break;
+ case V4L2_PIX_FMT_NV20: descr = "10-bit Y/UV 4:2:2 (Packed)"; break;
case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break;
case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 01e630f2ec78..cea44992aea3 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -628,6 +628,9 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */
#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0') /* 24 Y/CbCr 4:2:0 10-bit per component */
+#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/CbCr 4:2:0 10-bit packed */
+#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/CbCr 4:2:2 10-bit packed */
+
/* two non contiguous planes - one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: rkvdec: h264: Use bytesperline and buffer height to
calculate stride
Use bytesperline and buffer height to calculate the strides configured.
This does not really change anything other than ensuring the bytesperline
that is signaled to userspace matches what is configured in HW.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 4fc167b42cf0..a8635105e387 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -896,9 +896,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
dma_addr_t rlc_addr;
dma_addr_t refer_addr;
u32 rlc_len;
- u32 hor_virstride = 0;
- u32 ver_virstride = 0;
- u32 y_virstride = 0;
+ u32 hor_virstride;
+ u32 ver_virstride;
+ u32 y_virstride;
u32 yuv_virstride = 0;
u32 offset;
dma_addr_t dst_addr;
@@ -909,8 +909,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
f = &ctx->decoded_fmt;
dst_fmt = &f->fmt.pix_mp;
- hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8;
- ver_virstride = round_up(dst_fmt->height, 16);
+ hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+ ver_virstride = dst_fmt->height;
y_virstride = hor_virstride * ver_virstride;
if (sps->chroma_format_idc == 0)
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Extract rkvdec_fill_decoded_pixfmt helper
method
This extract setting decoded pixfmt into a helper method, current code is
replaced with a call to the new helper method.
The helper method is also called from a new function in next patch.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 29 ++++++++++++++-------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 7bab7586918c..40cc791aef26 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -27,6 +27,17 @@
#include "rkvdec.h"
#include "rkvdec-regs.h"
+static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+ pix_mp->plane_fmt[0].sizeimage += 128 *
+ DIV_ROUND_UP(pix_mp->width, 16) *
+ DIV_ROUND_UP(pix_mp->height, 16);
+ pix_mp->field = V4L2_FIELD_NONE;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
@@ -192,13 +203,9 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
- ctx->coded_fmt_desc->decoded_fmts[0],
- ctx->coded_fmt.fmt.pix_mp.width,
- ctx->coded_fmt.fmt.pix_mp.height);
- f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 *
- DIV_ROUND_UP(f->fmt.pix_mp.width, 16) *
- DIV_ROUND_UP(f->fmt.pix_mp.height, 16);
+ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
+ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height;
+ rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp);
}
static int rkvdec_enum_framesizes(struct file *file, void *priv,
@@ -264,13 +271,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
&pix_mp->height,
&coded_desc->frmsize);
- v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
- pix_mp->plane_fmt[0].sizeimage +=
- 128 *
- DIV_ROUND_UP(pix_mp->width, 16) *
- DIV_ROUND_UP(pix_mp->height, 16);
- pix_mp->field = V4L2_FIELD_NONE;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
return 0;
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Lock capture pixel format in s_ctrl and s_fmt
Add an optional valid_fmt operation that should return the valid
pixelformat of CAPTURE buffers.
This is used in next patch to ensure correct pixelformat is used for 10-bit
and 4:2:2 content.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 67 +++++++++++++++++++++++----
drivers/staging/media/rkvdec/rkvdec.h | 2 +
2 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 40cc791aef26..e93e1cb0f829 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -38,19 +38,56 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
pix_mp->field = V4L2_FIELD_NONE;
}
+static u32 rkvdec_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc;
+
+ if (coded_desc->ops->valid_fmt)
+ return coded_desc->ops->valid_fmt(ctx, ctrl);
+
+ return ctx->valid_fmt;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc;
- if (desc->ops->try_ctrl)
- return desc->ops->try_ctrl(ctx, ctrl);
+ if (desc->ops->try_ctrl) {
+ int ret;
+ ret = desc->ops->try_ctrl(ctx, ctrl);
+ if (ret)
+ return ret;
+ }
+
+ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl))
+ /* Only current valid format */
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
+
+ if (ctrl->id == V4L2_CID_STATELESS_H264_SPS && !ctx->valid_fmt) {
+ ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl);
+ if (ctx->valid_fmt) {
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ pix_mp = &ctx->decoded_fmt.fmt.pix_mp;
+ pix_mp->pixelformat = ctx->valid_fmt;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
+ }
+ }
return 0;
}
static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = {
.try_ctrl = rkvdec_try_ctrl,
+ .s_ctrl = rkvdec_s_ctrl,
};
static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
@@ -201,6 +238,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
{
struct v4l2_format *f = &ctx->decoded_fmt;
+ ctx->valid_fmt = 0;
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
@@ -256,13 +294,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!coded_desc))
return -EINVAL;
- for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
- if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
- break;
- }
+ if (ctx->valid_fmt) {
+ pix_mp->pixelformat = ctx->valid_fmt;
+ } else {
+ for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
+ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
+ break;
+ }
- if (i == coded_desc->num_decoded_fmts)
- pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ if (i == coded_desc->num_decoded_fmts)
+ pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ }
/* Always apply the frmsize constraint of the coded end. */
pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
@@ -326,6 +368,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv,
return ret;
ctx->decoded_fmt = *f;
+ ctx->valid_fmt = f->fmt.pix_mp.pixelformat;
return 0;
}
@@ -429,6 +472,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!ctx->coded_fmt_desc))
return -EINVAL;
+ if (ctx->valid_fmt) {
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = ctx->valid_fmt;
+ return 0;
+ }
+
if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts)
return -EINVAL;
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index 633335ebb9c4..b9e219438bc9 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -66,6 +66,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
struct rkvdec_coded_fmt_ops {
int (*adjust_fmt)(struct rkvdec_ctx *ctx,
struct v4l2_format *f);
+ u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
int (*start)(struct rkvdec_ctx *ctx);
void (*stop)(struct rkvdec_ctx *ctx);
int (*run)(struct rkvdec_ctx *ctx);
@@ -101,6 +102,7 @@ struct rkvdec_ctx {
struct v4l2_fh fh;
struct v4l2_format coded_fmt;
struct v4l2_format decoded_fmt;
+ u32 valid_fmt;
const struct rkvdec_coded_fmt_desc *coded_fmt_desc;
struct v4l2_ctrl_handler ctrl_hdl;
struct rkvdec_dev *dev;
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: h264: Support High 10 and 4:2:2 profiles
Add support and enable decoding of H264 High 10 and 4:2:2 profiles.
Decoded CAPTURE buffer width is aligned to 64 pixels to accommodate HW
requirement on 10-bit format buffers.
The new valid_fmt operation is implemented and return a valid pixelformat
for the provided SPS control.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 33 ++++++++++++++++------
drivers/staging/media/rkvdec/rkvdec.c | 19 +++++++++----
2 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index a8635105e387..0069d3d198db 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -1031,19 +1031,14 @@ static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
{
unsigned int width, height;
- /*
- * TODO: The hardware supports 10-bit and 4:2:2 profiles,
- * but it's currently broken in the driver.
- * Reject them for now, until it's fixed.
- */
- if (sps->chroma_format_idc > 1)
- /* Only 4:0:0 and 4:2:0 are supported */
+ if (sps->chroma_format_idc > 2)
+ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
return -EINVAL;
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
/* Luma and chroma bit depth mismatch */
return -EINVAL;
- if (sps->bit_depth_luma_minus8 != 0)
- /* Only 8-bit is supported */
+ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+ /* Only 8-bit and 10-bit is supported */
return -EINVAL;
width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
@@ -1064,6 +1059,25 @@ static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
return 0;
}
+static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+ if (sps->bit_depth_luma_minus8 == 0) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV16;
+ else
+ return V4L2_PIX_FMT_NV12;
+ } else if (sps->bit_depth_luma_minus8 == 2) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV20;
+ else
+ return V4L2_PIX_FMT_NV15;
+ }
+
+ return 0;
+}
+
static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
{
struct rkvdec_dev *rkvdec = ctx->dev;
@@ -1185,6 +1199,7 @@ static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = {
.adjust_fmt = rkvdec_h264_adjust_fmt,
+ .valid_fmt = rkvdec_h264_valid_fmt,
.start = rkvdec_h264_start,
.stop = rkvdec_h264_stop,
.run = rkvdec_h264_run,
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index e93e1cb0f829..4f5436c89e08 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -31,7 +31,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
+ ALIGN(pix_mp->width, 64), pix_mp->height);
pix_mp->plane_fmt[0].sizeimage += 128 *
DIV_ROUND_UP(pix_mp->width, 16) *
DIV_ROUND_UP(pix_mp->height, 16);
@@ -136,8 +136,11 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
};
-static const u32 rkvdec_h264_vp9_decoded_fmts[] = {
+static const u32 rkvdec_h264_decoded_fmts[] = {
V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_NV15,
+ V4L2_PIX_FMT_NV16,
+ V4L2_PIX_FMT_NV20,
};
static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = {
@@ -160,6 +163,10 @@ static const struct rkvdec_ctrls rkvdec_vp9_ctrls = {
.num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs),
};
+static const u32 rkvdec_vp9_decoded_fmts[] = {
+ V4L2_PIX_FMT_NV12,
+};
+
static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -173,8 +180,8 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
},
.ctrls = &rkvdec_h264_ctrls,
.ops = &rkvdec_h264_fmt_ops,
- .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts),
- .decoded_fmts = rkvdec_h264_vp9_decoded_fmts,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+ .decoded_fmts = rkvdec_h264_decoded_fmts,
.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
},
{
@@ -189,8 +196,8 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
},
.ctrls = &rkvdec_vp9_ctrls,
.ops = &rkvdec_vp9_fmt_ops,
- .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts),
- .decoded_fmts = rkvdec_h264_vp9_decoded_fmts,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts),
+ .decoded_fmts = rkvdec_vp9_decoded_fmts,
}
};
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sun, 27 Mar 2022 14:18:07 +0200
Subject: [PATCH] media: rkvdec-h264: Don't hardcode SPS/PPS parameters
Some SPS/PPS parameters are currently hardcoded in the driver
even though so do exist in the uapi which is stable by now.
Use them instead of hardcoding them.
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 0069d3d198db..2c27acaba85e 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -655,13 +655,14 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value)
/* write sps */
- WRITE_PPS(0xf, SEQ_PARAMETER_SET_ID);
- WRITE_PPS(0xff, PROFILE_IDC);
- WRITE_PPS(1, CONSTRAINT_SET3_FLAG);
+ WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID);
+ WRITE_PPS(sps->profile_idc, PROFILE_IDC);
+ WRITE_PPS((sps->constraint_set_flags & 1 << 3) ? 1 : 0, CONSTRAINT_SET3_FLAG);
WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC);
WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA);
WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA);
- WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG);
+ WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS),
+ QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG);
WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4);
WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES);
WRITE_PPS(sps->pic_order_cnt_type, PIC_ORDER_CNT_TYPE);
@@ -688,8 +689,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
DIRECT_8X8_INFERENCE_FLAG);
/* write pps */
- WRITE_PPS(0xff, PIC_PARAMETER_SET_ID);
- WRITE_PPS(0x1f, PPS_SEQ_PARAMETER_SET_ID);
+ WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID);
+ WRITE_PPS(pps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID);
WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE),
ENTROPY_CODING_MODE_FLAG);
WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT),

View File

@ -0,0 +1,493 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 23 May 2020 10:16:01 +0000
Subject: [PATCH] WIP: media: rkvdec: pm runtime dont use autosuspend before
disable and cleanup
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 4f5436c89e08..eaf2f133a264 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -1125,9 +1125,9 @@ static int rkvdec_remove(struct platform_device *pdev)
{
struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev);
- rkvdec_v4l2_cleanup(rkvdec);
- pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ rkvdec_v4l2_cleanup(rkvdec);
return 0;
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Randy Li <ayaka@soulik.info>
Date: Sun, 6 Jan 2019 01:48:37 +0800
Subject: [PATCH] soc: rockchip: power-domain: export idle request
We need to put the power status of HEVC IP into IDLE unless
we can't reset that IP or the SoC would crash down.
rockchip_pmu_idle_request(dev, true)---> enter idle
rockchip_pmu_idle_request(dev, false)---> exit idle
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Randy Li <ayaka@soulik.info>
---
drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++
include/linux/rockchip_pmu.h | 15 +++++++++++++++
include/soc/rockchip/pm_domains.h | 6 ++++++
3 files changed, 44 insertions(+)
create mode 100644 include/linux/rockchip_pmu.h
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 89795abac951..ffb5d62c9d52 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -309,6 +309,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
return 0;
}
+int rockchip_pmu_idle_request(struct device *dev, bool idle)
+{
+ struct generic_pm_domain *genpd;
+ struct rockchip_pm_domain *pd;
+ int ret;
+
+ if (IS_ERR_OR_NULL(dev))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(dev->pm_domain))
+ return -EINVAL;
+
+ genpd = pd_to_genpd(dev->pm_domain);
+ pd = to_rockchip_pd(genpd);
+
+ mutex_lock(&pd->pmu->mutex);
+ ret = rockchip_pmu_set_idle_request(pd, idle);
+ mutex_unlock(&pd->pmu->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(rockchip_pmu_idle_request);
+
static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
{
int i;
diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h
new file mode 100644
index 000000000000..720b3314e71a
--- /dev/null
+++ b/include/linux/rockchip_pmu.h
@@ -0,0 +1,15 @@
+/*
+ * pm_domain.h - Definitions and headers related to device power domains.
+ *
+ * Copyright (C) 2017 Randy Li <ayaka@soulik.info>.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _LINUX_ROCKCHIP_PM_H
+#define _LINUX_ROCKCHIP_PM_H
+#include <linux/device.h>
+
+int rockchip_pmu_idle_request(struct device *dev, bool idle);
+
+#endif /* _LINUX_ROCKCHIP_PM_H */
diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h
index 7dbd941fc937..c5a59dd71754 100644
--- a/include/soc/rockchip/pm_domains.h
+++ b/include/soc/rockchip/pm_domains.h
@@ -10,6 +10,7 @@
int rockchip_pmu_block(void);
void rockchip_pmu_unblock(void);
+int rockchip_pmu_idle_request(struct device *dev, bool idle);
#else /* CONFIG_ROCKCHIP_PM_DOMAINS */
@@ -20,6 +21,11 @@ static inline int rockchip_pmu_block(void)
static inline void rockchip_pmu_unblock(void) { }
+static inline int rockchip_pmu_idle_request(struct device *dev, bool idle)
+{
+ return -ENOTSUPP;
+}
+
#endif /* CONFIG_ROCKCHIP_PM_DOMAINS */
#endif /* __SOC_ROCKCHIP_PM_DOMAINS_H__ */
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 20 May 2020 17:04:47 +0200
Subject: [PATCH] WIP: media: rkvdec: implement reset controls
---
.../bindings/media/rockchip,vdec.yaml | 19 +++++++
drivers/staging/media/rkvdec/rkvdec-regs.h | 5 ++
drivers/staging/media/rkvdec/rkvdec.c | 53 +++++++++++++++++++
drivers/staging/media/rkvdec/rkvdec.h | 11 +++-
4 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
index 3bcfb8e12333..dd6958df1de8 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -53,6 +53,18 @@ properties:
iommus:
maxItems: 1
+ resets:
+ maxItems: 6
+
+ reset-names:
+ items:
+ - const: video_h
+ - const: video_a
+ - const: video_core
+ - const: video_cabac
+ - const: niu_a
+ - const: niu_h
+
required:
- compatible
- reg
@@ -60,6 +72,8 @@ required:
- clocks
- clock-names
- power-domains
+ - resets
+ - reset-names
additionalProperties: false
@@ -78,6 +92,11 @@ examples:
clock-names = "axi", "ahb", "cabac", "core";
power-domains = <&power RK3399_PD_VDU>;
iommus = <&vdec_mmu>;
+ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>,
+ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>,
+ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
};
...
diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h
index 15b9bee92016..3acc914888f6 100644
--- a/drivers/staging/media/rkvdec/rkvdec-regs.h
+++ b/drivers/staging/media/rkvdec/rkvdec-regs.h
@@ -28,6 +28,11 @@
#define RKVDEC_SOFTRST_EN_P BIT(20)
#define RKVDEC_FORCE_SOFTRESET_VALID BIT(21)
#define RKVDEC_SOFTRESET_RDY BIT(22)
+#define RKVDEC_ERR_MASK (RKVDEC_BUS_STA \
+ | RKVDEC_ERR_STA \
+ | RKVDEC_TIMEOUT_STA \
+ | RKVDEC_BUF_EMPTY_STA \
+ | RKVDEC_COLMV_REF_ERR_STA )
#define RKVDEC_REG_SYSCTRL 0x008
#define RKVDEC_IN_ENDIAN BIT(0)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index eaf2f133a264..f55abb7c377f 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -10,12 +10,15 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/rockchip_pmu.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
@@ -717,6 +720,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx,
pm_runtime_mark_last_busy(rkvdec->dev);
pm_runtime_put_autosuspend(rkvdec->dev);
+
+ if (result == VB2_BUF_STATE_ERROR &&
+ rkvdec->reset_mask == RESET_NONE)
+ rkvdec->reset_mask |= RESET_SOFT;
+
rkvdec_job_finish_no_pm(ctx, result);
}
@@ -754,6 +762,33 @@ static void rkvdec_device_run(void *priv)
if (WARN_ON(!desc))
return;
+ if (rkvdec->reset_mask != RESET_NONE) {
+
+ if (rkvdec->reset_mask & RESET_SOFT) {
+ writel(RKVDEC_SOFTRST_EN_P,
+ rkvdec->regs + RKVDEC_REG_INTERRUPT);
+ udelay(RKVDEC_RESET_DELAY);
+ if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT)
+ & RKVDEC_SOFTRESET_RDY)
+ dev_info_ratelimited(rkvdec->dev,
+ "softreset failed\n");
+ }
+
+ if (rkvdec->reset_mask & RESET_HARD) {
+ rockchip_pmu_idle_request(rkvdec->dev, true);
+ ret = reset_control_assert(rkvdec->rstc);
+ if (!ret) {
+ udelay(RKVDEC_RESET_DELAY);
+ ret = reset_control_deassert(rkvdec->rstc);
+ }
+ rockchip_pmu_idle_request(rkvdec->dev, false);
+ if (ret)
+ dev_notice_ratelimited(rkvdec->dev,
+ "hardreset failed\n");
+ }
+ rkvdec->reset_mask = RESET_NONE;
+ pm_runtime_suspend(rkvdec->dev);
+ }
ret = pm_runtime_resume_and_get(rkvdec->dev);
if (ret < 0) {
@@ -1020,6 +1055,11 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
if (cancel_delayed_work(&rkvdec->watchdog_work)) {
struct rkvdec_ctx *ctx;
+ if (state == VB2_BUF_STATE_ERROR) {
+ rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ?
+ RESET_HARD : RESET_SOFT;
+ }
+
ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
rkvdec_job_finish(ctx, state);
}
@@ -1037,6 +1077,7 @@ static void rkvdec_watchdog_func(struct work_struct *work)
ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
if (ctx) {
dev_err(rkvdec->dev, "Frame processing timed out!\n");
+ rkvdec->reset_mask |= RESET_HARD;
writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
@@ -1105,6 +1146,18 @@ static int rkvdec_probe(struct platform_device *pdev)
return ret;
}
+
+ rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, false, true);
+ if (IS_ERR(rkvdec->rstc)) {
+ dev_err(&pdev->dev,
+ "get resets failed %ld\n", PTR_ERR(rkvdec->rstc));
+ return PTR_ERR(rkvdec->rstc);
+ } else {
+ dev_dbg(&pdev->dev,
+ "requested %d resets\n",
+ reset_control_get_count(&pdev->dev));
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index b9e219438bc9..f02f79c405f0 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -11,10 +11,11 @@
#ifndef RKVDEC_H_
#define RKVDEC_H_
+#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/videodev2.h>
#include <linux/wait.h>
-#include <linux/clk.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -22,6 +23,12 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#define RESET_NONE 0
+#define RESET_SOFT BIT(0)
+#define RESET_HARD BIT(1)
+
+#define RKVDEC_RESET_DELAY 5
+
struct rkvdec_ctx;
struct rkvdec_ctrl_desc {
@@ -96,6 +103,8 @@ struct rkvdec_dev {
void __iomem *regs;
struct mutex vdev_lock; /* serializes ioctls */
struct delayed_work watchdog_work;
+ struct reset_control *rstc;
+ u8 reset_mask;
};
struct rkvdec_ctx {
@@ -1345,6 +1348,11 @@ vdec: video-codec@ff660000 {
clock-names = "axi", "ahb", "cabac", "core";
iommus = <&vdec_mmu>;
power-domains = <&power RK3399_PD_VDU>;
+ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>,
+ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>,
+ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
};
vdec_mmu: iommu@ff660480 {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sat, 21 Aug 2021 16:12:36 +0200
Subject: [PATCH] media: hantro: rockchip: Increase RK3288's max ACLK
Required to proper decode H.264@4K
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/media/platform/verisilicon/rockchip_vpu_hw.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 8de6fd2e8eef..002b1a600f93 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -15,7 +15,8 @@
#include "rockchip_vpu2_regs.h"
#define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000)
-#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+#define RK3288_ACLK_MAX_FREQ (600 * 1000 * 1000)
+#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
/*
* Supported formats.
@@ -346,13 +347,20 @@ static int rk3066_vpu_hw_init(struct hantro_dev *vpu)
return 0;
}
-static int rockchip_vpu_hw_init(struct hantro_dev *vpu)
+static int rk3288_vpu_hw_init(struct hantro_dev *vpu)
{
/* Bump ACLK to max. possible freq. to improve performance. */
clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
return 0;
}
+static int rockchip_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLK to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
+ return 0;
+}
+
static void rk3066_vpu_dec_reset(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
@@ -592,7 +600,7 @@ const struct hantro_variant rk3288_vpu_variant = {
.codec_ops = rk3288_vpu_codec_ops,
.irqs = rockchip_vpu1_irqs,
.num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
- .init = rockchip_vpu_hw_init,
+ .init = rk3288_vpu_hw_init,
.clk_names = rockchip_vpu_clk_names,
.num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
};
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sun, 4 Jul 2021 15:19:44 +0200
Subject: [PATCH] media: rkvdec: disable QoS for VP9 (corruptions on RK3328
otherwise)
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/staging/media/rkvdec/rkvdec-regs.h | 2 ++
drivers/staging/media/rkvdec/rkvdec-vp9.c | 8 ++++++++
2 files changed, 10 insertions(+)
diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h
index 3acc914888f6..265f5234f4eb 100644
--- a/drivers/staging/media/rkvdec/rkvdec-regs.h
+++ b/drivers/staging/media/rkvdec/rkvdec-regs.h
@@ -222,6 +222,8 @@
#define RKVDEC_REG_H264_ERR_E 0x134
#define RKVDEC_H264_ERR_EN_HIGHBITS(x) ((x) & 0x3fffffff)
+#define RKVDEC_QOS_CTRL 0x18C
+
#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND 0x410
#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND 0x450
diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c
index d8c1c0db15c7..a289bc968e91 100644
--- a/drivers/staging/media/rkvdec/rkvdec-vp9.c
+++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c
@@ -802,6 +802,7 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
struct rkvdec_dev *rkvdec = ctx->dev;
struct rkvdec_vp9_run run = { };
int ret;
+ u32 reg;
ret = rkvdec_vp9_run_preamble(ctx, &run);
if (ret) {
@@ -823,6 +824,13 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
+
+ /* disable QOS for RK3328 - no effect on other SoCs */
+ reg = readl(rkvdec->regs + RKVDEC_QOS_CTRL);
+ reg |= 0xFFFF;
+ reg &= (~BIT(12));
+ writel(reg, rkvdec->regs + RKVDEC_QOS_CTRL);
+
/* Start decoding! */
writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E,
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Thu, 16 Jun 2022 13:18:22 +0200
Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3328
---
arch/arm64/boot/dts/rockchip/rk3328.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 5519347232f6..431c4ec198be 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -674,6 +674,11 @@ vdec: video-codec@ff360000 {
assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>,
<&cru SCLK_VDEC_CORE>;
assigned-clock-rates = <400000000>, <400000000>, <300000000>;
+ resets = <&cru SRST_VDEC_H>, <&cru SRST_VDEC_A>,
+ <&cru SRST_VDEC_CORE>, <&cru SRST_VDEC_CABAC>,
+ <&cru SRST_VDEC_NIU_A>, <&cru SRST_VDEC_NIU_H>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
iommus = <&vdec_mmu>;
power-domains = <&power RK3328_PD_VIDEO>;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,659 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:35 +0000
Subject: [PATCH] media: v4l2-common: Add helpers to calculate bytesperline and
sizeimage
Add helper functions to calculate plane bytesperline and sizeimage, these
new helpers consider block width and height when calculating plane
bytesperline and sizeimage.
This prepare support for new pixel formats added in next patch that make
use of block width and height.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/media/v4l2-core/v4l2-common.c | 77 +++++++++++++--------------
1 file changed, 38 insertions(+), 39 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index e0fbe6ba4b6c..cb2f1acab7cf 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -338,6 +338,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
return info->block_h[plane];
}
+static inline unsigned int v4l2_format_plane_width(const struct v4l2_format_info *info, int plane,
+ unsigned int width)
+{
+ unsigned int hdiv = plane ? info->hdiv : 1;
+ unsigned int bytes = DIV_ROUND_UP(width * info->bpp[plane],
+ v4l2_format_block_width(info, plane) *
+ v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(bytes, hdiv);
+}
+
+static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane,
+ unsigned int height)
+{
+ unsigned int vdiv = plane ? info->vdiv : 1;
+ unsigned int lines = ALIGN(height, v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(lines, vdiv);
+}
+
+static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
+ unsigned int width, unsigned int height)
+{
+ return v4l2_format_plane_width(info, plane, width) *
+ v4l2_format_plane_height(info, plane, height);
+}
+
void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
const struct v4l2_frmsize_stepwise *frmsize)
{
@@ -373,37 +400,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
if (info->mem_planes == 1) {
plane = &pixfmt->plane_fmt[0];
- plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0];
+ plane->bytesperline = v4l2_format_plane_width(info, 0, width);
plane->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- plane->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i];
- }
+ for (i = 0; i < info->comp_planes; i++)
+ plane->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
} else {
for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
plane = &pixfmt->plane_fmt[i];
plane->bytesperline =
- info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv) / info->bpp_div[i];
- plane->sizeimage =
- plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
+ v4l2_format_plane_width(info, i, width);
+ plane->sizeimage = plane->bytesperline *
+ v4l2_format_plane_height(info, i, height);
}
}
return 0;
@@ -427,22 +436,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
pixfmt->width = width;
pixfmt->height = height;
pixfmt->pixelformat = pixelformat;
- pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0];
+ pixfmt->bytesperline = v4l2_format_plane_width(info, 0, width);
pixfmt->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- pixfmt->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i];
- }
+ for (i = 0; i < info->comp_planes; i++)
+ pixfmt->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: v4l2: Add NV15 and NV20 pixel formats
Add NV15 and NV20 pixel formats used by the Rockchip Video Decoder for
10-bit buffers.
NV15 and NV20 is a packed 10-bit 4:2:0/4:2:2 semi-planar Y/UV format
similar to P010 and P210 but has no padding between components. Instead,
luminance and chrominance samples are grouped into 4s so that each group is
packed into an integer number of bytes:
YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes
The '15' and '20' suffix refers to the optimum effective bits per pixel
which is achieved when the total number of luminance samples is a multiple
of 8 for NV15 and 4 for NV20.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/media/v4l2-core/v4l2-common.c | 3 +++
drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++
include/uapi/linux/videodev2.h | 3 +++
3 files changed, 8 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index cb2f1acab7cf..8446a1deffd8 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -268,6 +268,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+ { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index e6fd355a2e92..24771edaa4f2 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1354,6 +1354,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break;
case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
case V4L2_PIX_FMT_P012: descr = "12-bit Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_NV15: descr = "10-bit Y/UV 4:2:0 (Packed)"; break;
+ case V4L2_PIX_FMT_NV20: descr = "10-bit Y/UV 4:2:2 (Packed)"; break;
case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break;
case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 01e630f2ec78..cea44992aea3 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -628,6 +628,9 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/VU 4:4:4 */
#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0') /* 24 Y/UV 4:2:0 10-bit per component */
+#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/UV 4:2:0 10-bit packed */
+#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/UV 4:2:2 10-bit packed */
+
/* two non contiguous planes - one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/UV 4:2:0 */
#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/VU 4:2:0 */
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: rkvdec: h264: Use bytesperline and buffer height to
calculate stride
Use bytesperline and buffer height to calculate the strides configured.
This does not really change anything other than ensuring the bytesperline
that is signaled to userspace matches what is configured in HW.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 4fc167b42cf0..a8635105e387 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -896,9 +896,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
dma_addr_t rlc_addr;
dma_addr_t refer_addr;
u32 rlc_len;
- u32 hor_virstride = 0;
- u32 ver_virstride = 0;
- u32 y_virstride = 0;
+ u32 hor_virstride;
+ u32 ver_virstride;
+ u32 y_virstride;
u32 yuv_virstride = 0;
u32 offset;
dma_addr_t dst_addr;
@@ -909,8 +909,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
f = &ctx->decoded_fmt;
dst_fmt = &f->fmt.pix_mp;
- hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8;
- ver_virstride = round_up(dst_fmt->height, 16);
+ hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+ ver_virstride = dst_fmt->height;
y_virstride = hor_virstride * ver_virstride;
if (sps->chroma_format_idc == 0)
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Extract rkvdec_fill_decoded_pixfmt helper
method
This extract setting decoded pixfmt into a helper method, current code is
replaced with a call to the new helper method.
The helper method is also called from a new function in next patch.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 29 ++++++++++++++-------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 7bab7586918c..40cc791aef26 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -27,6 +27,17 @@
#include "rkvdec.h"
#include "rkvdec-regs.h"
+static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+ pix_mp->plane_fmt[0].sizeimage += 128 *
+ DIV_ROUND_UP(pix_mp->width, 16) *
+ DIV_ROUND_UP(pix_mp->height, 16);
+ pix_mp->field = V4L2_FIELD_NONE;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
@@ -192,13 +203,9 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
- ctx->coded_fmt_desc->decoded_fmts[0],
- ctx->coded_fmt.fmt.pix_mp.width,
- ctx->coded_fmt.fmt.pix_mp.height);
- f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 *
- DIV_ROUND_UP(f->fmt.pix_mp.width, 16) *
- DIV_ROUND_UP(f->fmt.pix_mp.height, 16);
+ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
+ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height;
+ rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp);
}
static int rkvdec_enum_framesizes(struct file *file, void *priv,
@@ -264,13 +271,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
&pix_mp->height,
&coded_desc->frmsize);
- v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
- pix_mp->plane_fmt[0].sizeimage +=
- 128 *
- DIV_ROUND_UP(pix_mp->width, 16) *
- DIV_ROUND_UP(pix_mp->height, 16);
- pix_mp->field = V4L2_FIELD_NONE;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
return 0;
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Lock capture pixel format in s_ctrl and s_fmt
Add an optional valid_fmt operation that should return the valid
pixelformat of CAPTURE buffers.
This is used in next patch to ensure correct pixelformat is used for 10-bit
and 4:2:2 content.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 67 +++++++++++++++++++++++----
drivers/staging/media/rkvdec/rkvdec.h | 2 +
2 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 40cc791aef26..e93e1cb0f829 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -38,19 +38,56 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
pix_mp->field = V4L2_FIELD_NONE;
}
+static u32 rkvdec_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc;
+
+ if (coded_desc->ops->valid_fmt)
+ return coded_desc->ops->valid_fmt(ctx, ctrl);
+
+ return ctx->valid_fmt;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc;
- if (desc->ops->try_ctrl)
- return desc->ops->try_ctrl(ctx, ctrl);
+ if (desc->ops->try_ctrl) {
+ int ret;
+ ret = desc->ops->try_ctrl(ctx, ctrl);
+ if (ret)
+ return ret;
+ }
+
+ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl))
+ /* Only current valid format */
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
+
+ if (ctrl->id == V4L2_CID_STATELESS_H264_SPS && !ctx->valid_fmt) {
+ ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl);
+ if (ctx->valid_fmt) {
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ pix_mp = &ctx->decoded_fmt.fmt.pix_mp;
+ pix_mp->pixelformat = ctx->valid_fmt;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
+ }
+ }
return 0;
}
static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = {
.try_ctrl = rkvdec_try_ctrl,
+ .s_ctrl = rkvdec_s_ctrl,
};
static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
@@ -201,6 +238,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
{
struct v4l2_format *f = &ctx->decoded_fmt;
+ ctx->valid_fmt = 0;
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
@@ -256,13 +294,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!coded_desc))
return -EINVAL;
- for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
- if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
- break;
- }
+ if (ctx->valid_fmt) {
+ pix_mp->pixelformat = ctx->valid_fmt;
+ } else {
+ for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
+ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
+ break;
+ }
- if (i == coded_desc->num_decoded_fmts)
- pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ if (i == coded_desc->num_decoded_fmts)
+ pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ }
/* Always apply the frmsize constraint of the coded end. */
pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
@@ -326,6 +368,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv,
return ret;
ctx->decoded_fmt = *f;
+ ctx->valid_fmt = f->fmt.pix_mp.pixelformat;
return 0;
}
@@ -429,6 +472,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!ctx->coded_fmt_desc))
return -EINVAL;
+ if (ctx->valid_fmt) {
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = ctx->valid_fmt;
+ return 0;
+ }
+
if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts)
return -EINVAL;
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index 633335ebb9c4..b9e219438bc9 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -66,6 +66,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
struct rkvdec_coded_fmt_ops {
int (*adjust_fmt)(struct rkvdec_ctx *ctx,
struct v4l2_format *f);
+ u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
int (*start)(struct rkvdec_ctx *ctx);
void (*stop)(struct rkvdec_ctx *ctx);
int (*run)(struct rkvdec_ctx *ctx);
@@ -101,6 +102,7 @@ struct rkvdec_ctx {
struct v4l2_fh fh;
struct v4l2_format coded_fmt;
struct v4l2_format decoded_fmt;
+ u32 valid_fmt;
const struct rkvdec_coded_fmt_desc *coded_fmt_desc;
struct v4l2_ctrl_handler ctrl_hdl;
struct rkvdec_dev *dev;
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: h264: Support High 10 and 4:2:2 profiles
Add support and enable decoding of H264 High 10 and 4:2:2 profiles.
Decoded CAPTURE buffer width is aligned to 64 pixels to accommodate HW
requirement on 10-bit format buffers.
The new valid_fmt operation is implemented and return a valid pixelformat
for the provided SPS control.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 33 ++++++++++++++++------
drivers/staging/media/rkvdec/rkvdec.c | 19 +++++++++----
2 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index a8635105e387..0069d3d198db 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -1031,19 +1031,14 @@ static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
{
unsigned int width, height;
- /*
- * TODO: The hardware supports 10-bit and 4:2:2 profiles,
- * but it's currently broken in the driver.
- * Reject them for now, until it's fixed.
- */
- if (sps->chroma_format_idc > 1)
- /* Only 4:0:0 and 4:2:0 are supported */
+ if (sps->chroma_format_idc > 2)
+ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
return -EINVAL;
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
/* Luma and chroma bit depth mismatch */
return -EINVAL;
- if (sps->bit_depth_luma_minus8 != 0)
- /* Only 8-bit is supported */
+ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+ /* Only 8-bit and 10-bit is supported */
return -EINVAL;
width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
@@ -1064,6 +1059,25 @@ static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx,
return 0;
}
+static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+ if (sps->bit_depth_luma_minus8 == 0) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV16;
+ else
+ return V4L2_PIX_FMT_NV12;
+ } else if (sps->bit_depth_luma_minus8 == 2) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV20;
+ else
+ return V4L2_PIX_FMT_NV15;
+ }
+
+ return 0;
+}
+
static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
{
struct rkvdec_dev *rkvdec = ctx->dev;
@@ -1185,6 +1199,7 @@ static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = {
.adjust_fmt = rkvdec_h264_adjust_fmt,
+ .valid_fmt = rkvdec_h264_valid_fmt,
.start = rkvdec_h264_start,
.stop = rkvdec_h264_stop,
.run = rkvdec_h264_run,
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index e93e1cb0f829..4f5436c89e08 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -31,7 +31,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
+ ALIGN(pix_mp->width, 64), pix_mp->height);
pix_mp->plane_fmt[0].sizeimage += 128 *
DIV_ROUND_UP(pix_mp->width, 16) *
DIV_ROUND_UP(pix_mp->height, 16);
@@ -136,8 +136,11 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
.num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs),
};
-static const u32 rkvdec_h264_vp9_decoded_fmts[] = {
+static const u32 rkvdec_h264_decoded_fmts[] = {
V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_NV15,
+ V4L2_PIX_FMT_NV16,
+ V4L2_PIX_FMT_NV20,
};
static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = {
@@ -160,6 +163,10 @@ static const struct rkvdec_ctrls rkvdec_vp9_ctrls = {
.num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs),
};
+static const u32 rkvdec_vp9_decoded_fmts[] = {
+ V4L2_PIX_FMT_NV12,
+};
+
static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -173,8 +180,8 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
},
.ctrls = &rkvdec_h264_ctrls,
.ops = &rkvdec_h264_fmt_ops,
- .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts),
- .decoded_fmts = rkvdec_h264_vp9_decoded_fmts,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
+ .decoded_fmts = rkvdec_h264_decoded_fmts,
.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
},
{
@@ -189,8 +196,8 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
},
.ctrls = &rkvdec_vp9_ctrls,
.ops = &rkvdec_vp9_fmt_ops,
- .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts),
- .decoded_fmts = rkvdec_h264_vp9_decoded_fmts,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts),
+ .decoded_fmts = rkvdec_vp9_decoded_fmts,
}
};
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sun, 27 Mar 2022 14:18:07 +0200
Subject: [PATCH] media: rkvdec-h264: Don't hardcode SPS/PPS parameters
Some SPS/PPS parameters are currently hardcoded in the driver
even though so do exist in the uapi which is stable by now.
Use them instead of hardcoding them.
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 0069d3d198db..2c27acaba85e 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -655,13 +655,14 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value)
/* write sps */
- WRITE_PPS(0xf, SEQ_PARAMETER_SET_ID);
- WRITE_PPS(0xff, PROFILE_IDC);
- WRITE_PPS(1, CONSTRAINT_SET3_FLAG);
+ WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID);
+ WRITE_PPS(sps->profile_idc, PROFILE_IDC);
+ WRITE_PPS((sps->constraint_set_flags & 1 << 3) ? 1 : 0, CONSTRAINT_SET3_FLAG);
WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC);
WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA);
WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA);
- WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG);
+ WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS),
+ QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG);
WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4);
WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES);
WRITE_PPS(sps->pic_order_cnt_type, PIC_ORDER_CNT_TYPE);
@@ -688,8 +689,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
DIRECT_8X8_INFERENCE_FLAG);
/* write pps */
- WRITE_PPS(0xff, PIC_PARAMETER_SET_ID);
- WRITE_PPS(0x1f, PPS_SEQ_PARAMETER_SET_ID);
+ WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID);
+ WRITE_PPS(pps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID);
WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE),
ENTROPY_CODING_MODE_FLAG);
WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT),

View File

@ -0,0 +1,493 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 23 May 2020 10:16:01 +0000
Subject: [PATCH] WIP: media: rkvdec: pm runtime dont use autosuspend before
disable and cleanup
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 4f5436c89e08..eaf2f133a264 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -1125,9 +1125,9 @@ static int rkvdec_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&rkvdec->watchdog_work);
- rkvdec_v4l2_cleanup(rkvdec);
- pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ rkvdec_v4l2_cleanup(rkvdec);
}
#ifdef CONFIG_PM
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Randy Li <ayaka@soulik.info>
Date: Sun, 6 Jan 2019 01:48:37 +0800
Subject: [PATCH] soc: rockchip: power-domain: export idle request
We need to put the power status of HEVC IP into IDLE unless
we can't reset that IP or the SoC would crash down.
rockchip_pmu_idle_request(dev, true)---> enter idle
rockchip_pmu_idle_request(dev, false)---> exit idle
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: Randy Li <ayaka@soulik.info>
---
drivers/pmdomain/rockchip/pm-domains.c | 23 +++++++++++++++++++++++
include/linux/rockchip_pmu.h | 15 +++++++++++++++
include/soc/rockchip/pm_domains.h | 6 ++++++
3 files changed, 44 insertions(+)
create mode 100644 include/linux/rockchip_pmu.h
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index 89795abac951..ffb5d62c9d52 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -309,6 +309,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
return 0;
}
+int rockchip_pmu_idle_request(struct device *dev, bool idle)
+{
+ struct generic_pm_domain *genpd;
+ struct rockchip_pm_domain *pd;
+ int ret;
+
+ if (IS_ERR_OR_NULL(dev))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(dev->pm_domain))
+ return -EINVAL;
+
+ genpd = pd_to_genpd(dev->pm_domain);
+ pd = to_rockchip_pd(genpd);
+
+ mutex_lock(&pd->pmu->mutex);
+ ret = rockchip_pmu_set_idle_request(pd, idle);
+ mutex_unlock(&pd->pmu->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(rockchip_pmu_idle_request);
+
static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
{
int i;
diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h
new file mode 100644
index 000000000000..720b3314e71a
--- /dev/null
+++ b/include/linux/rockchip_pmu.h
@@ -0,0 +1,15 @@
+/*
+ * pm_domain.h - Definitions and headers related to device power domains.
+ *
+ * Copyright (C) 2017 Randy Li <ayaka@soulik.info>.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _LINUX_ROCKCHIP_PM_H
+#define _LINUX_ROCKCHIP_PM_H
+#include <linux/device.h>
+
+int rockchip_pmu_idle_request(struct device *dev, bool idle);
+
+#endif /* _LINUX_ROCKCHIP_PM_H */
diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h
index 7dbd941fc937..c5a59dd71754 100644
--- a/include/soc/rockchip/pm_domains.h
+++ b/include/soc/rockchip/pm_domains.h
@@ -10,6 +10,7 @@
int rockchip_pmu_block(void);
void rockchip_pmu_unblock(void);
+int rockchip_pmu_idle_request(struct device *dev, bool idle);
#else /* CONFIG_ROCKCHIP_PM_DOMAINS */
@@ -20,6 +21,11 @@ static inline int rockchip_pmu_block(void)
static inline void rockchip_pmu_unblock(void) { }
+static inline int rockchip_pmu_idle_request(struct device *dev, bool idle)
+{
+ return -ENOTSUPP;
+}
+
#endif /* CONFIG_ROCKCHIP_PM_DOMAINS */
#endif /* __SOC_ROCKCHIP_PM_DOMAINS_H__ */
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 20 May 2020 17:04:47 +0200
Subject: [PATCH] WIP: media: rkvdec: implement reset controls
---
.../bindings/media/rockchip,vdec.yaml | 19 +++++++
drivers/staging/media/rkvdec/rkvdec-regs.h | 5 ++
drivers/staging/media/rkvdec/rkvdec.c | 53 +++++++++++++++++++
drivers/staging/media/rkvdec/rkvdec.h | 11 +++-
4 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
index 3bcfb8e12333..dd6958df1de8 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -53,6 +53,18 @@ properties:
iommus:
maxItems: 1
+ resets:
+ maxItems: 6
+
+ reset-names:
+ items:
+ - const: video_h
+ - const: video_a
+ - const: video_core
+ - const: video_cabac
+ - const: niu_a
+ - const: niu_h
+
required:
- compatible
- reg
@@ -60,6 +72,8 @@ required:
- clocks
- clock-names
- power-domains
+ - resets
+ - reset-names
additionalProperties: false
@@ -78,6 +92,11 @@ examples:
clock-names = "axi", "ahb", "cabac", "core";
power-domains = <&power RK3399_PD_VDU>;
iommus = <&vdec_mmu>;
+ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>,
+ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>,
+ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
};
...
diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h
index 15b9bee92016..3acc914888f6 100644
--- a/drivers/staging/media/rkvdec/rkvdec-regs.h
+++ b/drivers/staging/media/rkvdec/rkvdec-regs.h
@@ -28,6 +28,11 @@
#define RKVDEC_SOFTRST_EN_P BIT(20)
#define RKVDEC_FORCE_SOFTRESET_VALID BIT(21)
#define RKVDEC_SOFTRESET_RDY BIT(22)
+#define RKVDEC_ERR_MASK (RKVDEC_BUS_STA \
+ | RKVDEC_ERR_STA \
+ | RKVDEC_TIMEOUT_STA \
+ | RKVDEC_BUF_EMPTY_STA \
+ | RKVDEC_COLMV_REF_ERR_STA )
#define RKVDEC_REG_SYSCTRL 0x008
#define RKVDEC_IN_ENDIAN BIT(0)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index eaf2f133a264..f55abb7c377f 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -10,12 +10,15 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/rockchip_pmu.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
@@ -717,6 +720,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx,
pm_runtime_mark_last_busy(rkvdec->dev);
pm_runtime_put_autosuspend(rkvdec->dev);
+
+ if (result == VB2_BUF_STATE_ERROR &&
+ rkvdec->reset_mask == RESET_NONE)
+ rkvdec->reset_mask |= RESET_SOFT;
+
rkvdec_job_finish_no_pm(ctx, result);
}
@@ -754,6 +762,33 @@ static void rkvdec_device_run(void *priv)
if (WARN_ON(!desc))
return;
+ if (rkvdec->reset_mask != RESET_NONE) {
+
+ if (rkvdec->reset_mask & RESET_SOFT) {
+ writel(RKVDEC_SOFTRST_EN_P,
+ rkvdec->regs + RKVDEC_REG_INTERRUPT);
+ udelay(RKVDEC_RESET_DELAY);
+ if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT)
+ & RKVDEC_SOFTRESET_RDY)
+ dev_info_ratelimited(rkvdec->dev,
+ "softreset failed\n");
+ }
+
+ if (rkvdec->reset_mask & RESET_HARD) {
+ rockchip_pmu_idle_request(rkvdec->dev, true);
+ ret = reset_control_assert(rkvdec->rstc);
+ if (!ret) {
+ udelay(RKVDEC_RESET_DELAY);
+ ret = reset_control_deassert(rkvdec->rstc);
+ }
+ rockchip_pmu_idle_request(rkvdec->dev, false);
+ if (ret)
+ dev_notice_ratelimited(rkvdec->dev,
+ "hardreset failed\n");
+ }
+ rkvdec->reset_mask = RESET_NONE;
+ pm_runtime_suspend(rkvdec->dev);
+ }
ret = pm_runtime_resume_and_get(rkvdec->dev);
if (ret < 0) {
@@ -1020,6 +1055,11 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
if (cancel_delayed_work(&rkvdec->watchdog_work)) {
struct rkvdec_ctx *ctx;
+ if (state == VB2_BUF_STATE_ERROR) {
+ rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ?
+ RESET_HARD : RESET_SOFT;
+ }
+
ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
rkvdec_job_finish(ctx, state);
}
@@ -1037,6 +1077,7 @@ static void rkvdec_watchdog_func(struct work_struct *work)
ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
if (ctx) {
dev_err(rkvdec->dev, "Frame processing timed out!\n");
+ rkvdec->reset_mask |= RESET_HARD;
writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
@@ -1105,6 +1146,18 @@ static int rkvdec_probe(struct platform_device *pdev)
return ret;
}
+
+ rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, false, true);
+ if (IS_ERR(rkvdec->rstc)) {
+ dev_err(&pdev->dev,
+ "get resets failed %ld\n", PTR_ERR(rkvdec->rstc));
+ return PTR_ERR(rkvdec->rstc);
+ } else {
+ dev_dbg(&pdev->dev,
+ "requested %d resets\n",
+ reset_control_get_count(&pdev->dev));
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index b9e219438bc9..f02f79c405f0 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -11,10 +11,11 @@
#ifndef RKVDEC_H_
#define RKVDEC_H_
+#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/videodev2.h>
#include <linux/wait.h>
-#include <linux/clk.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -22,6 +23,12 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#define RESET_NONE 0
+#define RESET_SOFT BIT(0)
+#define RESET_HARD BIT(1)
+
+#define RKVDEC_RESET_DELAY 5
+
struct rkvdec_ctx;
struct rkvdec_ctrl_desc {
@@ -96,6 +103,8 @@ struct rkvdec_dev {
void __iomem *regs;
struct mutex vdev_lock; /* serializes ioctls */
struct delayed_work watchdog_work;
+ struct reset_control *rstc;
+ u8 reset_mask;
};
struct rkvdec_ctx {
@@ -1345,6 +1348,11 @@ vdec: video-codec@ff660000 {
clock-names = "axi", "ahb", "cabac", "core";
iommus = <&vdec_mmu>;
power-domains = <&power RK3399_PD_VDU>;
+ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>,
+ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>,
+ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
};
vdec_mmu: iommu@ff660480 {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sat, 21 Aug 2021 16:12:36 +0200
Subject: [PATCH] media: hantro: rockchip: Increase RK3288's max ACLK
Required to proper decode H.264@4K
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/media/platform/verisilicon/rockchip_vpu_hw.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 8de6fd2e8eef..002b1a600f93 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -15,7 +15,8 @@
#include "rockchip_vpu2_regs.h"
#define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000)
-#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+#define RK3288_ACLK_MAX_FREQ (600 * 1000 * 1000)
+#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
#define RK3588_ACLK_MAX_FREQ (300 * 1000 * 1000)
#define ROCKCHIP_VPU981_MIN_SIZE 64
@@ -346,13 +347,20 @@ static int rk3066_vpu_hw_init(struct hantro_dev *vpu)
return 0;
}
-static int rockchip_vpu_hw_init(struct hantro_dev *vpu)
+static int rk3288_vpu_hw_init(struct hantro_dev *vpu)
{
/* Bump ACLK to max. possible freq. to improve performance. */
clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
return 0;
}
+static int rockchip_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLK to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
+ return 0;
+}
+
static void rk3066_vpu_dec_reset(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
@@ -592,7 +600,7 @@ const struct hantro_variant rk3288_vpu_variant = {
.codec_ops = rk3288_vpu_codec_ops,
.irqs = rockchip_vpu1_irqs,
.num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
- .init = rockchip_vpu_hw_init,
+ .init = rk3288_vpu_hw_init,
.clk_names = rockchip_vpu_clk_names,
.num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
};
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sun, 4 Jul 2021 15:19:44 +0200
Subject: [PATCH] media: rkvdec: disable QoS for VP9 (corruptions on RK3328
otherwise)
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
drivers/staging/media/rkvdec/rkvdec-regs.h | 2 ++
drivers/staging/media/rkvdec/rkvdec-vp9.c | 8 ++++++++
2 files changed, 10 insertions(+)
diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h
index 3acc914888f6..265f5234f4eb 100644
--- a/drivers/staging/media/rkvdec/rkvdec-regs.h
+++ b/drivers/staging/media/rkvdec/rkvdec-regs.h
@@ -222,6 +222,8 @@
#define RKVDEC_REG_H264_ERR_E 0x134
#define RKVDEC_H264_ERR_EN_HIGHBITS(x) ((x) & 0x3fffffff)
+#define RKVDEC_QOS_CTRL 0x18C
+
#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND 0x410
#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND 0x450
diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c
index d8c1c0db15c7..a289bc968e91 100644
--- a/drivers/staging/media/rkvdec/rkvdec-vp9.c
+++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c
@@ -802,6 +802,7 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
struct rkvdec_dev *rkvdec = ctx->dev;
struct rkvdec_vp9_run run = { };
int ret;
+ u32 reg;
ret = rkvdec_vp9_run_preamble(ctx, &run);
if (ret) {
@@ -823,6 +824,13 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
+
+ /* disable QOS for RK3328 - no effect on other SoCs */
+ reg = readl(rkvdec->regs + RKVDEC_QOS_CTRL);
+ reg |= 0xFFFF;
+ reg &= (~BIT(12));
+ writel(reg, rkvdec->regs + RKVDEC_QOS_CTRL);
+
/* Start decoding! */
writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E,
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Thu, 16 Jun 2022 13:18:22 +0200
Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3328
---
arch/arm64/boot/dts/rockchip/rk3328.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 5519347232f6..431c4ec198be 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -674,6 +674,11 @@ vdec: video-codec@ff360000 {
assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>,
<&cru SCLK_VDEC_CORE>;
assigned-clock-rates = <400000000>, <400000000>, <300000000>;
+ resets = <&cru SRST_VDEC_H>, <&cru SRST_VDEC_A>,
+ <&cru SRST_VDEC_CORE>, <&cru SRST_VDEC_CABAC>,
+ <&cru SRST_VDEC_NIU_A>, <&cru SRST_VDEC_NIU_H>;
+ reset-names = "video_h", "video_a", "video_core", "video_cabac",
+ "niu_a", "niu_h";
iommus = <&vdec_mmu>;
power-domains = <&power RK3328_PD_VIDEO>;
};

File diff suppressed because it is too large Load Diff