From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 19 Dec 2024 01:47:39 +0000
Subject: [PATCH] add wifi6 8852be driver

---
 kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c |  584 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 491 insertions(+), 93 deletions(-)

diff --git a/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c b/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c
index f6d605d..a463fc2 100644
--- a/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c
+++ b/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c
@@ -7,6 +7,8 @@
  *	Ding Wei, leo.ding@rock-chips.com
  *
  */
+#include <linux/pm_runtime.h>
+
 #include "mpp_debug.h"
 #include "mpp_common.h"
 #include "mpp_iommu.h"
@@ -17,11 +19,13 @@
 
 #include <linux/devfreq_cooling.h>
 #include <soc/rockchip/rockchip_ipa.h>
+#include <soc/rockchip/rockchip_dmc.h>
 #include <soc/rockchip/rockchip_opp_select.h>
 #include <soc/rockchip/rockchip_system_monitor.h>
+#include <soc/rockchip/rockchip_iommu.h>
 
 #ifdef CONFIG_PM_DEVFREQ
-#include "../../../devfreq/governor.h"
+#include "../drivers/devfreq/governor.h"
 #endif
 
 /*
@@ -36,13 +40,22 @@
 	.link_info = &rkvdec_link_v2_hw_info,
 };
 
-static struct mpp_hw_info rkvdec_rk3568_hw_info = {
+static struct mpp_hw_info rkvdec_rk356x_hw_info = {
 	.reg_num = RKVDEC_REG_NUM,
 	.reg_id = RKVDEC_REG_HW_ID_INDEX,
 	.reg_start = RKVDEC_REG_START_INDEX,
 	.reg_end = RKVDEC_REG_END_INDEX,
 	.reg_en = RKVDEC_REG_START_EN_INDEX,
-	.link_info = &rkvdec_link_rk3568_hw_info,
+	.link_info = &rkvdec_link_rk356x_hw_info,
+};
+
+static struct mpp_hw_info rkvdec_vdpu382_hw_info = {
+	.reg_num = RKVDEC_REG_NUM,
+	.reg_id = RKVDEC_REG_HW_ID_INDEX,
+	.reg_start = RKVDEC_REG_START_INDEX,
+	.reg_end = RKVDEC_REG_END_INDEX,
+	.reg_en = RKVDEC_REG_START_EN_INDEX,
+	.link_info = &rkvdec_link_vdpu382_hw_info,
 };
 
 /*
@@ -180,9 +193,8 @@
 	return 0;
 }
 
-static int mpp_set_rcbbuf(struct mpp_dev *mpp,
-			  struct mpp_session *session,
-			  struct rkvdec2_task *task)
+int mpp_set_rcbbuf(struct mpp_dev *mpp, struct mpp_session *session,
+		   struct mpp_task *task)
 {
 	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
 	struct rkvdec2_session_priv *priv = session->priv;
@@ -202,10 +214,11 @@
 		for (i = 0; i < rcb_inf->cnt; i++) {
 			reg_idx = rcb_inf->elem[i].index;
 			rcb_size = rcb_inf->elem[i].size;
-			if (!rcb_size ||
-			    rcb_offset > dec->sram_size ||
-			    (rcb_offset + rcb_size) > dec->rcb_size)
+			if ((rcb_offset + rcb_size) > dec->rcb_size) {
+				mpp_debug(DEBUG_SRAM_INFO,
+					  "rcb: reg %d use original buffer\n", reg_idx);
 				continue;
+			}
 			mpp_debug(DEBUG_SRAM_INFO, "rcb: reg %d offset %d, size %d\n",
 				  reg_idx, rcb_offset, rcb_size);
 			task->reg[reg_idx] = dec->rcb_iova + rcb_offset;
@@ -218,45 +231,38 @@
 	return 0;
 }
 
-void *rkvdec2_alloc_task(struct mpp_session *session,
-			 struct mpp_task_msgs *msgs)
+int rkvdec2_task_init(struct mpp_dev *mpp, struct mpp_session *session,
+		      struct rkvdec2_task *task, struct mpp_task_msgs *msgs)
 {
 	int ret;
-	struct mpp_task *mpp_task = NULL;
-	struct rkvdec2_task *task = NULL;
-	struct mpp_dev *mpp = session->mpp;
+	struct mpp_task *mpp_task = &task->mpp_task;
 
 	mpp_debug_enter();
 
-	task = kzalloc(sizeof(*task), GFP_KERNEL);
-	if (!task)
-		return NULL;
-
-	mpp_task = &task->mpp_task;
 	mpp_task_init(session, mpp_task);
 	mpp_task->hw_info = mpp->var->hw_info;
 	mpp_task->reg = task->reg;
 	/* extract reqs for current task */
 	ret = rkvdec2_extract_task_msg(session, task, msgs);
 	if (ret)
