2021-07-07 06:24:03

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 00/14] Using component framework to support multi hardware decode

This series adds support for multi hardware decode into mtk-vcodec, by first
adding component framework to manage each hardware information: interrupt,
clock, register bases and power. Secondly add core thread to deal with core
hardware message, at the same time, add msg queue for different hardware
share messages. Lastly, the architecture of different specs are not the same,
using specs type to separate them.

This series has been tested with both MT8183 and MT8173. Decoding was working
for both chips.

Patches 1,2 rewrite get register bases and power on/off interface.

Patch 3-5 add component framework to support multi hardware.

Patches 6-14 add interfaces to support core hardware.
----
This patch dependents on "media: mtk-vcodec: support for MT8183 decoder"[1].

Multi hardware decode is based on stateless decoder, MT8183 is the first
time to add stateless decoder. Otherwise it will cause conflict.
Please also accept this patch together with [1].

[1]https://lore.kernel.org/patchwork/project/lkml/list/?series=507084
----

Yunfei Dong (14):
media: mtk-vcodec: Get numbers of register bases from DT
media: mtk-vcodec: Refactor vcodec pm interface
media: mtk-vcodec: Use component framework to manage each hardware
information
dt-bindings: media: mtk-vcodec: Separate video encoder and decoder
dt-bindings
media: mtk-vcodec: Use pure single core for MT8183
media: mtk-vcodec: Add irq interface for core hardware
media: mtk-vcodec: Add msg queue feature for lat and core architecture
media: mtk-vcodec: Generalize power and clock on/off interfaces
media: mtk-vcodec: Add new interface to lock different hardware
media: mtk-vcodec: Add core thread
media: mtk-vcodec: Support 34bits dma address for vdec
dt-bindings: media: mtk-vcodec: Adds decoder dt-bindings for mt8192
media: mtk-vcodec: Add core dec and dec end ipi msg
media: mtk-vcodec: Use codec type to separate different hardware

.../media/mediatek-vcodec-comp-decoder.txt | 93 ++++++
.../media/mediatek-vcodec-decoder.txt | 169 +++++++++++
.../media/mediatek-vcodec-encoder.txt | 73 +++++
drivers/media/platform/mtk-vcodec/Makefile | 2 +
.../platform/mtk-vcodec/mtk_vcodec_dec.c | 4 +-
.../platform/mtk-vcodec/mtk_vcodec_dec.h | 4 +
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 286 +++++++++++++++---
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.c | 193 ++++++++++++
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.h | 51 ++++
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 98 ++++--
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 13 +-
.../mtk-vcodec/mtk_vcodec_dec_stateful.c | 1 +
.../mtk-vcodec/mtk_vcodec_dec_stateless.c | 1 +
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 69 ++++-
.../platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 1 -
.../platform/mtk-vcodec/mtk_vcodec_intr.c | 30 ++
.../platform/mtk-vcodec/mtk_vcodec_intr.h | 2 +
.../platform/mtk-vcodec/mtk_vcodec_util.c | 87 +++++-
.../platform/mtk-vcodec/mtk_vcodec_util.h | 8 +-
.../media/platform/mtk-vcodec/vdec_drv_if.c | 21 +-
.../media/platform/mtk-vcodec/vdec_ipi_msg.h | 16 +-
.../platform/mtk-vcodec/vdec_msg_queue.c | 266 ++++++++++++++++
.../platform/mtk-vcodec/vdec_msg_queue.h | 136 +++++++++
.../media/platform/mtk-vcodec/vdec_vpu_if.c | 46 ++-
.../media/platform/mtk-vcodec/vdec_vpu_if.h | 22 ++
25 files changed, 1582 insertions(+), 110 deletions(-)
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_msg_queue.h

--
2.18.0


2021-07-07 06:24:03

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 01/14] media: mtk-vcodec: Get numbers of register bases from DT

Different platform may has different numbers of register bases. Gets the
numbers of register bases from DT (sizeof(u32) * 4 bytes for each).

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 38 ++++++++++++++-----
1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 55ae198dbcf9..d3f34cd04759 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -78,6 +78,31 @@ static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}

+static int mtk_vcodec_get_reg_bases(struct mtk_vcodec_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ int reg_num, i, ret = 0;
+
+ /* Sizeof(u32) * 4 bytes for each register base. */
+ reg_num = of_property_count_elems_of_size(pdev->dev.of_node, "reg",
+ sizeof(u32) * 4);
+ if (!reg_num || reg_num > NUM_MAX_VDEC_REG_BASE) {
+ dev_err(&pdev->dev, "Invalid register property size: %d\n", reg_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < reg_num; i++) {
+ dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i);
+ if (IS_ERR((__force void *)dev->reg_base[i])) {
+ ret = PTR_ERR((__force void *)dev->reg_base[i]);
+ break;
+ }
+ mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
+ }
+
+ return ret;
+}
+
static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
@@ -206,7 +231,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
struct resource *res;
phandle rproc_phandle;
enum mtk_vcodec_fw_type fw_type;
- int i, ret;
+ int ret;

dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -238,14 +263,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_dec_pm;
}

- for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
- dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i);
- if (IS_ERR((__force void *)dev->reg_base[i])) {
- ret = PTR_ERR((__force void *)dev->reg_base[i]);
- goto err_res;
- }
- mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
- }
+ ret = mtk_vcodec_get_reg_bases(dev);
+ if (ret)
+ goto err_res;

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
--
2.18.0

2021-07-07 06:24:04

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 03/14] media: mtk-vcodec: Use component framework to manage each hardware information

Uses component framework to manage each hardware information which
includes irq/power/clk. The hardware includes LAT0, LAT1 and CORE.

Signed-off-by: Yunfei Dong <[email protected]>
---
drivers/media/platform/mtk-vcodec/Makefile | 1 +
.../platform/mtk-vcodec/mtk_vcodec_dec.h | 4 +
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 210 +++++++++++++++---
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.c | 191 ++++++++++++++++
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.h | 47 ++++
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 28 +++
6 files changed, 446 insertions(+), 35 deletions(-)
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h

diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
index ca8e9e7a9c4e..edeb3b66e9e9 100644
--- a/drivers/media/platform/mtk-vcodec/Makefile
+++ b/drivers/media/platform/mtk-vcodec/Makefile
@@ -15,6 +15,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
mtk_vcodec_dec_stateful.o \
mtk_vcodec_dec_stateless.o \
mtk_vcodec_dec_pm.o \
+ mtk_vcodec_dec_hw.o \

mtk-vcodec-enc-y := venc/venc_vp8_if.o \
venc/venc_h264_if.o \
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
index 9fbd24186c1a..57039cc5b90d 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
@@ -8,7 +8,10 @@
#ifndef _MTK_VCODEC_DEC_H_
#define _MTK_VCODEC_DEC_H_

+#include "mtk_vcodec_util.h"
+
#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-mem2mem.h>

#define VCODEC_CAPABILITY_4K_DISABLED 0x10
@@ -66,6 +69,7 @@ extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
extern const struct media_device_ops mtk_vcodec_media_ops;

+extern struct platform_driver mtk_vdec_comp_driver;

/*
* mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 8d7ba881ef75..8f5b3c9345a4 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -23,14 +23,50 @@
#include "mtk_vcodec_util.h"
#include "mtk_vcodec_fw.h"

-#define VDEC_HW_ACTIVE 0x10
-#define VDEC_IRQ_CFG 0x11
-#define VDEC_IRQ_CLR 0x10
-#define VDEC_IRQ_CFG_REG 0xa4
-
module_param(mtk_v4l2_dbg_level, int, 0644);
module_param(mtk_vcodec_dbg, bool, 0644);

+static struct of_device_id mtk_vdec_drv_ids[] = {
+ {
+ .compatible = "mediatek,mtk-vcodec-lat",
+ .data = (void *)MTK_VDEC_LAT0,
+ },
+ {
+ .compatible = "mediatek,mtk-vcodec-core",
+ .data = (void *)MTK_VDEC_CORE,
+ },
+ {},
+};
+
+static inline int mtk_vdec_compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static inline void mtk_vdec_release_of(struct device *dev, void *data)
+{
+ of_node_put(data);
+}
+
+static inline int mtk_vdec_bind(struct device *dev)
+{
+ struct mtk_vcodec_dev *data = dev_get_drvdata(dev);
+
+ return component_bind_all(dev, data);
+}
+
+static inline void mtk_vdec_unbind(struct device *dev)
+{
+ struct mtk_vcodec_dev *data = dev_get_drvdata(dev);
+
+ component_unbind_all(dev, data);
+}
+
+static const struct component_master_ops mtk_vdec_ops = {
+ .bind = mtk_vdec_bind,
+ .unbind = mtk_vdec_unbind,
+};
+
/* Wake up context wait_queue */
static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
{
@@ -38,6 +74,47 @@ static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
wake_up_interruptible(&ctx->queue);
}

+static struct component_match *mtk_vcodec_match_add(
+ struct mtk_vcodec_dev *vdec_dev)
+{
+ struct platform_device *pdev = vdec_dev->plat_dev;
+ struct component_match *match = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtk_vdec_drv_ids); i++) {
+ struct device_node *comp_node;
+ enum mtk_vdec_hw_id comp_idx;
+ const struct of_device_id *of_id;
+
+ comp_node = of_find_compatible_node(NULL, NULL,
+ mtk_vdec_drv_ids[i].compatible);
+ if (!comp_node)
+ continue;
+
+ if (!of_device_is_available(comp_node)) {
+ of_node_put(comp_node);
+ dev_err(&pdev->dev, "Fail to get MMSYS node\n");
+ continue;
+ }
+
+ of_id = of_match_node(mtk_vdec_drv_ids, comp_node);
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to get match node\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ comp_idx = (enum mtk_vdec_hw_id)of_id->data;
+ mtk_v4l2_debug(4, "Get component:hw_id(%d),vdec_dev(0x%p),comp_node(0x%p)\n",
+ comp_idx, vdec_dev, comp_node);
+ vdec_dev->component_node[comp_idx] = comp_node;
+
+ component_match_add_release(&pdev->dev, &match, mtk_vdec_release_of,
+ mtk_vdec_compare_of, comp_node);
+ }
+
+ return match;
+}
+
static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
{
struct mtk_vcodec_dev *dev = priv;
@@ -103,6 +180,62 @@ static int mtk_vcodec_get_reg_bases(struct mtk_vcodec_dev *dev)
return ret;
}

+static int mtk_vcodec_init_master(struct mtk_vcodec_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ struct component_match *match;
+ int ret = 0;
+
+ match = mtk_vcodec_match_add(dev);
+ if (IS_ERR_OR_NULL(match))
+ return -EINVAL;
+
+ platform_set_drvdata(pdev, dev);
+ ret = component_master_add_with_match(&pdev->dev, &mtk_vdec_ops, match);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mtk_vcodec_init_dec_params(struct mtk_vcodec_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ struct resource *res;
+ int ret = 0;
+
+ if (!dev->is_support_comp) {
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource");
+ return -ENOENT;
+ }
+
+ dev->dec_irq = platform_get_irq(dev->plat_dev, 0);
+ irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev, dev->dec_irq,
+ mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to install dev->dec_irq %d (%d)",
+ dev->dec_irq,
+ ret);
+ return ret;
+ }
+
+ ret = mtk_vcodec_init_dec_pm(dev->plat_dev, &dev->pm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get mt vcodec clock source");
+ return ret;
+ }
+ }
+
+ ret = mtk_vcodec_get_reg_bases(dev);
+ if (ret && !dev->is_support_comp)
+ mtk_vcodec_release_dec_pm(&dev->pm);
+
+ return ret;
+}
+
static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
@@ -228,7 +361,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
{
struct mtk_vcodec_dev *dev;
struct video_device *vfd_dec;
- struct resource *res;
phandle rproc_phandle;
enum mtk_vcodec_fw_type fw_type;
int ret;
@@ -257,31 +389,14 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
if (IS_ERR(dev->fw_handler))
return PTR_ERR(dev->fw_handler);

- ret = mtk_vcodec_init_dec_pm(dev->plat_dev, &dev->pm);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
- goto err_dec_pm;
- }
-
- ret = mtk_vcodec_get_reg_bases(dev);
- if (ret)
- goto err_res;
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get irq resource");
- ret = -ENOENT;
- goto err_res;
- }
+ if (!of_find_compatible_node(NULL, NULL, "mediatek,mtk-vcodec-core"))
+ dev->is_support_comp = false;
+ else
+ dev->is_support_comp = true;

- dev->dec_irq = platform_get_irq(pdev, 0);
- irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
- ret = devm_request_irq(&pdev->dev, dev->dec_irq,
- mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
- dev->dec_irq,
- ret);
+ if (mtk_vcodec_init_dec_params(dev)) {
+ dev_err(&pdev->dev, "Failed to init pm and registers");
+ ret = -EINVAL;
goto err_res;
}

@@ -319,7 +434,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
MTK_VCODEC_DEC_NAME);
video_set_drvdata(vfd_dec, dev);
dev->vfd_dec = vfd_dec;
- platform_set_drvdata(pdev, dev);

dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops);
if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
@@ -370,8 +484,17 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
mtk_v4l2_debug(0, "decoder registered as /dev/video%d",
vfd_dec->num);

- return 0;
+ if (dev->is_support_comp) {
+ ret = mtk_vcodec_init_master(dev);
+ if (ret < 0)
+ goto err_component_match;
+ } else {
+ platform_set_drvdata(pdev, dev);
+ }

+ return 0;
+err_component_match:
+ video_unregister_device(vfd_dec);
err_dec_reg:
if (dev->vdec_pdata->uses_stateless_api)
media_device_unregister(&dev->mdev_dec);
@@ -387,9 +510,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_res:
- mtk_vcodec_release_dec_pm(&dev->pm);
-err_dec_pm:
mtk_vcodec_fw_release(dev->fw_handler);
+
return ret;
}

@@ -444,7 +566,25 @@ static struct platform_driver mtk_vcodec_dec_driver = {
},
};

