From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 23 May 2020 10:18:16 +0000
Subject: [PATCH] WIP: media: rkvdec: continue to gate clock when decoding
 finish

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
 drivers/staging/media/rkvdec/rkvdec.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index d068383aeea8..5c03fdbd45ec 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -986,7 +986,8 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 	state = (status & RKVDEC_RDY_STA) ?
 		VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
 
-	writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT);
+	writel(RKVDEC_CONFIG_DEC_CLK_GATE_E,
+	       rkvdec->regs + RKVDEC_REG_INTERRUPT);
 	if (cancel_delayed_work(&rkvdec->watchdog_work)) {
 		struct rkvdec_ctx *ctx;
 
@@ -1007,7 +1008,8 @@ 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");
-		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
+		writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS,
+		       rkvdec->regs + RKVDEC_REG_INTERRUPT);
 		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
 		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
 	}

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 5c03fdbd45ec..ad5e02bbd8d0 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -1105,9 +1105,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: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 23 May 2020 11:23:04 +0000
Subject: [PATCH] WIP: media: rkvdec: h264: return early when no reference
 pictures

NOTE: also change from a switch statement to access reflists from a pointer array,
should simplify once we add support for field reference list

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
 drivers/staging/media/rkvdec/rkvdec-h264.c | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index c9a551dbd9bc..6ce11b736363 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -734,6 +734,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 	const struct v4l2_ctrl_h264_sps *sps = run->sps;
 	struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
 	u32 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
+	u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 };
 
 	u32 *hw_rps = priv_tbl->rps;
 	u32 i, j;
@@ -741,6 +742,9 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 
 	memset(hw_rps, 0, sizeof(priv_tbl->rps));
 
+	if (!h264_ctx->reflists.num_valid)
+		return;
+
 	/*
 	 * Assign an invalid pic_num if DPB entry at that position is inactive.
 	 * If we assign 0 in that position hardware will treat that as a real

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 23 May 2020 14:42:27 +0000
Subject: [PATCH] WIP: media: rkvdec: h264: add field decoding support

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
 drivers/staging/media/rkvdec/rkvdec-h264.c | 79 ++++++++++++++++++----
 1 file changed, 64 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 6ce11b736363..9c3f08c94800 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -737,7 +737,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
 	u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 };
 
 	u32 *hw_rps = priv_tbl->rps;
-	u32 i, j;
+	u32 i, j, k;
 	u16 *p = (u16 *)hw_rps;
 
 	memset(hw_rps, 0, sizeof(priv_tbl->rps));
@@ -968,10 +1021,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 				       rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15);
 	}
 
-	/*
-	 * Since support frame mode only
-	 * top_field_order_cnt is the same as bottom_field_order_cnt
-	 */
 	reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt);
 	writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0);
 

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Tue, 29 Oct 2019 01:26:02 +0000
Subject: [PATCH] RFC: media: hantro: Fix H264 decoding of field encoded
 content

This still need code cleanup and formatting

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
 drivers/staging/media/hantro/hantro_h264.c | 91 ++++++++++++++++------
 1 file changed, 69 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 0b4d2491be3b..7b56a68c176c 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -227,30 +227,67 @@ static void prepare_table(struct hantro_ctx *ctx)
 {
 	const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
 	const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode;
+	const struct v4l2_ctrl_h264_sps *sps = ctrls->sps;
 	struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu;
 	const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
 	u32 dpb_longterm = 0;
 	u32 dpb_valid = 0;
 	int i;
 
-	for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) {
-		tbl->poc[i * 2] = dpb[i].top_field_order_cnt;
-		tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt;
+	/*
+	 * Set up bit maps of valid and long term DPBs.
+	 * NOTE: The bits are reversed, i.e. MSb is DPB 0.
+	 */
+	if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) {
+		for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) {
+			// check for correct reference use
+			enum v4l2_h264_field_reference parity = (i & 0x1) ?
+				V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF;
+			if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE &&
+			    dpb[i / 2].reference & parity)
+				dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i);
+
+			if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+				dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i);
+		}
 