-		goto fail;
+		return ret;
 
 	/* process fd in register */
 	if (!(msgs->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
 		u32 fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_FORMAT_INDEX]);
 
-		ret = mpp_translate_reg_address(session, &task->mpp_task,
+		ret = mpp_translate_reg_address(session, mpp_task,
 						fmt, task->reg, &task->off_inf);
 		if (ret)
 			goto fail;
 
-		mpp_translate_reg_offset_info(&task->mpp_task, &task->off_inf, task->reg);
+		mpp_translate_reg_offset_info(mpp_task, &task->off_inf, task->reg);
 	}
-	mpp_set_rcbbuf(mpp, session, task);
+
 	task->strm_addr = task->reg[RKVDEC_REG_RLC_BASE_INDEX];
 	task->clk_mode = CLK_MODE_NORMAL;
 	task->slot_idx = -1;
-	init_waitqueue_head(&task->wait);
+	init_waitqueue_head(&mpp_task->wait);
 	/* get resolution info */
 	if (session->priv) {
 		struct rkvdec2_session_priv *priv = session->priv;
@@ -272,18 +278,37 @@
 
 	mpp_debug_leave();
 
-	return mpp_task;
+	return 0;
 
 fail:
 	mpp_task_dump_mem_region(mpp, mpp_task);
 	mpp_task_dump_reg(mpp, mpp_task);
 	mpp_task_finalize(session, mpp_task);
-	kfree(task);
-	return NULL;
+	return ret;
+}
+
+void *rkvdec2_alloc_task(struct mpp_session *session,
+			 struct mpp_task_msgs *msgs)
+{
+	int ret;
+	struct rkvdec2_task *task;
+
+	task = kzalloc(sizeof(*task), GFP_KERNEL);
+	if (!task)
+		return NULL;
+
+	ret = rkvdec2_task_init(session->mpp, session, task, msgs);
+	if (ret) {
+		kfree(task);
+		return NULL;
+	}
+	mpp_set_rcbbuf(session->mpp, session, &task->mpp_task);
+
+	return &task->mpp_task;
 }
 
 static void *rkvdec2_rk3568_alloc_task(struct mpp_session *session,
-				struct mpp_task_msgs *msgs)
+				       struct mpp_task_msgs *msgs)
 {
 	u32 fmt;
 	struct mpp_task *mpp_task = NULL;
@@ -304,6 +329,7 @@
 static int rkvdec2_run(struct mpp_dev *mpp, struct mpp_task *mpp_task)
 {
 	struct rkvdec2_task *task = to_rkvdec2_task(mpp_task);
+	u32 timing_en = mpp->srv->timing_en;
 	u32 reg_en = mpp_task->hw_info->reg_en;
 	/* set cache size */
 	u32 reg = RKVDEC_CACHE_PERMIT_CACHEABLE_ACCESS |
@@ -332,12 +358,20 @@
 		e = s + req->size / sizeof(u32);
 		mpp_write_req(mpp, task->reg, s, e, reg_en);
 	}
+
+	/* flush tlb before starting hardware */
+	mpp_iommu_flush_tlb(mpp->iommu_info);
+
 	/* init current task */
 	mpp->cur_task = mpp_task;
-	mpp_time_record(mpp_task);
+
+	mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY);
+
 	/* Flush the register before the start the device */
 	wmb();
 	mpp_write(mpp, RKVDEC_REG_START_EN_BASE, task->reg[reg_en] | RKVDEC_START_EN);
+
+	mpp_task_run_end(mpp_task, timing_en);
 
 	mpp_debug_leave();
 
@@ -381,13 +415,15 @@
 	u32 err_mask;
 	struct rkvdec2_task *task = NULL;
 	struct mpp_task *mpp_task = mpp->cur_task;
+	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
 
 	/* FIXME use a spin lock here */
 	if (!mpp_task) {
 		dev_err(mpp->dev, "no current task\n");
 		return IRQ_HANDLED;
 	}
