[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250210090725.4580-5-nas.chung@chipsnmedia.com>
Date: Mon, 10 Feb 2025 18:07:21 +0900
From: Nas Chung <nas.chung@...psnmedia.com>
To: mchehab@...nel.org,
hverkuil@...all.nl,
sebastian.fricke@...labora.com,
robh@...nel.org,
krzk+dt@...nel.org,
conor+dt@...nel.org
Cc: linux-media@...r.kernel.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-imx@....com,
linux-arm-kernel@...ts.infradead.org,
jackson.lee@...psnmedia.com,
lafley.kim@...psnmedia.com,
Nas Chung <nas.chung@...psnmedia.com>
Subject: [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver
Chips&Media Wave6 stateful codec driver.
The codec driver provides encoding and decoding capabilities
for H.264, HEVC, and other video formats.
Signed-off-by: Nas Chung <nas.chung@...psnmedia.com>
---
drivers/media/platform/chips-media/Kconfig | 1 +
drivers/media/platform/chips-media/Makefile | 1 +
.../media/platform/chips-media/wave6/Kconfig | 26 +
.../media/platform/chips-media/wave6/Makefile | 17 +
.../platform/chips-media/wave6/wave6-vpu.c | 487 ++++++++++++++++++
.../platform/chips-media/wave6/wave6-vpu.h | 106 ++++
6 files changed, 638 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig
create mode 100644 drivers/media/platform/chips-media/wave6/Makefile
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h
diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig
index ad350eb6b1fc..8ef7fc8029a4 100644
--- a/drivers/media/platform/chips-media/Kconfig
+++ b/drivers/media/platform/chips-media/Kconfig
@@ -4,3 +4,4 @@ comment "Chips&Media media platform drivers"
source "drivers/media/platform/chips-media/coda/Kconfig"
source "drivers/media/platform/chips-media/wave5/Kconfig"
+source "drivers/media/platform/chips-media/wave6/Kconfig"
diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile
index 6b5d99de8b54..b9a07a91c9d6 100644
--- a/drivers/media/platform/chips-media/Makefile
+++ b/drivers/media/platform/chips-media/Makefile
@@ -2,3 +2,4 @@
obj-y += coda/
obj-y += wave5/
+obj-y += wave6/
diff --git a/drivers/media/platform/chips-media/wave6/Kconfig b/drivers/media/platform/chips-media/wave6/Kconfig
new file mode 100644
index 000000000000..0f45581ff273
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_WAVE6_VPU
+ tristate "Chips&Media Wave6 Codec Driver"
+ depends on V4L_MEM2MEM_DRIVERS
+ depends on VIDEO_DEV && OF
+ depends on ARCH_MXC || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ select GENERIC_ALLOCATOR
+ help
+ Chips&Media Wave6 stateful codec driver.
+ The codec driver provides encoding and decoding capabilities
+ for H.264, HEVC, and other video formats.
+ To compile this driver as modules, choose M here: the
+ modules will be called wave6.
+
+config VIDEO_WAVE6_VPU_CTRL
+ tristate "Chips&Media Wave6 Codec Control Driver"
+ depends on VIDEO_WAVE6_VPU
+ default VIDEO_WAVE6_VPU if ARCH_MXC || COMPILE_TEST
+ help
+ Chips&Media Wave6 control driver.
+ The control driver manages shared resources such as firmware
+ access and power domains and clock.
+ To compile this driver as modules, choose M here: the
+ modules will be called wave6-ctrl.
diff --git a/drivers/media/platform/chips-media/wave6/Makefile b/drivers/media/platform/chips-media/wave6/Makefile
new file mode 100644
index 000000000000..c2180406c193
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# tell define_trace.h where to find the trace header
+CFLAGS_wave6-vpu.o := -I$(src)
+
+wave6-ctrl-objs += wave6-vpu-ctrl.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU_CTRL) += wave6-ctrl.o
+
+wave6-objs += wave6-vpu.o \
+ wave6-vpu-v4l2.o \
+ wave6-vpu-dbg.o \
+ wave6-vdi.o \
+ wave6-vpuapi.o \
+ wave6-vpu-dec.o \
+ wave6-vpu-enc.o \
+ wave6-hw.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU) += wave6.o
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.c b/drivers/media/platform/chips-media/wave6/wave6-vpu.c
new file mode 100644
index 000000000000..470d22489ecc
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 codec driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
+#include <linux/debugfs.h>
+#include "wave6-vpu.h"
+#include "wave6-regdefine.h"
+#include "wave6-vpuconfig.h"
+#include "wave6-hw.h"
+#include "wave6-vpu-ctrl.h"
+#include "wave6-vpu-dbg.h"
+
+#define CREATE_TRACE_POINTS
+#include "wave6-trace.h"
+
+#define VPU_PLATFORM_DEVICE_NAME "wave6-vpu"
+#define VPU_CLK_NAME "vcodec"
+#define WAVE6_VPU_DEBUGFS_DIR "wave6"
+
+#define WAVE6_IS_ENC BIT(0)
+#define WAVE6_IS_DEC BIT(1)
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+
+struct wave6_match_data {
+ int codec_types;
+ u32 compatible_fw_version;
+};
+
+static const struct wave6_match_data wave633c_data = {
+ .codec_types = WAVE6_IS_ENC | WAVE6_IS_DEC,
+ .compatible_fw_version = 0x3000000,
+};
+
+unsigned int wave6_vpu_debug(void)
+{
+ return debug;
+}
+
+static void wave6_vpu_get_clk(struct vpu_device *vpu_dev)
+{
+ int i;
+
+ if (!vpu_dev || !vpu_dev->num_clks || vpu_dev->clk_vpu)
+ return;
+
+ for (i = 0; i < vpu_dev->num_clks; i++) {
+ if (vpu_dev->clks[i].id && !strcmp(vpu_dev->clks[i].id, "vpu")) {
+ vpu_dev->clk_vpu = vpu_dev->clks[i].clk;
+ return;
+ }
+ }
+
+ vpu_dev->clk_vpu = vpu_dev->clks[0].clk;
+}
+
+static irqreturn_t wave6_vpu_irq(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
+ u32 irq_status;
+
+ if (wave6_vdi_readl(dev, W6_VPU_VPU_INT_STS)) {
+ irq_status = wave6_vdi_readl(dev, W6_VPU_VINT_REASON);
+
+ wave6_vdi_writel(dev, W6_VPU_VINT_REASON_CLR, irq_status);
+ wave6_vdi_writel(dev, W6_VPU_VINT_CLEAR, 0x1);
+
+ trace_irq(dev, irq_status);
+
+ kfifo_in(&dev->irq_status, &irq_status, sizeof(int));
+
+ return IRQ_WAKE_THREAD;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wave6_vpu_irq_thread(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
+ struct vpu_instance *inst;
+ int irq_status, ret;
+
+ while (kfifo_len(&dev->irq_status)) {
+ bool error = false;
+
+ ret = kfifo_out(&dev->irq_status, &irq_status, sizeof(int));
+ if (!ret)
+ break;
+
+ if (irq_status & BIT(W6_INT_BIT_REQ_WORK_BUF)) {
+ if (!dev->ctrl)
+ continue;
+
+ wave6_vpu_ctrl_require_buffer(dev->ctrl, &dev->entity);
+ continue;
+ }
+
+ if ((irq_status & BIT(W6_INT_BIT_INIT_SEQ)) ||
+ (irq_status & BIT(W6_INT_BIT_ENC_SET_PARAM))) {
+ complete(&dev->irq_done);
+ continue;
+ }
+
+ if (irq_status & BIT(W6_INT_BIT_BSBUF_ERROR))
+ error = true;
+
+ inst = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (inst)
+ inst->ops->finish_process(inst, error);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static u32 wave6_vpu_read_reg(struct device *dev, u32 addr)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ return wave6_vdi_readl(vpu_dev, addr);
+}
+
+static void wave6_vpu_write_reg(struct device *dev, u32 addr, u32 data)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ wave6_vdi_writel(vpu_dev, addr, data);
+}
+
+static void wave6_vpu_on_boot(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ u32 product_code;
+ u32 version;
+ u32 revision;
+ u32 hw_version;
+ int ret;
+
+ product_code = wave6_vdi_readl(vpu_dev, W6_VPU_RET_PRODUCT_VERSION);
+
+ wave6_vpu_enable_interrupt(vpu_dev);
+ ret = wave6_vpu_get_version(vpu_dev, &version, &revision);
+ if (ret) {
+ dev_err(dev, "wave6_vpu_get_version fail\n");
+ return;
+ }
+
+ hw_version = wave6_vdi_readl(vpu_dev, W6_RET_CONF_REVISION);
+
+ if (vpu_dev->product_code != product_code ||
+ vpu_dev->fw_version != version ||
+ vpu_dev->fw_revision != revision ||
+ vpu_dev->hw_version != hw_version) {
+ vpu_dev->product_code = product_code;
+ vpu_dev->fw_version = version;
+ vpu_dev->fw_revision = revision;
+ vpu_dev->hw_version = hw_version;
+ dev_info(dev, "product: %08x, fw_version : %d.%d.%d(r%d), hw_version : 0x%x\n",
+ vpu_dev->product_code,
+ (version >> 24) & 0xFF,
+ (version >> 16) & 0xFF,
+ (version >> 0) & 0xFFFF,
+ revision,
+ vpu_dev->hw_version);
+ }
+
+ if (vpu_dev->res->compatible_fw_version > version)
+ dev_err(dev, "compatible firmware version is v%d.%d.%d or higher, but only v%d.%d.%d\n",
+ (vpu_dev->res->compatible_fw_version >> 24) & 0xFF,
+ (vpu_dev->res->compatible_fw_version >> 16) & 0xFF,
+ vpu_dev->res->compatible_fw_version & 0xFFFF,
+ (version >> 24) & 0xFF,
+ (version >> 16) & 0xFF,
+ version & 0xFFFF);
+
+ wave6_vpu_get_clk(vpu_dev);
+}
+
+void wave6_vpu_pause(struct device *dev, int resume)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ mutex_lock(&vpu_dev->pause_lock);
+ if (resume) {
+ vpu_dev->pause_request--;
+ if (!vpu_dev->pause_request)
+ v4l2_m2m_resume(vpu_dev->m2m_dev);
+ } else {
+ if (!vpu_dev->pause_request)
+ v4l2_m2m_suspend(vpu_dev->m2m_dev);
+ vpu_dev->pause_request++;
+ }
+ mutex_unlock(&vpu_dev->pause_lock);
+}
+
+void wave6_vpu_activate(struct vpu_device *dev)
+{
+ dev->active = true;
+}
+
+void wave6_vpu_wait_activated(struct vpu_device *dev)
+{
+ wave6_vpu_check_state(dev);
+}
+
+static int wave6_vpu_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct vpu_device *dev;
+ const struct wave6_match_data *match_data;
+ struct device_node *np;
+ struct platform_device *pctrl;
+
+ match_data = device_get_match_data(&pdev->dev);
+ if (!match_data) {
+ dev_err(&pdev->dev, "missing match_data\n");
+ return -EINVAL;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "dma_set_mask_and_coherent failed: %d\n", ret);
+ return ret;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mutex_init(&dev->dev_lock);
+ mutex_init(&dev->hw_lock);
+ mutex_init(&dev->pause_lock);
+ init_completion(&dev->irq_done);
+ dev_set_drvdata(&pdev->dev, dev);
+ dev->dev = &pdev->dev;
+ dev->res = match_data;
+
+ dev->entity.dev = dev->dev;
+ dev->entity.read_reg = wave6_vpu_read_reg;
+ dev->entity.write_reg = wave6_vpu_write_reg;
+ dev->entity.on_boot = wave6_vpu_on_boot;
+ dev->entity.pause = wave6_vpu_pause;
+
+ dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dev->reg_base))
+ return PTR_ERR(dev->reg_base);
+
+ np = of_parse_phandle(pdev->dev.of_node, "cnm,ctrl", 0);
+ if (np) {
+ pctrl = of_find_device_by_node(np);
+ of_node_put(np);
+ if (pctrl) {
+ dev->ctrl = &pctrl->dev;
+ if (wave6_vpu_ctrl_get_state(dev->ctrl) < 0) {
+ dev_info(&pdev->dev, "vpu ctrl is not ready, defer probe\n");
+ return -EPROBE_DEFER;
+ }
+ } else {
+ dev_info(&pdev->dev, "vpu ctrl is not found\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "unable to get clocks: %d\n", ret);
+ ret = 0;
+ }
+ dev->num_clks = ret;
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "v4l2_device_register fail: %d\n", ret);
+ return ret;
+ }
+
+ ret = wave6_vpu_init_m2m_dev(dev);
+ if (ret)
+ goto err_v4l2_unregister;
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ ret = -ENXIO;
+ goto err_m2m_dev_release;
+ }
+
+ if (kfifo_alloc(&dev->irq_status, 16 * sizeof(int), GFP_KERNEL)) {
+ dev_err(&pdev->dev, "failed to allocate fifo\n");
+ goto err_m2m_dev_release;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, dev->irq, wave6_vpu_irq,
+ wave6_vpu_irq_thread, 0, "vpu_irq", dev);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to register interrupt handler: %d\n", ret);
+ goto err_kfifo_free;
+ }
+
+ dev->temp_vbuf.size = ALIGN(WAVE6_TEMPBUF_SIZE, 4096);
+ ret = wave6_alloc_dma(dev->dev, &dev->temp_vbuf);
+ if (ret) {
+ dev_err(&pdev->dev, "alloc temp of size %zu failed\n",
+ dev->temp_vbuf.size);
+ goto err_kfifo_free;
+ }
+
+ dev->debugfs = debugfs_lookup(WAVE6_VPU_DEBUGFS_DIR, NULL);
+ if (IS_ERR_OR_NULL(dev->debugfs))
+ dev->debugfs = debugfs_create_dir(WAVE6_VPU_DEBUGFS_DIR, NULL);
+
+ pm_runtime_enable(&pdev->dev);
+
+ if (dev->res->codec_types & WAVE6_IS_DEC) {
+ ret = wave6_vpu_dec_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave6_vpu_dec_register_device fail: %d\n", ret);
+ goto err_temp_vbuf_free;
+ }
+ }
+ if (dev->res->codec_types & WAVE6_IS_ENC) {
+ ret = wave6_vpu_enc_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave6_vpu_enc_register_device fail: %d\n", ret);
+ goto err_dec_unreg;
+ }
+ }
+
+ if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
+ wave6_vpu_activate(dev);
+ ret = pm_runtime_resume_and_get(dev->dev);
+ if (ret)
+ goto err_enc_unreg;
+ }
+
+ dev_dbg(&pdev->dev, "Added wave6 driver with caps %s %s\n",
+ dev->res->codec_types & WAVE6_IS_ENC ? "'ENCODE'" : "",
+ dev->res->codec_types & WAVE6_IS_DEC ? "'DECODE'" : "");
+
+ return 0;
+
+err_enc_unreg:
+ if (dev->res->codec_types & WAVE6_IS_ENC)
+ wave6_vpu_enc_unregister_device(dev);
+err_dec_unreg:
+ if (dev->res->codec_types & WAVE6_IS_DEC)
+ wave6_vpu_dec_unregister_device(dev);
+err_temp_vbuf_free:
+ wave6_free_dma(&dev->temp_vbuf);
+err_kfifo_free:
+ kfifo_free(&dev->irq_status);
+err_m2m_dev_release:
+ wave6_vpu_release_m2m_dev(dev);
+err_v4l2_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return ret;
+}
+
+static void wave6_vpu_remove(struct platform_device *pdev)
+{
+ struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
+
+ if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put_sync(&pdev->dev);
+ }
+ pm_runtime_disable(&pdev->dev);
+
+ wave6_vpu_enc_unregister_device(dev);
+ wave6_vpu_dec_unregister_device(dev);
+ wave6_free_dma(&dev->temp_vbuf);
+ kfifo_free(&dev->irq_status);
+ wave6_vpu_release_m2m_dev(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+static int wave6_vpu_runtime_suspend(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ if (!vpu_dev)
+ return -ENODEV;
+
+ dprintk(dev, "runtime suspend\n");
+ if (vpu_dev->ctrl && vpu_dev->active)
+ wave6_vpu_ctrl_put_sync(vpu_dev->ctrl, &vpu_dev->entity);
+ if (vpu_dev->num_clks)
+ clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
+
+ return 0;
+}
+
+static int wave6_vpu_runtime_resume(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (!vpu_dev)
+ return -ENODEV;
+
+ dprintk(dev, "runtime resume\n");
+ if (vpu_dev->num_clks) {
+ ret = clk_bulk_prepare_enable(vpu_dev->num_clks, vpu_dev->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (vpu_dev->ctrl && vpu_dev->active) {
+ ret = wave6_vpu_ctrl_resume_and_get(vpu_dev->ctrl, &vpu_dev->entity);
+ if (ret && vpu_dev->num_clks)
+ clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
+ } else {
+ wave6_vpu_check_state(vpu_dev);
+ }
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int wave6_vpu_suspend(struct device *dev)
+{
+ int ret;
+
+ dprintk(dev, "suspend\n");
+ wave6_vpu_pause(dev, 0);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ wave6_vpu_pause(dev, 1);
+
+ return ret;
+}
+
+static int wave6_vpu_resume(struct device *dev)
+{
+ int ret;
+
+ dprintk(dev, "resume\n");
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ wave6_vpu_pause(dev, 1);
+ return 0;
+}
+#endif
+static const struct dev_pm_ops wave6_vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend, wave6_vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_suspend, wave6_vpu_resume)
+};
+
+static const struct of_device_id wave6_dt_ids[] = {
+ { .compatible = "nxp,imx95-wave633c", .data = &wave633c_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wave6_dt_ids);
+
+static struct platform_driver wave6_vpu_driver = {
+ .driver = {
+ .name = VPU_PLATFORM_DEVICE_NAME,
+ .of_match_table = of_match_ptr(wave6_dt_ids),
+ .pm = &wave6_vpu_pm_ops,
+ },
+ .probe = wave6_vpu_probe,
+ .remove = wave6_vpu_remove,
+};
+
+module_platform_driver(wave6_vpu_driver);
+MODULE_DESCRIPTION("chips&media VPU V4L2 driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.h b/drivers/media/platform/chips-media/wave6/wave6-vpu.h
new file mode 100644
index 000000000000..51cda07863a4
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 codec driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPU_H__
+#define __WAVE6_VPU_H__
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include "wave6-vpuconfig.h"
+#include "wave6-vpuapi.h"
+
+struct vpu_buffer {
+ struct v4l2_m2m_buffer v4l2_m2m_buf;
+ bool consumed;
+ bool used;
+ bool error;
+ bool force_key_frame;
+ bool force_frame_qp;
+ u32 force_i_frame_qp;
+ u32 force_p_frame_qp;
+ u32 force_b_frame_qp;
+ ktime_t ts_input;
+ ktime_t ts_start;
+ ktime_t ts_finish;
+ ktime_t ts_output;
+ u64 hw_time;
+ u32 average_qp;
+};
+
+enum vpu_fmt_type {
+ VPU_FMT_TYPE_CODEC = 0,
+ VPU_FMT_TYPE_RAW = 1
+};
+
+struct vpu_format {
+ unsigned int v4l2_pix_fmt;
+ unsigned int max_width;
+ unsigned int min_width;
+ unsigned int max_height;
+ unsigned int min_height;
+ unsigned int num_planes;
+};
+
+static inline struct vpu_instance *wave6_to_vpu_inst(struct v4l2_fh *vfh)
+{
+ return container_of(vfh, struct vpu_instance, v4l2_fh);
+}
+
+static inline struct vpu_instance *wave6_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl)
+{
+ return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl);
+}
+
+static inline struct vpu_buffer *wave6_to_vpu_buf(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct vpu_buffer, v4l2_m2m_buf.vb);
+}
+
+static inline bool wave6_vpu_both_queues_are_streaming(struct vpu_instance *inst)
+{
+ struct vb2_queue *vq_cap = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx);
+ struct vb2_queue *vq_out = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx);
+
+ return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out);
+}
+
+u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst);
+u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst);
+void wave6_vpu_pause(struct device *dev, int resume);
+void wave6_vpu_activate(struct vpu_device *dev);
+void wave6_vpu_wait_activated(struct vpu_device *dev);
+void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ unsigned int width,
+ unsigned int height);
+struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct vpu_instance *inst,
+ dma_addr_t addr);
+dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf,
+ unsigned int plane_no);
+enum codec_std wave6_to_codec_std(enum vpu_instance_type type, unsigned int v4l2_pix_fmt);
+const char *wave6_vpu_instance_state_name(u32 state);
+void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32 state);
+u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle);
+int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout);
+int wave6_vpu_dec_register_device(struct vpu_device *dev);
+void wave6_vpu_dec_unregister_device(struct vpu_device *dev);
+int wave6_vpu_enc_register_device(struct vpu_device *dev);
+void wave6_vpu_enc_unregister_device(struct vpu_device *dev);
+void wave6_vpu_finish_job(struct vpu_instance *inst);
+void wave6_vpu_handle_performance(struct vpu_instance *inst, struct vpu_buffer *vpu_buf);
+void wave6_vpu_reset_performance(struct vpu_instance *inst);
+int wave6_vpu_init_m2m_dev(struct vpu_device *dev);
+void wave6_vpu_release_m2m_dev(struct vpu_device *dev);
+int wave6_vpu_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub);
+void wave6_vpu_return_buffers(struct vpu_instance *inst,
+ unsigned int type, enum vb2_buffer_state state);
+
+#endif /* __WAVE6_VPU_H__ */
--
2.31.1
Powered by blists - more mailing lists