diff --git a/projects/Rockchip/README.md b/projects/Rockchip/README.md
index 29a58c4b72..def46069f0 100644
--- a/projects/Rockchip/README.md
+++ b/projects/Rockchip/README.md
@@ -23,8 +23,10 @@ This project is for Rockchip SoC devices
* [Orange Pi RK3399](devices/RK3399)
* [PINE64 RockPro64](devices/RK3399)
* [Radxa ROCK Pi 4](devices/RK3399)
+* [Radxa ROCK Pi 4+](devices/RK3399)
* [Radxa ROCK Pi N10](devices/RK3399)
* [ROC-RK3399-PC](devices/RK3399)
+* [ROC-RK3399-PC-PLUS](devices/RK3399)
* [Rockchip Sapphire Board](devices/RK3399)
**My single-board computer is not listed, will it be added in the future?**
diff --git a/projects/Rockchip/devices/RK3399/README.md b/projects/Rockchip/devices/RK3399/README.md
index 12567481d4..970c1d21dd 100644
--- a/projects/Rockchip/devices/RK3399/README.md
+++ b/projects/Rockchip/devices/RK3399/README.md
@@ -11,7 +11,9 @@ This is a SoC device for RK3399
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=orangepi make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=rock960 make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=rock-pi-4 make image`
+* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=rock-pi-4-plus make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=rock-pi-n10 make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=rockpro64 make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=roc-pc make image`
+* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=roc-pc-plus make image`
* `PROJECT=Rockchip DEVICE=RK3399 ARCH=arm UBOOT_SYSTEM=sapphire make image`
diff --git a/projects/Rockchip/filesystem/usr/share/alsa/cards/simple-card.conf b/projects/Rockchip/filesystem/usr/share/alsa/cards/simple-card.conf
new file mode 100644
index 0000000000..93b41e95c6
--- /dev/null
+++ b/projects/Rockchip/filesystem/usr/share/alsa/cards/simple-card.conf
@@ -0,0 +1,205 @@
+#
+# Configuration for HDMI
+#
+
+
+
+simple-card.pcm.hdmi."HDMI" {
+ @args [ CARD DEVICE AES0 AES1 AES2 AES3 ]
+ @args.CARD { type string }
+ @args.DEVICE { type integer }
+ @args.AES0 { type integer }
+ @args.AES1 { type integer }
+ @args.AES2 { type integer }
+ @args.AES3 { type integer }
+ type hooks
+ slave.pcm {
+ type hw
+ card $CARD
+ device $DEVICE
+ }
+ hooks.0 {
+ type ctl_elems
+ hook_args [
+ {
+ interface MIXER
+ name "IEC958 Playback Default"
+ lock true
+ preserve true
+ optional true
+ value [ $AES0 $AES1 $AES2 $AES3 ]
+ }
+ ]
+ }
+ hint.device $DEVICE
+}
+
+simple-card.pcm.hdmi.0 {
+ @args [ CARD AES0 AES1 AES2 AES3 ]
+ @args.CARD { type string }
+ @args.AES0 { type integer }
+ @args.AES1 { type integer }
+ @args.AES2 { type integer }
+ @args.AES3 { type integer }
+
+ @func refer
+ name {
+ @func concat
+ strings [
+ "cards.simple-card.pcm.hdmi."
+ { @func card_name card $CARD }
+ ":CARD=" $CARD ","
+ "DEVICE=0,"
+ "AES0=" $AES0 ","
+ "AES1=" $AES1 ","
+ "AES2=" $AES2 ","
+ "AES3=" $AES3
+ ]
+ }
+ default {
+ # point to non-existent device
+ card $CARD
+ device 999
+ hint.device 999
+ }
+
+}
+
+#
+# Configuration for SPDIF
+#
+
+
+
+simple-card.pcm.iec958."SPDIF" {
+ @args [ CARD DEVICE AES0 AES1 AES2 AES3 ]
+ @args.CARD { type string }
+ @args.DEVICE { type integer }
+ @args.AES0 { type integer }
+ @args.AES1 { type integer }
+ @args.AES2 { type integer }
+ @args.AES3 { type integer }
+ type hooks
+ slave.pcm {
+ type hw
+ card $CARD
+ device $DEVICE
+ }
+ hooks.0 {
+ type ctl_elems
+ hook_args [
+ {
+ interface MIXER
+ name "IEC958 Playback Default"
+ lock true
+ preserve true
+ optional true
+ value [ $AES0 $AES1 $AES2 $AES3 ]
+ }
+ ]
+ }
+ hint.device $DEVICE
+}
+
+simple-card.pcm.iec958.0 {
+ @args [ CARD AES0 AES1 AES2 AES3 ]
+ @args.CARD { type string }
+ @args.AES0 { type integer }
+ @args.AES1 { type integer }
+ @args.AES2 { type integer }
+ @args.AES3 { type integer }
+ @func refer
+ name {
+ @func concat
+ strings [
+ "cards.simple-card.pcm.iec958."
+ { @func card_name card $CARD }
+ ":CARD=" $CARD ","
+ "DEVICE=0,"
+ "AES0=" $AES0 ","
+ "AES1=" $AES1 ","
+ "AES2=" $AES2 ","
+ "AES3=" $AES3
+ ]
+ }
+ default {
+ # point to non-existent device
+ card $CARD
+ device 999
+ hint.device 999
+ }
+}
+
+simple-card.pcm.iec958.1 {
+ @args [ CARD AES0 AES1 AES2 AES3 ]
+ @args.CARD { type string }
+ @args.AES0 { type integer }
+ @args.AES1 { type integer }
+ @args.AES2 { type integer }
+ @args.AES3 { type integer }
+ @func refer
+ name {
+ @func concat
+ strings [
+ "cards.simple-card.pcm.iec958."
+ { @func card_name card $CARD }
+ ":CARD=" $CARD ","
+ "DEVICE=0,"
+ "AES0=" $AES0 ","
+ "AES1=" $AES1 ","
+ "AES2=" $AES2 ","
+ "AES3=" $AES3
+ ]
+ }
+ default {
+ # point to non-existent device
+ card $CARD
+ device 999
+ hint.device 999
+ }
+}
+
+#
+# Configuration for Analog/I2S
+#
+
+
+
+simple-card.pcm.front."Analog" {
+ @args [ CARD DEVICE ]
+ @args.CARD { type string }
+ @args.DEVICE { type integer }
+ type hw
+ card $CARD
+ hint.device $DEVICE
+}
+
+simple-card.pcm.front."I2S" {
+ @args [ CARD ]
+ @args.CARD { type string }
+ @args.DEVICE { type integer }
+ type hw
+ card $CARD
+ hint.device $DEVICE
+}
+
+simple-card.pcm.front.0 {
+ @args [ CARD ]
+ @args.CARD { type string }
+ @func refer
+ name {
+ @func concat
+ strings [
+ "cards.simple-card.pcm.front."
+ { @func card_name card $CARD }
+ ":CARD=" $CARD ","
+ "DEVICE=0"
+ ]
+ }
+ default {
+ # point to non-existent device
+ card $CARD
+ device 999
+ hint.device 999
+ }
+}
diff --git a/projects/Rockchip/patches/ffmpeg/ffmpeg-0001-v4l2_request-validate-supported-framesizes.patch b/projects/Rockchip/patches/ffmpeg/ffmpeg-0001-v4l2_request-validate-supported-framesizes.patch
new file mode 100644
index 0000000000..cc79cde7f4
--- /dev/null
+++ b/projects/Rockchip/patches/ffmpeg/ffmpeg-0001-v4l2_request-validate-supported-framesizes.patch
@@ -0,0 +1,66 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alex Bee
+Date: Sun, 19 Sep 2021 13:10:55 +0200
+Subject: [PATCH] v4l2_request: validate supported framesizes
+
+Signed-off-by: Alex Bee
+---
+ libavcodec/v4l2_request.c | 38 +++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 37 insertions(+), 1 deletion(-)
+
+diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c
+index a8f0ee79ee..2fbe166341 100644
+--- a/libavcodec/v4l2_request.c
++++ b/libavcodec/v4l2_request.c
+@@ -376,6 +376,42 @@ int ff_v4l2_request_decode_frame(AVCodecContext *avctx, AVFrame *frame, struct v
+ return v4l2_request_queue_decode(avctx, frame, control, count, 1, 1);
+ }
+
++static int v4l2_request_try_framesize(AVCodecContext *avctx, uint32_t pixelformat)
++{
++ V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data;
++ struct v4l2_frmsizeenum frmsize = {
++ .index = 0,
++ .pixel_format = pixelformat,
++ };
++
++ if (ioctl(ctx->video_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) < 0)
++ return 0;
++
++ /*
++ * We only validate min/max framesize for V4L2_FRMSIZE_TYPE_STEPWISE here, since the alignment
++ * which is eventually needed will be done driver-side later in VIDIOC_S_FMT and there is no need
++ * validate step_width/step_height here
++ */
++
++ do {
++
++ if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE && frmsize.discrete.width == avctx->coded_width &&
++ frmsize.discrete.height == avctx->coded_height)
++ return 0;
++ else if ((frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE || frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) &&
++ avctx->coded_width >= frmsize.stepwise.min_width && avctx->coded_height >= frmsize.stepwise.min_height &&
++ avctx->coded_width <= frmsize.stepwise.max_width && avctx->coded_height <= frmsize.stepwise.max_height)
++ return 0;
++
++ frmsize.index++;
++
++ } while (ioctl(ctx->video_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0);
++
++ av_log(avctx, AV_LOG_INFO, "%s: pixelformat %u not supported for width %u height %u\n", __func__, pixelformat, avctx->coded_width, avctx->coded_height);
++
++ return -1;
++}
++
+ static int v4l2_request_try_format(AVCodecContext *avctx, enum v4l2_buf_type type, uint32_t pixelformat)
+ {
+ V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data;
+@@ -404,7 +440,7 @@ static int v4l2_request_try_format(AVCodecContext *avctx, enum v4l2_buf_type typ
+
+ while (ioctl(ctx->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) {
+ if (fmtdesc.pixelformat == pixelformat)
+- return 0;
++ return v4l2_request_try_framesize(avctx, pixelformat);
+
+ fmtdesc.index++;
+ }
diff --git a/projects/Rockchip/patches/ffmpeg/ffmpeg-0004-v4l2request-hevc-increase-max-slices.patch b/projects/Rockchip/patches/ffmpeg/ffmpeg-0004-v4l2request-hevc-increase-max-slices.patch
new file mode 100644
index 0000000000..4b665817f0
--- /dev/null
+++ b/projects/Rockchip/patches/ffmpeg/ffmpeg-0004-v4l2request-hevc-increase-max-slices.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alex Bee
+Date: Sun, 20 Jun 2021 20:19:19 +0200
+Subject: [PATCH] v4l2request: hevc: increase max slices
+
+It's required by some HEVC confromance tests
+
+Signed-off-by: Alex Bee
+---
+ libavcodec/v4l2_request_hevc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libavcodec/v4l2_request_hevc.c b/libavcodec/v4l2_request_hevc.c
+index be78382444..35ec87e310 100644
+--- a/libavcodec/v4l2_request_hevc.c
++++ b/libavcodec/v4l2_request_hevc.c
+@@ -21,7 +21,7 @@
+ #include "v4l2_request.h"
+ #include "hevc-ctrls.h"
+
+-#define MAX_SLICES 16
++#define MAX_SLICES 32
+
+ typedef struct V4L2RequestControlsHEVC {
+ struct v4l2_ctrl_hevc_sps sps;
diff --git a/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-deint_v4l2m2m-increase-input-and-output-buffers.patch b/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-deint_v4l2m2m-increase-input-and-output-buffers.patch
new file mode 100644
index 0000000000..8ccbe42b6c
--- /dev/null
+++ b/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-deint_v4l2m2m-increase-input-and-output-buffers.patch
@@ -0,0 +1,26 @@
+From 1a4b8070ff968a07dc24467922849c1142995e30 Mon Sep 17 00:00:00 2001
+From: popcornmix
+Date: Tue, 14 Sep 2021 19:14:24 +0100
+Subject: [PATCH] deint_v4l2m2m: increase input and output buffers
+
+Required for advanced deinterlacer on pi
+---
+ libavfilter/vf_deinterlace_v4l2m2m.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
+index a545d551d9ee..0adc96d25435 100644
+--- a/libavfilter/vf_deinterlace_v4l2m2m.c
++++ b/libavfilter/vf_deinterlace_v4l2m2m.c
+@@ -954,9 +954,9 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
+ priv->shared = ctx;
+ ctx->fd = -1;
+ ctx->output.ctx = ctx;
+- ctx->output.num_buffers = 6;
++ ctx->output.num_buffers = 8;
+ ctx->capture.ctx = ctx;
+- ctx->capture.num_buffers = 6;
++ ctx->capture.num_buffers = 8;
+ ctx->done = 0;
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
diff --git a/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-libavfilter-v4l2deinterlace-support-more-formats-aut.patch b/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-libavfilter-v4l2deinterlace-support-more-formats-aut.patch
new file mode 100644
index 0000000000..a46cc8f83d
--- /dev/null
+++ b/projects/Rockchip/patches/ffmpeg/ffmpeg-0006-libavfilter-v4l2deinterlace-support-more-formats-aut.patch
@@ -0,0 +1,288 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alex Bee
+Date: Wed, 15 Sep 2021 00:37:15 +0200
+Subject: [PATCH] libavfilter: v4l2deinterlace: support more formats /
+ automatic output format selection
+
+Signed-off-by: Alex Bee
+---
+ libavfilter/vf_deinterlace_v4l2m2m.c | 120 +++++++++++++++++++++++----
+ 1 file changed, 102 insertions(+), 18 deletions(-)
+
+diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
+index d7935d92f9..8161fd9e75 100644
+--- a/libavfilter/vf_deinterlace_v4l2m2m.c
++++ b/libavfilter/vf_deinterlace_v4l2m2m.c
+@@ -85,6 +85,9 @@ typedef struct DeintV4L2M2MContextShared {
+ int height;
+ int orig_width;
+ int orig_height;
++ uint64_t drm_in_format;
++ uint64_t drm_out_format;
++
+ atomic_uint refcount;
+
+ AVBufferRef *hw_frames_ctx;
+@@ -108,6 +111,65 @@ typedef struct DeintV4L2M2MContext {
+ DeintV4L2M2MContextShared *shared;
+ } DeintV4L2M2MContext;
+
++typedef struct drm_v4l2_pix_fmt_mapping {
++ uint64_t drm_format;
++ uint32_t v4l2_pix_fmt;
++};
++
++static struct drm_v4l2_pix_fmt_mapping drm_v4l2_pix_fmt_map[] = {
++ { .drm_format = DRM_FORMAT_NV12, .v4l2_pix_fmt = V4L2_PIX_FMT_NV12 },
++ { .drm_format = DRM_FORMAT_NV21, .v4l2_pix_fmt = V4L2_PIX_FMT_NV21 },
++ { .drm_format = DRM_FORMAT_NV16, .v4l2_pix_fmt = V4L2_PIX_FMT_NV16 },
++ { .drm_format = DRM_FORMAT_NV16, .v4l2_pix_fmt = V4L2_PIX_FMT_NV16 },
++#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
++ { .drm_format = DRM_FORMAT_MOD_ALLWINNER_TILED, .v4l2_pix_fmt = V4L2_PIX_FMT_SUNXI_TILED_NV12 },
++#endif
++#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15)
++ { .drm_format = DRM_FORMAT_NV15, .v4l2_pix_fmt = V4L2_PIX_FMT_NV15 },
++#endif
++#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20)
++ { .drm_format = DRM_FORMAT_NV20, .v4l2_pix_fmt = V4L2_PIX_FMT_NV20 },
++#endif
++};
++
++static inline uint32_t v4l2_pix_fmt_from_drm_format(uint64_t drm_format)
++{
++ unsigned int i;
++
++ for (i = 0; i < FF_ARRAY_ELEMS(drm_v4l2_pix_fmt_map); i++) {
++ if (drm_v4l2_pix_fmt_map[i].drm_format == drm_format)
++ return drm_v4l2_pix_fmt_map[i].v4l2_pix_fmt;
++ }
++
++ av_log(NULL, AV_LOG_WARNING, "%s unknown drm format 0x%llx using default v4l2_pix_fmt 0x%x\n",
++ __func__ , drm_format, drm_v4l2_pix_fmt_map[0].v4l2_pix_fmt);
++ return drm_v4l2_pix_fmt_map[0].v4l2_pix_fmt;
++}
++
++static inline uint64_t drm_format_from_v4l2_pix_fmt(uint32_t v4l2_pix_fmt)
++{
++ unsigned int i;
++
++ for (i = 0; i < FF_ARRAY_ELEMS(drm_v4l2_pix_fmt_map); i++) {
++ if (drm_v4l2_pix_fmt_map[i].v4l2_pix_fmt == v4l2_pix_fmt)
++ return drm_v4l2_pix_fmt_map[i].drm_format;
++ }
++
++ av_log(NULL, AV_LOG_WARNING, "%s unknown v4l2_pix_fmt format 0x%x using default drm_format 0x%llx\n",
++ __func__ , v4l2_pix_fmt, drm_v4l2_pix_fmt_map[0].drm_format);
++ return drm_v4l2_pix_fmt_map[0].drm_format;
++}
++
++static inline uint64_t drm_format_modifier(uint64_t drm_format)
++{
++#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
++ if (drm_format == DRM_FORMAT_MOD_ALLWINNER_TILED)
++ return DRM_FORMAT_MOD_ALLWINNER_TILED;
++#endif
++ return DRM_FORMAT_MOD_LINEAR;
++
++}
++
+ static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
+ {
+ struct v4l2_capability cap;
+@@ -138,11 +200,12 @@ static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx)
+ return AVERROR(EINVAL);
+ }
+
+-static int deint_v4l2m2m_try_format(V4L2Queue *queue)
++static int deint_v4l2m2m_try_format(V4L2Queue *queue, uint64_t drm_format)
+ {
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret, field;
++ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
+
+ ret = ioctl(ctx->fd, VIDIOC_G_FMT, fmt);
+ if (ret)
+@@ -154,12 +217,12 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+ field = V4L2_FIELD_NONE;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+- fmt->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
++ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = ctx->width;
+ fmt->fmt.pix_mp.height = ctx->height;
+ } else {
+- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
++ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = ctx->width;
+ fmt->fmt.pix.height = ctx->height;
+@@ -170,14 +233,14 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+ return AVERROR(EINVAL);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+- if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12 ||
++ if (fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt ||
+ fmt->fmt.pix_mp.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
+ return AVERROR(EINVAL);
+ }
+ } else {
+- if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12 ||
++ if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt ||
+ fmt->fmt.pix.field != field) {
+ av_log(NULL, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type);
+
+@@ -187,19 +250,21 @@ static int deint_v4l2m2m_try_format(V4L2Queue *queue)
+
+ return 0;
+ }
+-
+-static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height)
++static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width, int height, uint64_t drm_format)
+ {
+ struct v4l2_format *fmt = &queue->format;
+ DeintV4L2M2MContextShared *ctx = queue->ctx;
+ int ret;
++ uint32_t v4l2_pix_fmt = v4l2_pix_fmt_from_drm_format(drm_format);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
++ fmt->fmt.pix_mp.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix_mp.field = field;
+ fmt->fmt.pix_mp.width = width;
+ fmt->fmt.pix_mp.height = height;
+ /* TODO: bytesperline and imagesize */
+ } else {
++ fmt->fmt.pix.pixelformat = v4l2_pix_fmt;
+ fmt->fmt.pix.field = field;
+ fmt->fmt.pix.width = width;
+ fmt->fmt.pix.height = height;
+@@ -211,6 +276,18 @@ static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t field, int width,
+ if (ret)
+ av_log(NULL, AV_LOG_ERROR, "VIDIOC_S_FMT failed: %d\n", ret);
+
++ else if (!V4L2_TYPE_IS_OUTPUT(queue->format.type)) {
++ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type) && fmt->fmt.pix_mp.pixelformat != v4l2_pix_fmt) {
++ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix_mp.pixelformat);
++ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
++ __func__, v4l2_pix_fmt, fmt->fmt.pix_mp.pixelformat, ctx->drm_out_format);
++ } else if (fmt->fmt.pix.pixelformat != v4l2_pix_fmt) {
++ ctx->drm_out_format = drm_format_from_v4l2_pix_fmt(fmt->fmt.pix.pixelformat);
++ av_log(NULL, AV_LOG_DEBUG, "%s driver updated v4l2_pixfmt from: %x to %x, so now using %llx as drm output format\n",
++ __func__, v4l2_pix_fmt, fmt->fmt.pix.pixelformat, ctx->drm_out_format);
++ }
++ }
++
+ return ret;
+ }
+
+@@ -226,11 +303,11 @@ static int deint_v4l2m2m_probe_device(DeintV4L2M2MContextShared *ctx, char *node
+ if (ret)
+ goto fail;
+
+- ret = deint_v4l2m2m_try_format(&ctx->capture);
++ ret = deint_v4l2m2m_try_format(&ctx->capture, ctx->drm_out_format);
+ if (ret)
+ goto fail;
+
+- ret = deint_v4l2m2m_try_format(&ctx->output);
++ ret = deint_v4l2m2m_try_format(&ctx->output, ctx->drm_in_format);
+ if (ret)
+ goto fail;
+
+@@ -293,7 +370,7 @@ static int deint_v4l2m2m_enqueue_buffer(V4L2Buffer *buf)
+ return 0;
+ }
+
+-static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
++static int v4l2_buffer_export_drm(V4L2Buffer* avbuf, uint64_t drm_format)
+ {
+ struct v4l2_exportbuffer expbuf;
+ int i, ret;
+@@ -315,12 +392,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
+ /* drm frame */
+ avbuf->drm_frame.objects[i].size = avbuf->buffer.m.planes[i].length;
+ avbuf->drm_frame.objects[i].fd = expbuf.fd;
+- avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR;
++ avbuf->drm_frame.objects[i].format_modifier = drm_format_modifier(drm_format);
+ } else {
+ /* drm frame */
+ avbuf->drm_frame.objects[0].size = avbuf->buffer.length;
+ avbuf->drm_frame.objects[0].fd = expbuf.fd;
+- avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
++ avbuf->drm_frame.objects[0].format_modifier = drm_format_modifier(drm_format);
+ }
+ }
+
+@@ -405,7 +482,7 @@ static int deint_v4l2m2m_allocate_buffers(V4L2Queue *queue)
+ if (ret)
+ goto fail;
+
+- ret = v4l2_buffer_export_drm(buf);
++ ret = v4l2_buffer_export_drm(buf, ctx->drm_out_format);
+ if (ret)
+ goto fail;
+ }
+@@ -597,7 +674,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
+ deint_v4l2m2m_destroy_context(ctx);
+ }
+
+-static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
++static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height, uint64_t drm_format)
+ {
+ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
+ AVDRMLayerDescriptor *layer;
+@@ -615,7 +692,7 @@ static uint8_t *v4l2_get_drm_frame(V4L2Buffer *avbuf, int height)
+ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline;
+ }
+
+- layer->format = DRM_FORMAT_NV12;
++ layer->format = drm_format;
+
+ if (avbuf->num_planes == 1) {
+ layer->nb_planes = 2;
+@@ -647,7 +724,7 @@ static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int tim
+
+ atomic_fetch_add(&ctx->refcount, 1);
+
+- frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height);
++ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height, ctx->drm_out_format);
+ frame->format = AV_PIX_FMT_DRM_PRIME;
+ frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
+ frame->height = ctx->height;
+@@ -797,17 +874,22 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
+ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
+ ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
+ ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
++ ctx->drm_in_format = drm_desc->layers->format;
++ ctx->drm_out_format = drm_desc->layers->format;
++
+
+ if (in->top_field_first)
+ ctx->field_order = V4L2_FIELD_INTERLACED_TB;
+ else
+ ctx->field_order = V4L2_FIELD_INTERLACED_BT;
+
+- ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height);
++ ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height,
++ ctx->drm_in_format);
+ if (ret)
+ return ret;
+
+- ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height);
++ ret = deint_v4l2m2m_set_format(capture, V4L2_FIELD_NONE, ctx->orig_width, ctx->orig_height,
++ ctx->drm_out_format);
+ if (ret)
+ return ret;
+
+@@ -864,6 +946,8 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
+ ctx->prev_in_frame = NULL;
++ ctx->drm_in_format = drm_v4l2_pix_fmt_map[0].drm_format;
++ ctx->drm_out_format = drm_v4l2_pix_fmt_map[0].drm_format;
+ atomic_init(&ctx->refcount, 1);
+
+ return 0;
diff --git a/projects/Rockchip/patches/linux/default/linux-0001-rockchip-from-5.15.patch b/projects/Rockchip/patches/linux/default/linux-0001-rockchip-from-5.15.patch
index 014c34b156..ac5bbdd8bd 100644
--- a/projects/Rockchip/patches/linux/default/linux-0001-rockchip-from-5.15.patch
+++ b/projects/Rockchip/patches/linux/default/linux-0001-rockchip-from-5.15.patch
@@ -3368,3 +3368,56 @@ index 000000000000..7c4d47fe80c2
+MODULE_AUTHOR("Shawn Lin ");
+MODULE_AUTHOR("Chris Morgan ");
+MODULE_AUTHOR("Jon Lin ");
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Punit Agrawal
+Date: Wed, 29 Sep 2021 22:50:49 +0900
+Subject: [PATCH] net: stmmac: dwmac-rk: Fix ethernet on rk3399 based devices
+
+Commit 2d26f6e39afb ("net: stmmac: dwmac-rk: fix unbalanced pm_runtime_enable warnings")
+while getting rid of a runtime PM warning ended up breaking ethernet
+on rk3399 based devices. By dropping an extra reference to the device,
+the commit ends up enabling suspend / resume of the ethernet device -
+which appears to be broken.
+
+While the issue with runtime pm is being investigated, partially
+revert commit 2d26f6e39afb to restore the network on rk3399.
+
+Fixes: 2d26f6e39afb ("net: stmmac: dwmac-rk: fix unbalanced pm_runtime_enable warnings")
+Suggested-by: Heiko Stuebner
+Signed-off-by: Punit Agrawal
+Cc: Michael Riesch
+Tested-by: Heiko Stuebner
+---
+ drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+index ed817011a94a..6924a6aacbd5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -21,6 +21,7 @@
+ #include
+ #include
+ #include
++#include
+
+ #include "stmmac_platform.h"
+
+@@ -1528,6 +1529,8 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
+ return ret;
+ }
+
++ pm_runtime_get_sync(dev);
++
+ if (bsp_priv->integrated_phy)
+ rk_gmac_integrated_phy_powerup(bsp_priv);
+
+@@ -1539,6 +1542,8 @@ static void rk_gmac_powerdown(struct rk_priv_data *gmac)
+ if (gmac->integrated_phy)
+ rk_gmac_integrated_phy_powerdown(gmac);
+
++ pm_runtime_put_sync(&gmac->pdev->dev);
++
+ phy_power_on(gmac, false);
+ gmac_clk_enable(gmac, false);
+ }
diff --git a/projects/Rockchip/patches/linux/default/linux-1002-for-libreelec.patch b/projects/Rockchip/patches/linux/default/linux-1002-for-libreelec.patch
index 1a39f05dc1..1e9c2e0b51 100644
--- a/projects/Rockchip/patches/linux/default/linux-1002-for-libreelec.patch
+++ b/projects/Rockchip/patches/linux/default/linux-1002-for-libreelec.patch
@@ -6,12 +6,13 @@ Subject: [PATCH] arm64: dts: rockchip: add gpu powerdomain, gpu opp-table and
Note: since the regulator that supplies the GPU usually also supplies
other SoC components, we have to make sure voltage is never lower then
-1075 mV.
+1050 mV - also disable 500 MHz for now, since it will crash if rkvdec
+is running at the same time (voltage to high)
Signed-off-by: Alex Bee
---
arch/arm64/boot/dts/rockchip/rk3328.dtsi | 34 ++++++++++++++++++++++++
- 1 file changed, 34 insertions(+)
+ 1 file changed, 35 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 23021373e15b..ca03c8ed9708 100644
@@ -41,7 +42,7 @@ index 23021373e15b..ca03c8ed9708 100644
};
};
-@@ -620,7 +630,31 @@ gpu: gpu@ff300000 {
+@@ -620,7 +630,32 @@ gpu: gpu@ff300000 {
"ppmmu1";
clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
clock-names = "bus", "core";
@@ -56,19 +57,20 @@ index 23021373e15b..ca03c8ed9708 100644
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
-+ opp-microvolt = <1075000>;
++ opp-microvolt = <1050000>;
+ };
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
-+ opp-microvolt = <1075000>;
++ opp-microvolt = <1050000>;
+ };
+ opp-400000000 {
+ opp-hz = /bits/ 64 <400000000>;
-+ opp-microvolt = <1075000>;
++ opp-microvolt = <1050000>;
+ };
+ opp-500000000 {
+ opp-hz = /bits/ 64 <500000000>;
+ opp-microvolt = <1150000>;
++ status = "disabled";
+ };
};
@@ -644,72 +646,4 @@ index 3d98e2251ea5..b201700ccc8a 100644
.irqs = rockchip_vdpu2_irqs,
.num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs),
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Alex Bee
-Date: wed, 1 Sep 2021 14:00:00 +1000
-Subject: [PATCH] net: stmmac: dwmac-rk: fix unbalanced pm_runtime_enable warnings
-This LE11 REVERTS 5.14.0 commit
-- reverts 2d26f6e39afb88d32b8f39e76a51b542c3c51674
-
-BETWEEN THE LINE
-
-This reverts commit 2c896fb02e7f65299646f295a007bda043e0f382
-"net: stmmac: dwmac-rk: add pd_gmac support for rk3399" and fixes
-unbalanced pm_runtime_enable warnings.
-
-In the commit to be reverted, support for power management was
-introduced to the Rockchip glue code. Later, power management support
-was introduced to the stmmac core code, resulting in multiple
-invocations of pm_runtime_{enable,disable,get_sync,put_sync}.
-
-The multiple invocations happen in rk_gmac_powerup and
-stmmac_{dvr_probe, resume} as well as in rk_gmac_powerdown and
-stmmac_{dvr_remove, suspend}, respectively, which are always called
-in conjunction.
-
-Fixes: 5ec55823438e850c91c6b92aec93fb04ebde29e2 ("net: stmmac: add clocks management for gmac driver")
-Signed-off-by: Michael Riesch
-Signed-off-by: David S. Miller
----
- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 9 ---------
- 1 file changed, 9 deletions(-)
-
-ABOVE THE LINE
-
-diff -Nu a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
-@@ -21,6 +21,7 @@
- #include
- #include
- #include
-+#include
-
- #include "stmmac_platform.h"
-
-@@ -1528,6 +1529,9 @@
- return ret;
- }
-
-+ pm_runtime_enable(dev);
-+ pm_runtime_get_sync(dev);
-+
- if (bsp_priv->integrated_phy)
- rk_gmac_integrated_phy_powerup(bsp_priv);
-
-@@ -1536,9 +1540,14 @@
-
- static void rk_gmac_powerdown(struct rk_priv_data *gmac)
- {
-+ struct device *dev = &gmac->pdev->dev;
-+
- if (gmac->integrated_phy)
- rk_gmac_integrated_phy_powerdown(gmac);
-
-+ pm_runtime_put_sync(dev);
-+ pm_runtime_disable(dev);
-+
- phy_power_on(gmac, false);
- gmac_clk_enable(gmac, false);
- }
diff --git a/projects/Rockchip/patches/linux/default/linux-2001-v4l-wip-rkvdec-hevc.patch b/projects/Rockchip/patches/linux/default/linux-2001-v4l-wip-rkvdec-hevc.patch
index bd7b255037..6c72bcb544 100644
--- a/projects/Rockchip/patches/linux/default/linux-2001-v4l-wip-rkvdec-hevc.patch
+++ b/projects/Rockchip/patches/linux/default/linux-2001-v4l-wip-rkvdec-hevc.patch
@@ -2918,7 +2918,7 @@ index 2c0c6dcbd066..c269e4a21a29 100644
+ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
+ // HACK: match ffmpeg v4l2 request api hwaccel size,
+ // we should support variable length up to 600 slices
-+ .cfg.dims = { 16 },
++ .cfg.dims = { 32 },
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
@@ -3294,11 +3294,11 @@ Subject: [PATCH] WIP: media: rkvdec: hevc: implement lowdelay
Signed-off-by: Alex Bee
---
- drivers/staging/media/rkvdec/rkvdec-hevc.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
+ drivers/staging/media/rkvdec/rkvdec-hevc.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-hevc.c b/drivers/staging/media/rkvdec/rkvdec-hevc.c
-index 55bf61a84165..3cca79282111 100644
+index 55bf61a84165..db33f9d357cf 100644
--- a/drivers/staging/media/rkvdec/rkvdec-hevc.c
+++ b/drivers/staging/media/rkvdec/rkvdec-hevc.c
@@ -2187,6 +2187,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
@@ -3313,27 +3313,32 @@ index 55bf61a84165..3cca79282111 100644
for (j = 0; j < run->num_slices; j++) {
sl_params = &run->slices_params[j];
dpb = decode_params->dpb;
-+ lowdelay = 0;
++ lowdelay = (sl_params->slice_type == V4L2_HEVC_SLICE_TYPE_I) ? 0 : 1;
hw_ps = &priv_tbl->rps[j];
memset(hw_ps, 0, sizeof(*hw_ps));
-@@ -2221,8 +2223,18 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
+@@ -2211,18 +2213,23 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
+ WRITE_RPS(!!(dpb[sl_params->ref_idx_l0[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR),
+ REF_PIC_LONG_TERM_L0(i));
+ WRITE_RPS(sl_params->ref_idx_l0[i], REF_PIC_IDX_L0(i));
++
++ if (dpb[sl_params->ref_idx_l0[i]].pic_order_cnt[0] > sl_params->slice_pic_order_cnt)
++ lowdelay = 0;
+ }
+
+ for (i = 0; i <= sl_params->num_ref_idx_l1_active_minus1; i++) {
+ WRITE_RPS(!!(dpb[sl_params->ref_idx_l1[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR),
+ REF_PIC_LONG_TERM_L1(i));
+ WRITE_RPS(sl_params->ref_idx_l1[i], REF_PIC_IDX_L1(i));
++
++ if (dpb[sl_params->ref_idx_l1[i]].pic_order_cnt[0] > sl_params->slice_pic_order_cnt)
++ lowdelay = 0;
+ }
//WRITE_RPS(0xffffffff, PS_FIELD(96, 32));
- // TODO: lowdelay
- WRITE_RPS(0, LOWDELAY);
-+ if (sl_params->slice_type != V4L2_HEVC_SLICE_TYPE_I &&
-+ !(!!(sl_params->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT))) {
-+ lowdelay = 1;
-+ for (i = 0; i < decode_params->num_active_dpb_entries; i++) {
-+ if (dpb[i].pic_order_cnt[0] > sl_params->slice_pic_order_cnt) {
-+ lowdelay = 0;
-+ break;
-+ }
-+ }
-+ }
-+
+ WRITE_RPS(lowdelay, LOWDELAY);
WRITE_RPS(sl_params->long_term_ref_pic_set_size +
diff --git a/scripts/uboot_helper b/scripts/uboot_helper
index 98a9b7e351..741ad6bb9b 100755
--- a/scripts/uboot_helper
+++ b/scripts/uboot_helper
@@ -292,6 +292,10 @@ devices = \
'dtb': 'rk3399-rock-pi-4b.dtb',
'config': 'evb-rk3399_defconfig'
},
+ 'rock-pi-4-plus': {
+ 'dtb': 'rk3399-rock-pi-4b-plus.dtb',
+ 'config': 'evb-rk3399_defconfig'
+ },
'rock-pi-n10': {
'dtb': 'rk3399pro-rock-pi-n10.dtb',
'config': 'evb-rk3399_defconfig'
@@ -304,6 +308,10 @@ devices = \
'dtb': 'rk3399-roc-pc-mezzanine.dtb',
'config': 'firefly-rk3399_defconfig'
},
+ 'roc-pc-plus': {
+ 'dtb': 'rk3399-roc-pc-plus.dtb',
+ 'config': 'firefly-rk3399_defconfig'
+ },
'sapphire': {
'dtb': 'rk3399-sapphire.dtb',
'config': 'evb-rk3399_defconfig'