-	mpp_time_diff(mpp_task);
+	mpp_task->hw_cycles = mpp_read(mpp, RKVDEC_PERF_WORKING_CNT);
+	mpp_time_diff_with_hw_time(mpp_task, dec->cycle_clk->real_rate_hz);
 	mpp->cur_task = NULL;
 	task = to_rkvdec2_task(mpp_task);
 	task->irq_status = mpp->irq_status;
@@ -397,9 +433,10 @@
 		   RKVDEC_TIMEOUT_STA | RKVDEC_ERROR_STA;
 	if (err_mask & task->irq_status) {
 		atomic_inc(&mpp->reset_request);
-		mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n",
-			  task->irq_status);
-		mpp_task_dump_hw_reg(mpp, mpp_task);
+		if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
+			mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
+			mpp_task_dump_hw_reg(mpp);
+		}
 	}
 
 	mpp_task_finish(mpp_task->session, mpp_task);
@@ -470,6 +507,18 @@
 	dec_length = dec_get - task->strm_addr;
 	task->reg[RKVDEC_REG_RLC_BASE_INDEX] = dec_length << 10;
 	mpp_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length);
+
+	if (mpp->srv->timing_en) {
+		s64 time_diff;
+
+		mpp_task->on_finish = ktime_get();
+		set_bit(TASK_TIMING_FINISH, &mpp_task->state);
+
+		time_diff = ktime_us_delta(mpp_task->on_finish, mpp_task->on_create);
+
+		if (mpp->timing_check && time_diff > (s64)mpp->timing_check)
+			mpp_task_dump_timing(mpp_task, time_diff);
+	}
 
 	mpp_debug_leave();
 
@@ -610,13 +659,24 @@
 static int rkvdec2_procfs_init(struct mpp_dev *mpp)
 {
 	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
+	char name[32];
 
-	dec->procfs = proc_mkdir(mpp->dev->of_node->name, mpp->srv->procfs);
+	if (!mpp->dev || !mpp->dev->of_node || !mpp->dev->of_node->name ||
+	    !mpp->srv || !mpp->srv->procfs)
+		return -EINVAL;
+
+	snprintf(name, sizeof(name) - 1, "%s%d",
+		 mpp->dev->of_node->name, mpp->core_id);
+	dec->procfs = proc_mkdir(name, mpp->srv->procfs);
 	if (IS_ERR_OR_NULL(dec->procfs)) {
 		mpp_err("failed on open procfs\n");
 		dec->procfs = NULL;
 		return -EIO;
 	}
+
+	/* for common mpp_dev options */
+	mpp_procfs_create_common(dec->procfs, mpp);
+
 	mpp_procfs_create_u32("aclk", 0644,
 			      dec->procfs, &dec->aclk_info.debug_rate_hz);
 	mpp_procfs_create_u32("clk_core", 0644,
@@ -770,7 +830,7 @@
 };
 
 static struct monitor_dev_profile vdec2_mdevp = {
-	.type = MONITOR_TPYE_DEV,
+	.type = MONITOR_TYPE_DEV,
 	.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
 	.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
 };
@@ -878,6 +938,42 @@
 
 	return 0;
 }
+
+void mpp_devfreq_set_core_rate(struct mpp_dev *mpp, enum MPP_CLOCK_MODE mode)
+{
+	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
+
+	if (dec->devfreq) {
+		unsigned long core_rate_hz;
+
+		mutex_lock(&dec->devfreq->lock);
+		core_rate_hz = mpp_get_clk_info_rate_hz(&dec->core_clk_info, mode);
+		if (dec->core_rate_hz != core_rate_hz) {
+			dec->core_rate_hz = core_rate_hz;
+			update_devfreq(dec->devfreq);
+		}
+		mutex_unlock(&dec->devfreq->lock);
+	}
+
+	mpp_clk_set_rate(&dec->core_clk_info, mode);
+}
+#else
+static inline int rkvdec2_devfreq_init(struct mpp_dev *mpp)
+{
+	return 0;
+}
+
+static inline int rkvdec2_devfreq_remove(struct mpp_dev *mpp)
+{
+	return 0;
+}
+
+void mpp_devfreq_set_core_rate(struct mpp_dev *mpp, enum MPP_CLOCK_MODE mode)
+{
+	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
+
+	mpp_clk_set_rate(&dec->core_clk_info, mode);
+}
 #endif
 
 static int rkvdec2_init(struct mpp_dev *mpp)