-module_platform_driver(mtk_vcodec_dec_driver);
+static struct platform_driver * const mtk_vdec_drivers[] = {
+ &mtk_vdec_comp_driver,
+ &mtk_vcodec_dec_driver,
+};
+
+static int __init mtk_vdec_init(void)
+{
+ return platform_register_drivers(mtk_vdec_drivers,
+ ARRAY_SIZE(mtk_vdec_drivers));
+}
+
+static void __exit mtk_vdec_exit(void)
+{
+ platform_unregister_drivers(mtk_vdec_drivers,
+ ARRAY_SIZE(mtk_vdec_drivers));
+}
+
+module_init(mtk_vdec_init);
+module_exit(mtk_vdec_exit);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver");
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
new file mode 100644
index 000000000000..a97bb1dd2cc4
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_dec_hw.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+
+static int mtk_vdec_comp_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct mtk_vdec_comp_dev *comp_dev = dev_get_drvdata(dev);
+ struct mtk_vcodec_dev *master_dev = data;
+ int i;
+
+ for (i = 0; i < MTK_VDEC_HW_MAX; i++) {
+ if (dev->of_node != master_dev->component_node[i])
+ continue;
+
+ master_dev->comp_dev[i] = comp_dev;
+ comp_dev->comp_idx = i;
+ comp_dev->master_dev = master_dev;
+ break;
+ }
+
+ if (i == MTK_VDEC_HW_MAX) {
+ dev_err(dev, "Failed to get component node\n");
+ return -EINVAL;
+ }
+
+ comp_dev->reg_base[VDEC_COMP_SYS] =
+ master_dev->reg_base[VDEC_COMP_SYS];
+ return 0;
+}
+
+static void mtk_vdec_comp_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct mtk_vdec_comp_dev *comp_dev = dev_get_drvdata(dev);
+
+ comp_dev->reg_base[VDEC_COMP_SYS] = NULL;
+}
+
+static const struct component_ops mtk_vdec_hw_component_ops = {
+ .bind = mtk_vdec_comp_bind,
+ .unbind = mtk_vdec_comp_unbind,
+};
+
+/* Wake up context wait_queue */
+static void mtk_vdec_comp_wake_up_ctx(struct mtk_vcodec_ctx *ctx)
+{
+ ctx->int_cond = 1;
+ wake_up_interruptible(&ctx->queue);
+}
+
+static irqreturn_t mtk_vdec_comp_irq_handler(int irq, void *priv)
+{
+ struct mtk_vdec_comp_dev *dev = priv;
+ struct mtk_vcodec_ctx *ctx;
+ u32 cg_status;
+ unsigned int dec_done_status;
+ void __iomem *vdec_misc_addr = dev->reg_base[VDEC_COMP_MISC] +
+ VDEC_IRQ_CFG_REG;
+
+ ctx = mtk_vcodec_get_curr_ctx(dev->master_dev);
+
+ /* check if HW active or not */
+ cg_status = readl(dev->reg_base[VDEC_COMP_SYS]);
+ if ((cg_status & VDEC_HW_ACTIVE) != 0) {
+ mtk_v4l2_err("vdec active is not 0x0 (0x%08x)",
+ cg_status);
+ return IRQ_HANDLED;
+ }
+
+ dec_done_status = readl(vdec_misc_addr);
+ if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
+ MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
+ return IRQ_HANDLED;
+
+ /* clear interrupt */
+ writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG), vdec_misc_addr);
+ writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR), vdec_misc_addr);
+
+ mtk_vdec_comp_wake_up_ctx(ctx);
+
+ mtk_v4l2_debug(3, "wake up ctx %d, dec_done_status=%x",
+ ctx->id, dec_done_status);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_vdec_comp_init_irq(struct mtk_vdec_comp_dev *dev)
+{
+ struct platform_device *pdev = dev->plat_dev;
+ int ret;
+
+ dev->dec_irq = platform_get_irq(pdev, 0);
+ if (dev->dec_irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq resource");
+ return dev->dec_irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, dev->dec_irq,
+ mtk_vdec_comp_irq_handler,
+ 0, pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
+ dev->dec_irq, ret);
+ return -ENOENT;
+ }
+
+ disable_irq(dev->dec_irq);
+ return 0;
+}
+
+static int mtk_vdec_comp_probe(struct platform_device *pdev)
+{
+ struct mtk_vdec_comp_dev *dev;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->plat_dev = pdev;
+ spin_lock_init(&dev->irqlock);
+
+ ret = mtk_vcodec_init_dec_pm(dev->plat_dev, &dev->pm);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
+ return ret;
+ }
+
+ dev->reg_base[VDEC_COMP_MISC] =
+ devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR((__force void *)dev->reg_base[VDEC_COMP_MISC])) {
+ ret = PTR_ERR((__force void *)dev->reg_base[VDEC_COMP_MISC]);
+ goto err;
+ }
+
+ if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
+ ret = mtk_vdec_comp_init_irq(dev);
+ if (ret)
+ goto err;
+
+ platform_set_drvdata(pdev, dev);
+
+ ret = component_add(&pdev->dev, &mtk_vdec_hw_component_ops);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add component: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+err:
+ mtk_vcodec_release_dec_pm(&dev->pm);
+ return ret;
+}
+
+static const struct of_device_id mtk_vdec_comp_ids[] = {
+ {
+ .compatible = "mediatek,mtk-vcodec-lat",
+ },
+ {
+ .compatible = "mediatek,mtk-vcodec-core",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_vdec_comp_ids);
+
+struct platform_driver mtk_vdec_comp_driver = {
+ .probe = mtk_vdec_comp_probe,
+ .driver = {
+ .name = "mtk-vdec-comp",
+ .of_match_table = mtk_vdec_comp_ids,
+ },
+};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
new file mode 100644
index 000000000000..e80ea51a623b
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <[email protected]>
+ */
+
+#ifndef _MTK_VCODEC_DEC_HW_H_
+#define _MTK_VCODEC_DEC_HW_H_
+
+#include <linux/component.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "mtk_vcodec_drv.h"
+
+/**
+ * enum mtk_comp_hw_reg_idx - component register base index
+ */
+enum mtk_comp_hw_reg_idx {
+ VDEC_COMP_SYS,
+ VDEC_COMP_MISC,
+ NUM_MAX_COMP_VCODEC_REG_BASE
+};
+
+/**
+ * struct mtk_vdec_comp_dev - component framwork driver data
+ * @plat_dev: platform device
+ * @master_dev: master device
+ * @irqlock: protect data access by irq handler and work thread
+ * @reg_base: Mapped address of MTK Vcodec registers.
+ *
+ * @dec_irq: decoder irq resource
+ * @pm: power management control
+ * @comp_idx: component index
+ */
+struct mtk_vdec_comp_dev {
+ struct platform_device *plat_dev;
+ struct mtk_vcodec_dev *master_dev;
+ spinlock_t irqlock;
+ void __iomem *reg_base[NUM_MAX_COMP_VCODEC_REG_BASE];
+
+ int dec_irq;
+ struct mtk_vcodec_pm pm;
+ int comp_idx;
+};
+
+#endif /* _MTK_VCODEC_DEC_HW_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 19296fd41c31..807ee93d27dc 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -8,6 +8,8 @@
#ifndef _MTK_VCODEC_DRV_H_
#define _MTK_VCODEC_DRV_H_

+#include <linux/component.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
@@ -17,6 +19,11 @@
#include <media/videobuf2-core.h>
#include "mtk_vcodec_util.h"

+#define VDEC_HW_ACTIVE 0x10
+#define VDEC_IRQ_CFG 0x11
+#define VDEC_IRQ_CLR 0x10
+#define VDEC_IRQ_CFG_REG 0xa4
+
#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv"
#define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec"
#define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc"
@@ -93,6 +100,17 @@ enum mtk_fmt_type {
MTK_FMT_FRAME = 2,
};

+/**
+ * struct mtk_vdec_hw_id - Hardware index used to separate
+ * different hardware
+ */
+enum mtk_vdec_hw_id {
+ MTK_VDEC_CORE,
+ MTK_VDEC_LAT0,
+ MTK_VDEC_LAT1,
+ MTK_VDEC_HW_MAX,
+ };
+
/*
* struct mtk_video_fmt - Structure used to store information about pixelformats
*/
@@ -404,6 +422,7 @@ struct mtk_vcodec_enc_pdata {
*
* @fw_handler: used to communicate with the firmware.
* @id_counter: used to identify current opened instance
+ * @is_support_comp: 1: using compoent framework, 0: not support
*
* @decode_workqueue: decode work queue
* @encode_workqueue: encode work queue
@@ -422,6 +441,10 @@ struct mtk_vcodec_enc_pdata {
* @pm: power management control
* @dec_capability: used to identify decode capability, ex: 4k
* @enc_capability: used to identify encode capability
+ *
+ * comp_dev: component hardware device
+ * component_node: component node
+ * comp_idx: component index
*/
struct mtk_vcodec_dev {
struct v4l2_device v4l2_dev;
@@ -442,6 +465,7 @@ struct mtk_vcodec_dev {
struct mtk_vcodec_fw *fw_handler;

unsigned long id_counter;
+ bool is_support_comp;

struct workqueue_struct *decode_workqueue;
struct workqueue_struct *encode_workqueue;
@@ -459,6 +483,10 @@ struct mtk_vcodec_dev {
struct mtk_vcodec_pm pm;
unsigned int dec_capability;
unsigned int enc_capability;
+
+ void *comp_dev[MTK_VDEC_HW_MAX];
+ struct device_node *component_node[MTK_VDEC_HW_MAX];
+ int comp_idx;
};

static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
--
2.18.0

2021-07-07 06:24:05

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 05/14] media: mtk-vcodec: Use pure single core for MT8183

Separates different architecture for hardware: pure_sin_core
and lat_sin_core. MT8183 is pure single core. Uses .hw_arch to
distinguish.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_stateful.c | 1 +
.../platform/mtk-vcodec/mtk_vcodec_dec_stateless.c | 1 +
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 10 ++++++++++
3 files changed, 12 insertions(+)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c
index 59c24b22ab6d..61d24091c70c 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c
@@ -623,4 +623,5 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
.num_framesizes = NUM_SUPPORTED_FRAMESIZE,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
+ .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c
index 8f4a1f0a0769..9b6bd7c7cb0b 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c
@@ -357,4 +357,5 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
.uses_stateless_api = true,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
+ .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 807ee93d27dc..0539fc50ad4e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -330,6 +330,14 @@ enum mtk_chip {
MTK_MT8192,
};

+/**
+ * struct mtk_vdec_hw_arch - Used to separate different hardware architecture
+ */
+enum mtk_vdec_hw_arch {
+ MTK_VDEC_PURE_SINGLE_CORE,
+ MTK_VDEC_LAT_SINGLE_CORE,
+};
+
/**
* struct mtk_vcodec_dec_pdata - compatible data for each IC
* @init_vdec_params: init vdec params
@@ -348,6 +356,7 @@ enum mtk_chip {
* @num_framesizes: count of video decoder frame sizes
*
* @chip: chip this decoder is compatible with
+ * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core
*
* @uses_stateless_api: whether the decoder uses the stateless API with requests
*/
@@ -369,6 +378,7 @@ struct mtk_vcodec_dec_pdata {
const int num_framesizes;

enum mtk_chip chip;
+ enum mtk_vdec_hw_arch hw_arch;

bool uses_stateless_api;
};
--
2.18.0

2021-07-07 06:24:07

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 09/14] media: mtk-vcodec: Add new interface to lock different hardware

For add new hardware, not only need to lock lat hardware, also
need to lock core hardware in case of different instance start
to decoder at the same time.

Signed-off-by: Yunfei Dong <[email protected]>
---
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 4 ++--
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 5 +++--
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +-
3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 2b334a8a81c6..130ecef2e766 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -105,12 +105,12 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,

void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
{
- mutex_unlock(&ctx->dev->dec_mutex);
+ mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]);
}

void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx)
{
- mutex_lock(&ctx->dev->dec_mutex);
+ mutex_lock(&ctx->dev->dec_mutex[ctx->hw_id]);
}

void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx)
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index b13fb69c6e2f..f156a943ca62 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -386,7 +386,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
struct video_device *vfd_dec;
phandle rproc_phandle;
enum mtk_vcodec_fw_type fw_type;
- int ret;
+ int i, ret;

dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -423,7 +423,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_res;
}

- mutex_init(&dev->dec_mutex);
+ for (i = 0; i < MTK_VDEC_HW_MAX; i++)
+ mutex_init(&dev->dec_mutex[i]);
mutex_init(&dev->dev_mutex);
spin_lock_init(&dev->irqlock);

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index b42e0c7e0731..68b3fbcd95b0 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -508,7 +508,7 @@ struct mtk_vcodec_dev {
int dec_irq;
int enc_irq;

- struct mutex dec_mutex;
+ struct mutex dec_mutex[MTK_VDEC_HW_MAX];
struct mutex enc_mutex;

struct mtk_vcodec_pm pm;
--
2.18.0

2021-07-07 06:24:08

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 10/14] media: mtk-vcodec: Add core thread

Core thread:
1. Gets lat_buf from core msg queue.
2. Proceeds core decode.
3. Puts the lat_buf back to lat msg queue.

Both H264 and VP9 rely on the core thread.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 9 ++++++
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 2 ++
.../platform/mtk-vcodec/vdec_msg_queue.c | 32 +++++++++++++++++++
.../platform/mtk-vcodec/vdec_msg_queue.h | 6 ++++
4 files changed, 49 insertions(+)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index f156a943ca62..1bcb070ef947 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -423,6 +423,15 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_res;
}

+ if (VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch)) {
+ init_waitqueue_head(&dev->core_read);
+ INIT_LIST_HEAD(&dev->core_queue);
+ spin_lock_init(&dev->core_lock);
+ dev->kthread_core = kthread_run(vdec_msg_queue_core_thead, dev,
+ "mtk-%s", "core");
+ dev->num_core = 0;
+ }
+
for (i = 0; i < MTK_VDEC_HW_MAX; i++)
mutex_init(&dev->dec_mutex[i]);
mutex_init(&dev->dev_mutex);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 68b3fbcd95b0..9a2a3821d4e1 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -34,6 +34,7 @@
#define MTK_VCODEC_MAX_PLANES 3
#define MTK_V4L2_BENCHMARK 0
#define WAIT_INTR_TIMEOUT_MS 1000
+#define VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE)

/*
* enum mtk_hw_reg_idx - MTK hw register base index
@@ -519,6 +520,7 @@ struct mtk_vcodec_dev {
struct device_node *component_node[MTK_VDEC_HW_MAX];
int comp_idx;

+ struct task_struct *kthread_core;
wait_queue_head_t core_read;
struct list_head core_queue;
spinlock_t core_lock;
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
index 9d684e5f051c..4841b7c17c41 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
@@ -232,3 +232,35 @@ void vdec_msg_queue_deinit(

msg_queue->init_done = false;
}
+
+int vdec_msg_queue_core_thead(void *data)
+{
+ struct mtk_vcodec_dev *dev = data;
+ struct vdec_lat_buf *lat_buf;
+ struct mtk_vcodec_ctx *ctx;
+
+ set_freezable();
+ for (;;) {
+ try_to_freeze();
+ if (kthread_should_stop())
+ break;
+
+ lat_buf = vdec_msg_queue_get_core_buf(dev);
+ if (!lat_buf)
+ continue;
+
+ ctx = lat_buf->ctx;
+ mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE);
+
+ if (!lat_buf->core_decode)
+ mtk_v4l2_err("Core decode callback func is NULL");
+ else
+ lat_buf->core_decode(lat_buf);
+
+ mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE);
+ vdec_msg_queue_buf_to_lat(lat_buf);
+ }
+
+ mtk_v4l2_debug(3, "Video Capture Thread End");
+ return 0;
+}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
index 62261702c464..dba127843f14 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
@@ -127,4 +127,10 @@ void vdec_msg_queue_deinit(
struct mtk_vcodec_ctx *ctx,
struct vdec_msg_queue *msg_queue);

+/**
+ * vdec_msg_queue_core_thead - used for core decoder.
+ * @data: private data used for each codec
+ */
+int vdec_msg_queue_core_thead(void *data);
+
#endif
--
2.18.0

2021-07-07 06:24:07

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 08/14] media: mtk-vcodec: Generalize power and clock on/off interfaces

Generalizes power and clock on/off interfaces to support different hardware.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 6 +-
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.c | 2 +-
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.h | 4 +
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 76 ++++++++++++++--
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 8 +-
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +
.../platform/mtk-vcodec/mtk_vcodec_util.c | 87 ++++++++++++++++---
.../platform/mtk-vcodec/mtk_vcodec_util.h | 8 +-
.../media/platform/mtk-vcodec/vdec_drv_if.c | 21 ++---
9 files changed, 174 insertions(+), 40 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index ab9f06f250cd..b13fb69c6e2f 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -134,7 +134,7 @@ static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] +
VDEC_IRQ_CFG_REG;

- ctx = mtk_vcodec_get_curr_ctx(dev);
+ ctx = mtk_vcodec_get_curr_ctx(dev, MTK_VDEC_CORE);

/* check if HW active or not */
cg_status = readl(dev->reg_base[0]);
@@ -299,7 +299,7 @@ static int fops_vcodec_open(struct file *file)
mtk_vcodec_dec_set_default_params(ctx);

