From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198

---
 kernel/drivers/video/rockchip/mpp/mpp_rkvenc2.c |  191 +++++++++++++++++++++++++++++++++--------------
 1 files changed, 135 insertions(+), 56 deletions(-)

diff --git a/kernel/drivers/video/rockchip/mpp/mpp_rkvenc2.c b/kernel/drivers/video/rockchip/mpp/mpp_rkvenc2.c
index 5bd7054..111c106 100644
--- a/kernel/drivers/video/rockchip/mpp/mpp_rkvenc2.c
+++ b/kernel/drivers/video/rockchip/mpp/mpp_rkvenc2.c
@@ -32,6 +32,7 @@
 #include <soc/rockchip/rockchip_ipa.h>
 #include <soc/rockchip/rockchip_opp_select.h>
 #include <soc/rockchip/rockchip_system_monitor.h>
+#include <soc/rockchip/rockchip_iommu.h>
 
 #include "mpp_debug.h"
 #include "mpp_iommu.h"
@@ -44,6 +45,8 @@
 #define RKVENC_MAX_DCHS_ID			4
 #define RKVENC_MAX_SLICE_FIFO_LEN		256
 #define RKVENC_SCLR_DONE_STA			BIT(2)
+#define RKVENC_WDG				0x38
+#define TIMEOUT_MS				100
 
 #define to_rkvenc_info(info)		\
 		container_of(info, struct rkvenc_hw_info, hw)
@@ -127,6 +130,11 @@
 #define INT_STA_WBUS_ERR_STA	BIT(6)
 #define INT_STA_RBUS_ERR_STA	BIT(7)
 #define INT_STA_WDG_STA		BIT(8)
+
+#define INT_STA_ERROR		(INT_STA_BRSP_OTSD_STA | \
+				INT_STA_WBUS_ERR_STA | \
+				INT_STA_RBUS_ERR_STA | \
+				INT_STA_WDG_STA)
 
 #define DCHS_REG_OFFSET		(0x304)
 #define DCHS_CLASS_OFFSET	(33)
@@ -294,6 +302,7 @@
 #ifdef CONFIG_PM_DEVFREQ
 	struct rockchip_opp_info opp_info;
 	struct monitor_dev_info *mdev_info;
+	struct opp_table *opp_table;
 #endif
 };
 
@@ -1194,6 +1203,7 @@
 	struct rkvenc_task *task = to_rkvenc_task(mpp_task);
 	struct rkvenc_hw_info *hw = enc->hw_info;
 	u32 timing_en = mpp->srv->timing_en;
+	u32 timeout_thd;
 
 	mpp_debug_enter();
 
@@ -1242,11 +1252,18 @@
 	/* init current task */
 	mpp->cur_task = mpp_task;
 
+	/*
+	 * reconfig timeout threshold.
+	 * bit0-bit23,x1024 core clk cycles
+	 */
+	timeout_thd = mpp_read(mpp, RKVENC_WDG) & 0xff000000;
+	timeout_thd |= TIMEOUT_MS * clk_get_rate(enc->core_clk_info.clk) / 1024000;
+	mpp_write(mpp, RKVENC_WDG, timeout_thd);
+
 	mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY);
 
 	/* Flush the register before the start the device */
 	wmb();
-
 	mpp_write(mpp, enc->hw_info->enc_start_base, start_val);
 
 	mpp_task_run_end(mpp_task, timing_en);
@@ -1256,9 +1273,9 @@
 	return 0;
 }
 