@@ -910,6 +1006,7 @@
 	mpp_set_clk_info_rate_hz(&dec->cabac_clk_info, CLK_MODE_DEFAULT, 200 * MHZ);
 	mpp_set_clk_info_rate_hz(&dec->hevc_cabac_clk_info, CLK_MODE_DEFAULT, 300 * MHZ);
 
+	dec->cycle_clk = &dec->aclk_info;
 	/* Get normal max workload from dtsi */
 	of_property_read_u32(mpp->dev->of_node,
 			     "rockchip,default-max-load", &dec->default_max_load);
@@ -936,11 +1033,10 @@
 	if (!dec->rst_hevc_cabac)
 		mpp_err("No hevc cabac reset resource define\n");
 
-#ifdef CONFIG_PM_DEVFREQ
 	ret = rkvdec2_devfreq_init(mpp);
 	if (ret)
 		mpp_err("failed to add vdec devfreq\n");
-#endif
+
 	return ret;
 }
 
@@ -965,9 +1061,7 @@
 {
 	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
 
-#ifdef CONFIG_PM_DEVFREQ
 	rkvdec2_devfreq_remove(mpp);
-#endif
 
 	if (dec->fix)
 		mpp_dma_free(dec->fix);
@@ -1046,38 +1140,61 @@
 	mpp_clk_set_rate(&dec->aclk_info, task->clk_mode);
 	mpp_clk_set_rate(&dec->cabac_clk_info, task->clk_mode);
 	mpp_clk_set_rate(&dec->hevc_cabac_clk_info, task->clk_mode);
-
-#ifdef CONFIG_PM_DEVFREQ
-	if (dec->devfreq) {
-		unsigned long core_rate_hz;
-
-		mutex_lock(&dec->devfreq->lock);
-		core_rate_hz = mpp_get_clk_info_rate_hz(&dec->core_clk_info, task->clk_mode);
-		if (dec->core_rate_hz != core_rate_hz) {
-			dec->core_rate_hz = core_rate_hz;
-			update_devfreq(dec->devfreq);
-		}
-		mutex_unlock(&dec->devfreq->lock);
-
-		return 0;
-	}
-#endif
-	mpp_clk_set_rate(&dec->core_clk_info, task->clk_mode);
+	mpp_devfreq_set_core_rate(mpp, task->clk_mode);
 
 	return 0;
 }
 