if (v4l2_fh_is_singular(&ctx->fh)) {
- ret = mtk_vcodec_dec_pw_on(&dev->pm);
+ ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0);
if (ret < 0)
goto err_load_fw;
/*
@@ -360,7 +360,7 @@ static int fops_vcodec_release(struct file *file)
mtk_vcodec_dec_release(ctx);

if (v4l2_fh_is_singular(&ctx->fh))
- mtk_vcodec_dec_pw_off(&dev->pm);
+ mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
index 2763ef298f8a..26a3750895ed 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
@@ -75,7 +75,7 @@ static irqreturn_t mtk_vdec_comp_irq_handler(int irq, void *priv)
void __iomem *vdec_misc_addr = dev->reg_base[VDEC_COMP_MISC] +
VDEC_IRQ_CFG_REG;

- ctx = mtk_vcodec_get_curr_ctx(dev->master_dev);
+ ctx = mtk_vcodec_get_curr_ctx(dev->master_dev, dev->comp_idx);

/* check if HW active or not */
cg_status = readl(dev->reg_base[VDEC_COMP_SYS]);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
index e80ea51a623b..7d19c4d461c5 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
@@ -29,6 +29,8 @@ enum mtk_comp_hw_reg_idx {
* @irqlock: protect data access by irq handler and work thread
* @reg_base: Mapped address of MTK Vcodec registers.
*
+ * @curr_ctx: The context that is waiting for codec hardware
+ *
* @dec_irq: decoder irq resource
* @pm: power management control
* @comp_idx: component index
@@ -39,6 +41,8 @@ struct mtk_vdec_comp_dev {
spinlock_t irqlock;
void __iomem *reg_base[NUM_MAX_COMP_VCODEC_REG_BASE];

+ struct mtk_vcodec_ctx *curr_ctx;
+
int dec_irq;
struct mtk_vcodec_pm pm;
int comp_idx;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
index 20bd157a855c..6d6a5a6a7022 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -5,11 +5,13 @@
*/

#include <linux/clk.h>
+#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <soc/mediatek/smi.h>

+#include "mtk_vcodec_dec_hw.h"
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vcodec_util.h"

@@ -84,10 +86,23 @@ void mtk_vcodec_release_dec_pm(struct mtk_vcodec_pm *pm)
put_device(pm->larbvdec);
}

-int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int comp_idx)
{
+ struct mtk_vdec_comp_dev *comp_dev;
+ struct mtk_vcodec_pm *pm;
int ret;

+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev\n");
+ return -EINVAL;
+ }
+ pm = &comp_dev->pm;
+ } else {
+ pm = &vdec_dev->pm;
+ }
+
ret = pm_runtime_resume_and_get(pm->dev);
if (ret)
mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
@@ -95,20 +110,49 @@ int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
return ret;
}

-void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
+void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int comp_idx)
{
+ struct mtk_vdec_comp_dev *comp_dev;
+ struct mtk_vcodec_pm *pm;
int ret;

+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev\n");
+ return;
+ }
+ pm = &comp_dev->pm;
+ } else {
+ pm = &vdec_dev->pm;
+ }
+
ret = pm_runtime_put_sync(pm->dev);
if (ret)
mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
}

-void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
+void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int comp_idx)
{
- struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
- int ret, i = 0;
+ struct mtk_vdec_comp_dev *comp_dev;
+ struct mtk_vcodec_pm *pm;
+ struct mtk_vcodec_clk *dec_clk;
+ int ret, i;
+
+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev\n");
+ return;
+ }
+ pm = &comp_dev->pm;
+ enable_irq(comp_dev->dec_irq);
+ } else {
+ pm = &vdec_dev->pm;
+ enable_irq(vdec_dev->dec_irq);
+ }

+ dec_clk = &pm->vdec_clk;
for (i = 0; i < dec_clk->clk_num; i++) {
ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
if (ret) {
@@ -130,11 +174,27 @@ void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}

-void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
+void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int comp_idx)
{
- struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
- int i = 0;
+ struct mtk_vdec_comp_dev *comp_dev;
+ struct mtk_vcodec_pm *pm;
+ struct mtk_vcodec_clk *dec_clk;
+ int i;

+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev\n");
+ return;
+ }
+ pm = &comp_dev->pm;
+ disable_irq(comp_dev->dec_irq);
+ } else {
+ pm = &vdec_dev->pm;
+ disable_irq(vdec_dev->dec_irq);
+ }
+
+ dec_clk = &pm->vdec_clk;
mtk_smi_larb_put(pm->larbvdec);
for (i = dec_clk->clk_num - 1; i >= 0; i--)
clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
index a3df6aef6cb9..698750572b57 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -13,9 +13,9 @@ int mtk_vcodec_init_dec_pm(struct platform_device *pdev,
struct mtk_vcodec_pm *pm);
void mtk_vcodec_release_dec_pm(struct mtk_vcodec_pm *pm);

-int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
-void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
-void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
-void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int comp_idx);
+void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int comp_idx);
+void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int comp_idx);
+void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int comp_idx);

#endif /* _MTK_VCODEC_DEC_PM_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 53a3bab0da52..b42e0c7e0731 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -286,6 +286,7 @@ struct vdec_pic_info {
* @decoded_frame_cnt: number of decoded frames
* @lock: protect variables accessed by V4L2 threads and worker thread such as
* mtk_video_dec_buf.
+ * @hw_id: hardware index used to identify different hardware.
*
* @msg_queue: msg queue used to store lat buffer information.
*/
@@ -334,6 +335,7 @@ struct mtk_vcodec_ctx {

int decoded_frame_cnt;
struct mutex lock;
+ int hw_id;

struct vdec_msg_queue msg_queue;
};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
index ac5973b6735f..99ccbc73a85e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
@@ -6,7 +6,10 @@
*/

#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>

+#include "mtk_vcodec_dec_hw.h"
#include "mtk_vcodec_drv.h"
#include "mtk_vcodec_util.h"

@@ -81,25 +84,87 @@ void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
}
EXPORT_SYMBOL(mtk_vcodec_mem_free);

-void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
- struct mtk_vcodec_ctx *ctx)
+void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int comp_idx)
{
- unsigned long flags;
+ struct platform_device *hw_pdev;
+ struct device_node *node;
+ struct mtk_vdec_comp_dev *master_dev;
+
+ if (comp_idx >= MTK_VDEC_HW_MAX || comp_idx < 0) {
+ mtk_v4l2_err("Comp idx is out of range:%d", comp_idx);
+ return NULL;
+ }
+
+ if (dev->comp_dev[comp_idx])
+ return dev->comp_dev[comp_idx];
+
+ node = dev->component_node[comp_idx];
+ if (!node) {
+ mtk_v4l2_err("Get lat node fail:%d", comp_idx);
+ return NULL;
+ }
+
+ hw_pdev = of_find_device_by_node(node);
+ of_node_put(node);
+
+ if (WARN_ON(!hw_pdev)) {
+ mtk_v4l2_err("Get hw id(%d) node fail", comp_idx);
+ return NULL;
+ }
+
+ master_dev = platform_get_drvdata(hw_pdev);
+ if (!master_dev) {
+ mtk_v4l2_err("Get hw id(%d) pdev fail", comp_idx);
+ return NULL;
+ }

- spin_lock_irqsave(&dev->irqlock, flags);
- dev->curr_ctx = ctx;
- spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->comp_dev[master_dev->comp_idx] = master_dev;
+ return master_dev;
+}
+EXPORT_SYMBOL(mtk_vcodec_get_hw_dev);
+
+void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+ struct mtk_vcodec_ctx *ctx, int comp_idx)
+{
+ unsigned long flags;
+ struct mtk_vdec_comp_dev *comp_dev;
+
+ spin_lock_irqsave(&vdec_dev->irqlock, flags);
+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev");
+ spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+ return;
+ }
+ comp_dev->curr_ctx = ctx;
+ } else {
+ vdec_dev->curr_ctx = ctx;
+ }
+ spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
}
EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);

-struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev)
+struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+ unsigned int comp_idx)
{
unsigned long flags;
struct mtk_vcodec_ctx *ctx;
-
- spin_lock_irqsave(&dev->irqlock, flags);
- ctx = dev->curr_ctx;
- spin_unlock_irqrestore(&dev->irqlock, flags);
+ struct mtk_vdec_comp_dev *comp_dev;
+
+ spin_lock_irqsave(&vdec_dev->irqlock, flags);
+ if (vdec_dev->is_support_comp) {
+ comp_dev = mtk_vcodec_get_hw_dev(vdec_dev, comp_idx);
+ if (!comp_dev) {
+ mtk_v4l2_err("Failed to get hw dev");
+ spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+ return NULL;
+ }
+ ctx = comp_dev->curr_ctx;
+ } else {
+ ctx = vdec_dev->curr_ctx;
+ }
+ spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
return ctx;
}
EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
index b999d7b84ed1..4cb0fc60c94f 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
@@ -79,8 +79,10 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
struct mtk_vcodec_mem *mem);
void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
struct mtk_vcodec_mem *mem);
-void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
- struct mtk_vcodec_ctx *ctx);
-struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev);
+void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+ struct mtk_vcodec_ctx *ctx, int comp_idx);
+struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+ unsigned int comp_idx);
+void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int comp_idx);

#endif /* _MTK_VCODEC_UTIL_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
index 42008243ceac..05a5b240e906 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -24,21 +24,24 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
break;
case V4L2_PIX_FMT_H264:
ctx->dec_if = &vdec_h264_if;
+ ctx->hw_id = MTK_VDEC_CORE;
break;
case V4L2_PIX_FMT_VP8:
ctx->dec_if = &vdec_vp8_if;
+ ctx->hw_id = MTK_VDEC_CORE;
break;
case V4L2_PIX_FMT_VP9:
ctx->dec_if = &vdec_vp9_if;
+ ctx->hw_id = MTK_VDEC_CORE;
break;
default:
return -EINVAL;
}

mtk_vdec_lock(ctx);
- mtk_vcodec_dec_clock_on(&ctx->dev->pm);
+ mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
ret = ctx->dec_if->init(ctx);
- mtk_vcodec_dec_clock_off(&ctx->dev->pm);
+ mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
mtk_vdec_unlock(ctx);

return ret;
@@ -69,13 +72,11 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,

mtk_vdec_lock(ctx);

- mtk_vcodec_set_curr_ctx(ctx->dev, ctx);
- mtk_vcodec_dec_clock_on(&ctx->dev->pm);
- enable_irq(ctx->dev->dec_irq);
+ mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id);
+ mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
- disable_irq(ctx->dev->dec_irq);
- mtk_vcodec_dec_clock_off(&ctx->dev->pm);
- mtk_vcodec_set_curr_ctx(ctx->dev, NULL);
+ mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
+ mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id);

mtk_vdec_unlock(ctx);

@@ -103,9 +104,9 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
return;

mtk_vdec_lock(ctx);
- mtk_vcodec_dec_clock_on(&ctx->dev->pm);
+ mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
ctx->dec_if->deinit(ctx->drv_handle);
- mtk_vcodec_dec_clock_off(&ctx->dev->pm);
+ mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
mtk_vdec_unlock(ctx);

ctx->drv_handle = NULL;
--
2.18.0

2021-07-07 06:24:10

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 06/14] media: mtk-vcodec: Add irq interface for core hardware

Adds irq interface for core hardware.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 27 +++++++++++++++--
.../platform/mtk-vcodec/mtk_vcodec_dec_hw.c | 18 ++++++-----
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 9 ++++++
.../platform/mtk-vcodec/mtk_vcodec_intr.c | 30 +++++++++++++++++++
.../platform/mtk-vcodec/mtk_vcodec_intr.h | 2 ++
5 files changed, 76 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 8f5b3c9345a4..ab9f06f250cd 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -74,6 +74,16 @@ static void wake_up_ctx(struct mtk_vcodec_ctx *ctx)
wake_up_interruptible(&ctx->queue);
}

+static int mtk_vcodec_get_hw_count(struct mtk_vcodec_dev *dev)
+{
+ if (dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE)
+ return 1;
+ else if (dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE)
+ return 2;
+ else
+ return 0;
+}
+
static struct component_match *mtk_vcodec_match_add(
struct mtk_vcodec_dev *vdec_dev)
{
@@ -240,7 +250,7 @@ static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
struct mtk_vcodec_ctx *ctx = NULL;
- int ret = 0;
+ int ret = 0, i, hw_count;
struct vb2_queue *src_vq;

ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -254,7 +264,19 @@ static int fops_vcodec_open(struct file *file)
v4l2_fh_add(&ctx->fh);
INIT_LIST_HEAD(&ctx->list);
ctx->dev = dev;
- init_waitqueue_head(&ctx->queue);
+
+ if (ctx->dev->is_support_comp) {
+ hw_count = mtk_vcodec_get_hw_count(dev);
+ if (!hw_count) {
+ ret = -EINVAL;
+ goto err_init_queue;
+ }
+ for (i = 0; i < hw_count; i++)
+ init_waitqueue_head(&ctx->core_queue[i]);
+ } else {
+ init_waitqueue_head(&ctx->queue);
+ }
+
mutex_init(&ctx->lock);

ctx->type = MTK_INST_DECODER;
@@ -311,6 +333,7 @@ static int fops_vcodec_open(struct file *file)
err_m2m_ctx_init:
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
err_ctrls_setup:
+err_init_queue:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
kfree(ctx);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
index a97bb1dd2cc4..2763ef298f8a 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
@@ -58,11 +58,12 @@ static const struct component_ops mtk_vdec_hw_component_ops = {
.unbind = mtk_vdec_comp_unbind,
};

-/* Wake up context wait_queue */
-static void mtk_vdec_comp_wake_up_ctx(struct mtk_vcodec_ctx *ctx)
+/* Wake up core context wait_queue */
+static void mtk_vdec_comp_wake_up_ctx(struct mtk_vcodec_ctx *ctx,
+ unsigned int hw_id)
{
- ctx->int_cond = 1;
- wake_up_interruptible(&ctx->queue);
+ ctx->int_core_cond[hw_id] = 1;
+ wake_up_interruptible(&ctx->core_queue[hw_id]);
}

static irqreturn_t mtk_vdec_comp_irq_handler(int irq, void *priv)
@@ -93,7 +94,7 @@ static irqreturn_t mtk_vdec_comp_irq_handler(int irq, void *priv)
writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG), vdec_misc_addr);
writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR), vdec_misc_addr);

- mtk_vdec_comp_wake_up_ctx(ctx);
+ mtk_vdec_comp_wake_up_ctx(ctx, dev->comp_idx);

mtk_v4l2_debug(3, "wake up ctx %d, dec_done_status=%x",
ctx->id, dec_done_status);
@@ -113,8 +114,7 @@ static int mtk_vdec_comp_init_irq(struct mtk_vdec_comp_dev *dev)
}

ret = devm_request_irq(&pdev->dev, dev->dec_irq,
- mtk_vdec_comp_irq_handler,
- 0, pdev->name, dev);
+ mtk_vdec_comp_irq_handler, 0, pdev->name, dev);
if (ret) {
dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
dev->dec_irq, ret);
@@ -154,8 +154,10 @@ static int mtk_vdec_comp_probe(struct platform_device *pdev)
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));

ret = mtk_vdec_comp_init_irq(dev);
- if (ret)
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register irq handler.\n");
goto err;
+ }