-		/*
-		 * Set up bit maps of valid and long term DPBs.
-		 * NOTE: The bits are reversed, i.e. MSb is DPB 0.
-		 */
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
-			dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
-		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
-			dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
+		ctx->h264_dec.dpb_valid = dpb_valid;
+		ctx->h264_dec.dpb_longterm = dpb_longterm;
+	} else {
+		for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) {
+			if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
+				dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
+
+			if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+				dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i);
+		}
+
+		ctx->h264_dec.dpb_valid = dpb_valid << 16;
+		ctx->h264_dec.dpb_longterm = dpb_longterm << 16;
 	}
-	ctx->h264_dec.dpb_valid = dpb_valid << 16;
-	ctx->h264_dec.dpb_longterm = dpb_longterm << 16;
 
-	tbl->poc[32] = dec_param->top_field_order_cnt;
-	tbl->poc[33] = dec_param->bottom_field_order_cnt;
+	for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) {
+		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
+			tbl->poc[i * 2] = dpb[i].top_field_order_cnt;
+			tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt;
+		} else {
+			tbl->poc[i * 2] = 0;
+			tbl->poc[i * 2 + 1] = 0;
+		}
+	}
+
+	if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || !(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) {
+		if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
+			tbl->poc[32] = (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ?
+					dec_param->bottom_field_order_cnt :
+					dec_param->top_field_order_cnt;
+		else
+			tbl->poc[32] = min(dec_param->top_field_order_cnt, dec_param->bottom_field_order_cnt);
+		tbl->poc[33] = 0;
+	} else {
+		tbl->poc[32] = dec_param->top_field_order_cnt;
+		tbl->poc[33] = dec_param->bottom_field_order_cnt;
+	};
 
 	assemble_scaling_list(ctx);
 }
@@ -258,8 +295,7 @@ static void prepare_table(struct hantro_ctx *ctx)
 static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a,
 			    const struct v4l2_h264_dpb_entry *b)
 {
-	return a->top_field_order_cnt == b->top_field_order_cnt &&
-	       a->bottom_field_order_cnt == b->bottom_field_order_cnt;
+	return a->reference_ts == b->reference_ts;
 }
 
 static void update_dpb(struct hantro_ctx *ctx)
@@ -273,13 +309,13 @@ static void update_dpb(struct hantro_ctx *ctx)
 
 	/* Disable all entries by default. */
 	for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++)
-		ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
+		ctx->h264_dec.dpb[i].flags = 0;
 
 	/* Try to match new DPB entries with existing ones by their POCs. */
 	for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
 		const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
 