-static int rkvdec2_reset(struct mpp_dev *mpp)
+static int rkvdec2_soft_reset(struct mpp_dev *mpp)
+{
+	int ret = 0;
+
+	/*
+	 * for rk3528 and rk3562
+	 * use mmu reset instead of rkvdec soft reset
+	 * rkvdec will reset together when rkvdec_mmu force reset
+	 */
+	ret = rockchip_iommu_force_reset(mpp->dev);
+	if (ret)
+		mpp_err("soft mmu reset fail, ret %d\n", ret);
+	mpp_write(mpp, RKVDEC_REG_INT_EN, 0);
+
+	return ret;
+
+}
+
+static int rkvdec2_sip_reset(struct mpp_dev *mpp)
+{
+	mpp_debug_enter();
+
+	if (IS_REACHABLE(CONFIG_ROCKCHIP_SIP)) {
+		/* sip reset */
+		rockchip_dmcfreq_lock();
+		sip_smc_vpu_reset(0, 0, 0);
+		rockchip_dmcfreq_unlock();
+	} else {
+		rkvdec2_reset(mpp);
+	}
+
+	mpp_debug_leave();
+
+	return 0;
+}
+
+int rkvdec2_reset(struct mpp_dev *mpp)
 {
 	struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
+	int ret = 0;
 
 	mpp_debug_enter();
-#ifdef CONFIG_PM_DEVFREQ
-	if (dec->devfreq)
-		mutex_lock(&dec->devfreq->lock);
-#endif
-	if (dec->rst_a && dec->rst_h) {
-		rockchip_pmu_idle_request(mpp->dev, true);
+
+	/* safe reset first*/
+	ret = rkvdec2_soft_reset(mpp);
+
+	/* cru reset */
+	if (ret && dec->rst_a && dec->rst_h) {
+		mpp_err("soft reset timeout, use cru reset\n");
+		mpp_pmu_idle_request(mpp, true);
 		mpp_safe_reset(dec->rst_niu_a);
 		mpp_safe_reset(dec->rst_niu_h);
 		mpp_safe_reset(dec->rst_a);
@@ -1093,12 +1210,8 @@
 		mpp_safe_unreset(dec->rst_core);
 		mpp_safe_unreset(dec->rst_cabac);
 		mpp_safe_unreset(dec->rst_hevc_cabac);
-		rockchip_pmu_idle_request(mpp->dev, false);
+		mpp_pmu_idle_request(mpp, false);
 	}
-#ifdef CONFIG_PM_DEVFREQ
-	if (dec->devfreq)
-		mutex_unlock(&dec->devfreq->lock);
-#endif
 	mpp_debug_leave();
 
 	return 0;
@@ -1120,7 +1233,16 @@
 	.clk_off = rkvdec2_clk_off,
 	.get_freq = rkvdec2_get_freq,
 	.set_freq = rkvdec2_set_freq,
-	.reset = rkvdec2_reset,
+	.reset = rkvdec2_sip_reset,
+};
+
+static struct mpp_hw_ops rkvdec_rk3588_hw_ops = {
+	.init = rkvdec2_init,
+	.clk_on = rkvdec2_clk_on,
+	.clk_off = rkvdec2_clk_off,
+	.get_freq = rkvdec2_get_freq,
+	.set_freq = rkvdec2_set_freq,
+	.reset = rkvdec2_sip_reset,
 };
 
 static struct mpp_dev_ops rkvdec_v2_dev_ops = {
@@ -1160,10 +1282,26 @@
 
 static const struct mpp_dev_var rkvdec_rk3568_data = {
 	.device_type = MPP_DEVICE_RKVDEC,
-	.hw_info = &rkvdec_rk3568_hw_info,
+	.hw_info = &rkvdec_rk356x_hw_info,
 	.trans_info = rkvdec_v2_trans,
 	.hw_ops = &rkvdec_rk3568_hw_ops,
 	.dev_ops = &rkvdec_rk3568_dev_ops,
+};
+
+static const struct mpp_dev_var rkvdec_vdpu382_data = {
+	.device_type = MPP_DEVICE_RKVDEC,
+	.hw_info = &rkvdec_vdpu382_hw_info,
+	.trans_info = rkvdec_v2_trans,
+	.hw_ops = &rkvdec_v2_hw_ops,
+	.dev_ops = &rkvdec_v2_dev_ops,
+};
+
+static const struct mpp_dev_var rkvdec_rk3588_data = {
+	.device_type = MPP_DEVICE_RKVDEC,
+	.hw_info = &rkvdec_v2_hw_info,
+	.trans_info = rkvdec_v2_trans,
+	.hw_ops = &rkvdec_rk3588_hw_ops,
+	.dev_ops = &rkvdec_v2_dev_ops,
 };
 
 static const struct of_device_id mpp_rkvdec2_dt_match[] = {
@@ -1177,8 +1315,91 @@
 		.data = &rkvdec_rk3568_data,
 	},
 #endif
+#ifdef CONFIG_CPU_RK3588
+	{
+		.compatible = "rockchip,rkv-decoder-v2-ccu",
+		.data = &rkvdec_rk3588_data,
+	},
+#endif
+#ifdef CONFIG_CPU_RK3528
+	{
+		.compatible = "rockchip,rkv-decoder-rk3528",
+		.data = &rkvdec_vdpu382_data,
+	},
+#endif
+#ifdef CONFIG_CPU_RK3562
+	{
+		.compatible = "rockchip,rkv-decoder-rk3562",
+		.data = &rkvdec_vdpu382_data,
+	},
+#endif
 	{},
 };
+
+static int rkvdec2_ccu_remove(struct device *dev)
+{
+	device_init_wakeup(dev, false);
+	pm_runtime_disable(dev);
+
+	return 0;
+}
+
+static int rkvdec2_ccu_probe(struct platform_device *pdev)
+{
+	struct rkvdec2_ccu *ccu;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	u32 ccu_mode;
+
+	ccu = devm_kzalloc(dev, sizeof(*ccu), GFP_KERNEL);
+	if (!ccu)
+		return -ENOMEM;
+
+	ccu->dev = dev;
+	/* use task-level soft ccu default */
+	ccu->ccu_mode = RKVDEC2_CCU_TASK_SOFT;
+	atomic_set(&ccu->power_enabled, 0);
+	INIT_LIST_HEAD(&ccu->unused_list);
+	INIT_LIST_HEAD(&ccu->used_list);
+	platform_set_drvdata(pdev, ccu);
+
+	if (!of_property_read_u32(dev->of_node, "rockchip,ccu-mode", &ccu_mode)) {
+		if (ccu_mode <= RKVDEC2_CCU_MODE_NULL || ccu_mode >= RKVDEC2_CCU_MODE_BUTT)
+			ccu_mode = RKVDEC2_CCU_TASK_SOFT;
+		ccu->ccu_mode = (enum RKVDEC2_CCU_MODE)ccu_mode;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccu");
+	if (!res) {
+		dev_err(dev, "no memory resource defined\n");
+		return -ENODEV;
+	}
+
+	ccu->reg_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!ccu->reg_base) {
+		dev_err(dev, "ioremap failed for resource %pR\n", res);
+		return -ENODEV;
+	}
+
+	ccu->aclk_info.clk = devm_clk_get(dev, "aclk_ccu");
+	if (!ccu->aclk_info.clk)
+		mpp_err("failed on clk_get ccu aclk\n");
+
+	ccu->rst_a = devm_reset_control_get(dev, "video_ccu");
+	if (ccu->rst_a)
+		mpp_safe_unreset(ccu->rst_a);
+	else
+		mpp_err("failed on clk_get ccu reset\n");
+
+	/* power domain autosuspend delay 2s */
+	pm_runtime_set_autosuspend_delay(dev, 2000);
+	pm_runtime_use_autosuspend(dev);
+	device_init_wakeup(dev, true);
+	pm_runtime_enable(dev);
+
+	dev_info(dev, "ccu-mode: %d\n", ccu->ccu_mode);
+	return 0;
+}
 
 static int rkvdec2_alloc_rcbbuf(struct platform_device *pdev, struct rkvdec2_dev *dec)
 {
@@ -1273,6 +1494,22 @@
 	if (!ret && dec->rcb_min_width)
 		dev_info(dev, "min_width %u\n", dec->rcb_min_width);
 
+	/* if have, read rcb_info */
+	dec->rcb_info_count = device_property_count_u32(dev, "rockchip,rcb-info");
+	if (dec->rcb_info_count > 0 &&
+	    dec->rcb_info_count <= (sizeof(dec->rcb_infos) / sizeof(u32))) {
+		int i;
+
+		ret = device_property_read_u32_array(dev, "rockchip,rcb-info",
+						     dec->rcb_infos, dec->rcb_info_count);
+		if (!ret) {
+			dev_info(dev, "rcb_info_count %u\n", dec->rcb_info_count);
+			for (i = 0; i < dec->rcb_info_count; i += 2)
+				dev_info(dev, "[%u, %u]\n",
+					 dec->rcb_infos[i], dec->rcb_infos[i+1]);
+		}
+	}
+
 	return 0;
 
 err_sram_map:
@@ -1281,7 +1518,94 @@
 	return ret;
 }
 
-static int rkvdec2_probe(struct platform_device *pdev)
+static int rkvdec2_core_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct rkvdec2_dev *dec;
+	struct mpp_dev *mpp;
+	struct device *dev = &pdev->dev;
+	irq_handler_t irq_proc = NULL;
+
+	dec = devm_kzalloc(dev, sizeof(*dec), GFP_KERNEL);
+	if (!dec)
+		return -ENOMEM;
+
+	mpp = &dec->mpp;
+	platform_set_drvdata(pdev, mpp);
+	mpp->is_irq_startup = false;
+	if (dev->of_node) {
+		struct device_node *np = pdev->dev.of_node;
+		const struct of_device_id *match;
+
+		match = of_match_node(mpp_rkvdec2_dt_match, dev->of_node);
+		if (match)
+			mpp->var = (struct mpp_dev_var *)match->data;
+		mpp->core_id = of_alias_get_id(np, "rkvdec");
+	}
+
+	ret = mpp_dev_probe(mpp, pdev);
+	if (ret) {
+		dev_err(dev, "probe sub driver failed\n");
+		return ret;
+	}
+	dec->mmu_base = ioremap(dec->mpp.io_base + 0x600, 0x80);
+	if (!dec->mmu_base)
+		dev_err(dev, "mmu base map failed!\n");
+
+	/* attach core to ccu */
+	ret = rkvdec2_attach_ccu(dev, dec);
+	if (ret) {
+		dev_err(dev, "attach ccu failed\n");
+		return ret;
+	}
+
+	/* alloc rcb buffer */
+	rkvdec2_alloc_rcbbuf(pdev, dec);
+
+	/* set device for link */
+	ret = rkvdec2_ccu_link_init(pdev, dec);
+	if (ret)
+		return ret;
+
+	mpp->dev_ops->alloc_task = rkvdec2_ccu_alloc_task;
+	if (dec->ccu->ccu_mode == RKVDEC2_CCU_TASK_SOFT) {
+		mpp->dev_ops->task_worker = rkvdec2_soft_ccu_worker;
+		irq_proc = rkvdec2_soft_ccu_irq;
+		mpp->fault_handler = rkvdec2_soft_ccu_iommu_fault_handle;
+	} else if (dec->ccu->ccu_mode == RKVDEC2_CCU_TASK_HARD) {
+		if (mpp->core_id == 0 && mpp->task_capacity > 1) {
+			dec->link_dec->task_capacity = mpp->task_capacity;
+			ret = rkvdec2_ccu_alloc_table(dec, dec->link_dec);
+			if (ret)
+				return ret;
+		}
+		mpp->dev_ops->task_worker = rkvdec2_hard_ccu_worker;
+		irq_proc = rkvdec2_hard_ccu_irq;
+		mpp->fault_handler = rkvdec2_hard_ccu_iommu_fault_handle;
+	}
+	kthread_init_work(&mpp->work, mpp->dev_ops->task_worker);
+
+	/* get irq request */
+	ret = devm_request_threaded_irq(dev, mpp->irq, irq_proc, NULL,
+					IRQF_SHARED, dev_name(dev), mpp);
+	if (ret) {
+		dev_err(dev, "register interrupter runtime failed\n");
+		return -EINVAL;
+	}
+	/*make sure mpp->irq is startup then can be en/disable*/
+	mpp->is_irq_startup = true;
+
+	mpp->session_max_buffers = RKVDEC_SESSION_MAX_BUFFERS;
+	rkvdec2_procfs_init(mpp);
+
+	/* if is main-core, register to mpp service */
+	if (mpp->core_id == 0)
+		mpp_dev_register_srv(mpp, mpp->srv);
+
+	return ret;
+}
+
+static int rkvdec2_probe_default(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rkvdec2_dev *dec = NULL;
@@ -1289,13 +1613,12 @@
 	const struct of_device_id *match = NULL;
 	int ret = 0;
 
-	dev_info(dev, "probing start\n");
 	dec = devm_kzalloc(dev, sizeof(*dec), GFP_KERNEL);
 	if (!dec)
 		return -ENOMEM;
 
 	mpp = &dec->mpp;
-	platform_set_drvdata(pdev, dec);
+	platform_set_drvdata(pdev, mpp);
 
 	if (pdev->dev.of_node) {
 		match = of_match_node(mpp_rkvdec2_dt_match, pdev->dev.of_node);
@@ -1336,9 +1659,28 @@
 	rkvdec2_link_procfs_init(mpp);
 	/* register current device to mpp service */
 	mpp_dev_register_srv(mpp, mpp->srv);
+
+	return ret;
+}
+
+static int rkvdec2_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+
+	dev_info(dev, "%s, probing start\n", np->name);
+
+	if (strstr(np->name, "ccu"))
+		ret = rkvdec2_ccu_probe(pdev);
+	else if (strstr(np->name, "core"))
+		ret = rkvdec2_core_probe(pdev);
+	else
+		ret = rkvdec2_probe_default(pdev);
+
 	dev_info(dev, "probing finish\n");
 
-	return 0;
+	return ret;
 }
 
 static int rkvdec2_free_rcbbuf(struct platform_device *pdev, struct rkvdec2_dev *dec)