platform_set_drvdata(pdev, dev);

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 0539fc50ad4e..50c87bca3973 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -263,6 +263,11 @@ struct vdec_pic_info {
* finish
* @irq_status: irq status
*
+ * @int_core_cond: variable used by the waitqueue for component arch
+ * @int_core_type: type of the last interrupt for component arch
+ * @core_queue: waitqueue that can be used to wait for this context to
+ * finish for component arch
+ *
* @ctrl_hdl: handler for v4l2 framework
* @decode_work: worker for the decoding
* @encode_work: worker for the encoding
@@ -305,6 +310,10 @@ struct mtk_vcodec_ctx {
wait_queue_head_t queue;
unsigned int irq_status;

+ int int_core_cond[MTK_VDEC_HW_MAX];
+ int int_core_type[MTK_VDEC_HW_MAX];
+ wait_queue_head_t core_queue[MTK_VDEC_HW_MAX];
+
struct v4l2_ctrl_handler ctrl_hdl;
struct work_struct decode_work;
struct work_struct encode_work;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
index 70580c2525ba..8411c670a761 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
@@ -43,3 +43,33 @@ int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx, int command,
return status;
}
EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
+
+int mtk_vcodec_wait_for_comp_done_ctx(struct mtk_vcodec_ctx *ctx,
+ int command, unsigned int timeout_ms, unsigned hw_id)
+{
+ long timeout_jiff, ret;
+ int status = 0;
+
+ timeout_jiff = msecs_to_jiffies(timeout_ms);
+ ret = wait_event_interruptible_timeout(ctx->core_queue[hw_id],
+ ctx->int_core_cond[hw_id],
+ timeout_jiff);
+
+ if (!ret) {
+ status = -1; /* timeout */
+ mtk_v4l2_err("[%d] cmd=%d, type=%d, dec timeout=%ums (%d %d)",
+ ctx->id, command, ctx->type, timeout_ms,
+ ctx->int_core_cond[hw_id], ctx->int_core_type[hw_id]);
+ } else if (-ERESTARTSYS == ret) {
+ status = -1;
+ mtk_v4l2_err("[%d] cmd=%d, type=%d, dec inter fail (%d %d)",
+ ctx->id, command, ctx->type,
+ ctx->int_core_cond[hw_id], ctx->int_core_type[hw_id]);
+ }
+
+ ctx->int_core_cond[hw_id] = 0;
+ ctx->int_core_type[hw_id] = 0;
+
+ return status;
+}
+EXPORT_SYMBOL(mtk_vcodec_wait_for_comp_done_ctx);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
index 638cd1f3526a..345f63953fa1 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
@@ -14,5 +14,7 @@ struct mtk_vcodec_ctx;
/* timeout is ms */
int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *data, int command,
unsigned int timeout_ms);
+int mtk_vcodec_wait_for_comp_done_ctx(struct mtk_vcodec_ctx *ctx,
+ int command, unsigned int timeout_ms, unsigned int hw_id);

#endif /* _MTK_VCODEC_INTR_H_ */
--
2.18.0

2021-07-07 06:24:10

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 11/14] media: mtk-vcodec: Support 34bits dma address for vdec

Use the dma_set_mask_and_coherent helper to set vdec
DMA bit mask to support 34bits iova space(16GB) that
the mt8192 iommu HW support.

Whole the iova range separate to 0~4G/4G~8G/8G~12G/12G~16G,
regarding which iova range VDEC actually locate, it
depends on the dma-ranges property of vdec dtsi node.

Signed-off-by: Yunfei Dong <[email protected]>
---
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 1bcb070ef947..c29154c30dcc 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -432,6 +432,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
dev->num_core = 0;
}

+ if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
for (i = 0; i < MTK_VDEC_HW_MAX; i++)
mutex_init(&dev->dec_mutex[i]);
mutex_init(&dev->dev_mutex);
--
2.18.0

2021-07-07 06:24:10

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 04/14] dt-bindings: media: mtk-vcodec: Separate video encoder and decoder dt-bindings

Decoder will use component framework to manage hardware, it is big
difference with encoder.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../media/mediatek-vcodec-decoder.txt | 169 ++++++++++++++++++
.../media/mediatek-vcodec-encoder.txt | 73 ++++++++
2 files changed, 242 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt

diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
new file mode 100644
index 000000000000..e09c1d0b6820
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
@@ -0,0 +1,169 @@
+Mediatek Video Decoder
+
+Mediatek Video Decoder is the video decode hw present in Mediatek SoCs which
+supports high resolution decoding functionalities. With component framework
+require master and component node properties:
+
+Required properties(no component framework):
+- compatible : must be one of the following string:
+ "mediatek,mt8173-vcodec-dec" for MT8173 decoder.
+ "mediatek,mt8183-vcodec-dec" for MT8183 decoder.
+- reg : Physical base address of the video decoder registers and length of
+ memory mapped region.
+- interrupts : interrupt number to the cpu.
+- mediatek,larb : must contain the local arbiters in the current Socs.
+- clocks : list of clock specifiers, corresponding to entries in
+ the clock-names property.
+- clock-names: must contain "vcodecpll", "univpll_d2", "clk_cci400_sel"
+ "vdec_sel", "vdecpll", "vencpll", "venc_lt_sel", "vdec_bus_clk_src".
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+- dma-ranges : describes the dma address range space that the codec hw access.
+One of the two following nodes:
+- mediatek,vpu : the node of the video processor unit, if using VPU.
+- mediatek,scp : the node of the SCP unit, if using SCP.
+
+Master properties(component framework):
+- compatible :
+ "mediatek,mt8192-vcodec-dec" for MT8192 decoder.
+- reg : Physical base address of the video decoder registers and length of
+ memory mapped region.
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+One of the two following nodes:
+- mediatek,vpu : the node of the video processor unit, if using VPU.
+- mediatek,scp : the node of the SCP unit, if using SCP.
+
+component properties(lat/core):
+- compatible :
+ "mediatek,mtk-vcodec-lat" for lat hardware decoder.
+ "mediatek,mtk-vcodec-core" core hardware decoder
+- reg : Physical base address of the video decoder registers and length of
+ memory mapped region.
+- interrupts : interrupt number to the cpu.
+- clocks : list of clock specifiers, corresponding to entries in
+ the clock-names property.
+- clock-names: "vdec-soc-vdec", "vdec-soc-lat", "vdec-vdec", "vdec-top".
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+One of the two following nodes:
+- mediatek,vpu : the node of the video processor unit, if using VPU.
+- mediatek,scp : the node of the SCP unit, if using SCP.
+
+Example:
+
+No component framework:
+vcodec_dec: vcodec@16000000 {
+ compatible = "mediatek,mt8173-vcodec-dec";
+ reg = <0 0x16000000 0 0x100>, /*VDEC_SYS*/
+ <0 0x16020000 0 0x1000>, /*VDEC_MISC*/
+ <0 0x16021000 0 0x800>, /*VDEC_LD*/
+ <0 0x16021800 0 0x800>, /*VDEC_TOP*/
+ <0 0x16022000 0 0x1000>, /*VDEC_CM*/
+ <0 0x16023000 0 0x1000>, /*VDEC_AD*/
+ <0 0x16024000 0 0x1000>, /*VDEC_AV*/
+ <0 0x16025000 0 0x1000>, /*VDEC_PP*/
+ <0 0x16026800 0 0x800>, /*VP8_VD*/
+ <0 0x16027000 0 0x800>, /*VP6_VD*/
+ <0 0x16027800 0 0x800>, /*VP8_VL*/
+ <0 0x16028400 0 0x400>; /*VP9_VD*/
+ interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,larb = <&larb1>;
+ iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PP_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_AVC_MV_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PRED_RD_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_PRED_WR_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_UFO_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_VLD_EXT>,
+ <&iommu M4U_PORT_HW_VDEC_VLD2_EXT>;
+ mediatek,vpu = <&vpu>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
+ clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>,
+ <&topckgen CLK_TOP_UNIVPLL_D2>,
+ <&topckgen CLK_TOP_CCI400_SEL>,
+ <&topckgen CLK_TOP_VDEC_SEL>,
+ <&topckgen CLK_TOP_VCODECPLL>,
+ <&apmixedsys CLK_APMIXED_VENCPLL>,
+ <&topckgen CLK_TOP_VENC_LT_SEL>,
+ <&topckgen CLK_TOP_VCODECPLL_370P5>;
+ clock-names = "vcodecpll",
+ "univpll_d2",
+ "clk_cci400_sel",
+ "vdec_sel",
+ "vdecpll",
+ "vencpll",
+ "venc_lt_sel",
+ "vdec_bus_clk_src";
+ assigned-clocks = <&topckgen CLK_TOP_VENC_LT_SEL>,
+ <&topckgen CLK_TOP_CCI400_SEL>,
+ <&topckgen CLK_TOP_VDEC_SEL>,
+ <&apmixedsys CLK_APMIXED_VCODECPLL>,
+ <&apmixedsys CLK_APMIXED_VENCPLL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL_370P5>,
+ <&topckgen CLK_TOP_UNIVPLL_D2>,
+ <&topckgen CLK_TOP_VCODECPLL>;
+ assigned-clock-rates = <0>, <0>, <0>, <1482000000>, <800000000>;
+ };
+
+With component framework:
+vcodec_dec: vcodec_dec@16000000 {
+ compatible = "mediatek,mt8192-vcodec-dec";
+ reg = <0 0x16000000 0 0x1000>; /* VDEC_SYS */
+ mediatek,scp = <&scp>;
+ iommus = <&iommu0 M4U_PORT_L4_VDEC_MC_EXT>;
+ };
+
+vcodec_lat: vcodec_lat@0x16010000 {
+ compatible = "mediatek,mtk-vcodec-lat";
+ reg = <0 0x16010000 0 0x800>; /* VDEC_MISC */
+ interrupts = <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH 0>;
+ iommus = <&iommu0 M4U_PORT_L5_VDEC_LAT0_VLD_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_VLD2_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_AVC_MV_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_PRED_RD_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_TILE_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_WDMA_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_RG_CTRL_DMA_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_UFO_ENC_EXT>;
+ clocks = <&topckgen CLK_TOP_VDEC_SEL>,
+ <&vdecsys_soc CLK_VDEC_SOC_VDEC>,
+ <&vdecsys_soc CLK_VDEC_SOC_LAT>,
+ <&vdecsys_soc CLK_VDEC_SOC_LARB1>,
+ <&topckgen CLK_TOP_MAINPLL_D4>;
+ clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat",
+ "vdec-vdec", "vdec-top";
+ assigned-clocks = <&topckgen CLK_TOP_VDEC_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4>;
+ power-domains = <&spm MT8192_POWER_DOMAIN_VDEC>;
+ };
+
+vcodec_core: vcodec_core@0x16025000 {
+ compatible = "mediatek,mtk-vcodec-core";
+ reg = <0 0x16025000 0 0x1000>; /* VDEC_CORE_MISC */
+ interrupts = <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH 0>;
+ iommus = <&iommu0 M4U_PORT_L4_VDEC_MC_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_UFO_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PP_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PRED_RD_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PRED_WR_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PPWRAP_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_TILE_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_VLD_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_VLD2_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_AVC_MV_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_RG_CTRL_DMA_EXT>;
+ clocks = <&topckgen CLK_TOP_VDEC_SEL>,
+ <&vdecsys CLK_VDEC_VDEC>,
+ <&vdecsys CLK_VDEC_LAT>,
+ <&vdecsys CLK_VDEC_LARB1>,
+ <&topckgen CLK_TOP_MAINPLL_D4>;
+ clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat",
+ "vdec-vdec", "vdec-top";
+ assigned-clocks = <&topckgen CLK_TOP_VDEC_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4>;
+ power-domains = <&spm MT8192_POWER_DOMAIN_VDEC2>;
+ };
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt
new file mode 100644
index 000000000000..e73682dc0c81
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt
@@ -0,0 +1,73 @@
+Mediatek Video Encoder
+
+Mediatek Video Encoder is the video encode hw present in Mediatek SoCs which
+supports high resolution encoding functionalities.
+
+Required properties:
+- compatible : must be one of the following string:
+ "mediatek,mt8173-vcodec-enc-vp8" for mt8173 vp8 encoder.
+ "mediatek,mt8173-vcodec-enc" for mt8173 avc encoder.
+ "mediatek,mt8183-vcodec-enc" for MT8183 encoder.
+ "mediatek,mt8192-vcodec-enc" for MT8192 encoder.
+- reg : Physical base address of the video encoder registers and length of
+ memory mapped region.
+- interrupts : interrupt number to the cpu.
+- mediatek,larb : must contain the local arbiters in the current Socs.
+- clocks : list of clock specifiers, corresponding to entries in
+ the clock-names property.
+- clock-names: avc encoder must contain "venc_sel", vp8 encoder must
+ contain "venc_lt_sel".
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+- dma-ranges : describes the dma address range space that the codec hw access.
+One of the two following nodes:
+- mediatek,vpu : the node of the video processor unit, if using VPU.
+- mediatek,scp : the node of the SCP unit, if using SCP.
+
+
+Example:
+
+vcodec_enc_avc: vcodec@18002000 {
+ compatible = "mediatek,mt8173-vcodec-enc";
+ reg = <0 0x18002000 0 0x1000>;
+ interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>;
+ iommus = <&iommu M4U_PORT_VENC_RCPU>,
+ <&iommu M4U_PORT_VENC_REC>,
+ <&iommu M4U_PORT_VENC_BSDMA>,
+ <&iommu M4U_PORT_VENC_SV_COMV>,
+ <&iommu M4U_PORT_VENC_RD_COMV>,
+ <&iommu M4U_PORT_VENC_CUR_LUMA>,
+ <&iommu M4U_PORT_VENC_CUR_CHROMA>,
+ <&iommu M4U_PORT_VENC_REF_LUMA>,
+ <&iommu M4U_PORT_VENC_REF_CHROMA>,
+ <&iommu M4U_PORT_VENC_NBM_RDMA>,
+ <&iommu M4U_PORT_VENC_NBM_WDMA>;
+ mediatek,larb = <&larb3>;
+ mediatek,vpu = <&vpu>;
+ clocks = <&topckgen CLK_TOP_VENC_SEL>;
+ clock-names = "venc_sel";
+ assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL>;
+ };
+
+vcodec_enc_vp8: vcodec@19002000 {
+ compatible = "mediatek,mt8173-vcodec-enc-vp8";
+ reg = <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */
+ interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_LOW>;
+ iommus = <&iommu M4U_PORT_VENC_RCPU_SET2>,
+ <&iommu M4U_PORT_VENC_REC_FRM_SET2>,
+ <&iommu M4U_PORT_VENC_BSDMA_SET2>,
+ <&iommu M4U_PORT_VENC_SV_COMA_SET2>,
+ <&iommu M4U_PORT_VENC_RD_COMA_SET2>,
+ <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>,
+ <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>,
+ <&iommu M4U_PORT_VENC_REF_LUMA_SET2>,
+ <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>;
+ mediatek,larb = <&larb5>;
+ mediatek,vpu = <&vpu>;
+ clocks = <&topckgen CLK_TOP_VENC_LT_SEL>;
+ clock-names = "venc_lt_sel";
+ assigned-clocks = <&topckgen CLK_TOP_VENC_LT_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL_370P5>;
+ };
--
2.18.0

2021-07-07 06:24:13

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 07/14] media: mtk-vcodec: Add msg queue feature for lat and core architecture

For lat and core architecture, lat thread will send message to core
thread when lat decode done. Core hardware will use the message
from lat to decode, then free message to lat thread when decode done.

Signed-off-by: Yunfei Dong <[email protected]>
---
drivers/media/platform/mtk-vcodec/Makefile | 1 +
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 15 ++
.../platform/mtk-vcodec/vdec_msg_queue.c | 234 ++++++++++++++++++
.../platform/mtk-vcodec/vdec_msg_queue.h | 130 ++++++++++
4 files changed, 380 insertions(+)
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
create mode 100644 drivers/media/platform/mtk-vcodec/vdec_msg_queue.h

diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
index edeb3b66e9e9..5000e59da576 100644
--- a/drivers/media/platform/mtk-vcodec/Makefile
+++ b/drivers/media/platform/mtk-vcodec/Makefile
@@ -11,6 +11,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
mtk_vcodec_dec_drv.o \
vdec_drv_if.o \
vdec_vpu_if.o \
+ vdec_msg_queue.o \
mtk_vcodec_dec.o \
mtk_vcodec_dec_stateful.o \
mtk_vcodec_dec_stateless.o \
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 50c87bca3973..53a3bab0da52 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -17,7 +17,9 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
+
#include "mtk_vcodec_util.h"
+#include "vdec_msg_queue.h"

