Add the control driver for the Chips&Media Wave6 video codec IP.
On NXP i.MX platforms, the Wave6 consists of two functional regions:
a control region responsible for firmware and shared resources,
and a core region for encoding and decoding.
The control driver manages shared resources such as firmware loading,
firmware memory allocation, and synchronization required by the core.
It also binds the `wave6-core` sub-device and coordinates with it
for firmware and power state management.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
Tested-by: Ming Qian <ming.qian@oss.nxp.com>
Tested-by: Marek Vasut <marek.vasut@mailbox.org>
---
drivers/media/platform/chips-media/Kconfig | 1 +
drivers/media/platform/chips-media/Makefile | 1 +
.../media/platform/chips-media/wave6/Kconfig | 17 +
.../media/platform/chips-media/wave6/Makefile | 17 +
.../platform/chips-media/wave6/wave6-vpu.c | 667 ++++++++++++++++++
.../platform/chips-media/wave6/wave6-vpu.h | 121 ++++
6 files changed, 824 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..63d79c56c7fc
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/Kconfig
@@ -0,0 +1,17 @@
+# 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 wave6 driver manages shared resources such as firmware memory.
+ The wave6-core 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 and wave6-core.
diff --git a/drivers/media/platform/chips-media/wave6/Makefile b/drivers/media/platform/chips-media/wave6/Makefile
new file mode 100644
index 000000000000..06f8ac9bef14
--- /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-core.o := -I$(src)
+
+wave6-objs += wave6-vpu.o \
+ wave6-vpu-thermal.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU) += wave6.o
+
+wave6-core-objs += wave6-vpu-core.o \
+ wave6-vpu-v4l2.o \
+ wave6-vpu-dbg.o \
+ wave6-vpuapi.o \
+ wave6-vpu-dec.o \
+ wave6-vpu-enc.o \
+ wave6-hw.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU) += wave6-core.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..daf2e92c1fae
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.c
@@ -0,0 +1,667 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 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/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/genalloc.h>
+
+#include "wave6-vpuconfig.h"
+#include "wave6-regdefine.h"
+#include "wave6-vpu.h"
+
+static const struct wave6_vpu_resource wave633c_data = {
+ .fw_name = "cnm/wave633c_imx9_codec_fw.bin",
+ /* For HEVC, AVC, 4096x4096, 8bit */
+ .sram_size = 0x14800,
+};
+
+static const char *wave6_vpu_state_name(enum wave6_vpu_state state)
+{
+ switch (state) {
+ case WAVE6_VPU_STATE_OFF:
+ return "off";
+ case WAVE6_VPU_STATE_PREPARE:
+ return "prepare";
+ case WAVE6_VPU_STATE_ON:
+ return "on";
+ case WAVE6_VPU_STATE_SLEEP:
+ return "sleep";
+ default:
+ return "unknown";
+ }
+}
+
+static bool wave6_vpu_valid_transition(struct wave6_vpu_device *vpu,
+ enum wave6_vpu_state next)
+{
+ switch (vpu->state) {
+ case WAVE6_VPU_STATE_OFF:
+ /* to PREPARE: first boot attempt */
+ /* to ON: already booted before, skipping boot */
+ if (next == WAVE6_VPU_STATE_PREPARE ||
+ next == WAVE6_VPU_STATE_ON)
+ return true;
+ break;
+ case WAVE6_VPU_STATE_PREPARE:
+ /* to OFF: boot failed */
+ /* to ON: boot successful */
+ if (next == WAVE6_VPU_STATE_OFF ||
+ next == WAVE6_VPU_STATE_ON)
+ return true;
+ break;
+ case WAVE6_VPU_STATE_ON:
+ /* to OFF: sleep failed */
+ /* to SLEEP: sleep successful */
+ if (next == WAVE6_VPU_STATE_OFF ||
+ next == WAVE6_VPU_STATE_SLEEP)
+ return true;
+ break;
+ case WAVE6_VPU_STATE_SLEEP:
+ /* to OFF: resume failed */
+ /* to ON: resume successful */
+ if (next == WAVE6_VPU_STATE_OFF ||
+ next == WAVE6_VPU_STATE_ON)
+ return true;
+ break;
+ }
+
+ dev_err(vpu->dev, "invalid transition: %s -> %s\n",
+ wave6_vpu_state_name(vpu->state), wave6_vpu_state_name(next));
+
+ return false;
+}
+
+static void wave6_vpu_set_state(struct wave6_vpu_device *vpu,
+ enum wave6_vpu_state state)
+{
+ if (!wave6_vpu_valid_transition(vpu, state))
+ return;
+
+ dev_dbg(vpu->dev, "set state: %s -> %s\n",
+ wave6_vpu_state_name(vpu->state), wave6_vpu_state_name(state));
+
+ vpu->state = state;
+}
+
+static int wave6_vpu_wait_busy(struct vpu_core_device *core)
+{
+ u32 val;
+
+ return read_poll_timeout(wave6_vdi_readl, val, !val,
+ W6_VPU_POLL_DELAY_US, W6_VPU_POLL_TIMEOUT,
+ false, core->reg_base, W6_VPU_BUSY_STATUS);
+}
+
+static int wave6_vpu_check_result(struct vpu_core_device *core)
+{
+ if (wave6_vdi_readl(core->reg_base, W6_RET_SUCCESS))
+ return 0;
+
+ return wave6_vdi_readl(core->reg_base, W6_RET_FAIL_REASON);
+}
+
+static u32 wave6_vpu_get_code_buf_size(struct wave6_vpu_device *vpu)
+{
+ return min_t(u32, vpu->code_buf.size, W6_MAX_CODE_BUF_SIZE);
+}
+
+static void wave6_vpu_remap_code_buf(struct wave6_vpu_device *vpu)
+{
+ dma_addr_t code_base = vpu->code_buf.dma_addr;
+ u32 i, reg_val;
+
+ for (i = 0; i < wave6_vpu_get_code_buf_size(vpu) / W6_MAX_REMAP_PAGE_SIZE; i++) {
+ reg_val = REMAP_CTRL_ON |
+ REMAP_CTRL_INDEX(i) |
+ REMAP_CTRL_PAGE_SIZE_ON |
+ REMAP_CTRL_PAGE_SIZE(W6_MAX_REMAP_PAGE_SIZE);
+ wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_CTRL_GB, reg_val);
+ wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_VADDR_GB,
+ i * W6_MAX_REMAP_PAGE_SIZE);
+ wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_PADDR_GB,
+ code_base + i * W6_MAX_REMAP_PAGE_SIZE);
+ }
+}
+
+static void wave6_vpu_init_code_buf(struct wave6_vpu_device *vpu)
+{
+ if (vpu->code_buf.size < W6_CODE_BUF_SIZE) {
+ dev_warn(vpu->dev,
+ "code buf size (%zu) is too small\n", vpu->code_buf.size);
+ vpu->code_buf.phys_addr = 0;
+ vpu->code_buf.size = 0;
+ memset(&vpu->code_buf, 0, sizeof(vpu->code_buf));
+ return;
+ }
+
+ vpu->code_buf.vaddr = devm_memremap(vpu->dev,
+ vpu->code_buf.phys_addr,
+ vpu->code_buf.size,
+ MEMREMAP_WC);
+ if (!vpu->code_buf.vaddr) {
+ memset(&vpu->code_buf, 0, sizeof(vpu->code_buf));
+ return;
+ }
+
+ vpu->code_buf.dma_addr = dma_map_resource(vpu->dev,
+ vpu->code_buf.phys_addr,
+ vpu->code_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ if (!vpu->code_buf.dma_addr) {
+ memset(&vpu->code_buf, 0, sizeof(vpu->code_buf));
+ return;
+ }
+}
+
+static void wave6_vpu_allocate_work_buffers(struct wave6_vpu_device *vpu)
+{
+ struct vpu_buf *buf;
+ int i;
+
+ for (i = 0; i < MAX_NUM_INSTANCE; i++) {
+ buf = &vpu->work_buffers[i];
+ buf->size = W637DEC_WORKBUF_SIZE_FOR_CQ;
+
+ if (wave6_vdi_alloc_dma(vpu->dev, buf)) {
+ dev_warn(vpu->dev, "Failed to allocate work_buffers\n");
+ return;
+ }
+
+ vpu->work_buffers_alloc++;
+ }
+}
+
+static void wave6_vpu_free_work_buffers(struct wave6_vpu_device *vpu)
+{
+ int i;
+
+ for (i = 0; i < vpu->work_buffers_alloc; i++)
+ wave6_vdi_free_dma(&vpu->work_buffers[i]);
+
+ vpu->work_buffers_alloc = 0;
+ vpu->work_buffers_avail = 0;
+}
+
+static void wave6_vpu_init_work_buf(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ int ret;
+
+ lockdep_assert_held(&vpu->lock);
+
+ wave6_vdi_writel(core->reg_base, W6_VPU_BUSY_STATUS, BUSY_STATUS_SET);
+ wave6_vdi_writel(core->reg_base, W6_COMMAND, W6_CMD_INIT_WORK_BUF);
+ wave6_vdi_writel(core->reg_base, W6_VPU_HOST_INT_REQ, HOST_INT_REQ_ON);
+
+ ret = wave6_vpu_wait_busy(core);
+ if (ret) {
+ dev_err(vpu->dev, "init work buf failed\n");
+ return;
+ }
+
+ ret = wave6_vpu_check_result(core);
+ if (ret) {
+ dev_err(vpu->dev, "init work buf failed, reason 0x%x\n", ret);
+ return;
+ }
+
+ vpu->work_buffers_avail = vpu->work_buffers_alloc;
+}
+
+static int wave6_vpu_init_vpu(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ int ret;
+
+ lockdep_assert_held(&vpu->lock);
+
+ /* try init directly as firmware is running */
+ if (wave6_vdi_readl(core->reg_base, W6_VPU_VCPU_CUR_PC))
+ goto init_done;
+
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_PREPARE);
+
+ wave6_vpu_remap_code_buf(vpu);
+
+ wave6_vdi_writel(core->reg_base, W6_VPU_BUSY_STATUS, BUSY_STATUS_SET);
+ wave6_vdi_writel(core->reg_base, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0,
+ vpu->sram_buf.dma_addr);
+ wave6_vdi_writel(core->reg_base, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0,
+ vpu->sram_buf.size);
+ wave6_vdi_writel(vpu->reg_base, W6_COMMAND_GB, W6_CMD_INIT_VPU);
+ wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_CORE_START_GB,
+ REMAP_CORE_START_ON);
+
+ ret = wave6_vpu_wait_busy(core);
+ if (ret) {
+ dev_err(vpu->dev, "init vpu timeout\n");
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_check_result(core);
+ if (ret) {
+ dev_err(vpu->dev, "init vpu fail, reason 0x%x\n", ret);
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EIO;
+ }
+
+init_done:
+ wave6_vpu_init_work_buf(vpu, core);
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_ON);
+
+ return 0;
+}
+
+static int wave6_vpu_sleep(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ int ret;
+
+ lockdep_assert_held(&vpu->lock);
+
+ if (!wave6_vdi_readl(core->reg_base, W6_VPU_VCPU_CUR_PC)) {
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return 0;
+ }
+
+ wave6_vdi_writel(core->reg_base, W6_VPU_BUSY_STATUS, BUSY_STATUS_SET);
+ wave6_vdi_writel(core->reg_base, W6_COMMAND, W6_CMD_SLEEP_VPU);
+ wave6_vdi_writel(core->reg_base, W6_VPU_HOST_INT_REQ, HOST_INT_REQ_ON);
+
+ ret = wave6_vpu_wait_busy(core);
+ if (ret) {
+ dev_err(vpu->dev, "sleep vpu timeout\n");
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_check_result(core);
+ if (ret) {
+ dev_err(vpu->dev, "sleep vpu fail, reason 0x%x\n", ret);
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EIO;
+ }
+
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_SLEEP);
+
+ return 0;
+}
+
+static int wave6_vpu_wakeup(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ int ret;
+
+ lockdep_assert_held(&vpu->lock);
+
+ /* try wakeup directly as firmware is running */
+ if (wave6_vdi_readl(core->reg_base, W6_VPU_VCPU_CUR_PC))
+ goto wakeup_done;
+
+ wave6_vpu_remap_code_buf(vpu);
+
+ wave6_vdi_writel(core->reg_base, W6_VPU_BUSY_STATUS, BUSY_STATUS_SET);
+ wave6_vdi_writel(core->reg_base, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0,
+ vpu->sram_buf.dma_addr);
+ wave6_vdi_writel(core->reg_base, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0,
+ vpu->sram_buf.size);
+ wave6_vdi_writel(vpu->reg_base, W6_COMMAND_GB, W6_CMD_WAKEUP_VPU);
+ wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_CORE_START_GB,
+ REMAP_CORE_START_ON);
+
+ ret = wave6_vpu_wait_busy(core);
+ if (ret) {
+ dev_err(vpu->dev, "wakeup vpu timeout\n");
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_check_result(core);
+ if (ret) {
+ dev_err(vpu->dev, "wakeup vpu fail, reason 0x%x\n", ret);
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_OFF);
+ return -EIO;
+ }
+
+wakeup_done:
+ wave6_vpu_set_state(vpu, WAVE6_VPU_STATE_ON);
+
+ return 0;
+}
+
+static int wave6_vpu_try_boot(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ u32 product_code;
+ int ret;
+
+ lockdep_assert_held(&vpu->lock);
+
+ if (vpu->state != WAVE6_VPU_STATE_OFF && vpu->state != WAVE6_VPU_STATE_SLEEP)
+ return 0;
+
+ product_code = wave6_vdi_readl(core->reg_base, W6_VPU_RET_PRODUCT_CODE);
+ if (!PRODUCT_CODE_W_SERIES(product_code)) {
+ dev_err(vpu->dev, "unknown product : %08x\n", product_code);
+ return -EINVAL;
+ }
+
+ if (vpu->state == WAVE6_VPU_STATE_SLEEP) {
+ ret = wave6_vpu_wakeup(vpu, core);
+ return ret;
+ }
+
+ ret = wave6_vpu_init_vpu(vpu, core);
+
+ return ret;
+}
+
+static int wave6_vpu_get(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ int ret;
+
+ if (WARN_ON(!vpu || !core))
+ return -EINVAL;
+
+ guard(mutex)(&vpu->lock);
+
+ if (!vpu->fw_available)
+ return -EINVAL;
+
+ /* Only the first core executes boot; others return */
+ if (atomic_inc_return(&vpu->core_count) > 1)
+ return 0;
+
+ ret = pm_runtime_resume_and_get(vpu->dev);
+ if (ret)
+ goto error_pm;
+
+ ret = wave6_vpu_try_boot(vpu, core);
+ if (ret)
+ goto error_boot;
+
+ return 0;
+
+error_boot:
+ pm_runtime_put_sync(vpu->dev);
+error_pm:
+ atomic_dec(&vpu->core_count);
+
+ return ret;
+}
+
+static void wave6_vpu_put(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ if (WARN_ON(!vpu || !core))
+ return;
+
+ guard(mutex)(&vpu->lock);
+
+ if (!vpu->fw_available)
+ return;
+
+ /* Only the last core executes sleep; others return */
+ if (atomic_dec_return(&vpu->core_count) > 0)
+ return;
+
+ wave6_vpu_sleep(vpu, core);
+
+ if (!pm_runtime_suspended(vpu->dev))
+ pm_runtime_put_sync(vpu->dev);
+}
+
+static void wave6_vpu_require_work_buffer(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core)
+{
+ struct vpu_buf *vb;
+ u32 size;
+
+ if (WARN_ON(!vpu || !core))
+ return;
+
+ size = wave6_vdi_readl(core->reg_base, W6_CMD_SET_WORK_BUF_SIZE);
+ if (!size)
+ return;
+
+ if (WARN_ON(size > W637DEC_WORKBUF_SIZE_FOR_CQ))
+ goto exit;
+
+ if (WARN_ON(vpu->work_buffers_avail <= 0))
+ goto exit;
+
+ vpu->work_buffers_avail--;
+ vb = &vpu->work_buffers[vpu->work_buffers_avail];
+
+ wave6_vdi_writel(core->reg_base, W6_CMD_SET_WORK_BUF_ADDR, vb->daddr);
+
+exit:
+ wave6_vdi_writel(core->reg_base, W6_CMD_SET_WORK_BUF_SIZE, SET_WORK_BUF_SIZE_ACK);
+}
+
+static void wave6_vpu_release(struct wave6_vpu_device *vpu)
+{
+ guard(mutex)(&vpu->lock);
+
+ vpu->fw_available = false;
+ wave6_vpu_free_work_buffers(vpu);
+ if (vpu->sram_pool && vpu->sram_buf.vaddr) {
+ dma_unmap_resource(vpu->dev,
+ vpu->sram_buf.dma_addr,
+ vpu->sram_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ gen_pool_free(vpu->sram_pool,
+ (unsigned long)vpu->sram_buf.vaddr,
+ vpu->sram_buf.size);
+ }
+ if (vpu->code_buf.dma_addr)
+ dma_unmap_resource(vpu->dev,
+ vpu->code_buf.dma_addr,
+ vpu->code_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+}
+
+static void wave6_vpu_load_firmware(const struct firmware *fw, void *context)
+{
+ struct wave6_vpu_device *vpu = context;
+
+ guard(mutex)(&vpu->lock);
+
+ if (!fw || !fw->data) {
+ dev_err(vpu->dev, "No firmware.\n");
+ return;
+ }
+
+ if (!vpu->fw_available)
+ goto exit;
+
+ if (fw->size + W6_EXTRA_CODE_BUF_SIZE > wave6_vpu_get_code_buf_size(vpu)) {
+ dev_err(vpu->dev, "firmware size (%zd > %zd) is too big\n",
+ fw->size, vpu->code_buf.size);
+ vpu->fw_available = false;
+ goto exit;
+ }
+
+ memcpy(vpu->code_buf.vaddr, fw->data, fw->size);
+
+ vpu->get_vpu = wave6_vpu_get;
+ vpu->put_vpu = wave6_vpu_put;
+ vpu->req_work_buffer = wave6_vpu_require_work_buffer;
+ of_platform_populate(vpu->dev->of_node, NULL, NULL, vpu->dev);
+
+exit:
+ release_firmware(fw);
+}
+
+static int wave6_vpu_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ struct wave6_vpu_device *vpu;
+ const struct wave6_vpu_resource *res;
+ int ret;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set DMA mask: %d\n", ret);
+ return ret;
+ }
+
+ res = of_device_get_match_data(&pdev->dev);
+ if (!res)
+ return -ENODEV;
+
+ vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL);
+ if (!vpu)
+ return -ENOMEM;
+
+ ret = devm_mutex_init(&pdev->dev, &vpu->lock);
+ if (ret)
+ return ret;
+
+ atomic_set(&vpu->core_count, 0);
+ dev_set_drvdata(&pdev->dev, vpu);
+ vpu->dev = &pdev->dev;
+ vpu->res = res;
+ vpu->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(vpu->reg_base))
+ return PTR_ERR(vpu->reg_base);
+
+ ret = devm_clk_bulk_get_all(&pdev->dev, &vpu->clks);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "failed to get clocks\n");
+
+ vpu->num_clks = ret;
+
+ np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+ if (np) {
+ struct resource mem;
+
+ ret = of_address_to_resource(np, 0, &mem);
+ of_node_put(np);
+ if (!ret) {
+ vpu->code_buf.phys_addr = mem.start;
+ vpu->code_buf.size = resource_size(&mem);
+ wave6_vpu_init_code_buf(vpu);
+ } else {
+ dev_warn(&pdev->dev, "memory-region is not available.\n");
+ }
+ }
+
+ vpu->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+ if (vpu->sram_pool) {
+ vpu->sram_buf.size = vpu->res->sram_size;
+ vpu->sram_buf.vaddr = gen_pool_dma_alloc(vpu->sram_pool,
+ vpu->sram_buf.size,
+ &vpu->sram_buf.phys_addr);
+ if (!vpu->sram_buf.vaddr)
+ vpu->sram_buf.size = 0;
+ else
+ vpu->sram_buf.dma_addr = dma_map_resource(&pdev->dev,
+ vpu->sram_buf.phys_addr,
+ vpu->sram_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ }
+
+ vpu->thermal.dev = &pdev->dev;
+ ret = wave6_vpu_cooling_init(&vpu->thermal);
+ if (ret)
+ dev_err(&pdev->dev, "failed to initialize thermal cooling, ret = %d\n", ret);
+
+ wave6_vpu_allocate_work_buffers(vpu);
+
+ pm_runtime_enable(&pdev->dev);
+ vpu->fw_available = true;
+
+ ret = firmware_request_nowait_nowarn(THIS_MODULE,
+ vpu->res->fw_name,
+ &pdev->dev,
+ GFP_KERNEL,
+ vpu,
+ wave6_vpu_load_firmware);
+ if (ret) {
+ dev_err(&pdev->dev, "request firmware fail, ret = %d\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ wave6_vpu_release(vpu);
+ wave6_vpu_cooling_remove(&vpu->thermal);
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static void wave6_vpu_remove(struct platform_device *pdev)
+{
+ struct wave6_vpu_device *vpu = dev_get_drvdata(&pdev->dev);
+
+ wave6_vpu_release(vpu);
+ wave6_vpu_cooling_remove(&vpu->thermal);
+ of_platform_depopulate(vpu->dev);
+ pm_runtime_disable(vpu->dev);
+}
+
+static int __maybe_unused wave6_vpu_runtime_suspend(struct device *dev)
+{
+ struct wave6_vpu_device *vpu = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks);
+
+ return 0;
+}
+
+static int __maybe_unused wave6_vpu_runtime_resume(struct device *dev)
+{
+ struct wave6_vpu_device *vpu = dev_get_drvdata(dev);
+
+ return clk_bulk_prepare_enable(vpu->num_clks, vpu->clks);
+}
+
+static const struct dev_pm_ops wave6_vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend,
+ wave6_vpu_runtime_resume, NULL)
+};
+
+static const struct of_device_id wave6_vpu_ids[] = {
+ { .compatible = "nxp,imx95-vpu", .data = &wave633c_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wave6_vpu_ids);
+
+static struct platform_driver wave6_vpu_driver = {
+ .driver = {
+ .name = WAVE6_VPU_PLATFORM_DRIVER_NAME,
+ .of_match_table = wave6_vpu_ids,
+ .pm = &wave6_vpu_pm_ops,
+ },
+ .probe = wave6_vpu_probe,
+ .remove = wave6_vpu_remove,
+};
+
+module_platform_driver(wave6_vpu_driver);
+MODULE_DESCRIPTION("chips&media Wave6 VPU 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..5e3a78f0ec45
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPU_H__
+#define __WAVE6_VPU_H__
+
+#include <linux/device.h>
+#include "wave6-vpu-thermal.h"
+#include "wave6-vdi.h"
+#include "wave6-vpuapi.h"
+
+#define WAVE6_VPU_PLATFORM_DRIVER_NAME "wave6-vpu"
+
+struct wave6_vpu_device;
+struct vpu_core_device;
+
+/**
+ * enum wave6_vpu_state - VPU states
+ * @WAVE6_VPU_STATE_OFF: VPU is powered off
+ * @WAVE6_VPU_STATE_PREPARE: VPU is booting
+ * @WAVE6_VPU_STATE_ON: VPU is running
+ * @WAVE6_VPU_STATE_SLEEP: VPU is in a sleep mode
+ */
+enum wave6_vpu_state {
+ WAVE6_VPU_STATE_OFF,
+ WAVE6_VPU_STATE_PREPARE,
+ WAVE6_VPU_STATE_ON,
+ WAVE6_VPU_STATE_SLEEP
+};
+
+/**
+ * struct wave6_vpu_dma_buf - VPU buffer from reserved memory or gen_pool
+ * @size: Buffer size
+ * @dma_addr: Mapped address for device access
+ * @vaddr: Kernel virtual address
+ * @phys_addr: Physical address of the reserved memory region or gen_pool
+ *
+ * Represents a buffer allocated from pre-reserved device memory regions or
+ * SRAM via gen_pool_dma_alloc(). Used for code and SRAM buffers only.
+ * Managed by the VPU device.
+ */
+struct wave6_vpu_dma_buf {
+ size_t size;
+ dma_addr_t dma_addr;
+ void *vaddr;
+ phys_addr_t phys_addr;
+};
+
+/**
+ * struct wave6_vpu_resource - VPU device compatible data
+ * @fw_name: Firmware name for the device
+ * @sram_size: Required SRAM size
+ */
+struct wave6_vpu_resource {
+ const char *fw_name;
+ u32 sram_size;
+};
+
+/**
+ * struct wave6_vpu_device - VPU driver structure
+ * @get_vpu: Function pointer, boot or wake the device
+ * @put_vpu: Function pointer, power off or suspend the device
+ * @req_work_buffer: Function pointer, request allocation of a work buffer
+ * @dev: Platform device pointer
+ * @reg_base: Base address of MMIO registers
+ * @clks: Array of clock handles
+ * @num_clks: Number of entries in @clks
+ * @state: Device state
+ * @lock: Mutex protecting device data, register access
+ * @fw_available: Firmware availability flag
+ * @res: Device compatible data
+ * @sram_pool: Genalloc pool for SRAM allocations
+ * @sram_buf: Optional SRAM buffer
+ * @code_buf: Firmware code buffer
+ * @work_buffers: Array of work buffers
+ * @work_buffers_alloc: Number of allocated work buffers
+ * @work_buffers_avail: Number of available work buffers
+ * @thermal: Thermal cooling device
+ * @core_count: Number of available VPU core devices
+ *
+ * @get_vpu, @put_vpu, @req_work_buffer are called by VPU core devices.
+ *
+ * Buffers such as @sram_buf, @code_buf, and @work_buffers are managed
+ * by the VPU device and accessed exclusively by the firmware.
+ */
+struct wave6_vpu_device {
+ int (*get_vpu)(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core);
+ void (*put_vpu)(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core);
+ void (*req_work_buffer)(struct wave6_vpu_device *vpu,
+ struct vpu_core_device *core);
+ struct device *dev;
+ void __iomem *reg_base;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ enum wave6_vpu_state state;
+ struct mutex lock; /* Protects device data, register access */
+
+ /* Prevents boot or sleep sequence if firmware is unavailable. */
+ bool fw_available;
+
+ const struct wave6_vpu_resource *res;
+ struct gen_pool *sram_pool;
+ struct wave6_vpu_dma_buf sram_buf;
+ struct wave6_vpu_dma_buf code_buf;
+
+ /* Allocates per-instance, used for storing instance-specific data. */
+ struct vpu_buf work_buffers[MAX_NUM_INSTANCE];
+ u32 work_buffers_alloc;
+ u32 work_buffers_avail;
+
+ struct vpu_thermal_cooling thermal;
+ atomic_t core_count;
+};
+
+#endif /* __WAVE6_VPU_H__ */
--
2.31.1
Hi Nas,
kernel test robot noticed the following build errors:
[auto build test ERROR on shawnguo/for-next]
[also build test ERROR on linuxtv-media-pending/master robh/for-next linus/master v6.18-rc2 next-20251022]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nas-Chung/media-v4l2-common-Add-YUV24-format-info/20251022-155246
base: https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git for-next
patch link: https://lore.kernel.org/r/20251022074710.575-9-nas.chung%40chipsnmedia.com
patch subject: [PATCH v4 8/9] media: chips-media: wave6: Add Wave6 control driver
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20251023/202510230756.m2qLZNJc-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251023/202510230756.m2qLZNJc-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510230756.m2qLZNJc-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/media/platform/chips-media/wave6/wave6-vpu.c:25:
drivers/media/platform/chips-media/wave6/wave6-vpu.c: In function 'wave6_vpu_remap_code_buf':
>> drivers/media/platform/chips-media/wave6/wave6-regdefine.h:83:57: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
83 | #define REMAP_CTRL_INDEX(x) FIELD_PREP(GENMASK(15, 12), (x))
| ^~~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu.c:131:27: note: in expansion of macro 'REMAP_CTRL_INDEX'
131 | REMAP_CTRL_INDEX(i) |
| ^~~~~~~~~~~~~~~~
--
In file included from drivers/media/platform/chips-media/wave6/wave6-vpu-core.h:18,
from drivers/media/platform/chips-media/wave6/wave6-vpu-core.c:17:
drivers/media/platform/chips-media/wave6/wave6-vpu-core.c: In function 'wave6_vpu_core_check_state':
>> drivers/media/platform/chips-media/wave6/wave6-vpuapi.h:125:33: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
125 | #define FW_VERSION_MAJOR(x) FIELD_GET(FW_VERSION_MAJOR_MASK, (x))
| ^~~~~~~~~
include/linux/dynamic_debug.h:224:29: note: in expansion of macro 'FW_VERSION_MAJOR'
224 | func(&id, ##__VA_ARGS__); \
| ^~~~~~~~~~~
include/linux/dynamic_debug.h:248:9: note: in expansion of macro '__dynamic_func_call_cls'
248 | __dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~
include/linux/dynamic_debug.h:250:9: note: in expansion of macro '_dynamic_func_call_cls'
250 | _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
include/linux/dynamic_debug.h:273:9: note: in expansion of macro '_dynamic_func_call'
273 | _dynamic_func_call(fmt, __dynamic_dev_dbg, \
| ^~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg'
165 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-core.c:133:9: note: in expansion of macro 'dev_dbg'
133 | dev_dbg(core->dev, "product 0x%x, fw_ver %d.%d.%d(r%d), hw_ver 0x%x\n",
| ^~~~~~~
--
In file included from drivers/media/platform/chips-media/wave6/wave6-vpu-core.h:18,
from drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c:10:
drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c: In function 'wave6_vpu_dbg_instance':
>> drivers/media/platform/chips-media/wave6/wave6-vpuapi.h:125:33: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
125 | #define FW_VERSION_MAJOR(x) FIELD_GET(FW_VERSION_MAJOR_MASK, (x))
| ^~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c:34:25: note: in expansion of macro 'FW_VERSION_MAJOR'
34 | FW_VERSION_MAJOR(inst->dev->attr.fw_version),
| ^~~~~~~~~~~~~~~~
--
In file included from drivers/media/platform/chips-media/wave6/wave6-hw.c:11:
drivers/media/platform/chips-media/wave6/wave6-hw.c: In function 'wave6_send_command':
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:99:57: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
99 | #define INSTANCE_INFO_CODEC_STD(x) FIELD_PREP(GENMASK(31, 16), (x))
| ^~~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-hw.c:237:27: note: in expansion of macro 'INSTANCE_INFO_CODEC_STD'
237 | reg_val = INSTANCE_INFO_CODEC_STD(std);
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-hw.c: In function 'wave6_vpu_get_version':
>> drivers/media/platform/chips-media/wave6/wave6-regdefine.h:125:57: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
125 | #define STD_DEF1_HEVC_DEC(x) FIELD_GET(GENMASK(2, 2), (x))
| ^~~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-hw.c:308:35: note: in expansion of macro 'STD_DEF1_HEVC_DEC'
308 | attr->support_decoders |= STD_DEF1_HEVC_DEC(std_def1) << W_HEVC_DEC;
| ^~~~~~~~~~~~~~~~~
vim +/FIELD_PREP +83 drivers/media/platform/chips-media/wave6/wave6-regdefine.h
2fef07d3bbe662 Nas Chung 2025-10-22 71
2fef07d3bbe662 Nas Chung 2025-10-22 72 #define W6_VPU_VCPU_CUR_PC (W6_REG_BASE + 0x0004)
2fef07d3bbe662 Nas Chung 2025-10-22 73 #define W6_VPU_VINT_REASON_CLEAR (W6_REG_BASE + 0x0034)
2fef07d3bbe662 Nas Chung 2025-10-22 74 #define W6_VPU_HOST_INT_REQ (W6_REG_BASE + 0x0038)
2fef07d3bbe662 Nas Chung 2025-10-22 75 #define HOST_INT_REQ_ON BIT(0)
2fef07d3bbe662 Nas Chung 2025-10-22 76 #define W6_VPU_VINT_CLEAR (W6_REG_BASE + 0x003C)
2fef07d3bbe662 Nas Chung 2025-10-22 77 #define VINT_CLEAR BIT(0)
2fef07d3bbe662 Nas Chung 2025-10-22 78 #define W6_VPU_VPU_INT_STS (W6_REG_BASE + 0x0044)
2fef07d3bbe662 Nas Chung 2025-10-22 79 #define W6_VPU_VINT_ENABLE (W6_REG_BASE + 0x0048)
2fef07d3bbe662 Nas Chung 2025-10-22 80 #define W6_VPU_VINT_REASON (W6_REG_BASE + 0x004C)
2fef07d3bbe662 Nas Chung 2025-10-22 81 #define W6_VPU_REMAP_CTRL_GB (W6_REG_BASE + 0x0060)
2fef07d3bbe662 Nas Chung 2025-10-22 82 #define REMAP_CTRL_ON BIT(31)
2fef07d3bbe662 Nas Chung 2025-10-22 @83 #define REMAP_CTRL_INDEX(x) FIELD_PREP(GENMASK(15, 12), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 84 #define REMAP_CTRL_PAGE_SIZE_ON BIT(11)
2fef07d3bbe662 Nas Chung 2025-10-22 85 #define REMAP_CTRL_PAGE_SIZE(x) FIELD_PREP(GENMASK(8, 0), ((x) >> 12))
2fef07d3bbe662 Nas Chung 2025-10-22 86 #define W6_VPU_REMAP_VADDR_GB (W6_REG_BASE + 0x0064)
2fef07d3bbe662 Nas Chung 2025-10-22 87 #define W6_VPU_REMAP_PADDR_GB (W6_REG_BASE + 0x0068)
2fef07d3bbe662 Nas Chung 2025-10-22 88 #define W6_VPU_REMAP_CORE_START_GB (W6_REG_BASE + 0x006C)
2fef07d3bbe662 Nas Chung 2025-10-22 89 #define REMAP_CORE_START_ON BIT(0)
2fef07d3bbe662 Nas Chung 2025-10-22 90 #define W6_VPU_BUSY_STATUS (W6_REG_BASE + 0x0070)
2fef07d3bbe662 Nas Chung 2025-10-22 91 #define BUSY_STATUS_SET BIT(0)
2fef07d3bbe662 Nas Chung 2025-10-22 92 #define W6_VPU_RET_PRODUCT_CODE (W6_REG_BASE + 0x0094)
2fef07d3bbe662 Nas Chung 2025-10-22 93
2fef07d3bbe662 Nas Chung 2025-10-22 94 /* COMMON */
2fef07d3bbe662 Nas Chung 2025-10-22 95 #define W6_COMMAND_GB (W6_REG_BASE + 0x104)
2fef07d3bbe662 Nas Chung 2025-10-22 96 #define W6_COMMAND (W6_REG_BASE + 0x200)
2fef07d3bbe662 Nas Chung 2025-10-22 97 #define W6_QUERY_OPTION (W6_REG_BASE + 0x204)
2fef07d3bbe662 Nas Chung 2025-10-22 98 #define W6_CMD_INSTANCE_INFO (W6_REG_BASE + 0x210)
2fef07d3bbe662 Nas Chung 2025-10-22 99 #define INSTANCE_INFO_CODEC_STD(x) FIELD_PREP(GENMASK(31, 16), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 100 #define INSTANCE_INFO_ID(x) FIELD_PREP(GENMASK(15, 0), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 101 #define W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0 (W6_REG_BASE + 0x364)
2fef07d3bbe662 Nas Chung 2025-10-22 102 #define W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0 (W6_REG_BASE + 0x368)
2fef07d3bbe662 Nas Chung 2025-10-22 103 #define W6_CMD_SET_WORK_BUF_ADDR (W6_REG_BASE + 0x5F0)
2fef07d3bbe662 Nas Chung 2025-10-22 104 #define W6_CMD_SET_WORK_BUF_SIZE (W6_REG_BASE + 0x5F4)
2fef07d3bbe662 Nas Chung 2025-10-22 105 #define SET_WORK_BUF_SIZE_ACK 0
2fef07d3bbe662 Nas Chung 2025-10-22 106 #define W6_RET_SUCCESS (W6_REG_BASE + 0x208)
2fef07d3bbe662 Nas Chung 2025-10-22 107 #define W6_RET_FAIL_REASON (W6_REG_BASE + 0x20C)
2fef07d3bbe662 Nas Chung 2025-10-22 108 #define W6_RET_INT_INSTANCE_INFO (W6_REG_BASE + 0x21C)
2fef07d3bbe662 Nas Chung 2025-10-22 109 #define INT_INSTANCE_INFO_CLEAR 0
2fef07d3bbe662 Nas Chung 2025-10-22 110 #define W6_RET_INSTANCE_ID (W6_REG_BASE + 0x220)
2fef07d3bbe662 Nas Chung 2025-10-22 111 #define W6_RET_CQ_IN_TICK (W6_REG_BASE + 0x23C)
2fef07d3bbe662 Nas Chung 2025-10-22 112 #define W6_RET_FW_RUN_TICK (W6_REG_BASE + 0x240)
2fef07d3bbe662 Nas Chung 2025-10-22 113 #define W6_RET_HW_RUN_TICK (W6_REG_BASE + 0x244)
2fef07d3bbe662 Nas Chung 2025-10-22 114 #define W6_RET_HW_DONE_TICK (W6_REG_BASE + 0x248)
2fef07d3bbe662 Nas Chung 2025-10-22 115 #define W6_RET_FW_DONE_TICK (W6_REG_BASE + 0x24C)
2fef07d3bbe662 Nas Chung 2025-10-22 116 #define W6_RET_RQ_OUT_TICK (W6_REG_BASE + 0x250)
2fef07d3bbe662 Nas Chung 2025-10-22 117
2fef07d3bbe662 Nas Chung 2025-10-22 118 /* COMMON - QUERY : GET_VPU_INFO */
2fef07d3bbe662 Nas Chung 2025-10-22 119 #define W6_RET_FW_VERSION (W6_REG_BASE + 0x300)
2fef07d3bbe662 Nas Chung 2025-10-22 120 #define W6_RET_PRODUCT_NAME (W6_REG_BASE + 0x304)
2fef07d3bbe662 Nas Chung 2025-10-22 121 #define W6_RET_PRODUCT_VERSION (W6_REG_BASE + 0x308)
2fef07d3bbe662 Nas Chung 2025-10-22 122 #define W6_RET_STD_DEF0 (W6_REG_BASE + 0x30C)
2fef07d3bbe662 Nas Chung 2025-10-22 123 #define W6_RET_STD_DEF1 (W6_REG_BASE + 0x310)
2fef07d3bbe662 Nas Chung 2025-10-22 124 #define STD_DEF1_AVC_DEC(x) FIELD_GET(GENMASK(3, 3), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 @125 #define STD_DEF1_HEVC_DEC(x) FIELD_GET(GENMASK(2, 2), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 126 #define STD_DEF1_AVC_ENC(x) FIELD_GET(GENMASK(1, 1), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 127 #define STD_DEF1_HEVC_ENC(x) FIELD_GET(GENMASK(0, 0), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 128 #define W6_RET_CONF_FEATURE (W6_REG_BASE + 0x314)
2fef07d3bbe662 Nas Chung 2025-10-22 129 #define CONF_FEATURE_AVC10BIT_ENC(x) FIELD_GET(GENMASK(11, 11), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 130 #define CONF_FEATURE_AVC10BIT_DEC(x) FIELD_GET(GENMASK(9, 9), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 131 #define CONF_FEATURE_HEVC10BIT_ENC(x) FIELD_GET(GENMASK(3, 3), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 132 #define CONF_FEATURE_HEVC10BIT_DEC(x) FIELD_GET(GENMASK(1, 1), (x))
2fef07d3bbe662 Nas Chung 2025-10-22 133 #define W6_RET_CONF_DATE (W6_REG_BASE + 0x318)
2fef07d3bbe662 Nas Chung 2025-10-22 134 #define W6_RET_CONF_HW_VERSION (W6_REG_BASE + 0x31C)
2fef07d3bbe662 Nas Chung 2025-10-22 135 #define W6_RET_CONF_TYPE (W6_REG_BASE + 0x320)
2fef07d3bbe662 Nas Chung 2025-10-22 136 #define W6_RET_FW_API_VERSION (W6_REG_BASE + 0x32C)
2fef07d3bbe662 Nas Chung 2025-10-22 137 #define W6_RET_SHA_ID (W6_REG_BASE + 0x330)
2fef07d3bbe662 Nas Chung 2025-10-22 138
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Nas,
kernel test robot noticed the following build errors:
[auto build test ERROR on shawnguo/for-next]
[also build test ERROR on linuxtv-media-pending/master robh/for-next linus/master v6.18-rc2 next-20251022]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nas-Chung/media-v4l2-common-Add-YUV24-format-info/20251022-155246
base: https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git for-next
patch link: https://lore.kernel.org/r/20251022074710.575-9-nas.chung%40chipsnmedia.com
patch subject: [PATCH v4 8/9] media: chips-media: wave6: Add Wave6 control driver
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20251023/202510230606.Ycv5XHv1-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251023/202510230606.Ycv5XHv1-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510230606.Ycv5XHv1-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/media/platform/chips-media/wave6/wave6-vpu.c:131:6: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
131 | REMAP_CTRL_INDEX(i) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:83:32: note: expanded from macro 'REMAP_CTRL_INDEX'
83 | #define REMAP_CTRL_INDEX(x) FIELD_PREP(GENMASK(15, 12), (x))
| ^
1 error generated.
--
>> drivers/media/platform/chips-media/wave6/wave6-vpu-core.c:135:3: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
135 | FW_VERSION_MAJOR(core->attr.fw_version),
| ^
drivers/media/platform/chips-media/wave6/wave6-vpu-core.c:143:4: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
143 | FW_VERSION_MAJOR(core->res->compatible_fw_version),
| ^
2 errors generated.
--
>> drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c:34:4: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
34 | FW_VERSION_MAJOR(inst->dev->attr.fw_version),
| ^
drivers/media/platform/chips-media/wave6/wave6-vpuapi.h:125:29: note: expanded from macro 'FW_VERSION_MAJOR'
125 | #define FW_VERSION_MAJOR(x) FIELD_GET(FW_VERSION_MAJOR_MASK, (x))
| ^
1 error generated.
--
>> drivers/media/platform/chips-media/wave6/wave6-hw.c:237:13: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
237 | reg_val = INSTANCE_INFO_CODEC_STD(std);
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:99:38: note: expanded from macro 'INSTANCE_INFO_CODEC_STD'
99 | #define INSTANCE_INFO_CODEC_STD(x) FIELD_PREP(GENMASK(31, 16), (x))
| ^
>> drivers/media/platform/chips-media/wave6/wave6-hw.c:308:28: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
308 | attr->support_decoders |= STD_DEF1_HEVC_DEC(std_def1) << W_HEVC_DEC;
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:125:33: note: expanded from macro 'STD_DEF1_HEVC_DEC'
125 | #define STD_DEF1_HEVC_DEC(x) FIELD_GET(GENMASK(2, 2), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:362:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
362 | reg_val = CREATE_INST_CORE_INFO_CQ_DEPTH(COMMAND_QUEUE_DEPTH) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:145:44: note: expanded from macro 'CREATE_INST_CORE_INFO_CQ_DEPTH'
145 | #define CREATE_INST_CORE_INFO_CQ_DEPTH(x) FIELD_PREP(GENMASK(10, 8), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:405:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
405 | reg_val = DEC_PIC_BS_OPTION_STREAM_END(p_dec_info->stream_end) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:259:43: note: expanded from macro 'DEC_PIC_BS_OPTION_STREAM_END'
259 | #define DEC_PIC_BS_OPTION_STREAM_END(x) FIELD_PREP(GENMASK(1, 1), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:438:20: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
438 | info->pic_width = DEC_PIC_SIZE_WIDTH(reg_val);
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:299:34: note: expanded from macro 'DEC_PIC_SIZE_WIDTH'
299 | #define DEC_PIC_SIZE_WIDTH(x) FIELD_GET(GENMASK(31, 16), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:561:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
561 | reg_val = SET_FB_PIC_SIZE_WIDTH(p_dec_info->seq_info.pic_width) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:167:36: note: expanded from macro 'SET_FB_PIC_SIZE_WIDTH'
167 | #define SET_FB_PIC_SIZE_WIDTH(x) FIELD_PREP(GENMASK(31, 16), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:650:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
650 | reg_val = SET_DISP_SCL_PIC_SIZE_WIDTH(inst->scaler_info.width) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:250:42: note: expanded from macro 'SET_DISP_SCL_PIC_SIZE_WIDTH'
250 | #define SET_DISP_SCL_PIC_SIZE_WIDTH(x) FIELD_PREP(GENMASK(31, 16), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:732:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
732 | reg_val = DEC_PIC_BS_OPTION_STREAM_END(p_dec_info->stream_end) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:259:43: note: expanded from macro 'DEC_PIC_BS_OPTION_STREAM_END'
259 | #define DEC_PIC_BS_OPTION_STREAM_END(x) FIELD_PREP(GENMASK(1, 1), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:789:21: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
789 | result->ctu_size = DEC_PIC_TYPE_CTU_SIZE(reg_val);
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:310:43: note: expanded from macro 'DEC_PIC_TYPE_CTU_SIZE'
310 | #define DEC_PIC_TYPE_CTU_SIZE(x) (16 << FIELD_GET(GENMASK(11, 10), (x)))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1074:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1074 | reg_val = CREATE_INST_CORE_INFO_CQ_DEPTH(COMMAND_QUEUE_DEPTH) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:145:44: note: expanded from macro 'CREATE_INST_CORE_INFO_CQ_DEPTH'
145 | #define CREATE_INST_CORE_INFO_CQ_DEPTH(x) FIELD_PREP(GENMASK(10, 8), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1217:18: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1217 | reg->src_size = SET_PARAM_SRC_SIZE_HEIGHT(p_enc_info->height) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:359:40: note: expanded from macro 'SET_PARAM_SRC_SIZE_HEIGHT'
359 | #define SET_PARAM_SRC_SIZE_HEIGHT(x) FIELD_PREP(GENMASK(31, 16), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1304:13: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1304 | reg->sps = SET_PARAM_SPS_DEFAULT_SCALING_LIST(p_param->en_scaling_list) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:363:48: note: expanded from macro 'SET_PARAM_SPS_DEFAULT_SCALING_LIST'
363 | #define SET_PARAM_SPS_DEFAULT_SCALING_LIST(x) FIELD_PREP(GENMASK(31, 31), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1346:13: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1346 | reg->sps = SET_PARAM_SPS_DEFAULT_SCALING_LIST(p_param->en_scaling_list) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:363:48: note: expanded from macro 'SET_PARAM_SPS_DEFAULT_SCALING_LIST'
363 | #define SET_PARAM_SPS_DEFAULT_SCALING_LIST(x) FIELD_PREP(GENMASK(31, 31), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1594:18: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1594 | reg->pic_info = SET_FB_PIC_INFO_STRIDE(p_enc_info->stride);
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:165:37: note: expanded from macro 'SET_FB_PIC_INFO_STRIDE'
165 | #define SET_FB_PIC_INFO_STRIDE(x) FIELD_PREP(GENMASK(15, 0), (x))
| ^
drivers/media/platform/chips-media/wave6/wave6-hw.c:1953:17: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1953 | reg->src_fmt = ENC_PIC_SRC_FMT_C_FMT_IDC(c_fmt_idc) |
| ^
drivers/media/platform/chips-media/wave6/wave6-regdefine.h:542:40: note: expanded from macro 'ENC_PIC_SRC_FMT_C_FMT_IDC'
542 | #define ENC_PIC_SRC_FMT_C_FMT_IDC(x) FIELD_PREP(GENMASK(30, 28), (x))
| ^
15 errors generated.
vim +/FIELD_PREP +131 drivers/media/platform/chips-media/wave6/wave6-vpu.c
123
124 static void wave6_vpu_remap_code_buf(struct wave6_vpu_device *vpu)
125 {
126 dma_addr_t code_base = vpu->code_buf.dma_addr;
127 u32 i, reg_val;
128
129 for (i = 0; i < wave6_vpu_get_code_buf_size(vpu) / W6_MAX_REMAP_PAGE_SIZE; i++) {
130 reg_val = REMAP_CTRL_ON |
> 131 REMAP_CTRL_INDEX(i) |
132 REMAP_CTRL_PAGE_SIZE_ON |
133 REMAP_CTRL_PAGE_SIZE(W6_MAX_REMAP_PAGE_SIZE);
134 wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_CTRL_GB, reg_val);
135 wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_VADDR_GB,
136 i * W6_MAX_REMAP_PAGE_SIZE);
137 wave6_vdi_writel(vpu->reg_base, W6_VPU_REMAP_PADDR_GB,
138 code_base + i * W6_MAX_REMAP_PAGE_SIZE);
139 }
140 }
141
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.