@@ -1347,8 +1689,9 @@
 
 	if (dec->rcb_page) {
 		size_t page_size = PAGE_ALIGN(dec->rcb_size - dec->sram_size);
+		int order = min(get_order(page_size), MAX_ORDER);
 
-		__free_pages(dec->rcb_page, get_order(page_size));
+		__free_pages(dec->rcb_page, order);
 	}
 	if (dec->rcb_iova) {
 		domain = dec->mpp.iommu_info->domain;
@@ -1361,34 +1704,88 @@
 static int rkvdec2_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct rkvdec2_dev *dec = platform_get_drvdata(pdev);
 
-	dev_info(dev, "remove device\n");
-	rkvdec2_free_rcbbuf(pdev, dec);
-	mpp_dev_remove(&dec->mpp);
-	rkvdec2_procfs_remove(&dec->mpp);
-	rkvdec2_link_remove(&dec->mpp, dec->link_dec);
+	if (strstr(dev_name(dev), "ccu")) {
+		dev_info(dev, "remove ccu device\n");
+		rkvdec2_ccu_remove(dev);
+	} else {
+		struct mpp_dev *mpp = dev_get_drvdata(dev);
+		struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
+
+		dev_info(dev, "remove device\n");
+		if (dec->mmu_base) {
+			iounmap(dec->mmu_base);
+			dec->mmu_base = NULL;
+		}
+		rkvdec2_free_rcbbuf(pdev, dec);
+		mpp_dev_remove(mpp);
+		rkvdec2_procfs_remove(mpp);
+		rkvdec2_link_remove(mpp, dec->link_dec);
+	}
 
 	return 0;
 }
 
 static void rkvdec2_shutdown(struct platform_device *pdev)
 {
-	int ret;
-	int val;
 	struct device *dev = &pdev->dev;
-	struct rkvdec2_dev *dec = platform_get_drvdata(pdev);
-	struct mpp_dev *mpp = &dec->mpp;
 
-	dev_info(dev, "shutdown device\n");
-
-	atomic_inc(&mpp->srv->shutdown_request);
-	ret = readx_poll_timeout(atomic_read,
-				 &mpp->task_count,
-				 val, val == 0, 20000, 200000);
-	if (ret == -ETIMEDOUT)
-		dev_err(dev, "wait total running time out\n");
+	if (!strstr(dev_name(dev), "ccu"))
+		mpp_dev_shutdown(pdev);
 }