#define VDEC_HW_ACTIVE 0x10
#define VDEC_IRQ_CFG 0x11
@@ -284,6 +286,8 @@ struct vdec_pic_info {
* @decoded_frame_cnt: number of decoded frames
* @lock: protect variables accessed by V4L2 threads and worker thread such as
* mtk_video_dec_buf.
+ *
+ * @msg_queue: msg queue used to store lat buffer information.
*/
struct mtk_vcodec_ctx {
enum mtk_instance_type type;
@@ -331,6 +335,7 @@ struct mtk_vcodec_ctx {
int decoded_frame_cnt;
struct mutex lock;

+ struct vdec_msg_queue msg_queue;
};

enum mtk_chip {
@@ -464,6 +469,11 @@ struct mtk_vcodec_enc_pdata {
* comp_dev: component hardware device
* component_node: component node
* comp_idx: component index
+ *
+ * core_read: Wait queue used to signalize when core get useful lat buffer
+ * core_queue: List of V4L2 lat_buf
+ * core_lock: spin lock to protect the struct usage
+ * num_core: number of buffers ready to be processed
*/
struct mtk_vcodec_dev {
struct v4l2_device v4l2_dev;
@@ -506,6 +516,11 @@ struct mtk_vcodec_dev {
void *comp_dev[MTK_VDEC_HW_MAX];
struct device_node *component_node[MTK_VDEC_HW_MAX];
int comp_idx;
+
+ wait_queue_head_t core_read;
+ struct list_head core_queue;
+ spinlock_t core_lock;
+ int num_core;
};

static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
new file mode 100644
index 000000000000..9d684e5f051c
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <[email protected]>
+ */
+
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_drv.h"
+#include "vdec_msg_queue.h"
+
+#define VDEC_LAT_SLICE_HEADER_SZ (640 * 1024)
+#define VDEC_ERR_MAP_SZ_AVC ((8192 / 16) * (4352 / 16) / 8)
+
+static int vde_msg_queue_get_trans_size(int width, int height)
+{
+ if (width > 1920 || height > 1088)
+ return (30 * 1024 * 1024);
+ else
+ return 6 * 1024 * 1024;
+}
+
+int vdec_msg_queue_init(
+ struct mtk_vcodec_ctx *ctx,
+ struct vdec_msg_queue *msg_queue,
+ core_decode_cb_t core_decode,
+ int private_size)
+{
+ struct vdec_lat_buf *lat_buf;
+ int i, err;
+
+ init_waitqueue_head(&msg_queue->lat_read);
+ INIT_LIST_HEAD(&msg_queue->lat_queue);
+ spin_lock_init(&msg_queue->lat_lock);
+ msg_queue->num_lat = 0;
+
+ msg_queue->wdma_addr.size = vde_msg_queue_get_trans_size(
+ ctx->picinfo.buf_w, ctx->picinfo.buf_h);
+
+ err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
+ if (err) {
+ mtk_v4l2_err("failed to allocate wdma_addr buf");
+ return -ENOMEM;
+ }
+ msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr;
+ msg_queue->wdma_wptr_addr = msg_queue->wdma_addr.dma_addr;
+
+ for (i = 0; i < NUM_BUFFER_COUNT; i++) {
+ lat_buf = &msg_queue->lat_buf[i];
+
+ lat_buf->wdma_err_addr.size = VDEC_ERR_MAP_SZ_AVC;
+ err = mtk_vcodec_mem_alloc(ctx, &lat_buf->wdma_err_addr);
+ if (err) {
+ mtk_v4l2_err("failed to allocate wdma_err_addr buf[%d]", i);
+ return -ENOMEM;
+ }
+
+ lat_buf->slice_bc_addr.size = VDEC_LAT_SLICE_HEADER_SZ;
+ err = mtk_vcodec_mem_alloc(ctx, &lat_buf->slice_bc_addr);
+ if (err) {
+ mtk_v4l2_err("failed to allocate wdma_addr buf[%d]", i);
+ return -ENOMEM;
+ }
+
+ lat_buf->private_data = kzalloc(private_size, GFP_KERNEL);
+ if (!lat_buf->private_data) {
+ mtk_v4l2_err("failed to allocate private_data[%d]", i);
+ return -ENOMEM;
+ }
+
+ lat_buf->ctx = ctx;
+ lat_buf->core_decode = core_decode;
+ vdec_msg_queue_buf_to_lat(lat_buf);
+ }
+
+ msg_queue->init_done = true;
+ return 0;
+}
+
+struct vdec_lat_buf *vdec_msg_queue_get_lat_buf(
+ struct vdec_msg_queue *msg_queue)
+{
+ struct vdec_lat_buf *buf;
+ long timeout_jiff;
+ int ret;
+
+ spin_lock(&msg_queue->lat_lock);
+ if (list_empty(&msg_queue->lat_queue)) {
+ mtk_v4l2_debug(3, "lat queue is NULL, num_lat = %d", msg_queue->num_lat);
+ spin_unlock(&msg_queue->lat_lock);
+ timeout_jiff = msecs_to_jiffies(1500);
+ ret = wait_event_timeout(msg_queue->lat_read,
+ !list_empty(&msg_queue->lat_queue), timeout_jiff);
+ if (!ret)
+ return NULL;
+ spin_lock(&msg_queue->lat_lock);
+ }
+
+ buf = list_first_entry(&msg_queue->lat_queue, struct vdec_lat_buf,
+ lat_list);
+ list_del(&buf->lat_list);
+ msg_queue->num_lat--;
+
+ mtk_v4l2_debug(4, "lat num in msg queue = %d", msg_queue->num_lat);
+ mtk_v4l2_debug(3, "get lat(0x%p) trans(0x%llx) err:0x%llx slice(0x%llx)\n",
+ buf, msg_queue->wdma_addr.dma_addr,
+ buf->wdma_err_addr.dma_addr,
+ buf->slice_bc_addr.dma_addr);
+
+ spin_unlock(&msg_queue->lat_lock);
+ return buf;
+}
+
+struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
+ struct mtk_vcodec_dev *dev)
+{
+ struct vdec_lat_buf *buf;
+ int ret;
+
+ spin_lock(&dev->core_lock);
+ if (list_empty(&dev->core_queue)) {
+ mtk_v4l2_debug(3, "core queue is NULL, num_core = %d", dev->num_core);
+ spin_unlock(&dev->core_lock);
+ ret = wait_event_freezable(dev->core_read,
+ !list_empty(&dev->core_queue));
+ if (ret)
+ return NULL;
+ spin_lock(&dev->core_lock);
+ }
+
+ buf = list_first_entry(&dev->core_queue, struct vdec_lat_buf,
+ core_list);
+ mtk_v4l2_debug(3, "get core buf addr: (0x%p)", buf);
+ list_del(&buf->core_list);
+ dev->num_core--;
+ spin_unlock(&dev->core_lock);
+ return buf;
+}
+
+void vdec_msg_queue_buf_to_lat(struct vdec_lat_buf *buf)
+{
+ struct vdec_msg_queue *msg_queue = &buf->ctx->msg_queue;
+
+ spin_lock(&msg_queue->lat_lock);
+ list_add_tail(&buf->lat_list, &msg_queue->lat_queue);
+ msg_queue->num_lat++;
+ wake_up_all(&msg_queue->lat_read);
+ mtk_v4l2_debug(3, "queue buf addr: (0x%p) lat num = %d",
+ buf, msg_queue->num_lat);
+ spin_unlock(&msg_queue->lat_lock);
+}
+
+void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
+ struct vdec_lat_buf *buf)
+{
+ spin_lock(&dev->core_lock);
+ list_add_tail(&buf->core_list, &dev->core_queue);
+ dev->num_core++;
+ wake_up_all(&dev->core_read);
+ mtk_v4l2_debug(3, "queu buf addr: (0x%p)", buf);
+ spin_unlock(&dev->core_lock);
+}
+
+void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue,
+ uint64_t ube_rptr)
+{
+ spin_lock(&msg_queue->lat_lock);
+ msg_queue->wdma_rptr_addr = ube_rptr;
+ mtk_v4l2_debug(3, "update ube rprt (0x%llx)", ube_rptr);
+ spin_unlock(&msg_queue->lat_lock);
+}
+
+void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue,
+ uint64_t ube_wptr)
+{
+ spin_lock(&msg_queue->lat_lock);
+ msg_queue->wdma_wptr_addr = ube_wptr;
+ mtk_v4l2_debug(3, "update ube wprt: (0x%llx 0x%llx) offset: 0x%llx",
+ msg_queue->wdma_rptr_addr, msg_queue->wdma_wptr_addr, ube_wptr);
+ spin_unlock(&msg_queue->lat_lock);
+}
+
+bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
+{
+ long timeout_jiff;
+ int ret, i;
+
+ for (i = 0; i < NUM_BUFFER_COUNT + 2; i++) {
+ timeout_jiff = msecs_to_jiffies(1000);
+ ret = wait_event_timeout(msg_queue->lat_read,
+ msg_queue->num_lat == NUM_BUFFER_COUNT, timeout_jiff);
+ if (ret) {
+ mtk_v4l2_debug(3, "success to get lat buf: %d",
+ msg_queue->num_lat);
+ return true;
+ }
+ }
+
+ mtk_v4l2_err("failed with lat buf isn't full: %d",
+ msg_queue->num_lat);
+ return false;
+}
+
+void vdec_msg_queue_deinit(
+ struct mtk_vcodec_ctx *ctx,
+ struct vdec_msg_queue *msg_queue)
+{
+ struct vdec_lat_buf *lat_buf;
+ struct mtk_vcodec_mem *mem;
+ int i;
+
+ mem = &msg_queue->wdma_addr;
+ if (mem->va)
+ mtk_vcodec_mem_free(ctx, mem);
+ for (i = 0; i < NUM_BUFFER_COUNT; i++) {
+ lat_buf = &msg_queue->lat_buf[i];
+
+ mem = &lat_buf->wdma_err_addr;
+ if (mem->va)
+ mtk_vcodec_mem_free(ctx, mem);
+
+ mem = &lat_buf->slice_bc_addr;
+ if (mem->va)
+ mtk_vcodec_mem_free(ctx, mem);
+
+ if (lat_buf->private_data)
+ kfree(lat_buf->private_data);
+ }
+
+ msg_queue->init_done = false;
+}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
new file mode 100644
index 000000000000..62261702c464
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <[email protected]>
+ */
+
+#ifndef _VDEC_MSG_QUEUE_H_
+#define _VDEC_MSG_QUEUE_H_
+
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "mtk_vcodec_util.h"
+
+#define NUM_BUFFER_COUNT 3
+
+struct vdec_lat_buf;
+struct mtk_vcodec_ctx;
+struct mtk_vcodec_dev;
+typedef int (*core_decode_cb_t)(struct vdec_lat_buf *lat_buf);
+
+/**
+ * struct vdec_lat_buf - lat buffer message used to store lat
+ * info for core decode
+ */
+struct vdec_lat_buf {
+ struct mtk_vcodec_mem wdma_err_addr;
+ struct mtk_vcodec_mem slice_bc_addr;
+ struct vb2_v4l2_buffer ts_info;
+
+ void *private_data;
+ struct mtk_vcodec_ctx *ctx;
+ core_decode_cb_t core_decode;
+ struct list_head lat_list;
+ struct list_head core_list;
+};
+
+/**
+ * struct vdec_msg_queue - used to store lat buffer message
+ */
+struct vdec_msg_queue {
+ struct vdec_lat_buf lat_buf[NUM_BUFFER_COUNT];
+
+ struct mtk_vcodec_mem wdma_addr;
+ uint64_t wdma_rptr_addr;
+ uint64_t wdma_wptr_addr;
+
+ wait_queue_head_t lat_read;
+ struct list_head lat_queue;
+ spinlock_t lat_lock;
+ int num_lat;
+ bool init_done;
+};
+
+/**
+ * vdec_msg_queue_init - init lat buffer information.
+ * @ctx: v4l2 ctx
+ * @msg_queue: used to store the lat buffer information
+ * @core_decode: core decode callback for each codec
+ * @private_size: the private data size used to share with core
+ */
+int vdec_msg_queue_init(
+ struct mtk_vcodec_ctx *ctx,
+ struct vdec_msg_queue *msg_queue,
+ core_decode_cb_t core_decode,
+ int private_size);
+
+/**
+ * vdec_msg_queue_get_lat_buf - get used lat buffer for core decode.
+ * @msg_queue: used to store the lat buffer information
+ */
+struct vdec_lat_buf *vdec_msg_queue_get_lat_buf(
+ struct vdec_msg_queue *msg_queue);
+
+/**
+ * vdec_msg_queue_get_core_buf - get used core buffer for lat decode.
+ * @dev: mtk vcodec device
+ */
+struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
+ struct mtk_vcodec_dev *dev);
+
+/**
+ * vdec_msg_queue_buf_to_core - queue buf to the core for core decode.
+ * @dev: mtk vcodec device
+ * @buf: current lat buffer
+ */
+void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
+ struct vdec_lat_buf *buf);
+
+/**
+ * vdec_msg_queue_buf_to_lat - queue buf to lat for lat decode.
+ * @buf: current lat buffer
+ */
+void vdec_msg_queue_buf_to_lat(struct vdec_lat_buf *buf);
+
+/**
+ * vdec_msg_queue_update_ube_rptr - used to updata the ube read point.
+ * @msg_queue: used to store the lat buffer information
+ * @ube_rptr: current ube read point
+ */
+void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue,
+ uint64_t ube_rptr);
+
+/**
+ * vdec_msg_queue_update_ube_wptr - used to updata the ube write point.
+ * @msg_queue: used to store the lat buffer information
+ * @ube_wptr: current ube write point
+ */
+void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue,
+ uint64_t ube_wptr);
+
+/**
+ * vdec_msg_queue_wait_lat_buf_full - used to check whether all lat buffer
+ * in lat list.
+ * @msg_queue: used to store the lat buffer information
+ */
+bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue);
+
+/**
+ * vdec_msg_queue_deinit - deinit lat buffer information.
+ * @ctx: v4l2 ctx
+ * @msg_queue: used to store the lat buffer information
+ */
+void vdec_msg_queue_deinit(
+ struct mtk_vcodec_ctx *ctx,
+ struct vdec_msg_queue *msg_queue);
+
+#endif
--
2.18.0

2021-07-07 06:24:33

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 13/14] media: mtk-vcodec: Add core dec and dec end ipi msg

Add core dec and dec end ipi msg: AP_IPIMSG_DEC_CORE/AP_IPIMSG_DEC_CORE_END.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../media/platform/mtk-vcodec/vdec_ipi_msg.h | 4 ++++
.../media/platform/mtk-vcodec/vdec_vpu_if.c | 12 ++++++++++++
.../media/platform/mtk-vcodec/vdec_vpu_if.h | 18 ++++++++++++++++++
3 files changed, 34 insertions(+)

diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
index 5f45a537beb4..9d8079c4f976 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -18,12 +18,16 @@ enum vdec_ipi_msgid {
AP_IPIMSG_DEC_END = 0xA002,
AP_IPIMSG_DEC_DEINIT = 0xA003,
AP_IPIMSG_DEC_RESET = 0xA004,
+ AP_IPIMSG_DEC_CORE = 0xA005,
+ AP_IPIMSG_DEC_CORE_END = 0xA006,

VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
VPU_IPIMSG_DEC_START_ACK = 0xB001,
VPU_IPIMSG_DEC_END_ACK = 0xB002,
VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
+ VPU_IPIMSG_DEC_CORE_ACK = 0xB005,
+ VPU_IPIMSG_DEC_CORE_END_ACK = 0xB006,
};

/**
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
index 5dffc459a33d..bfd8e87dceff 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -85,6 +85,8 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
case VPU_IPIMSG_DEC_END_ACK:
case VPU_IPIMSG_DEC_DEINIT_ACK:
case VPU_IPIMSG_DEC_RESET_ACK:
+ case VPU_IPIMSG_DEC_CORE_ACK:
+ case VPU_IPIMSG_DEC_CORE_END_ACK:
break;

default:
@@ -191,11 +193,21 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len)
return err;
}

+int vpu_dec_core(struct vdec_vpu_inst *vpu)
+{
+ return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE);
+}
+
int vpu_dec_end(struct vdec_vpu_inst *vpu)
{
return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END);
}

+int vpu_dec_core_end(struct vdec_vpu_inst *vpu)
+{
+ return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE_END);
+}
+
int vpu_dec_deinit(struct vdec_vpu_inst *vpu)
{
return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT);
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
index c2ed5b6cab8b..ae24b75d1649 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -82,4 +82,22 @@ int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
*/
int vpu_dec_reset(struct vdec_vpu_inst *vpu);