-static void rkvenc2_read_slice_len(struct mpp_dev *mpp, struct rkvenc_task *task)
+static void rkvenc2_read_slice_len(struct mpp_dev *mpp, struct rkvenc_task *task,
+				   u32 last)
 {
-	u32 last = mpp_read_relaxed(mpp, 0x002c) & INT_STA_ENC_DONE_STA;
 	u32 sli_num = mpp_read_relaxed(mpp, RKVENC2_REG_SLICE_NUM_BASE);
 	union rkvenc2_slice_len_info slice_info;
 	u32 task_id = task->mpp_task.task_id;
@@ -1298,46 +1315,49 @@
 	struct rkvenc_hw_info *hw = enc->hw_info;
 	struct mpp_task *mpp_task = NULL;
 	struct rkvenc_task *task = NULL;
-	u32 int_clear = 1;
-	u32 irq_mask = 0;
+	u32 irq_status;
 	int ret = IRQ_NONE;
 
 	mpp_debug_enter();
 
-	mpp->irq_status = mpp_read(mpp, hw->int_sta_base);
-	if (!mpp->irq_status)
+	irq_status = mpp_read(mpp, hw->int_sta_base);
+
+	mpp_debug(DEBUG_IRQ_STATUS, "%s irq_status: %08x\n",
+		  dev_name(mpp->dev), irq_status);
+
+	if (!irq_status)
 		return ret;
+
+	/* clear int first */
+	mpp_write(mpp, hw->int_clr_base, irq_status);
+
+	/*
+	 * prevent watch dog irq storm.
+	 * The encoder did not stop working when watchdog interrupt is triggered,
+	 * it still check timeout and trigger watch dog irq.
+	 */
+	if (irq_status & INT_STA_WDG_STA)
+		mpp_write(mpp, hw->int_mask_base, INT_STA_WDG_STA);
 
 	if (mpp->cur_task) {
 		mpp_task = mpp->cur_task;
 		task = to_rkvenc_task(mpp_task);
 	}
 
-	if (mpp->irq_status & INT_STA_ENC_DONE_STA) {
-		if (task) {
-			if (task->task_split)
-				rkvenc2_read_slice_len(mpp, task);
+	/* 1. read slice number and slice length */
+	if (task && task->task_split &&
+	    (irq_status & (INT_STA_SLC_DONE_STA | INT_STA_ENC_DONE_STA))) {
+		mpp_time_part_diff(mpp_task);
+		rkvenc2_read_slice_len(mpp, task, irq_status & INT_STA_ENC_DONE_STA);
+		wake_up(&mpp_task->wait);
+	}
 
-			wake_up(&mpp_task->wait);
-		}
+	/* 2. process slice irq */
+	if (irq_status & INT_STA_SLC_DONE_STA)
+		ret = IRQ_HANDLED;
 
-		irq_mask = INT_STA_ENC_DONE_STA;
-		ret = IRQ_WAKE_THREAD;
-		if (enc->bs_overflow) {
-			mpp->irq_status |= INT_STA_BSF_OFLW_STA;
-			enc->bs_overflow = 0;
-		}
-	} else if (mpp->irq_status & INT_STA_SLC_DONE_STA) {
-		if (task && task->task_split) {
-			mpp_time_part_diff(mpp_task);
-
-			rkvenc2_read_slice_len(mpp, task);
-			wake_up(&mpp_task->wait);
-		}
-
-		irq_mask = INT_STA_ENC_DONE_STA;
-		int_clear = 0;
-	} else if (mpp->irq_status & INT_STA_BSF_OFLW_STA) {
+	/* 3. process bitstream overflow */
+	if (irq_status & INT_STA_BSF_OFLW_STA) {
 		u32 bs_rd = mpp_read(mpp, RKVENC2_REG_ADR_BSBR);
 		u32 bs_wr = mpp_read(mpp, RKVENC2_REG_ST_BSB);
 		u32 bs_top = mpp_read(mpp, RKVENC2_REG_ADR_BSBT);
@@ -1349,33 +1369,43 @@
 		bs_wr += 128;
 		if (bs_wr >= bs_top)
 			bs_wr = bs_bot;
-		/* clear int first */
-		mpp_write(mpp, hw->int_clr_base, mpp->irq_status);
+
 		/* update write addr for enc continue */
 		mpp_write(mpp, RKVENC2_REG_ADR_BSBS, bs_wr);
 		enc->bs_overflow = 1;
-		irq_mask = 0;
-		int_clear = 0;
-		ret = IRQ_HANDLED;
-	} else {
-		dev_err(mpp->dev, "found error status %08x\n", mpp->irq_status);
 
-		irq_mask = mpp->irq_status;
+		ret = IRQ_HANDLED;
+	}
+
+	/* 4. process frame irq */
+	if (irq_status & INT_STA_ENC_DONE_STA) {
+		mpp->irq_status = irq_status;
+
+		if (enc->bs_overflow) {
+			mpp->irq_status |= INT_STA_BSF_OFLW_STA;
+			enc->bs_overflow = 0;
+		}
+
 		ret = IRQ_WAKE_THREAD;
 	}
 
-	if (irq_mask)
-		mpp_write(mpp, hw->int_mask_base, irq_mask);
+	/* 5. process error irq */
+	if (irq_status & INT_STA_ERROR) {
+		mpp->irq_status = irq_status;
 
-	if (int_clear) {
-		mpp_write(mpp, hw->int_clr_base, mpp->irq_status);
-		udelay(5);
-		mpp_write(mpp, hw->int_sta_base, 0);
+		dev_err(mpp->dev, "found error status %08x\n", irq_status);
+
+		ret = IRQ_WAKE_THREAD;
 	}
 
 	mpp_debug_leave();
 
 	return ret;
+}
+
+static int vepu540c_irq(struct mpp_dev *mpp)
+{
+	return rkvenc_irq(mpp);
 }
 
 static int rkvenc_isr(struct mpp_dev *mpp)
@@ -1405,9 +1435,6 @@
 	task->irq_status = mpp->irq_status;
 
 	rkvenc2_update_dchs(enc, task);
-
-	mpp_debug(DEBUG_IRQ_STATUS, "%s irq_status: %08x\n",
-		  dev_name(mpp->dev), task->irq_status);
 
 	if (task->irq_status & enc->hw_info->err_mask) {
 		atomic_inc(&mpp->reset_request);
@@ -1458,7 +1485,7 @@
 	if (task->bs_buf) {
 		u32 bs_size = mpp_read(mpp, 0x4064);
 
-		mpp_dma_buf_sync(task->bs_buf, 0, bs_size / 8 + task->offset_bs,
+		mpp_dma_buf_sync(task->bs_buf, 0, bs_size + task->offset_bs,
 				 DMA_FROM_DEVICE, true);
 	}
 
@@ -1785,16 +1812,19 @@
 		if (IS_ERR(reg_table))
 			return PTR_ERR(reg_table);
 	}
+	enc->opp_table = reg_table;
 
 	clk_table = dev_pm_opp_set_clkname(dev, "clk_core");
-	if (IS_ERR(clk_table))
-		return PTR_ERR(clk_table);
+	if (IS_ERR(clk_table)) {
+		ret = PTR_ERR(clk_table);
+		goto put_opp_reg;
+	}
 
 	rockchip_get_opp_data(rockchip_rkvenc_of_match, &enc->opp_info);
 	ret = rockchip_init_opp_table(dev, &enc->opp_info, "leakage", "venc");
 	if (ret) {
 		dev_err(dev, "failed to init_opp_table\n");
-		return ret;
+		goto put_opp_clk;
 	}
 
 	enc->mdev_info = rockchip_system_monitor_register(dev, &venc_mdevp);
@@ -1803,6 +1833,14 @@
 		enc->mdev_info = NULL;
 	}
 
+	return 0;
+
+put_opp_clk:
+	dev_pm_opp_put_clkname(enc->opp_table);
+put_opp_reg:
+	dev_pm_opp_put_regulators(enc->opp_table);
+	enc->opp_table = NULL;
+
 	return ret;
 }
 
@@ -1810,8 +1848,16 @@
 {
 	struct rkvenc_dev *enc = to_rkvenc_dev(mpp);
 
-	if (enc->mdev_info)
+	if (enc->mdev_info) {
 		rockchip_system_monitor_unregister(enc->mdev_info);
+		enc->mdev_info = NULL;
+	}
+	if (enc->opp_table) {
+		rockchip_uninit_opp_table(mpp->dev, &enc->opp_info);
+		dev_pm_opp_put_clkname(enc->opp_table);
+		dev_pm_opp_put_regulators(enc->opp_table);
+		enc->opp_table = NULL;
+	}
 
 	return 0;
 }
@@ -1880,7 +1926,7 @@
 
 	/* safe reset */
 	mpp_write(mpp, hw->int_mask_base, 0x3FF);
-	mpp_write(mpp, hw->enc_clr_base, 0x1);
+	mpp_write(mpp, hw->enc_clr_base, 0x3);
 	ret = readl_relaxed_poll_timeout(mpp->reg_base + hw->int_sta_base,
 					 rst_status,
 					 rst_status & RKVENC_SCLR_DONE_STA,
@@ -2169,6 +2215,20 @@
 	.dump_session = rkvenc_dump_session,
 };
 
+static struct mpp_dev_ops vepu540c_dev_ops_v2 = {
+	.wait_result = rkvenc2_wait_result,
+	.alloc_task = rkvenc_alloc_task,
+	.run = rkvenc_run,
+	.irq = vepu540c_irq,
+	.isr = rkvenc_isr,
+	.finish = rkvenc_finish,
+	.result = rkvenc_result,
+	.free_task = rkvenc_free_task,
+	.ioctl = rkvenc_control,
+	.init_session = rkvenc_init_session,
+	.free_session = rkvenc_free_session,
+	.dump_session = rkvenc_dump_session,
+};
 
 static const struct mpp_dev_var rkvenc_v2_data = {
 	.device_type = MPP_DEVICE_RKVENC,
@@ -2183,7 +2243,7 @@
 	.hw_info = &rkvenc_540c_hw_info.hw,
 	.trans_info = trans_rkvenc_540c,
 	.hw_ops = &rkvenc_hw_ops,
-	.dev_ops = &rkvenc_dev_ops_v2,
+	.dev_ops = &vepu540c_dev_ops_v2,
 };
 
 static const struct mpp_dev_var rkvenc_ccu_data = {
@@ -2404,13 +2464,32 @@
 {
 	struct mpp_dev *mpp = (struct mpp_dev *)arg;
 	struct rkvenc_dev *enc = to_rkvenc_dev(mpp);
-	struct mpp_task *mpp_task = mpp->cur_task;
+	struct mpp_task *mpp_task;
+	struct rkvenc_ccu *ccu = enc->ccu;
 
+	if (ccu) {
+		struct rkvenc_dev *core = NULL, *n;
+
+		list_for_each_entry_safe(core, n, &ccu->core_list, core_link) {
+			if (core->mpp.iommu_info &&
+			    (&core->mpp.iommu_info->pdev->dev == iommu_dev)) {
+				mpp = &core->mpp;
+				break;
+			}
+		}
+	}
+	mpp_task = mpp->cur_task;
 	dev_info(mpp->dev, "core %d page fault found dchs %08x\n",
 		 mpp->core_id, mpp_read_relaxed(&enc->mpp, DCHS_REG_OFFSET));
 
 	if (mpp_task)
 		mpp_task_dump_mem_region(mpp, mpp_task);
+
+	/*
+	 * Mask iommu irq, in order for iommu not repeatedly trigger pagefault.
+	 * Until the pagefault task finish by hw timeout.
+	 */
+	rockchip_iommu_mask_irq(mpp->dev);
 
 	return 0;
 }
@@ -2455,7 +2534,7 @@
 	ret = devm_request_threaded_irq(dev, mpp->irq,
 					mpp_dev_irq,
 					mpp_dev_isr_sched,
-					IRQF_SHARED,
+					IRQF_ONESHOT,
 					dev_name(dev), mpp);
 	if (ret) {
 		dev_err(dev, "register interrupter runtime failed\n");

--
Gitblit v1.6.2