+
+static int __maybe_unused rkvdec2_runtime_suspend(struct device *dev)
+{
+	if (strstr(dev_name(dev), "ccu")) {
+		struct rkvdec2_ccu *ccu = dev_get_drvdata(dev);
+
+		mpp_clk_safe_disable(ccu->aclk_info.clk);
+	} else {
+		struct mpp_dev *mpp = dev_get_drvdata(dev);
+
+		if (mpp->is_irq_startup) {
+			/* disable core irq */
+			disable_irq(mpp->irq);
+			if (mpp->iommu_info && mpp->iommu_info->got_irq)
+				/* disable mmu irq */
+				disable_irq(mpp->iommu_info->irq);
+		}
+
+		if (mpp->hw_ops->clk_off)
+			mpp->hw_ops->clk_off(mpp);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused rkvdec2_runtime_resume(struct device *dev)
+{
+	if (strstr(dev_name(dev), "ccu")) {
+		struct rkvdec2_ccu *ccu = dev_get_drvdata(dev);
+
+		mpp_clk_safe_enable(ccu->aclk_info.clk);
+	} else {
+		struct mpp_dev *mpp = dev_get_drvdata(dev);
+
+		if (mpp->hw_ops->clk_on)
+			mpp->hw_ops->clk_on(mpp);
+		if (mpp->is_irq_startup) {
+			/* enable core irq */
+			enable_irq(mpp->irq);
+			/* enable mmu irq */
+			if (mpp->iommu_info && mpp->iommu_info->got_irq)
+				enable_irq(mpp->iommu_info->irq);
+		}
+
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops rkvdec2_pm_ops = {
+	SET_RUNTIME_PM_OPS(rkvdec2_runtime_suspend, rkvdec2_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
 
 struct platform_driver rockchip_rkvdec2_driver = {
 	.probe = rkvdec2_probe,
@@ -1397,6 +1794,7 @@
 	.driver = {
 		.name = RKVDEC_DRIVER_NAME,
 		.of_match_table = of_match_ptr(mpp_rkvdec2_dt_match),
+		.pm = &rkvdec2_pm_ops,
 	},
 };
 EXPORT_SYMBOL(rockchip_rkvdec2_driver);

--
Gitblit v1.6.2