lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