-		if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+		if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
 			continue;
 
 		/*
@@ -290,8 +326,7 @@ static void update_dpb(struct hantro_ctx *ctx)
 			struct v4l2_h264_dpb_entry *cdpb;
 
 			cdpb = &ctx->h264_dec.dpb[j];
-			if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE ||
-			    !dpb_entry_match(cdpb, ndpb))
+			if (!dpb_entry_match(cdpb, ndpb))
 				continue;
 
 			*cdpb = *ndpb;
@@ -327,7 +362,10 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
 				   unsigned int dpb_idx)
 {
 	struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
+	const struct v4l2_ctrl_h264_decode_params *dec_param = ctx->h264_dec.ctrls.decode;
 	dma_addr_t dma_addr = 0;
+	s32 cur_poc;
+	u32 flags;
 
 	if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
 		dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts);
@@ -345,7 +383,16 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
 		dma_addr = hantro_get_dec_buf_addr(ctx, buf);
 	}
 
-	return dma_addr;
+	cur_poc = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD ?
+		  dec_param->bottom_field_order_cnt :
+		  dec_param->top_field_order_cnt;
+	flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD ? 0x2 : 0;
+	flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) <
+		 abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ?
+		 0x1 : 0;
+
+	return dma_addr | flags;
+
 }
 
 u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx)

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 14 Oct 2020 13:27:12 +0200
Subject: [PATCH] media: hantro: adapt to match 5.11 H.264 uapi changes

Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
 drivers/staging/media/hantro/hantro_h264.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 7b56a68c176c..befa69d5c855 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -241,10 +241,10 @@ static void prepare_table(struct hantro_ctx *ctx)
 	if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) {
 		for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) {
 			// check for correct reference use
-			enum v4l2_h264_field_reference parity = (i & 0x1) ?
+			u8 parity = (i & 0x1) ?
 				V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF;
 			if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE &&
-			    dpb[i / 2].reference & parity)
+			    dpb[i / 2].fields & parity)
 				dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i);
 
 			if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)

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 | 18 ++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 include/linux/rockchip_pmu.h
 create mode 100644 include/soc/rockchip/pm_domains.h

diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 0868b7d406fb..fddb4022c376 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -204,6 +204,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
new file mode 100644
index 000000000000..690db6118636
--- /dev/null
+++ b/include/soc/rockchip/pm_domains.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SOC_ROCKCHIP_PM_DOMAINS_H
+#define __SOC_ROCKCHIP_PM_DOMAINS_H
+
+#include <linux/errno.h>
+
+struct device;
+
+#ifdef CONFIG_ROCKCHIP_PM_DOMAINS
+int rockchip_pmu_idle_request(struct device *dev, bool idle);
+#else
+static inline int rockchip_pmu_idle_request(struct device *dev, bool idle)
+{
+	return -ENOTSUPP;
+}
+#endif
+
+#endif

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 089f11d21b25..3f4772c8d095 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -51,6 +51,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
@@ -58,6 +70,8 @@ required:
   - clocks
   - clock-names
   - power-domains
+  - resets
+  - reset-names
 
 additionalProperties: false
 
@@ -76,6 +90,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 ad5e02bbd8d0..6abce36eee7f 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>
@@ -687,6 +690,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);
 }
 
@@ -724,6 +732,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) {
@@ -991,6 +1026,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);
 	}
@@ -1008,6 +1048,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_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS,
 		       rkvdec->regs + RKVDEC_REG_INTERRUPT);
 		writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL);
@@ -1085,6 +1126,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 7b6f44ee8a1a..fa24bcb6ff42 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 {
@@ -90,6 +97,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 {

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Tue, 18 Aug 2020 11:38:04 +0200
Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3399

---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 52a748053a97..2c7b263a82cd 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -993,7 +993,10 @@ power-domain@RK3399_PD_VCODEC {
 			power-domain@RK3399_PD_VDU {
 				reg = <RK3399_PD_VDU>;
 				clocks = <&cru ACLK_VDU>,
-					 <&cru HCLK_VDU>;
+					 <&cru HCLK_VDU>,
+					 <&cru SCLK_VDU_CA>,
+					 <&cru SCLK_VDU_CORE>;
+
 				pm_qos = <&qos_video_m1_r>,
 					 <&qos_video_m1_w>;
 				#power-domain-cells = <0>;
@@ -1266,6 +1269,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: Fri, 1 Jan 2021 12:11:12 +0200
Subject: [PATCH] arm64: dts: rockchip: fix RK3399 vdec register witdh

Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 2c7b263a82cd..ec3561d147d5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1262,7 +1262,7 @@ vpu_mmu: iommu@ff650800 {
 
 	vdec: video-codec@ff660000 {
 		compatible = "rockchip,rk3399-vdec";
-		reg = <0x0 0xff660000 0x0 0x400>;
+		reg = <0x0 0xff660000 0x0 0x480>;
 		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH 0>;
 		clocks = <&cru ACLK_VDU>, <&cru HCLK_VDU>,
 			 <&cru SCLK_VDU_CA>, <&cru SCLK_VDU_CORE>;

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 19 Aug 2020 21:12:54 +0200
Subject: [PATCH] arm64: dts: rockchip: add rkvdec node for RK3328

Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
 .../bindings/media/rockchip,vdec.yaml         |  3 +++
 arch/arm64/boot/dts/rockchip/rk3328.dtsi      | 25 ++++++++++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
index 3f4772c8d095..21a78372dae6 100644
--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml
@@ -20,6 +20,9 @@ properties:
       - items:
           - const: rockchip,rk3228-vdec
           - const: rockchip,rk3399-vdec
+      - items:
+          - const: rockchip,rk3328-vdec
+          - const: rockchip,rk3399-vdec
 
   reg:
     maxItems: 1
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 9c10b6e3b9bc..23021373e15b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -306,6 +306,10 @@ power-domain@RK3328_PD_HEVC {
 			};
 			power-domain@RK3328_PD_VIDEO {
 				reg = <RK3328_PD_VIDEO>;
+				clocks = <&cru ACLK_RKVDEC>,
+					 <&cru HCLK_RKVDEC>,
+					 <&cru SCLK_VDEC_CABAC>,
+					 <&cru SCLK_VDEC_CORE>;
 				#power-domain-cells = <0>;
 			};
 			power-domain@RK3328_PD_VPU {
@@ -660,6 +664,25 @@ vpu_mmu: iommu@ff350800 {
 		power-domains = <&power RK3328_PD_VPU>;
 	};
 
+	rkvdec: video-codec@ff360000 {
+		compatible = "rockchip,rk3328-vdec", "rockchip,rk3399-vdec";
+		reg = <0x0 0xff360000 0x0 0x480>;
+		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+		assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>,
+				  <&cru SCLK_VDEC_CORE>;
+		assigned-clock-rates = <400000000>, <400000000>, <300000000>;
+		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>,
+			 <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>;
+		clock-names = "axi", "ahb", "cabac", "core";
+		iommus = <&rkvdec_mmu>;
+		power-domains = <&power RK3328_PD_VIDEO>;
+		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";
+	};
+
 	rkvdec_mmu: iommu@ff360480 {
 		compatible = "rockchip,iommu";
 		reg = <0x0 0xff360480 0x0 0x40>, <0x0 0xff3604c0 0x0 0x40>;
@@ -667,7 +690,7 @@ rkvdec_mmu: iommu@ff360480 {
 		clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>;
 		clock-names = "aclk", "iface";
 		#iommu-cells = <0>;
-		status = "disabled";
+		power-domains = <&power RK3328_PD_VIDEO>;
 	};
 
 	vop: vop@ff370000 {

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Sun, 3 May 2020 18:34:56 +0200
Subject: [PATCH] WIP: media/rkvdec: don't overclock IP

Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
 drivers/staging/media/rkvdec/rkvdec.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 6abce36eee7f..fbaf0303f7c2 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -1096,10 +1096,12 @@ static int rkvdec_probe(struct platform_device *pdev)
 		return ret;
 
 	/*
-	 * Bump ACLK to max. possible freq. (500 MHz) to improve performance
-	 * When 4k video playback.
+	 * Don't bump ACLK to max. possible freq. (500 MHz) to improve performance,
+	 * since it will lead to non-recoverable decoder lockups in case of decoding
+	 * errors, instead put it to 400 MHz, which seems to have no drawbacks
+	 * in decoding performance and doesn't result in those hangs.
 	 */
-	clk_set_rate(rkvdec->clocks[0].clk, 500 * 1000 * 1000);
+	clk_set_rate(rkvdec->clocks[0].clk, 400 * 1000 * 1000);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	rkvdec->regs = devm_ioremap_resource(&pdev->dev, res);

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/staging/media/hantro/rockchip_vpu_hw.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c
index d4f52957cc53..3d98e2251ea5 100644
--- a/drivers/staging/media/hantro/rockchip_vpu_hw.c
+++ b/drivers/staging/media/hantro/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.
@@ -272,13 +273,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;
@@ -511,7 +519,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)
 };