+/**
+ * vpu_dec_core - core start decoding, basically the function will be invoked once
+ * every frame.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ */
+int vpu_dec_core(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_core_end - core end decoding, basically the function will be invoked once
+ * when core HW decoding done and receive interrupt successfully. The
+ * decoder in VPU will updata hardware information and deinit hardware
+ * and check if there is a new decoded frame available to display.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ */
+int vpu_dec_core_end(struct vdec_vpu_inst *vpu);
+
#endif
--
2.18.0

2021-07-07 06:24:33

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 12/14] dt-bindings: media: mtk-vcodec: Adds decoder dt-bindings for mt8192

Adds decoder dt-bindings for mt8192.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../media/mediatek-vcodec-comp-decoder.txt | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt

diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt
new file mode 100644
index 000000000000..941428cb2f08
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt
@@ -0,0 +1,93 @@
+Mediatek Video Decoder With Component
+
+Mediatek Video Decoder is the video decode hw present in Mediatek SoCs which
+supports high resolution decoding functionalities. Required master and
+component node properties:
+
+Master properties:
+- compatible :
+ "mediatek,mt8192-vcodec-dec" for MT8192 decoder.
+- reg : Physical base address of the video decoder registers and length of
+ memory mapped region.
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+- mediatek,scp : the node of the SCP unit, if using SCP.
+
+component properties(core and lat):
+- compatible(core) : "mediatek,mtk-vcodec-core" core hardware decoder
+ "mediatek,mtk-vcodec-core" for core hardware decoder.
+- compatible(lat) : "mediatek,mtk-vcodec-lat" lat hardware decoder
+ "mediatek,mtk-vcodec-lat" for lat hardware decoder.
+- reg : Physical base address of the video decoder registers and length of
+ memory mapped region.
+- interrupts : interrupt number to the cpu.
+- clocks : list of clock specifiers, corresponding to entries in
+ the clock-names property.
+- clock-names: decoder must contain "vcodecpll", "univpll_d2",
+ "clk_cci400_sel", "vdec_sel", "vdecpll", "vencpll", "venc_lt_sel",
+ "vdec_bus_clk_src".
+- iommus : should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+- dma-ranges : describes how the physical address space of the IOMMU maps
+ to memory.
+
+vcodec_dec: vcodec_dec@16000000 {
+ compatible = "mediatek,mt8192-vcodec-dec";
+ reg = <0 0x16000000 0 0x1000>; /* VDEC_SYS */
+ mediatek,scp = <&scp>;
+ iommus = <&iommu0 M4U_PORT_L4_VDEC_MC_EXT>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ };
+
+vcodec_lat: vcodec_lat@0x16010000 {
+ compatible = "mediatek,mtk-vcodec-lat";
+ reg = <0 0x16010000 0 0x800>; /* VDEC_MISC */
+ interrupts = <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH 0>;
+ iommus = <&iommu0 M4U_PORT_L5_VDEC_LAT0_VLD_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_VLD2_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_AVC_MV_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_PRED_RD_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_TILE_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_WDMA_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_LAT0_RG_CTRL_DMA_EXT>,
+ <&iommu0 M4U_PORT_L5_VDEC_UFO_ENC_EXT>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ clocks = <&topckgen CLK_TOP_VDEC_SEL>,
+ <&vdecsys_soc CLK_VDEC_SOC_VDEC>,
+ <&vdecsys_soc CLK_VDEC_SOC_LAT>,
+ <&vdecsys_soc CLK_VDEC_SOC_LARB1>,
+ <&topckgen CLK_TOP_MAINPLL_D4>;
+ clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat", "vdec-vdec", "vdec-top";
+ assigned-clocks = <&topckgen CLK_TOP_VDEC_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4>;
+ power-domains = <&scpsys MT8192_POWER_DOMAIN_VDEC>;
+ };
+
+vcodec_core: vcodec_core@0x16025000 {
+ compatible = "mediatek,mtk-vcodec-core";
+ reg = <0 0x16025000 0 0x1000>; /* VDEC_CORE_MISC */
+ interrupts = <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH 0>;
+ iommus = <&iommu0 M4U_PORT_L4_VDEC_MC_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_UFO_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PP_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PRED_RD_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PRED_WR_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_PPWRAP_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_TILE_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_VLD_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_VLD2_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_AVC_MV_EXT>,
+ <&iommu0 M4U_PORT_L4_VDEC_RG_CTRL_DMA_EXT>;
+ dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+ clocks = <&topckgen CLK_TOP_VDEC_SEL>,
+ <&vdecsys CLK_VDEC_VDEC>,
+ <&vdecsys CLK_VDEC_LAT>,
+ <&vdecsys CLK_VDEC_LARB1>,
+ <&topckgen CLK_TOP_MAINPLL_D4>;
+ clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat", "vdec-vdec", "vdec-top";
+ assigned-clocks = <&topckgen CLK_TOP_VDEC_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D4>;
+ power-domains = <&scpsys MT8192_POWER_DOMAIN_VDEC2>;
+ };
--
2.18.0

2021-07-07 06:25:44

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 14/14] media: mtk-vcodec: Use codec type to separate different hardware

There are just one core thread, in order to separeate different
hardware, using codec type to separeate it in scp driver.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../media/platform/mtk-vcodec/vdec_ipi_msg.h | 12 ++++---
.../media/platform/mtk-vcodec/vdec_vpu_if.c | 34 ++++++++++++++++---
.../media/platform/mtk-vcodec/vdec_vpu_if.h | 4 +++
3 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
index 9d8079c4f976..c488f0c40190 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -35,6 +35,8 @@ enum vdec_ipi_msgid {
* @msg_id : vdec_ipi_msgid
* @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2.
* @inst_id : instance ID. Used if the ABI version >= 2.
+ * @codec_type : Codec fourcc
+ * @reserved : reserved param
*/
struct vdec_ap_ipi_cmd {
uint32_t msg_id;
@@ -42,6 +44,8 @@ struct vdec_ap_ipi_cmd {
uint32_t vpu_inst_addr;
uint32_t inst_id;
};
+ uint32_t codec_type;
+ uint32_t reserved;
};

/**
@@ -59,12 +63,12 @@ struct vdec_vpu_ipi_ack {
/**
* struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT
* @msg_id : AP_IPIMSG_DEC_INIT
- * @reserved : Reserved field
+ * @codec_type : Codec fourcc
* @ap_inst_addr : AP video decoder instance address
*/
struct vdec_ap_ipi_init {
uint32_t msg_id;
- uint32_t reserved;
+ uint32_t codec_type;
uint64_t ap_inst_addr;
};

@@ -77,7 +81,7 @@ struct vdec_ap_ipi_init {
* H264 decoder [0]:buf_sz [1]:nal_start
* VP8 decoder [0]:width/height
* VP9 decoder [0]:profile, [1][2] width/height
- * @reserved : Reserved field
+ * @codec_type : Codec fourcc
*/
struct vdec_ap_ipi_dec_start {
uint32_t msg_id;
@@ -86,7 +90,7 @@ struct vdec_ap_ipi_dec_start {
uint32_t inst_id;
};
uint32_t data[3];
- uint32_t reserved;
+ uint32_t codec_type;
};

/**
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
index bfd8e87dceff..c84fac52fe26 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -100,18 +100,29 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)

static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
{
- int err;
+ int err, id, msgid;

- mtk_vcodec_debug(vpu, "id=%X", *(uint32_t *)msg);
+ msgid = *(uint32_t *)msg;
+ mtk_vcodec_debug(vpu, "id=%X", msgid);

vpu->failure = 0;
vpu->signaled = 0;

- err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
+ if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
+ if (msgid == AP_IPIMSG_DEC_CORE ||
+ msgid == AP_IPIMSG_DEC_CORE_END)
+ id = vpu->core_id;
+ else
+ id = vpu->id;
+ } else {
+ id = vpu->id;
+ }
+
+ err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, id, msg,
len, 2000);
if (err) {
mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
- vpu->id, *(uint32_t *)msg, err);
+ id, msgid, err);
return err;
}

@@ -131,6 +142,7 @@ static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id)
msg.vpu_inst_addr = vpu->inst_addr;
else
msg.inst_id = vpu->inst_id;
+ msg.codec_type = vpu->codec_type;

err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg));
mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err);
@@ -149,14 +161,25 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu)

err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
vpu->handler, "vdec", NULL);
- if (err != 0) {
+ if (err) {
mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
return err;
}

+ if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
+ err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler,
+ vpu->core_id, vpu->handler,
+ "vdec", NULL);
+ if (err) {
+ mtk_vcodec_err(vpu, "vpu_ipi_register core fail status=%d", err);
+ return err;
+ }
+ }
+
memset(&msg, 0, sizeof(msg));
msg.msg_id = AP_IPIMSG_DEC_INIT;
msg.ap_inst_addr = (unsigned long)vpu;
+ msg.codec_type = vpu->codec_type;

mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu);

@@ -187,6 +210,7 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len)

for (i = 0; i < len; i++)
msg.data[i] = data[i];
+ msg.codec_type = vpu->codec_type;

err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
mtk_vcodec_debug(vpu, "- ret=%d", err);
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
index ae24b75d1649..802660770a87 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -14,6 +14,7 @@ struct mtk_vcodec_ctx;
/**
* struct vdec_vpu_inst - VPU instance for video codec
* @id : ipi msg id for each decoder
+ * @core_id : core id used to separate different hardware
* @vsi : driver structure allocated by VPU side and shared to AP side
* for control and info share
* @failure : VPU execution result status, 0: success, others: fail
@@ -26,9 +27,11 @@ struct mtk_vcodec_ctx;
* @dev : platform device of VPU
* @wq : wait queue to wait VPU message ack
* @handler : ipi handler for each decoder
+ * @codec_type : used codec type to separate different codecs
*/
struct vdec_vpu_inst {
int id;
+ int core_id;
void *vsi;
int32_t failure;
uint32_t inst_addr;
@@ -38,6 +41,7 @@ struct vdec_vpu_inst {
struct mtk_vcodec_ctx *ctx;
wait_queue_head_t wq;
mtk_vcodec_ipi_handler handler;
+ unsigned int codec_type;
};

/**
--
2.18.0

2021-07-07 06:27:55

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: [PATCH v1, 02/14] media: mtk-vcodec: Refactor vcodec pm interface

Using the needed param for pm init/release function and remove unused
param mtkdev in 'struct mtk_vcodec_pm'.

Signed-off-by: Yunfei Dong <[email protected]>
---
.../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 6 ++---
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 22 ++++++++-----------
.../platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 5 +++--
.../platform/mtk-vcodec/mtk_vcodec_drv.h | 1 -
.../platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 1 -
5 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index d3f34cd04759..8d7ba881ef75 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -257,7 +257,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
if (IS_ERR(dev->fw_handler))
return PTR_ERR(dev->fw_handler);

- ret = mtk_vcodec_init_dec_pm(dev);
+ ret = mtk_vcodec_init_dec_pm(dev->plat_dev, &dev->pm);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
goto err_dec_pm;
@@ -387,7 +387,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_res:
- mtk_vcodec_release_dec_pm(dev);
+ mtk_vcodec_release_dec_pm(&dev->pm);
err_dec_pm:
mtk_vcodec_fw_release(dev->fw_handler);
return ret;
@@ -430,7 +430,7 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev)
video_unregister_device(dev->vfd_dec);

v4l2_device_unregister(&dev->v4l2_dev);
- mtk_vcodec_release_dec_pm(dev);
+ mtk_vcodec_release_dec_pm(&dev->pm);
mtk_vcodec_fw_release(dev->fw_handler);
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
index 6038db96f71c..20bd157a855c 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -13,18 +13,15 @@
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vcodec_util.h"

-int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
+int mtk_vcodec_init_dec_pm(struct platform_device *pdev,
+ struct mtk_vcodec_pm *pm)
{
struct device_node *node;
- struct platform_device *pdev;
- struct mtk_vcodec_pm *pm;
+ struct platform_device *larb_pdev;
struct mtk_vcodec_clk *dec_clk;
struct mtk_vcodec_clk_info *clk_info;
int i = 0, ret = 0;

- pdev = mtkdev->plat_dev;
- pm = &mtkdev->pm;
- pm->mtkdev = mtkdev;
dec_clk = &pm->vdec_clk;
node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0);
if (!node) {
@@ -32,13 +29,12 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
return -1;
}

- pdev = of_find_device_by_node(node);
+ larb_pdev = of_find_device_by_node(node);
of_node_put(node);
- if (WARN_ON(!pdev)) {
+ if (WARN_ON(!larb_pdev)) {
return -1;
}
- pm->larbvdec = &pdev->dev;
- pdev = mtkdev->plat_dev;
+ pm->larbvdec = &larb_pdev->dev;
pm->dev = &pdev->dev;

dec_clk->clk_num =
@@ -82,10 +78,10 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
return ret;
}

-void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
+void mtk_vcodec_release_dec_pm(struct mtk_vcodec_pm *pm)
{
- pm_runtime_disable(dev->pm.dev);
- put_device(dev->pm.larbvdec);
+ pm_runtime_disable(pm->dev);
+ put_device(pm->larbvdec);
}

int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
index 280aeaefdb65..a3df6aef6cb9 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -9,8 +9,9 @@

#include "mtk_vcodec_drv.h"

-int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
-void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
+int mtk_vcodec_init_dec_pm(struct platform_device *pdev,
+ struct mtk_vcodec_pm *pm);
+void mtk_vcodec_release_dec_pm(struct mtk_vcodec_pm *pm);

int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index d4f840a7bbcb..19296fd41c31 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -195,7 +195,6 @@ struct mtk_vcodec_pm {
struct mtk_vcodec_clk venc_clk;
struct device *larbvenc;
struct device *dev;
- struct mtk_vcodec_dev *mtkdev;
};

/**
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 1b2e4930ed27..0c8c8f86788c 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -26,7 +26,6 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
pdev = mtkdev->plat_dev;
pm = &mtkdev->pm;
memset(pm, 0, sizeof(struct mtk_vcodec_pm));
- pm->mtkdev = mtkdev;
pm->dev = &pdev->dev;
dev = &pdev->dev;
enc_clk = &pm->venc_clk;
--
2.18.0

2021-07-08 10:05:43

by Tzung-Bi Shih

[permalink] [raw]
Subject: Re: [PATCH v1, 03/14] media: mtk-vcodec: Use component framework to manage each hardware information

On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> +#include "mtk_vcodec_util.h"
> +
> #include <media/videobuf2-core.h>
> +#include <media/v4l2-ctrls.h>
> #include <media/v4l2-mem2mem.h>
The changes look like independent ones. If any .c files need the
headers, include them in the .c files instead of here.

> + comp_node = of_find_compatible_node(NULL, NULL,
> + mtk_vdec_drv_ids[i].compatible);
> + if (!comp_node)
> + continue;
> +
> + if (!of_device_is_available(comp_node)) {
> + of_node_put(comp_node);
> + dev_err(&pdev->dev, "Fail to get MMSYS node\n");
> + continue;
> + }
> +
> + of_id = of_match_node(mtk_vdec_drv_ids, comp_node);
> + if (!of_id) {
Doesn't it need to call of_node_put(comp_node)?

> +static int mtk_vcodec_init_master(struct mtk_vcodec_dev *dev)
> +{
> + struct platform_device *pdev = dev->plat_dev;
> + struct component_match *match;
> + int ret = 0;
ret doesn't need to be initialized.

> + match = mtk_vcodec_match_add(dev);
> + if (IS_ERR_OR_NULL(match))
> + return -EINVAL;
> +
> + platform_set_drvdata(pdev, dev);
Why does platform_set_drvdata() need to be here? The function neither
creates pdev nor dev.

> +static int mtk_vcodec_init_dec_params(struct mtk_vcodec_dev *dev)
> +{
> + struct platform_device *pdev = dev->plat_dev;
> + struct resource *res;
> + int ret = 0;
ret doesn't need to be initialized.

> + if (!dev->is_support_comp) {
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (res == NULL) {
!res, res is not used BTW.

> + dev->dec_irq = platform_get_irq(dev->plat_dev, 0);
Check return value.

> + irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
> + ret = devm_request_irq(&pdev->dev, dev->dec_irq,
> + mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to install dev->dec_irq %d (%d)",
> + dev->dec_irq,
> + ret);
Can join to previous line.

> + if (!of_find_compatible_node(NULL, NULL, "mediatek,mtk-vcodec-core"))
> + dev->is_support_comp = false;
> + else
> + dev->is_support_comp = true;
Need a DT binding document patch for the attribute.

Does it really need to call of_find_compatible_node() for parsing an
attribute? If so, it needs to call of_node_put() afterward.

> @@ -319,7 +434,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
> MTK_VCODEC_DEC_NAME);
> video_set_drvdata(vfd_dec, dev);
> dev->vfd_dec = vfd_dec;
> - platform_set_drvdata(pdev, dev);
Why does it need to remove platform_set_drvdata()?

> @@ -370,8 +484,17 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
> mtk_v4l2_debug(0, "decoder registered as /dev/video%d",
> vfd_dec->num);
>
> - return 0;
> + if (dev->is_support_comp) {
> + ret = mtk_vcodec_init_master(dev);
> + if (ret < 0)
> + goto err_component_match;
> + } else {
> + platform_set_drvdata(pdev, dev);
> + }
mtk_vcodec_init_master() also calls platform_set_drvdata(). What is
the difference?

> + /* clear interrupt */
> + writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG), vdec_misc_addr);
> + writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR), vdec_misc_addr);
Can remove 1 parenthese pair.

