From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 13 May 2024 10:30:14 +0000
Subject: [PATCH] modify sin led gpio
---
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