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_vepu2.c | 422 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 397 insertions(+), 25 deletions(-)
diff --git a/kernel/drivers/video/rockchip/mpp/mpp_vepu2.c b/kernel/drivers/video/rockchip/mpp/mpp_vepu2.c
index d7dd2c1..fb5f5e5 100644
--- a/kernel/drivers/video/rockchip/mpp/mpp_vepu2.c
+++ b/kernel/drivers/video/rockchip/mpp/mpp_vepu2.c
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/nospec.h>
#include <soc/rockchip/pm_domains.h>
+#include <soc/rockchip/rockchip_iommu.h>
#include "mpp_debug.h"
#include "mpp_common.h"
@@ -36,6 +37,8 @@
#define VEPU2_REG_HW_ID_INDEX -1 /* INVALID */
#define VEPU2_REG_START_INDEX 0
#define VEPU2_REG_END_INDEX 183
+#define VEPU2_REG_OUT_INDEX (77)
+#define VEPU2_REG_STRM_INDEX (53)
#define VEPU2_REG_ENC_EN 0x19c
#define VEPU2_REG_ENC_EN_INDEX (103)
@@ -97,6 +100,8 @@
u32 width;
u32 height;
u32 pixels;
+ struct mpp_dma_buffer *bs_buf;
+ u32 offset_bs;
};
struct vepu_session_priv {
@@ -121,6 +126,18 @@
#endif
struct reset_control *rst_a;
struct reset_control *rst_h;
+ /* for ccu(central control unit) */
+ struct vepu_ccu *ccu;
+ bool disable_work;
+};
+
+struct vepu_ccu {
+ u32 core_num;
+ /* lock for core attach */
+ spinlock_t lock;
+ struct mpp_dev *main_core;
+ struct mpp_dev *cores[MPP_MAX_CORE_NUM];
+ unsigned long core_idle;
};
static struct mpp_hw_info vepu_v2_hw_info = {
@@ -167,7 +184,13 @@
struct mpp_task_msgs *msgs)
{
int ret;
+ int fd_bs;
int fmt = VEPU2_GET_FORMAT(task->reg[VEPU2_REG_ENC_EN_INDEX]);
+
+ if (session->msg_flags & MPP_FLAGS_REG_NO_OFFSET)
+ fd_bs = task->reg[VEPU2_REG_OUT_INDEX];
+ else
+ fd_bs = task->reg[VEPU2_REG_OUT_INDEX] & 0x3ff;
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
@@ -176,6 +199,15 @@
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf, task->reg);
+
+ if (fmt == VEPU2_FMT_JPEGE) {
+ struct mpp_dma_buffer *bs_buf = mpp_dma_find_buffer_fd(session->dma, fd_bs);
+
+ task->offset_bs = mpp_query_reg_offset_info(&task->off_inf, VEPU2_REG_OUT_INDEX);
+ if (bs_buf && task->offset_bs > 0)
+ mpp_dma_buf_sync(bs_buf, 0, task->offset_bs, DMA_TO_DEVICE, false);
+ task->bs_buf = bs_buf;
+ }
return 0;
}
@@ -281,6 +313,47 @@
return NULL;
}
+static void *vepu_prepare(struct mpp_dev *mpp, struct mpp_task *mpp_task)
+{
+ struct vepu_dev *enc = to_vepu_dev(mpp);
+ struct vepu_ccu *ccu = enc->ccu;
+ unsigned long core_idle;
+ unsigned long flags;
+ s32 core_id;
+ u32 i;
+
+ spin_lock_irqsave(&ccu->lock, flags);
+
+ core_idle = ccu->core_idle;
+
+ for (i = 0; i < ccu->core_num; i++) {
+ struct mpp_dev *mpp = ccu->cores[i];
+
+ if (mpp && mpp->disable)
+ clear_bit(mpp->core_id, &core_idle);
+ }
+
+ core_id = find_first_bit(&core_idle, ccu->core_num);
+ if (core_id >= ARRAY_SIZE(ccu->cores)) {
+ mpp_task = NULL;
+ mpp_dbg_core("core %d all busy %lx\n", core_id, ccu->core_idle);
+ goto done;
+ }
+
+ core_id = array_index_nospec(core_id, MPP_MAX_CORE_NUM);
+ clear_bit(core_id, &ccu->core_idle);
+ mpp_task->mpp = ccu->cores[core_id];
+ mpp_task->core_id = core_id;
+
+ mpp_dbg_core("core cnt %d core %d set idle %lx -> %lx\n",
+ ccu->core_num, core_id, core_idle, ccu->core_idle);
+
+done:
+ spin_unlock_irqrestore(&ccu->lock, flags);
+
+ return mpp_task;
+}
+
static int vepu_run(struct mpp_dev *mpp,
struct mpp_task *mpp_task)
{
@@ -327,6 +400,13 @@
return 0;
}
+static int vepu_px30_run(struct mpp_dev *mpp,
+ struct mpp_task *mpp_task)
+{
+ mpp_iommu_flush_tlb(mpp->iommu_info);
+ return vepu_run(mpp, mpp_task);
+}
+
static int vepu_irq(struct mpp_dev *mpp)
{
mpp->irq_status = mpp_read(mpp, VEPU2_REG_INT);
@@ -343,6 +423,9 @@
u32 err_mask;
struct vepu_task *task = NULL;
struct mpp_task *mpp_task = mpp->cur_task;
+ unsigned long core_idle;
+ struct vepu_dev *enc = to_vepu_dev(mpp);
+ struct vepu_ccu *ccu = enc->ccu;
/* FIXME use a spin lock here */
if (!mpp_task) {
@@ -364,6 +447,14 @@
atomic_inc(&mpp->reset_request);
mpp_task_finish(mpp_task->session, mpp_task);
+ /* the whole vepu has no ccu that manage multi core */
+ if (ccu) {
+ core_idle = ccu->core_idle;
+ set_bit(mpp->core_id, &ccu->core_idle);
+
+ mpp_dbg_core("core %d isr idle %lx -> %lx\n", mpp->core_id, core_idle,
+ ccu->core_idle);
+ }
mpp_debug_leave();
@@ -390,6 +481,11 @@
/* revert hack for irq status */
task->reg[VEPU2_REG_INT_INDEX] = task->irq_status;
+ if (task->bs_buf)
+ mpp_dma_buf_sync(task->bs_buf, 0,
+ task->reg[VEPU2_REG_STRM_INDEX] / 8 +
+ task->offset_bs,
+ DMA_FROM_DEVICE, true);
mpp_debug_leave();
return 0;
@@ -532,7 +628,7 @@
}
seq_puts(seq, "\n");
/* item data*/
- seq_printf(seq, "|%8p|", session);
+ seq_printf(seq, "|%8d|", session->index);
seq_printf(seq, "%8s|", mpp_device_name[session->device_type]);
for (i = ENC_INFO_BASE; i < ENC_INFO_BUTT; i++) {
u32 flag = priv->codec_info[i].flag;
@@ -565,8 +661,9 @@
mutex_lock(&mpp->srv->session_lock);
list_for_each_entry_safe(session, n,
&mpp->srv->session_list,
- session_link) {
- if (session->device_type != MPP_DEVICE_VEPU2)
+ service_link) {
+ if (session->device_type != MPP_DEVICE_VEPU2 &&
+ session->device_type != MPP_DEVICE_VEPU2_JPEG)
continue;
if (!session->priv)
continue;
@@ -581,8 +678,19 @@
static int vepu_procfs_init(struct mpp_dev *mpp)
{
struct vepu_dev *enc = to_vepu_dev(mpp);
+ char name[32];
- enc->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;
+ if (enc->ccu)
+ snprintf(name, sizeof(name) - 1, "%s%d",
+ mpp->dev->of_node->name, mpp->core_id);
+ else
+ snprintf(name, sizeof(name) - 1, "%s",
+ mpp->dev->of_node->name);
+
+ enc->procfs = proc_mkdir(name, mpp->srv->procfs);
if (IS_ERR_OR_NULL(enc->procfs)) {
mpp_err("failed on open procfs\n");
enc->procfs = NULL;
@@ -602,6 +710,17 @@
return 0;
}
+
+static int vepu_procfs_ccu_init(struct mpp_dev *mpp)
+{
+ struct vepu_dev *enc = to_vepu_dev(mpp);
+
+ if (!enc->procfs)
+ goto done;
+
+done:
+ return 0;
+}
#else
static inline int vepu_procfs_remove(struct mpp_dev *mpp)
{
@@ -609,6 +728,11 @@
}
static inline int vepu_procfs_init(struct mpp_dev *mpp)
+{
+ return 0;
+}
+
+static inline int vepu_procfs_ccu_init(struct mpp_dev *mpp)
{
return 0;
}
@@ -735,6 +859,7 @@
static int vepu_reset(struct mpp_dev *mpp)
{
struct vepu_dev *enc = to_vepu_dev(mpp);
+ struct vepu_ccu *ccu = enc->ccu;
mpp_write(mpp, VEPU2_REG_ENC_EN, 0);
udelay(5);
@@ -749,6 +874,53 @@
mpp_pmu_idle_request(mpp, false);
}
mpp_write(mpp, VEPU2_REG_INT, VEPU2_INT_CLEAR);
+
+ if (ccu) {
+ set_bit(mpp->core_id, &ccu->core_idle);
+ mpp_dbg_core("core %d reset idle %lx\n", mpp->core_id, ccu->core_idle);
+ }
+
+ return 0;
+}
+
+static int vepu2_iommu_fault_handle(struct iommu_domain *iommu, struct device *iommu_dev,
+ unsigned long iova, int status, void *arg)
+{
+ struct mpp_dev *mpp = (struct mpp_dev *)arg;
+ struct mpp_task *mpp_task;
+ struct vepu_dev *enc = to_vepu_dev(mpp);
+ struct vepu_ccu *ccu = enc->ccu;
+
+ dev_err(iommu_dev, "fault addr 0x%08lx status %x arg %p\n",
+ iova, status, arg);
+
+ if (ccu) {
+ int i;
+ struct mpp_dev *core;
+
+ for (i = 0; i < ccu->core_num; i++) {
+ core = ccu->cores[i];
+ if (core->iommu_info && (&core->iommu_info->pdev->dev == iommu_dev)) {
+ mpp = core;
+ break;
+ }
+ }
+ }
+
+ if (!mpp) {
+ dev_err(iommu_dev, "pagefault without device to handle\n");
+ return 0;
+ }
+ mpp_task = mpp->cur_task;
+ if (mpp_task)
+ mpp_task_dump_mem_region(mpp, mpp_task);
+
+ mpp_task_dump_hw_reg(mpp);
+ /*
+ * 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;
}
@@ -787,6 +959,36 @@
.dump_session = vepu_dump_session,
};
+static struct mpp_dev_ops vepu_px30_dev_ops = {
+ .alloc_task = vepu_alloc_task,
+ .run = vepu_px30_run,
+ .irq = vepu_irq,
+ .isr = vepu_isr,
+ .finish = vepu_finish,
+ .result = vepu_result,
+ .free_task = vepu_free_task,
+ .ioctl = vepu_control,
+ .init_session = vepu_init_session,
+ .free_session = vepu_free_session,
+ .dump_session = vepu_dump_session,
+};
+
+static struct mpp_dev_ops vepu_ccu_dev_ops = {
+ .alloc_task = vepu_alloc_task,
+ .prepare = vepu_prepare,
+ .run = vepu_run,
+ .irq = vepu_irq,
+ .isr = vepu_isr,
+ .finish = vepu_finish,
+ .result = vepu_result,
+ .free_task = vepu_free_task,
+ .ioctl = vepu_control,
+ .init_session = vepu_init_session,
+ .free_session = vepu_free_session,
+ .dump_session = vepu_dump_session,
+};
+
+
static const struct mpp_dev_var vepu_v2_data = {
.device_type = MPP_DEVICE_VEPU2,
.hw_info = &vepu_v2_hw_info,
@@ -800,7 +1002,15 @@
.hw_info = &vepu_v2_hw_info,
.trans_info = trans_rk_vepu2,
.hw_ops = &vepu_px30_hw_ops,
- .dev_ops = &vepu_v2_dev_ops,
+ .dev_ops = &vepu_px30_dev_ops,
+};
+
+static const struct mpp_dev_var vepu_ccu_data = {
+ .device_type = MPP_DEVICE_VEPU2_JPEG,
+ .hw_info = &vepu_v2_hw_info,
+ .trans_info = trans_rk_vepu2,
+ .hw_ops = &vepu_v2_hw_ops,
+ .dev_ops = &vepu_ccu_dev_ops,
};
static const struct of_device_id mpp_vepu2_dt_match[] = {
@@ -814,10 +1024,83 @@
.data = &vepu_px30_data,
},
#endif
+#ifdef CONFIG_CPU_RK3588
+ {
+ .compatible = "rockchip,vpu-jpege-core",
+ .data = &vepu_ccu_data,
+ },
+ {
+ .compatible = "rockchip,vpu-jpege-ccu",
+ },
+#endif
{},
};
-static int vepu_probe(struct platform_device *pdev)
+static int vepu_ccu_probe(struct platform_device *pdev)
+{
+ struct vepu_ccu *ccu;
+ struct device *dev = &pdev->dev;
+
+ ccu = devm_kzalloc(dev, sizeof(*ccu), GFP_KERNEL);
+ if (!ccu)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ccu);
+ spin_lock_init(&ccu->lock);
+ return 0;
+}
+
+static int vepu_attach_ccu(struct device *dev, struct vepu_dev *enc)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+ struct vepu_ccu *ccu;
+ unsigned long flags;
+
+ np = of_parse_phandle(dev->of_node, "rockchip,ccu", 0);
+ if (!np || !of_device_is_available(np))
+ return -ENODEV;
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!pdev)
+ return -ENODEV;
+
+ ccu = platform_get_drvdata(pdev);
+ if (!ccu)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&ccu->lock, flags);
+ ccu->core_num++;
+ ccu->cores[enc->mpp.core_id] = &enc->mpp;
+ set_bit(enc->mpp.core_id, &ccu->core_idle);
+ spin_unlock_irqrestore(&ccu->lock, flags);
+
+ /* attach the ccu-domain to current core */
+ if (!ccu->main_core) {
+ /**
+ * set the first device for the main-core,
+ * then the domain of the main-core named ccu-domain
+ */
+ ccu->main_core = &enc->mpp;
+ } else {
+ struct mpp_iommu_info *ccu_info, *cur_info;
+
+ /* set the ccu domain for current device */
+ ccu_info = ccu->main_core->iommu_info;
+ cur_info = enc->mpp.iommu_info;
+
+ if (cur_info)
+ cur_info->domain = ccu_info->domain;
+ mpp_iommu_attach(cur_info);
+ }
+ enc->ccu = ccu;
+
+ dev_info(dev, "attach ccu success\n");
+ return 0;
+}
+
+static int vepu_core_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct vepu_dev *enc = NULL;
@@ -825,18 +1108,73 @@
const struct of_device_id *match = NULL;
int ret = 0;
- dev_info(dev, "probe device\n");
enc = devm_kzalloc(dev, sizeof(struct vepu_dev), GFP_KERNEL);
if (!enc)
return -ENOMEM;
mpp = &enc->mpp;
- platform_set_drvdata(pdev, enc);
+ platform_set_drvdata(pdev, mpp);
if (pdev->dev.of_node) {
match = of_match_node(mpp_vepu2_dt_match, pdev->dev.of_node);
if (match)
mpp->var = (struct mpp_dev_var *)match->data;
+
+ mpp->core_id = of_alias_get_id(pdev->dev.of_node, "jpege");
+ }
+
+ ret = mpp_dev_probe(mpp, pdev);
+ if (ret) {
+ dev_err(dev, "probe sub driver failed\n");
+ return -EINVAL;
+ }
+ /* current device attach to ccu */
+ ret = vepu_attach_ccu(dev, enc);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, mpp->irq,
+ mpp_dev_irq,
+ mpp_dev_isr_sched,
+ IRQF_SHARED,
+ dev_name(dev), mpp);
+ if (ret) {
+ dev_err(dev, "register interrupter runtime failed\n");
+ return -EINVAL;
+ }
+
+ mpp->fault_handler = vepu2_iommu_fault_handle;
+ mpp->session_max_buffers = VEPU2_SESSION_MAX_BUFFERS;
+ vepu_procfs_init(mpp);
+ vepu_procfs_ccu_init(mpp);
+ /* if current is main-core, register current device to mpp service */
+ if (mpp == enc->ccu->main_core)
+ mpp_dev_register_srv(mpp, mpp->srv);
+
+ return 0;
+}
+
+static int vepu_probe_default(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vepu_dev *enc = NULL;
+ struct mpp_dev *mpp = NULL;
+ const struct of_device_id *match = NULL;
+ int ret = 0;
+
+ enc = devm_kzalloc(dev, sizeof(struct vepu_dev), GFP_KERNEL);
+ if (!enc)
+ return -ENOMEM;
+
+ mpp = &enc->mpp;
+ platform_set_drvdata(pdev, mpp);
+
+ if (pdev->dev.of_node) {
+ match = of_match_node(mpp_vepu2_dt_match, pdev->dev.of_node);
+ if (match)
+ mpp->var = (struct mpp_dev_var *)match->data;
+
+ mpp->core_id = of_alias_get_id(pdev->dev.of_node, "vepu");
}
ret = mpp_dev_probe(mpp, pdev);
@@ -855,43 +1193,77 @@
return -EINVAL;
}
+ mpp->fault_handler = vepu2_iommu_fault_handle;
mpp->session_max_buffers = VEPU2_SESSION_MAX_BUFFERS;
vepu_procfs_init(mpp);
/* register current device to mpp service */
mpp_dev_register_srv(mpp, mpp->srv);
- dev_info(dev, "probing finish\n");
return 0;
+}
+
+static int vepu_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ dev_info(dev, "probing start\n");
+
+ if (strstr(np->name, "ccu"))
+ ret = vepu_ccu_probe(pdev);
+ else if (strstr(np->name, "core"))
+ ret = vepu_core_probe(pdev);
+ else
+ ret = vepu_probe_default(pdev);
+
+ dev_info(dev, "probing finish\n");
+
+ return ret;
}
static int vepu_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct vepu_dev *enc = platform_get_drvdata(pdev);
+ struct device_node *np = dev->of_node;
- dev_info(dev, "remove device\n");
- mpp_dev_remove(&enc->mpp);
- vepu_procfs_remove(&enc->mpp);
+ if (strstr(np->name, "ccu")) {
+ dev_info(dev, "remove ccu device\n");
+ } else if (strstr(np->name, "core")) {
+ struct mpp_dev *mpp = dev_get_drvdata(dev);
+ struct vepu_dev *enc = to_vepu_dev(mpp);
+
+ dev_info(dev, "remove core\n");
+ if (enc->ccu) {
+ s32 core_id = mpp->core_id;
+ struct vepu_ccu *ccu = enc->ccu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ccu->lock, flags);
+ ccu->core_num--;
+ ccu->cores[core_id] = NULL;
+ clear_bit(core_id, &ccu->core_idle);
+ spin_unlock_irqrestore(&ccu->lock, flags);
+ }
+ mpp_dev_remove(&enc->mpp);
+ vepu_procfs_remove(&enc->mpp);
+ } else {
+ struct mpp_dev *mpp = dev_get_drvdata(dev);
+
+ dev_info(dev, "remove device\n");
+ mpp_dev_remove(mpp);
+ vepu_procfs_remove(mpp);
+ }
return 0;
}
static void vepu_shutdown(struct platform_device *pdev)
{
- int ret;
- int val;
struct device *dev = &pdev->dev;
- struct vepu_dev *enc = platform_get_drvdata(pdev);
- struct mpp_dev *mpp = &enc->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);
}
struct platform_driver rockchip_vepu2_driver = {
--
Gitblit v1.6.2