> +static int mtk_vdec_comp_probe(struct platform_device *pdev)
> +{
> + struct mtk_vdec_comp_dev *dev;
> + int ret;
> +
> + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
> + if (!dev)
> + return -ENOMEM;
> +
> + dev->plat_dev = pdev;
> + spin_lock_init(&dev->irqlock);
> +
> + ret = mtk_vcodec_init_dec_pm(dev->plat_dev, &dev->pm);
To be concise, use pdev.

> + dev->reg_base[VDEC_COMP_MISC] =
> + devm_platform_ioremap_resource(pdev, 0);
Confusing about the index 0, where:
VDEC_COMP_SYS = 0
VDEC_COMP_MISC = 1

> +#ifndef _MTK_VCODEC_DEC_HW_H_
> +#define _MTK_VCODEC_DEC_HW_H_
> +
> +#include <linux/component.h>
Does it really need to include component.h?

> +/**
> + * enum mtk_comp_hw_reg_idx - component register base index
> + */
> +enum mtk_comp_hw_reg_idx {
> + VDEC_COMP_SYS,
> + VDEC_COMP_MISC,
> + NUM_MAX_COMP_VCODEC_REG_BASE
The name is suboptimal. How about VDEC_COMP_MAX or VDEC_COMP_LAST?

> +#include <linux/component.h>
> +#include <linux/io.h>
> #include <linux/platform_device.h>
> #include <linux/videodev2.h>
> #include <media/v4l2-ctrls.h>
The newly added code in the file doesn't look like it needs anything
from component.h and io.h.

> @@ -404,6 +422,7 @@ struct mtk_vcodec_enc_pdata {
> *
> * @fw_handler: used to communicate with the firmware.
> * @id_counter: used to identify current opened instance
> + * @is_support_comp: 1: using compoent framework, 0: not support
is_support_comp is a boolean. Use true and false instead of 1 and 0.

> @@ -422,6 +441,10 @@ struct mtk_vcodec_enc_pdata {
> * @pm: power management control
> * @dec_capability: used to identify decode capability, ex: 4k
> * @enc_capability: used to identify encode capability
> + *
> + * comp_dev: component hardware device
> + * component_node: component node
> + * comp_idx: component index
To be neat, missing "@" before each symbol name.

2021-07-08 10:06:08

by Tzung-Bi Shih

[permalink] [raw]
Subject: Re: [PATCH v1, 04/14] dt-bindings: media: mtk-vcodec: Separate video encoder and decoder dt-bindings

On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> .../media/mediatek-vcodec-decoder.txt | 169 ++++++++++++++++++
> .../media/mediatek-vcodec-encoder.txt | 73 ++++++++
> 2 files changed, 242 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
> create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt
The patch is weird. Its title says "separate" but the changes are all
creating new content.

Would expect the patch to remove content from some files (e.g.
Documentation/devicetree/bindings/media/mediatek-vcodec.txt) and
separate into 2 files.

Also would expect the patch is a refactor which shouldn't introduce
any new things.

2021-07-09 08:04:43

by Tzung-Bi Shih

[permalink] [raw]
Subject: Re: [PATCH v1, 06/14] media: mtk-vcodec: Add irq interface for core hardware

On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> +static int mtk_vcodec_get_hw_count(struct mtk_vcodec_dev *dev)
> +{
> + if (dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE)
> + return 1;
> + else if (dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE)
> + return 2;
> + else
> + return 0;
> +}
Use a switch .. case .. would be easier to read.

Would it be better to use some macro or enums for the magic numbers?

> @@ -113,8 +114,7 @@ static int mtk_vdec_comp_init_irq(struct mtk_vdec_comp_dev *dev)
> }
>
> ret = devm_request_irq(&pdev->dev, dev->dec_irq,
> - mtk_vdec_comp_irq_handler,
> - 0, pdev->name, dev);
> + mtk_vdec_comp_irq_handler, 0, pdev->name, dev);
The change is irrelevant to this patch.

> @@ -154,8 +154,10 @@ static int mtk_vdec_comp_probe(struct platform_device *pdev)
> dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
>
> ret = mtk_vdec_comp_init_irq(dev);
> - if (ret)
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to register irq handler.\n");
> goto err;
> + }
The change shouldn't be in this patch. Instead, another patch that
adds the mtk_vdec_comp_init_irq() invocation.

> +int mtk_vcodec_wait_for_comp_done_ctx(struct mtk_vcodec_ctx *ctx,
Remove the extra space before "*ctx".

2021-07-09 09:40:18

by Tzung-Bi Shih

[permalink] [raw]
Subject: Re: [PATCH v1, 07/14] media: mtk-vcodec: Add msg queue feature for lat and core architecture

On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> @@ -464,6 +469,11 @@ struct mtk_vcodec_enc_pdata {
> * comp_dev: component hardware device
> * component_node: component node
> * comp_idx: component index
> + *
> + * core_read: Wait queue used to signalize when core get useful lat buffer
> + * core_queue: List of V4L2 lat_buf
To be neat, replace "Wait" to "wait" and "List" to "list".

> +int vdec_msg_queue_init(
> + struct mtk_vcodec_ctx *ctx,
> + struct vdec_msg_queue *msg_queue,
> + core_decode_cb_t core_decode,
> + int private_size)
> +{
> + struct vdec_lat_buf *lat_buf;
> + int i, err;
> +
> + init_waitqueue_head(&msg_queue->lat_read);
> + INIT_LIST_HEAD(&msg_queue->lat_queue);
> + spin_lock_init(&msg_queue->lat_lock);
> + msg_queue->num_lat = 0;
> +
> + msg_queue->wdma_addr.size = vde_msg_queue_get_trans_size(
> + ctx->picinfo.buf_w, ctx->picinfo.buf_h);
> +
> + err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
> + if (err) {
> + mtk_v4l2_err("failed to allocate wdma_addr buf");
> + return -ENOMEM;
> + }
> + msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr;
> + msg_queue->wdma_wptr_addr = msg_queue->wdma_addr.dma_addr;
> +
> + for (i = 0; i < NUM_BUFFER_COUNT; i++) {
> + lat_buf = &msg_queue->lat_buf[i];
> +
> + lat_buf->wdma_err_addr.size = VDEC_ERR_MAP_SZ_AVC;
> + err = mtk_vcodec_mem_alloc(ctx, &lat_buf->wdma_err_addr);
> + if (err) {
> + mtk_v4l2_err("failed to allocate wdma_err_addr buf[%d]", i);
> + return -ENOMEM;
> + }
> +
> + lat_buf->slice_bc_addr.size = VDEC_LAT_SLICE_HEADER_SZ;
> + err = mtk_vcodec_mem_alloc(ctx, &lat_buf->slice_bc_addr);
> + if (err) {
> + mtk_v4l2_err("failed to allocate wdma_addr buf[%d]", i);
> + return -ENOMEM;
> + }
> +
> + lat_buf->private_data = kzalloc(private_size, GFP_KERNEL);
> + if (!lat_buf->private_data) {
> + mtk_v4l2_err("failed to allocate private_data[%d]", i);
> + return -ENOMEM;
> + }
> +
> + lat_buf->ctx = ctx;
> + lat_buf->core_decode = core_decode;
> + vdec_msg_queue_buf_to_lat(lat_buf);
> + }
Doesn't it need to call mtk_vcodec_mem_free() and kfree() for any failure paths?

> +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> + struct mtk_vcodec_dev *dev)
> +{
> + struct vdec_lat_buf *buf;
> + int ret;
> +
> + spin_lock(&dev->core_lock);
> + if (list_empty(&dev->core_queue)) {
> + mtk_v4l2_debug(3, "core queue is NULL, num_core = %d", dev->num_core);
> + spin_unlock(&dev->core_lock);
> + ret = wait_event_freezable(dev->core_read,
> + !list_empty(&dev->core_queue));
> + if (ret)
> + return NULL;
Should be !ret?

> +void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
> + struct vdec_lat_buf *buf)
> +{
> + spin_lock(&dev->core_lock);
> + list_add_tail(&buf->core_list, &dev->core_queue);
> + dev->num_core++;
> + wake_up_all(&dev->core_read);
> + mtk_v4l2_debug(3, "queu buf addr: (0x%p)", buf);
Typo.

> +bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
> +{
> + long timeout_jiff;
> + int ret, i;
> +
> + for (i = 0; i < NUM_BUFFER_COUNT + 2; i++) {
> + timeout_jiff = msecs_to_jiffies(1000);
> + ret = wait_event_timeout(msg_queue->lat_read,
> + msg_queue->num_lat == NUM_BUFFER_COUNT, timeout_jiff);
> + if (ret) {
> + mtk_v4l2_debug(3, "success to get lat buf: %d",
> + msg_queue->num_lat);
> + return true;
> + }
> + }
Why does it need the loop? i is unused.

> +void vdec_msg_queue_deinit(
> + struct mtk_vcodec_ctx *ctx,
> + struct vdec_msg_queue *msg_queue)
> +{
> + struct vdec_lat_buf *lat_buf;
> + struct mtk_vcodec_mem *mem;
> + int i;
> +
> + mem = &msg_queue->wdma_addr;
> + if (mem->va)
> + mtk_vcodec_mem_free(ctx, mem);
> + for (i = 0; i < NUM_BUFFER_COUNT; i++) {
> + lat_buf = &msg_queue->lat_buf[i];
> +
> + mem = &lat_buf->wdma_err_addr;
> + if (mem->va)
> + mtk_vcodec_mem_free(ctx, mem);
> +
> + mem = &lat_buf->slice_bc_addr;
> + if (mem->va)
> + mtk_vcodec_mem_free(ctx, mem);
> +
> + if (lat_buf->private_data)
> + kfree(lat_buf->private_data);
> + }
> +
> + msg_queue->init_done = false;
Have no idea what init_done does in the code. It is not included in
any branch condition.

> +/**
> + * vdec_msg_queue_init - init lat buffer information.
> + * @ctx: v4l2 ctx
> + * @msg_queue: used to store the lat buffer information
> + * @core_decode: core decode callback for each codec
> + * @private_size: the private data size used to share with core
> + */
> +int vdec_msg_queue_init(
> + struct mtk_vcodec_ctx *ctx,
> + struct vdec_msg_queue *msg_queue,
> + core_decode_cb_t core_decode,
> + int private_size);
Would prefer to have *msg_queue as the first argument (also applies to
all operators of vdec_msg_queue).

> +/**
> + * vdec_msg_queue_get_core_buf - get used core buffer for lat decode.
> + * @dev: mtk vcodec device
> + */
> +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> + struct mtk_vcodec_dev *dev);
This is weird: vdec_msg_queue's operator but manipulating mtk_vcodec_dev?

> +
> +/**
> + * vdec_msg_queue_buf_to_core - queue buf to the core for core decode.
> + * @dev: mtk vcodec device
> + * @buf: current lat buffer
> + */
> +void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
> + struct vdec_lat_buf *buf);
Also weird.

> +/**
> + * vdec_msg_queue_buf_to_lat - queue buf to lat for lat decode.
> + * @buf: current lat buffer
> + */
> +void vdec_msg_queue_buf_to_lat(struct vdec_lat_buf *buf);
It should at least accept a struct vdec_msg_queue argument (or which
msg queue should the buf put into?).

> +/**
> + * vdec_msg_queue_update_ube_rptr - used to updata the ube read point.
Typo.

> +/**
> + * vdec_msg_queue_update_ube_wptr - used to updata the ube write point.
Typo.

> +/**
> + * vdec_msg_queue_deinit - deinit lat buffer information.
> + * @ctx: v4l2 ctx
> + * @msg_queue: used to store the lat buffer information
> + */
> +void vdec_msg_queue_deinit(
> + struct mtk_vcodec_ctx *ctx,
> + struct vdec_msg_queue *msg_queue);
Would prefer to have *msg_queue as the first argument.


The position of struct vdec_msg_queue is weird. It looks like the msg
queue is only for struct vdec_lat_buf. If so, would vdec_msg_queue be
better to call vdec_lat_queue or something similar?

It shouldn't touch the core queue in mtk_vcodec_dev anyway. Is it
possible to generalize the queue-related code for both lat and core
queues?

2021-07-12 08:15:15

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: Re: [PATCH v1, 07/14] media: mtk-vcodec: Add msg queue feature for lat and core architecture

Hi Tzung-Bi,

Thanks for your detail feedback.
I add the description according to your each comments.

On Fri, 2021-07-09 at 17:39 +0800, Tzung-Bi Shih wrote:
> On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> > @@ -464,6 +469,11 @@ struct mtk_vcodec_enc_pdata {
> > * comp_dev: component hardware device
> > * component_node: component node
> > * comp_idx: component index
> > + *
> > + * core_read: Wait queue used to signalize when core get useful lat buffer
> > + * core_queue: List of V4L2 lat_buf
> To be neat, replace "Wait" to "wait" and "List" to "list".
Will fix.
> > +int vdec_msg_queue_init(
> > + struct mtk_vcodec_ctx *ctx,
> > + struct vdec_msg_queue *msg_queue,
> > + core_decode_cb_t core_decode,
> > + int private_size)
> > +{
> > + struct vdec_lat_buf *lat_buf;
> > + int i, err;
> > +
> > + init_waitqueue_head(&msg_queue->lat_read);
> > + INIT_LIST_HEAD(&msg_queue->lat_queue);
> > + spin_lock_init(&msg_queue->lat_lock);
> > + msg_queue->num_lat = 0;
> > +
> > + msg_queue->wdma_addr.size = vde_msg_queue_get_trans_size(
> > + ctx->picinfo.buf_w, ctx->picinfo.buf_h);
> > +
> > + err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
> > + if (err) {
> > + mtk_v4l2_err("failed to allocate wdma_addr buf");
> > + return -ENOMEM;
> > + }
> > + msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr;
> > + msg_queue->wdma_wptr_addr = msg_queue->wdma_addr.dma_addr;
> > +
> > + for (i = 0; i < NUM_BUFFER_COUNT; i++) {
> > + lat_buf = &msg_queue->lat_buf[i];
> > +
> > + lat_buf->wdma_err_addr.size = VDEC_ERR_MAP_SZ_AVC;
> > + err = mtk_vcodec_mem_alloc(ctx, &lat_buf->wdma_err_addr);
> > + if (err) {
> > + mtk_v4l2_err("failed to allocate wdma_err_addr buf[%d]", i);
> > + return -ENOMEM;
> > + }
> > +
> > + lat_buf->slice_bc_addr.size = VDEC_LAT_SLICE_HEADER_SZ;
> > + err = mtk_vcodec_mem_alloc(ctx, &lat_buf->slice_bc_addr);
> > + if (err) {
> > + mtk_v4l2_err("failed to allocate wdma_addr buf[%d]", i);
> > + return -ENOMEM;
> > + }
> > +
> > + lat_buf->private_data = kzalloc(private_size, GFP_KERNEL);
> > + if (!lat_buf->private_data) {
> > + mtk_v4l2_err("failed to allocate private_data[%d]", i);
> > + return -ENOMEM;
> > + }
> > +
> > + lat_buf->ctx = ctx;
> > + lat_buf->core_decode = core_decode;
> > + vdec_msg_queue_buf_to_lat(lat_buf);
> > + }
> Doesn't it need to call mtk_vcodec_mem_free() and kfree() for any failure paths?
When allocate memory fail, will call deinit function auto, then free all allocated memory.
> > +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> > + struct mtk_vcodec_dev *dev)
> > +{
> > + struct vdec_lat_buf *buf;
> > + int ret;
> > +
> > + spin_lock(&dev->core_lock);
> > + if (list_empty(&dev->core_queue)) {
> > + mtk_v4l2_debug(3, "core queue is NULL, num_core = %d", dev->num_core);
> > + spin_unlock(&dev->core_lock);
> > + ret = wait_event_freezable(dev->core_read,
> > + !list_empty(&dev->core_queue));
> > + if (ret)
> > + return NULL;
> Should be !ret?
According the definidtion, when condition is true, return value is 0.
#define wait_event_freezable(wq_head, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_freezable(wq_head, condition); \
__ret; \
})
> > +void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
> > + struct vdec_lat_buf *buf)
> > +{
> > + spin_lock(&dev->core_lock);
> > + list_add_tail(&buf->core_list, &dev->core_queue);
> > + dev->num_core++;
> > + wake_up_all(&dev->core_read);
> > + mtk_v4l2_debug(3, "queu buf addr: (0x%p)", buf);
> Typo.
>
> > +bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
> > +{
> > + long timeout_jiff;
> > + int ret, i;
> > +
> > + for (i = 0; i < NUM_BUFFER_COUNT + 2; i++) {
> > + timeout_jiff = msecs_to_jiffies(1000);
> > + ret = wait_event_timeout(msg_queue->lat_read,
> > + msg_queue->num_lat == NUM_BUFFER_COUNT, timeout_jiff);
> > + if (ret) {
> > + mtk_v4l2_debug(3, "success to get lat buf: %d",
> > + msg_queue->num_lat);
> > + return true;
> > + }
> > + }
> Why does it need the loop? i is unused.
Core maybe decode timeout, need to wait all core buffer process
completely.
> > +void vdec_msg_queue_deinit(
> > + struct mtk_vcodec_ctx *ctx,
> > + struct vdec_msg_queue *msg_queue)
> > +{
> > + struct vdec_lat_buf *lat_buf;
> > + struct mtk_vcodec_mem *mem;
> > + int i;
> > +
> > + mem = &msg_queue->wdma_addr;
> > + if (mem->va)
> > + mtk_vcodec_mem_free(ctx, mem);
> > + for (i = 0; i < NUM_BUFFER_COUNT; i++) {
> > + lat_buf = &msg_queue->lat_buf[i];
> > +
> > + mem = &lat_buf->wdma_err_addr;
> > + if (mem->va)
> > + mtk_vcodec_mem_free(ctx, mem);
> > +
> > + mem = &lat_buf->slice_bc_addr;
> > + if (mem->va)
> > + mtk_vcodec_mem_free(ctx, mem);
> > +
> > + if (lat_buf->private_data)
> > + kfree(lat_buf->private_data);
> > + }
> > +
> > + msg_queue->init_done = false;
> Have no idea what init_done does in the code. It is not included in
> any branch condition.
When call vdec_msg_queue_init will set this parameter to true.
> > +/**
> > + * vdec_msg_queue_init - init lat buffer information.
> > + * @ctx: v4l2 ctx
> > + * @msg_queue: used to store the lat buffer information
> > + * @core_decode: core decode callback for each codec
> > + * @private_size: the private data size used to share with core
> > + */
> > +int vdec_msg_queue_init(
> > + struct mtk_vcodec_ctx *ctx,
> > + struct vdec_msg_queue *msg_queue,
> > + core_decode_cb_t core_decode,
> > + int private_size);
> Would prefer to have *msg_queue as the first argument (also applies to
> all operators of vdec_msg_queue).
Can fix.
> > +/**
> > + * vdec_msg_queue_get_core_buf - get used core buffer for lat decode.
> > + * @dev: mtk vcodec device
> > + */
> > +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> > + struct mtk_vcodec_dev *dev);
> This is weird: vdec_msg_queue's operator but manipulating mtk_vcodec_dev?
vdec_msg_queue is used to share message between lat and core, for each
instance has its lat msg queue list, but all instance share one core msg
queue list. When try to get core buffer need to get it from core queue
list. Then queue it to lat queue list when core decode done.
> > +
> > +/**
> > + * vdec_msg_queue_buf_to_core - queue buf to the core for core decode.
> > + * @dev: mtk vcodec device
> > + * @buf: current lat buffer
> > + */
> > +void vdec_msg_queue_buf_to_core(struct mtk_vcodec_dev *dev,
> > + struct vdec_lat_buf *buf);
> Also weird.
>
> > +/**
> > + * vdec_msg_queue_buf_to_lat - queue buf to lat for lat decode.
> > + * @buf: current lat buffer
> > + */
> > +void vdec_msg_queue_buf_to_lat(struct vdec_lat_buf *buf);
> It should at least accept a struct vdec_msg_queue argument (or which
> msg queue should the buf put into?).
All buffer is struct vdec_lat_buf, used to share info between lat and core queue list.
> > +/**
> > + * vdec_msg_queue_update_ube_rptr - used to updata the ube read point.
> Typo.
>
> > +/**
> > + * vdec_msg_queue_update_ube_wptr - used to updata the ube write point.
> Typo.
>
> > +/**
> > + * vdec_msg_queue_deinit - deinit lat buffer information.
> > + * @ctx: v4l2 ctx
> > + * @msg_queue: used to store the lat buffer information
> > + */
> > +void vdec_msg_queue_deinit(
> > + struct mtk_vcodec_ctx *ctx,
> > + struct vdec_msg_queue *msg_queue);
> Would prefer to have *msg_queue as the first argument.
Yes, can fix.
>
> The position of struct vdec_msg_queue is weird. It looks like the msg
> queue is only for struct vdec_lat_buf. If so, would vdec_msg_queue be
> better to call vdec_lat_queue or something similar?
>
> It shouldn't touch the core queue in mtk_vcodec_dev anyway. Is it
> possible to generalize the queue-related code for both lat and core
> queues?
Lat queue list is separately for each instance, but only has one core
queue list.

2021-07-12 09:06:17

by Yunfei Dong (董云飞)

[permalink] [raw]
Subject: Re: [PATCH v1, 06/14] media: mtk-vcodec: Add irq interface for core hardware

Hi Tzung-Bi,

Thanks for your detail feedback.
I add the description according to your each comments.

On Fri, 2021-07-09 at 15:59 +0800, Tzung-Bi Shih wrote:
> On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> > +static int mtk_vcodec_get_hw_count(struct mtk_vcodec_dev *dev)
> > +{
> > + if (dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE)
> > + return 1;
> > + else if (dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE)
> > + return 2;
> > + else
> > + return 0;
> > +}
> Use a switch .. case .. would be easier to read.
Yes
> Would it be better to use some macro or enums for the magic numbers?
Yes, add enums for magic numbers.
enum mtk_vdec_hw_count {
MTK_VDEC_NO_HW = 0,
MTK_VDEC_ONE_CORE,
MTK_VDEC_ONE_LAT_ONE_CORE,
MTK_VDEC_MAX_HW_COUNT,
};
> > @@ -113,8 +114,7 @@ static int mtk_vdec_comp_init_irq(struct mtk_vdec_comp_dev *dev)
> > }
> >
> > ret = devm_request_irq(&pdev->dev, dev->dec_irq,
> > - mtk_vdec_comp_irq_handler,
> > - 0, pdev->name, dev);
> > + mtk_vdec_comp_irq_handler, 0, pdev->name, dev);
> The change is irrelevant to this patch.
Will fix.
> > @@ -154,8 +154,10 @@ static int mtk_vdec_comp_probe(struct platform_device *pdev)
> > dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
> >
> > ret = mtk_vdec_comp_init_irq(dev);
> > - if (ret)
> > + if (ret) {
> > + dev_err(&pdev->dev, "Failed to register irq handler.\n");
> > goto err;
> > + }
> The change shouldn't be in this patch. Instead, another patch that
> adds the mtk_vdec_comp_init_irq() invocation.
>
> > +int mtk_vcodec_wait_for_comp_done_ctx(struct mtk_vcodec_ctx *ctx,
> Remove the extra space before "*ctx".
Wil fix.

2021-07-13 08:56:13

by Tzung-Bi Shih

[permalink] [raw]
Subject: Re: [PATCH v1, 07/14] media: mtk-vcodec: Add msg queue feature for lat and core architecture

On Mon, Jul 12, 2021 at 3:28 PM mtk12024 <[email protected]> wrote:
> On Fri, 2021-07-09 at 17:39 +0800, Tzung-Bi Shih wrote:
> > On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> > Doesn't it need to call mtk_vcodec_mem_free() and kfree() for any failure paths?
> When allocate memory fail, will call deinit function auto, then free all allocated memory.
I guess you mean: if vdec_msg_queue_init() fails,
vdec_msg_queue_deinit() should be called?

If so:
- It is not "auto". It depends on callers to invoke _deinit() if _init() fails.
- The API usage would be a bit weird: if the object hasn't been
initialized, shall we de-initialize it?

> > > +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> > > + struct mtk_vcodec_dev *dev)
> > > +{
> > > + struct vdec_lat_buf *buf;
> > > + int ret;
> > > +
> > > + spin_lock(&dev->core_lock);
> > > + if (list_empty(&dev->core_queue)) {
> > > + mtk_v4l2_debug(3, "core queue is NULL, num_core = %d", dev->num_core);
> > > + spin_unlock(&dev->core_lock);
> > > + ret = wait_event_freezable(dev->core_read,
> > > + !list_empty(&dev->core_queue));
> > > + if (ret)
> > > + return NULL;
> > Should be !ret?
> According the definidtion, when condition is true, return value is 0.
Yeah, you're right. I was confused a bit with wait_event_timeout().

> > > +bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
> > > +{
> > > + long timeout_jiff;
> > > + int ret, i;
> > > +
> > > + for (i = 0; i < NUM_BUFFER_COUNT + 2; i++) {
> > > + timeout_jiff = msecs_to_jiffies(1000);
> > > + ret = wait_event_timeout(msg_queue->lat_read,
> > > + msg_queue->num_lat == NUM_BUFFER_COUNT, timeout_jiff);
> > > + if (ret) {
> > > + mtk_v4l2_debug(3, "success to get lat buf: %d",
> > > + msg_queue->num_lat);
> > > + return true;
> > > + }
> > > + }
> > Why does it need the loop? i is unused.
> Core maybe decode timeout, need to wait all core buffer process
> completely.
The point is: the i is unused. If it needs more time to complete,
could it just wait for (NUM_BUFFER_COUNT + 2) * 1000 msecs?

> > > + msg_queue->init_done = false;
> > Have no idea what init_done does in the code. It is not included in
> > any branch condition.
> When call vdec_msg_queue_init will set this parameter to true.
The point is: if init_done doesn't change any code branch but just a
flag, does it really need the flag?

For example usages:
- If see the msg_queue->init_done has already been set to true in
vdec_msg_queue_init(), return errors.
- If see the msg_queue->init_done has already been set to false in
vdec_msg_queue_deinit(), return errors.

In the cases, I believe it brings very limited benefit (i.e. the
msg_queue is likely to _init and _deinit only once).

> > > +/**
> > > + * vdec_msg_queue_get_core_buf - get used core buffer for lat decode.
> > > + * @dev: mtk vcodec device
> > > + */
> > > +struct vdec_lat_buf *vdec_msg_queue_get_core_buf(
> > > + struct mtk_vcodec_dev *dev);
> > This is weird: vdec_msg_queue's operator but manipulating mtk_vcodec_dev?
> vdec_msg_queue is used to share message between lat and core, for each
> instance has its lat msg queue list, but all instance share one core msg
> queue list. When try to get core buffer need to get it from core queue
> list. Then queue it to lat queue list when core decode done.
I guess you mean: during runtime, it has n lat queues and 1 core queue.

If so, would it be intuitive and simple by:

msg_queue *core_q;
msg_queue *lat_q[LAT_N];

vdec_msg_queue_dequeue(core_q) if it wants to get from core queue.
vdec_msg_queue_enqueue(lat_q[X], data) if it wants to put data to lat queue X.

> > > +/**
> > > + * vdec_msg_queue_buf_to_lat - queue buf to lat for lat decode.
> > > + * @buf: current lat buffer
> > > + */
> > > +void vdec_msg_queue_buf_to_lat(struct vdec_lat_buf *buf);
> > It should at least accept a struct vdec_msg_queue argument (or which
> > msg queue should the buf put into?).
> All buffer is struct vdec_lat_buf, used to share info between lat and core queue list.
The API semantic needs to provide a way to specify which msg_queue the
buf would put into.

> > The position of struct vdec_msg_queue is weird. It looks like the msg
> > queue is only for struct vdec_lat_buf. If so, would vdec_msg_queue be
> > better to call vdec_lat_queue or something similar?
> >
> > It shouldn't touch the core queue in mtk_vcodec_dev anyway. Is it
> > possible to generalize the queue-related code for both lat and core
> > queues?
> Lat queue list is separately for each instance, but only has one core
> queue list.
Suggested to generalize the vdec_msg_queue to handle both lat and core
(and maybe furthermore). See comment above.

2021-07-15 00:26:39

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v1, 04/14] dt-bindings: media: mtk-vcodec: Separate video encoder and decoder dt-bindings

On Thu, Jul 08, 2021 at 06:04:54PM +0800, Tzung-Bi Shih wrote:
> On Wed, Jul 7, 2021 at 2:22 PM Yunfei Dong <[email protected]> wrote:
> > .../media/mediatek-vcodec-decoder.txt | 169 ++++++++++++++++++
> > .../media/mediatek-vcodec-encoder.txt | 73 ++++++++
> > 2 files changed, 242 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-decoder.txt
> > create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-encoder.txt
> The patch is weird. Its title says "separate" but the changes are all
> creating new content.
>
> Would expect the patch to remove content from some files (e.g.
> Documentation/devicetree/bindings/media/mediatek-vcodec.txt) and
> separate into 2 files.

Except h/w doesn't change. Using the component framework is not a reason
to change bindings.

Also, note that any major changes or additions should be in schema
format now.

Rob

2021-07-15 01:35:01

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v1, 12/14] dt-bindings: media: mtk-vcodec: Adds decoder dt-bindings for mt8192

On Wed, Jul 07, 2021 at 02:21:55PM +0800, Yunfei Dong wrote:
> Adds decoder dt-bindings for mt8192.
>
> Signed-off-by: Yunfei Dong <[email protected]>
> ---
> .../media/mediatek-vcodec-comp-decoder.txt | 93 +++++++++++++++++++
> 1 file changed, 93 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/mediatek-vcodec-comp-decoder.txt

Bindings are in schema format now.

Rob