* [PATCH v11 05/11] riscv: kexec_file: Fix potential buffer overflow in prepare_elf_headers()
From: Jinjie Ruan @ 2026-03-28 7:40 UTC (permalink / raw)
To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
dave.hansen, hpa, robh, saravanak, akpm, bhe, vgoyal, dyoung,
rdunlap, peterz, feng.tang, pawan.kumar.gupta, dapeng1.mi, kees,
elver, paulmck, lirongqing, rppt, leitao, ardb, cfsworks, osandov,
jbohac, tangyouling, sourabhjain, ritesh.list, eajames,
songshuaishuai, kevin.brodsky, vishal.moola, junhui.liu, coxu,
fuqiang.wang, liaoyuanhong, guoren, chenjiahao16, hbathini,
takahiro.akashi, james.morse, lizhengyu3, x86, linux-doc,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, devicetree, kexec
Cc: ruanjinjie
In-Reply-To: <20260328074013.3589544-1-ruanjinjie@huawei.com>
There is a race condition between the kexec_load() system call
(crash kernel loading path) and memory hotplug operations that can lead
to buffer overflow and potential kernel crash.
During prepare_elf_headers(), the following steps occur:
1. get_nr_ram_ranges_callback() queries current System RAM memory ranges
2. Allocates buffer based on queried count
3. prepare_elf64_ram_headers_callback() populates ranges from memblock
If memory hotplug occurs between step 1 and step 3, the number of ranges
can increase, causing out-of-bounds write when populating cmem->ranges[].
This happens because kexec_load() uses kexec_trylock (atomic_t) while
memory hotplug uses device_hotplug_lock (mutex), so they don't serialize
with each other.
Just add bounds checking in prepare_elf64_ram_headers_callback() to prevent
out-of-bounds (OOB) access.
Fixes: 8acea455fafa ("RISC-V: Support for kexec_file on panic")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
arch/riscv/kernel/machine_kexec_file.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 3f7766057cac..773a1cba8ba0 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -48,6 +48,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
{
struct crash_mem *cmem = arg;
+ if (cmem->nr_ranges >= cmem->max_nr_ranges)
+ return -ENOMEM;
+
cmem->ranges[cmem->nr_ranges].start = res->start;
cmem->ranges[cmem->nr_ranges].end = res->end;
cmem->nr_ranges++;
--
2.34.1
^ permalink raw reply related
* [PATCH v11 03/11] x86/kexec: Fix potential buffer overflow in prepare_elf_headers()
From: Jinjie Ruan @ 2026-03-28 7:40 UTC (permalink / raw)
To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
dave.hansen, hpa, robh, saravanak, akpm, bhe, vgoyal, dyoung,
rdunlap, peterz, feng.tang, pawan.kumar.gupta, dapeng1.mi, kees,
elver, paulmck, lirongqing, rppt, leitao, ardb, cfsworks, osandov,
jbohac, tangyouling, sourabhjain, ritesh.list, eajames,
songshuaishuai, kevin.brodsky, vishal.moola, junhui.liu, coxu,
fuqiang.wang, liaoyuanhong, guoren, chenjiahao16, hbathini,
takahiro.akashi, james.morse, lizhengyu3, x86, linux-doc,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, devicetree, kexec
Cc: ruanjinjie
In-Reply-To: <20260328074013.3589544-1-ruanjinjie@huawei.com>
There is a race condition between the kexec_load() system call
(crash kernel loading path) and memory hotplug operations that can lead
to buffer overflow and potential kernel crash.
During prepare_elf_headers(), the following steps occur:
1. get_nr_ram_ranges_callback() queries current System RAM memory ranges
2. Allocates buffer based on queried count
3. prepare_elf64_ram_headers_callback() populates ranges from memblock
If memory hotplug occurs between step 1 and step 3, the number of ranges
can increase, causing out-of-bounds write when populating cmem->ranges[].
This happens because kexec_load() uses kexec_trylock (atomic_t) while
memory hotplug uses device_hotplug_lock (mutex), so they don't serialize
with each other.
Just add bounds checking in prepare_elf64_ram_headers_callback() to
prevent out-of-bounds (OOB) access,
Fixes: 8d5f894a3108 ("x86: kexec_file: lift CRASH_MAX_RANGES limit on crash_mem buffer")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
arch/x86/kernel/crash.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 335fd2ee9766..7fa6d45ebe3f 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -225,6 +225,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
{
struct crash_mem *cmem = arg;
+ if (cmem->nr_ranges >= cmem->max_nr_ranges)
+ return -ENOMEM;
+
cmem->ranges[cmem->nr_ranges].start = res->start;
cmem->ranges[cmem->nr_ranges].end = res->end;
cmem->nr_ranges++;
--
2.34.1
^ permalink raw reply related
* [PATCH v11 00/11] arm64/riscv: Add support for crashkernel CMA reservation
From: Jinjie Ruan @ 2026-03-28 7:40 UTC (permalink / raw)
To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
dave.hansen, hpa, robh, saravanak, akpm, bhe, vgoyal, dyoung,
rdunlap, peterz, feng.tang, pawan.kumar.gupta, dapeng1.mi, kees,
elver, paulmck, lirongqing, rppt, leitao, ardb, cfsworks, osandov,
jbohac, tangyouling, sourabhjain, ritesh.list, eajames,
songshuaishuai, kevin.brodsky, vishal.moola, junhui.liu, coxu,
fuqiang.wang, liaoyuanhong, guoren, chenjiahao16, hbathini,
takahiro.akashi, james.morse, lizhengyu3, x86, linux-doc,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, devicetree, kexec
Cc: ruanjinjie
The crash memory allocation, and the exclude of crashk_res, crashk_low_res
and crashk_cma memory are almost identical across different architectures,
This patch set handle them in crash core in a general way, which eliminate
a lot of duplication code.
And add support for crashkernel CMA reservation for arm64 and riscv.
Rebased on v7.0-rc1.
Basic second kernel boot test were performed on QEMU platforms for x86,
ARM64, and RISC-V architectures with the following parameters:
>-------"cma=256M crashkernel=256M crashkernel=64M,cma"
Changes in v11:
- Avoid silently drop crash memory if the crash kernel is built without
CONFIG_CMA.
- Remove unnecessary "cmem->nr_ranges = 0" for arch_crash_populate_cmem()
as we use kvzalloc().
- Provide a separate patch for each architecture to fix the existing
buffer overflow issue.
- Add Acked-bys for arm64.
Changes in v10:
- Fix crashk_low_res not excluded bug in the existing
RISC-V code.
- Fix an existing memory leak issue in the existing PowerPC code.
- Fix the ordering issue of adding CMA ranges to
"linux,usable-memory-range".
- Fix an existing concurrency issue. A Concurrent memory hotplug may occur
between reading memblock and attempting to fill cmem during kexec_load()
for almost all existing architectures.
- Link to v9: https://lore.kernel.org/all/20260323072745.2481719-1-ruanjinjie@huawei.com/
Changes in v9:
- Collect Reviewed-by and Acked-by, and prepare for Sashiko AI review.
- Link to v8: https://lore.kernel.org/all/20260302035315.3892241-1-ruanjinjie@huawei.com/
Changes in v8:
- Fix the build issues reported by kernel test robot and Sourabh.
- Link to v7: https://lore.kernel.org/all/20260226130437.1867658-1-ruanjinjie@huawei.com/
Changes in v7:
- Correct the inclusion of CMA-reserved ranges for kdump kernel in of/kexec
for arm64 and riscv.
- Add Acked-by.
- Link to v6: https://lore.kernel.org/all/20260224085342.387996-1-ruanjinjie@huawei.com/
Changes in v6:
- Update the crash core exclude code as Mike suggested.
- Rebased on v7.0-rc1.
- Add acked-by.
- Link to v5: https://lore.kernel.org/all/20260212101001.343158-1-ruanjinjie@huawei.com/
Changes in v5:
- Fix the kernel test robot build warnings.
- Sort crash memory ranges before preparing elfcorehdr for powerpc
- Link to v4: https://lore.kernel.org/all/20260209095931.2813152-1-ruanjinjie@huawei.com/
Changes in v4:
- Move the size calculation (and the realloc if needed) into the
generic crash.
- Link to v3: https://lore.kernel.org/all/20260204093728.1447527-1-ruanjinjie@huawei.com/
Jinjie Ruan (10):
riscv: kexec_file: Fix crashk_low_res not exclude bug
powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
x86/kexec: Fix potential buffer overflow in prepare_elf_headers()
arm64: kexec_file: Fix potential buffer overflow in
prepare_elf_headers()
riscv: kexec_file: Fix potential buffer overflow in
prepare_elf_headers()
LoongArch: kexec: Fix potential buffer overflow in
prepare_elf_headers()
crash: Exclude crash kernel memory in crash core
crash: Use crash_exclude_core_ranges() on powerpc
arm64: kexec: Add support for crashkernel CMA reservation
riscv: kexec: Add support for crashkernel CMA reservation
Sourabh Jain (1):
powerpc/crash: sort crash memory ranges before preparing elfcorehdr
.../admin-guide/kernel-parameters.txt | 16 +--
arch/arm64/kernel/machine_kexec_file.c | 43 +++-----
arch/arm64/mm/init.c | 5 +-
arch/loongarch/kernel/machine_kexec_file.c | 43 +++-----
arch/powerpc/include/asm/kexec_ranges.h | 1 -
arch/powerpc/kexec/crash.c | 7 +-
arch/powerpc/kexec/ranges.c | 101 +-----------------
arch/riscv/kernel/machine_kexec_file.c | 42 +++-----
arch/riscv/mm/init.c | 5 +-
arch/x86/kernel/crash.c | 92 +++-------------
drivers/of/fdt.c | 9 +-
drivers/of/kexec.c | 9 ++
include/linux/crash_core.h | 9 ++
include/linux/crash_reserve.h | 4 +-
kernel/crash_core.c | 89 ++++++++++++++-
15 files changed, 194 insertions(+), 281 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v11 02/11] powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
From: Jinjie Ruan @ 2026-03-28 7:40 UTC (permalink / raw)
To: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
dave.hansen, hpa, robh, saravanak, akpm, bhe, vgoyal, dyoung,
rdunlap, peterz, feng.tang, pawan.kumar.gupta, dapeng1.mi, kees,
elver, paulmck, lirongqing, rppt, leitao, ardb, cfsworks, osandov,
jbohac, tangyouling, sourabhjain, ritesh.list, eajames,
songshuaishuai, kevin.brodsky, vishal.moola, junhui.liu, coxu,
fuqiang.wang, liaoyuanhong, guoren, chenjiahao16, hbathini,
takahiro.akashi, james.morse, lizhengyu3, x86, linux-doc,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, devicetree, kexec
Cc: ruanjinjie
In-Reply-To: <20260328074013.3589544-1-ruanjinjie@huawei.com>
In get_crash_memory_ranges(), if crash_exclude_mem_range() failed
after realloc_mem_ranges() has successfully allocated the cmem
memory, it just returns an error but leaves cmem pointing to
the allocated memory, nor is it freed in the caller
update_crash_elfcorehdr(), which cause a memory leak, goto out
to free the cmem.
Cc: Sourabh Jain <sourabhjain@linux.ibm.com>
Cc: Hari Bathini <hbathini@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
arch/powerpc/kexec/crash.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index a325c1c02f96..1d12cef8e1e0 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -440,7 +440,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
ret = get_crash_memory_ranges(&cmem);
if (ret) {
pr_err("Failed to get crash mem range\n");
- return;
+ goto out;
}
/*
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 2/3] soc: renesas: Add Renesas R-Car MFIS driver
From: Marek Vasut @ 2026-03-28 0:16 UTC (permalink / raw)
To: Wolfram Sang, linux-renesas-soc
Cc: Krzysztof Kozlowski, devicetree, Kuninori Morimoto,
Geert Uytterhoeven, Magnus Damm
In-Reply-To: <20260325110717.17083-3-wsa+renesas@sang-engineering.com>
On 3/25/26 12:07 PM, Wolfram Sang wrote:
Hello Wolfram,
> +static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data)
> +{
> + struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
> + struct mfis_chan_priv *chan_priv = chan->con_priv;
> +
> + /* Our doorbell still active? */
> + if (mfis_read(&priv->mbox_reg, chan_priv->reg) & 1)
Super-nitpick, please use BIT(0) instead of 1, since this is a register
bit check. This way:
if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0))
> + return -EBUSY;
> +
> + /* Start our doorbell */
> + mfis_write(&priv->mbox_reg, chan_priv->reg, 1);
Same here.
> + return 0;
> +}
> +
> +static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan)
> +{
> + struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
> + struct mfis_chan_priv *chan_priv = chan->con_priv;
> +
> + /* Our doorbell still active? */
> + return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & 1);
Same here.
The rest is very nice, thank you !
^ permalink raw reply
* Re: [PATCH v8 1/9] dt-bindings: display: fsl,ldb: Add i.MX94 LDB
From: Marek Vasut @ 2026-03-27 23:17 UTC (permalink / raw)
To: Liu Ying, Marco Felsch
Cc: Laurentiu Palcu, imx, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Marek Vasut, dri-devel, Frank Li, devicetree, linux-kernel
In-Reply-To: <2fe36f04-97d3-4e99-97e9-7a3ac53cffdb@nxp.com>
On 3/23/26 8:22 AM, Liu Ying wrote:
Hello Liu,
> ... i.MX8MP LVDS bridge node is fine with the reg property, but the property
> is not allowed for i.MX93 LVDS bridge node according to commit[1] while
> commit[2] requires the property for all LVDS bridge nodes. See the contradict
> here?
>
> [1] 3feaa4342637 dt-bindings: soc: imx93-media-blk-ctrl: Add PDFC subnode to schema and example
> [2] 8aa2f0ac08d3 dt-bindings: display: bridge: ldb: Add check for reg and reg-names
>
> To avoid the contradict, how about requiring the reg property only for i.MX6SX
> and i.MX8MP LVDS bridge nodes and making it kind of optional for i.MX93 and
> i.MX94 LVDS bridge nodes?
I would be fine with that, thanks !
^ permalink raw reply
* [PATCH v4 13/14] media: mediatek: decoder: fill av1 buffer size with picinfo
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The buffer size of y and c plane has been calculated in vcp/scp,
can fill each frame buffer size with picinfo directly.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 4932ef469594..a0c7e89b8ae4 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1811,18 +1811,19 @@ static int vdec_av1_slice_setup_core_buffer(struct vdec_av1_slice_instance *inst
{
struct vb2_buffer *vb;
struct vb2_queue *vq;
- int w, h, plane, size;
+ int plane;
int i;
plane = instance->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes;
- w = vsi->frame.uh.upscaled_width;
- h = vsi->frame.uh.frame_height;
- size = ALIGN(w, VCODEC_DEC_ALIGNED_64) * ALIGN(h, VCODEC_DEC_ALIGNED_64);
/* frame buffer */
vsi->fb.y.dma_addr = fb->base_y.dma_addr;
+
+ vsi->fb.y.size = instance->ctx->picinfo.fb_sz[0];
+ vsi->fb.c.size = instance->ctx->picinfo.fb_sz[1];
+
if (plane == 1)
- vsi->fb.c.dma_addr = fb->base_y.dma_addr + size;
+ vsi->fb.c.dma_addr = fb->base_y.dma_addr + vsi->fb.y.size;
else
vsi->fb.c.dma_addr = fb->base_c.dma_addr;
@@ -1845,8 +1846,9 @@ static int vdec_av1_slice_setup_core_buffer(struct vdec_av1_slice_instance *inst
}
vref->y.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ vref->y.size = vsi->fb.y.size;
if (plane == 1)
- vref->c.dma_addr = vref->y.dma_addr + size;
+ vref->c.dma_addr = vref->y.dma_addr + vsi->fb.y.size;
else
vref->c.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 1);
}
--
2.45.2
^ permalink raw reply related
* [PATCH v4 14/14] media: mediatek: decoder: support av1 extend vsi
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The driver can't access tile buffer address for extend architecture,
set tile group information in vcp and share it with kernel.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 59 ++++++++++++++++---
1 file changed, 52 insertions(+), 7 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index a0c7e89b8ae4..e9265b112bfb 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -25,6 +25,9 @@
#define AV1_INVALID_IDX -1
+#define AV1_NON_EXT_VSI_SIZE 0xD50
+#define AV1_TILE_SIZE 64
+
#define AV1_DIV_ROUND_UP_POW2(value, n) \
({ \
typeof(n) _n = n; \
@@ -641,6 +644,8 @@ struct vdec_av1_slice_fb {
* @frame: current frame info
* @state: status after decode done
* @cur_lst_tile_id: tile id for large scale
+ * @tile_group: tile group info
+ * @reserved: reserved
*/
struct vdec_av1_slice_vsi {
/* lat */
@@ -665,6 +670,8 @@ struct vdec_av1_slice_vsi {
struct vdec_av1_slice_frame frame;
struct vdec_av1_slice_state state;
u32 cur_lst_tile_id;
+ struct vdec_av1_slice_tile_group tile_group;
+ unsigned int reserved[4];
};
/**
@@ -1402,17 +1409,29 @@ static void vdec_av1_slice_setup_uh(struct vdec_av1_slice_instance *instance,
vdec_av1_slice_setup_tile(frame, &ctrl_fh->tile_info);
}
+static
+struct vdec_av1_slice_tile_group *vdec_av1_get_tile_group(struct vdec_av1_slice_instance *instance,
+ struct vdec_av1_slice_vsi *vsi)
+{
+ if (IS_VDEC_SUPPORT_EXT(instance->ctx->dev->dec_capability))
+ return &vsi->tile_group;
+ else
+ return &instance->tile_group;
+}
+
static int vdec_av1_slice_setup_tile_group(struct vdec_av1_slice_instance *instance,
struct vdec_av1_slice_vsi *vsi)
{
struct v4l2_ctrl_av1_tile_group_entry *ctrl_tge;
- struct vdec_av1_slice_tile_group *tile_group = &instance->tile_group;
+ struct vdec_av1_slice_tile_group *tile_group;
struct vdec_av1_slice_uncompressed_header *uh = &vsi->frame.uh;
struct vdec_av1_slice_tile *tile = &uh->tile;
struct v4l2_ctrl *ctrl;
u32 tge_size;
int i;
+ tile_group = vdec_av1_get_tile_group(instance, vsi);
+
ctrl = v4l2_ctrl_find(&instance->ctx->ctrl_hdl, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
if (!ctrl)
return -EINVAL;
@@ -1607,6 +1626,15 @@ static int vdec_av1_slice_setup_pfc(struct vdec_av1_slice_instance *instance,
return ret;
}
+static u32 vdec_av1_get_tiles_num(struct vdec_av1_slice_instance *instance,
+ struct vdec_av1_slice_vsi *vsi)
+{
+ if (IS_VDEC_SUPPORT_EXT(instance->ctx->dev->dec_capability))
+ return vsi->tile_group.num_tiles;
+ else
+ return instance->tile_group.num_tiles;
+}
+
static void vdec_av1_slice_setup_lat_buffer(struct vdec_av1_slice_instance *instance,
struct vdec_av1_slice_vsi *vsi,
struct mtk_vcodec_mem *bs,
@@ -1647,12 +1675,18 @@ static void vdec_av1_slice_setup_lat_buffer(struct vdec_av1_slice_instance *inst
vsi->tile.buf = instance->tile.dma_addr;
vsi->tile.size = instance->tile.size;
- memcpy(lat_buf->tile_addr.va, instance->tile.va, 64 * instance->tile_group.num_tiles);
vsi->cdf_table.buf = instance->cdf_table.dma_addr;
vsi->cdf_table.size = instance->cdf_table.size;
vsi->iq_table.buf = instance->iq_table.dma_addr;
vsi->iq_table.size = instance->iq_table.size;
+
+ /* lat_buf is used to share hardware decoder syntax between lat and core,
+ * there isn't only one. But there is only one tile.va for each instance.
+ * Need to copy tile information to lat_buf every time.
+ */
+ memcpy(lat_buf->tile_addr.va, instance->tile.va,
+ AV1_TILE_SIZE * vdec_av1_get_tiles_num(instance, vsi));
}
static void vdec_av1_slice_setup_seg_buffer(struct vdec_av1_slice_instance *instance,
@@ -1675,7 +1709,7 @@ static void vdec_av1_slice_setup_tile_buffer(struct vdec_av1_slice_instance *ins
struct vdec_av1_slice_vsi *vsi,
struct mtk_vcodec_mem *bs)
{
- struct vdec_av1_slice_tile_group *tile_group = &instance->tile_group;
+ struct vdec_av1_slice_tile_group *tile_group;
struct vdec_av1_slice_uncompressed_header *uh = &vsi->frame.uh;
struct vdec_av1_slice_tile *tile = &uh->tile;
u32 tile_num, tile_row, tile_col;
@@ -1686,6 +1720,8 @@ static void vdec_av1_slice_setup_tile_buffer(struct vdec_av1_slice_instance *ins
u32 *tile_info_buf = instance->tile.va;
u64 pa = (u64)bs->dma_addr;
+ tile_group = vdec_av1_get_tile_group(instance, vsi);
+
if (uh->disable_cdf_update == 0)
allow_update_cdf = 1;
@@ -1907,7 +1943,7 @@ static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
struct vdec_av1_slice_instance *instance;
struct vdec_av1_slice_init_vsi *vsi;
enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
- int ret;
+ int ret, vsi_size = AV1_NON_EXT_VSI_SIZE;
instance = kzalloc_obj(*instance);
if (!instance)
@@ -1941,9 +1977,18 @@ static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
goto error_vsi;
}
- if (vsi->vsi_size != sizeof(struct vdec_av1_slice_vsi))
- mtk_vdec_err(ctx, "remote vsi size 0x%x mismatch! expected: 0x%zx\n",
- vsi->vsi_size, sizeof(struct vdec_av1_slice_vsi));
+ if (IS_VDEC_SUPPORT_EXT(ctx->dev->dec_capability)) {
+ vsi_size = sizeof(struct vdec_av1_slice_vsi);
+ vsi->iq_table_size = AV1_IQ_TABLE_SIZE;
+ vsi->cdf_table_size = AV1_CDF_SIZE;
+ }
+
+ if (vsi->vsi_size != vsi_size) {
+ mtk_vdec_err(ctx, "remote vsi size 0x%x mismatch! expected: 0x%x\n",
+ vsi->vsi_size, vsi_size);
+ ret = -EINVAL;
+ goto error_vsi;
+ }
instance->irq_enabled = 1;
instance->inneracing_mode = IS_VDEC_INNER_RACING(instance->ctx->dev->dec_capability);
--
2.45.2
^ permalink raw reply related
* [PATCH v4 12/14] media: mediatek: vcodec: add decoder compatible to support mt8196
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
MT8196 is lat single core architecture. Support its compatible and
use `mtk_lat_sig_core_pdata` to initialize platform data.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 6 ++++++
.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index 5a748a60b453..e7c140b26955 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -347,6 +347,8 @@ static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev *vdec_dev)
vdec_dev->chip_name = MTK_VDEC_MT8186;
else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec"))
vdec_dev->chip_name = MTK_VDEC_MT8188;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8196-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8196;
else
vdec_dev->chip_name = MTK_VDEC_INVAL;
}
@@ -570,6 +572,10 @@ static const struct of_device_id mtk_vcodec_match[] = {
.compatible = "mediatek,mt8188-vcodec-dec",
.data = &mtk_lat_sig_core_pdata,
},
+ {
+ .compatible = "mediatek,mt8196-vcodec-dec",
+ .data = &mtk_lat_sig_core_pdata,
+ },
{},
};
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
index c9d27534c63e..f06dfc1a3455 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
@@ -29,6 +29,7 @@ enum mtk_vcodec_dec_chip_name {
MTK_VDEC_MT8188 = 8188,
MTK_VDEC_MT8192 = 8192,
MTK_VDEC_MT8195 = 8195,
+ MTK_VDEC_MT8196 = 8196,
};
/*
--
2.45.2
^ permalink raw reply related
* [PATCH v4 11/14] dt-bindings: media: mediatek: vcodec: add decoder dt-bindings for mt8196
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Add decoder document in dt-bindings yaml file for mt8196 platform.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Acked-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../bindings/media/mediatek,vcodec-subdev-decoder.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
index bf8082d87ac0..74e1d88d3056 100644
--- a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
@@ -76,6 +76,7 @@ properties:
- mediatek,mt8186-vcodec-dec
- mediatek,mt8188-vcodec-dec
- mediatek,mt8195-vcodec-dec
+ - mediatek,mt8196-vcodec-dec
reg:
minItems: 1
--
2.45.2
^ permalink raw reply related
* [PATCH v4 10/14] media: mediatek: vcodec: send share memory address to vcp
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The share memory is allocated in kernel for vcp architecture, it's different
with vpu which share memors is reserved in vpu micro processor. Need to send
share memory address to vcp.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
drivers/media/platform/mediatek/vcodec/decoder/vdec_ipi_msg.h | 2 ++
drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_ipi_msg.h b/drivers/media/platform/mediatek/vcodec/decoder/vdec_ipi_msg.h
index 47070be2a991..097561a1efdc 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_ipi_msg.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_ipi_msg.h
@@ -67,11 +67,13 @@ struct vdec_vpu_ipi_ack {
* @msg_id : AP_IPIMSG_DEC_INIT
* @codec_type : codec fourcc
* @ap_inst_addr : AP video decoder instance address
+ * @shared_iova : reserved share memory address
*/
struct vdec_ap_ipi_init {
uint32_t msg_id;
u32 codec_type;
uint64_t ap_inst_addr;
+ u64 shared_iova;
};
/**
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
index cdb673e6b477..3a10b32be094 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
@@ -236,6 +236,8 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu)
msg.msg_id = AP_IPIMSG_DEC_INIT;
msg.ap_inst_addr = (unsigned long)vpu;
msg.codec_type = vpu->codec_type;
+ if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VCP)
+ msg.shared_iova = vpu->ctx->dev->fw_handler->vcp->iova_addr;
mtk_vdec_debug(vpu->ctx, "vdec_inst=%p", vpu);
--
2.45.2
^ permalink raw reply related
* [PATCH v4 05/14] media: mediatek: vcodec: define MT8196 vcodec levels.
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The supported level and profile are not the same for different
codecs and architecture. Select the correct one.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index ab1894fba0d9..472ece5713a5 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -577,6 +577,7 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
break;
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
break;
case MTK_VDEC_MT8183:
@@ -595,6 +596,7 @@ static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
switch (ctx->dev->chip_name) {
case MTK_VDEC_MT8188:
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
break;
default:
@@ -611,6 +613,7 @@ static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
break;
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
break;
default:
@@ -625,6 +628,7 @@ static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
switch (ctx->dev->chip_name) {
case MTK_VDEC_MT8188:
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
break;
default:
@@ -642,6 +646,7 @@ static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
break;
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
break;
case MTK_VDEC_MT8186:
@@ -659,6 +664,7 @@ static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
switch (ctx->dev->chip_name) {
case MTK_VDEC_MT8188:
case MTK_VDEC_MT8195:
+ case MTK_VDEC_MT8196:
cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
break;
default:
--
2.45.2
^ permalink raw reply related
* [PATCH v4 09/14] media: mediatek: vcodec: add debug information
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Print hevc/av1 output format and 10bit capture format
information to debug.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../mediatek/vcodec/common/mtk_vcodec_dbgfs.c | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c
index 2da11521fc7b..b3c69c46240c 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c
@@ -29,6 +29,14 @@ static void mtk_vdec_dbgfs_get_format_type(struct mtk_vcodec_dec_ctx *ctx, char
curr_len = snprintf(buf + *used, total - *used,
"\toutput format: vp9 slice\n");
break;
+ case V4L2_PIX_FMT_HEVC_SLICE:
+ curr_len = snprintf(buf + *used, total - *used,
+ "\toutput format: hevc slice\n");
+ break;
+ case V4L2_PIX_FMT_AV1_FRAME:
+ curr_len = snprintf(buf + *used, total - *used,
+ "\toutput format: av1 slice\n");
+ break;
default:
curr_len = snprintf(buf + *used, total - *used,
"\tunsupported output format: 0x%x\n",
@@ -45,6 +53,14 @@ static void mtk_vdec_dbgfs_get_format_type(struct mtk_vcodec_dec_ctx *ctx, char
curr_len = snprintf(buf + *used, total - *used,
"\tcapture format: MT21C\n");
break;
+ case V4L2_PIX_FMT_MT2110T:
+ curr_len = snprintf(buf + *used, total - *used,
+ "\tcapture format: MT2110T (10bit tile mode)\n");
+ break;
+ case V4L2_PIX_FMT_MT2110R:
+ curr_len = snprintf(buf + *used, total - *used,
+ "\tcapture format: MT2110T (10bit raster mode)\n");
+ break;
default:
curr_len = snprintf(buf + *used, total - *used,
"\tunsupported capture format: 0x%x\n",
@@ -122,9 +138,10 @@ static ssize_t mtk_vdec_dbgfs_read(struct file *filp, char __user *ubuf,
if (dbgfs_index[MTK_VDEC_DBGFS_PICINFO]) {
curr_len = snprintf(buf + used_len, total_len - used_len,
- "\treal(%dx%d)=>align(%dx%d)\n",
+ "\treal(%dx%d)=>align(%dx%d) 10bit(%d)\n",
ctx->picinfo.pic_w, ctx->picinfo.pic_h,
- ctx->picinfo.buf_w, ctx->picinfo.buf_h);
+ ctx->picinfo.buf_w, ctx->picinfo.buf_h,
+ ctx->is_10bit_bitstream);
used_len += curr_len;
}
--
2.45.2
^ permalink raw reply related
* [PATCH v4 08/14] media: mediatek: vcodec: clean xpc status
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The driver need to clean xpc status when receive decoder hardware
interrupt for mt8196 platform.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../vcodec/decoder/mtk_vcodec_dec_hw.c | 28 +++++++++++++++++++
.../vcodec/decoder/mtk_vcodec_dec_hw.h | 13 +++++++--
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
index 881d5de41e05..e4e527fe54dc 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
@@ -61,6 +61,31 @@ static int mtk_vdec_hw_prob_done(struct mtk_vcodec_dec_dev *vdec_dev)
return 0;
}
+static void mtk_vdec_hw_write_reg_mask(void __iomem *reg_base, u32 reg_offset, u32 val, u32 mask)
+{
+ void __iomem *reg_addr = reg_base + reg_offset;
+ u32 reg_val;
+
+ reg_val = readl(reg_addr);
+ reg_val &= ~mask;
+ reg_val |= (val & mask);
+ writel(reg_val, reg_addr);
+}
+
+static void mtk_vdec_hw_clean_xpc(struct mtk_vdec_hw_dev *dev)
+{
+ u32 val, mask, addr = VDEC_XPC_CLEAN_ADDR;
+
+ if (dev->main_dev->chip_name != MTK_VDEC_MT8196)
+ return;
+
+ val = dev->hw_idx == MTK_VDEC_LAT0 ? VDEC_XPC_LAT_VAL : VDEC_XPC_CORE_VAL;
+ mask = dev->hw_idx == MTK_VDEC_LAT0 ? VDEC_XPC_LAT_MASK : VDEC_XPC_CORE_MASK;
+
+ mtk_vdec_hw_write_reg_mask(dev->reg_base[VDEC_HW_XPC], addr, val, mask);
+ mtk_vdec_hw_write_reg_mask(dev->reg_base[VDEC_HW_XPC], addr, 0, mask);
+}
+
static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv)
{
struct mtk_vdec_hw_dev *dev = priv;
@@ -88,6 +113,8 @@ static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv)
writel(dec_done_status | VDEC_IRQ_CFG, vdec_misc_addr);
writel(dec_done_status & ~VDEC_IRQ_CLR, vdec_misc_addr);
+ mtk_vdec_hw_clean_xpc(dev);
+
wake_up_dec_ctx(ctx, MTK_INST_IRQ_RECEIVED, dev->hw_idx);
mtk_v4l2_vdec_dbg(3, ctx, "wake up ctx %d, dec_done_status=%x",
@@ -166,6 +193,7 @@ static int mtk_vdec_hw_probe(struct platform_device *pdev)
subdev_dev->hw_idx = hw_idx;
subdev_dev->main_dev = main_dev;
subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS];
+ subdev_dev->reg_base[VDEC_HW_XPC] = main_dev->reg_base[VDEC_HW_MISC];
set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap);
if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) {
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.h
index 83fe8b9428e6..5c906143c9af 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.h
@@ -18,17 +18,26 @@
#define VDEC_IRQ_CLR 0x10
#define VDEC_IRQ_CFG_REG 0xa4
+#define VDEC_XPC_CLEAN_ADDR 0xc
+#define VDEC_XPC_LAT_VAL BIT(0)
+#define VDEC_XPC_LAT_MASK BIT(0)
+
+#define VDEC_XPC_CORE_VAL BIT(4)
+#define VDEC_XPC_CORE_MASK BIT(4)
+
#define IS_SUPPORT_VDEC_HW_IRQ(hw_idx) ((hw_idx) != MTK_VDEC_LAT_SOC)
/**
* enum mtk_vdec_hw_reg_idx - subdev hardware register base index
- * @VDEC_HW_SYS : vdec soc register index
+ * @VDEC_HW_SYS: vdec soc register index
* @VDEC_HW_MISC: vdec misc register index
- * @VDEC_HW_MAX : vdec supported max register index
+ * @VDEC_HW_XPC: vdec xpc register index
+ * @VDEC_HW_MAX: vdec supported max register index
*/
enum mtk_vdec_hw_reg_idx {
VDEC_HW_SYS,
VDEC_HW_MISC,
+ VDEC_HW_XPC,
VDEC_HW_MAX
};
--
2.45.2
^ permalink raw reply related
* [PATCH v4 07/14] media: mediatek: vcodec: support 36bit iova address
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Need to set dma mask to support 36bit iova address for decoder
hardware can use 36bit address to decode for mt8196.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index d220b645e455..5a748a60b453 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -387,6 +387,13 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
return -ENODEV;
}
dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+ if (dev->chip_name == MTK_VDEC_MT8196) {
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable 36-bit DMA: %d\n", ret);
+ return ret;
+ }
+ }
dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, DECODER);
if (IS_ERR(dev->fw_handler))
--
2.45.2
^ permalink raw reply related
* [PATCH v4 04/14] media: mediatek: vcodec: get share memory address
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
There is only one share memory for vcp architecture, need to
divide it into many different functions.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../vcodec/common/mtk_vcodec_fw_vcp.c | 20 ++++++++++-
.../vcodec/common/mtk_vcodec_fw_vcp.h | 13 +++++++
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 35 ++++++++++++++++---
.../decoder/vdec/vdec_h264_req_multi_if.c | 6 +++-
.../decoder/vdec/vdec_hevc_req_multi_if.c | 7 ++--
.../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 22 ++++++++++--
.../mediatek/vcodec/decoder/vdec_vpu_if.c | 10 +++++-
7 files changed, 102 insertions(+), 11 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
index 32d4e566f357..6b69ce44d4bb 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
@@ -439,8 +439,26 @@ static unsigned int mtk_vcodec_vcp_get_venc_capa(struct mtk_vcodec_fw *fw)
return MTK_VENC_4K_CAPABILITY_ENABLE;
}
-static void *mtk_vcodec_vcp_dm_addr(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr)
+static void *mtk_vcodec_vcp_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_type)
{
+ unsigned char *vsi_core = fw->vcp->vsi_core_addr;
+
+ switch (mem_type) {
+ case ENCODER_MEM:
+ case VCODEC_LAT_MEM:
+ return fw->vcp->vsi_addr;
+ case VCODEC_CORE_MEM:
+ return vsi_core;
+ case VP9_FRAME_MEM:
+ return vsi_core + VCODEC_VSI_LEN;
+ case AV1_CDF_MEM:
+ return vsi_core + VCODEC_VSI_LEN + VP9_FRAME_SIZE;
+ case AV1_IQ_MEM:
+ return vsi_core + VCODEC_VSI_LEN + VP9_FRAME_SIZE + AV1_CDF_SIZE;
+ default:
+ break;
+ }
+
return NULL;
}
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
index c0632a872892..9abc9aaba9a1 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
@@ -13,6 +13,19 @@ typedef void (*vcp_ipi_handler_t) (void *data, unsigned int len, void *priv);
#define VCP_SHARE_BUF_SIZE 64
#define VCODEC_VSI_LEN (0x2000)
+#define VP9_FRAME_SIZE (0x1000)
+#define AV1_CDF_SIZE (0xFE80)
+#define AV1_IQ_TABLE_SIZE (0x12200)
+
+/* enum mtk_vcp_mem_type - memory type for different hardware */
+enum mtk_vcp_mem_type {
+ ENCODER_MEM,
+ VCODEC_LAT_MEM,
+ VCODEC_CORE_MEM,
+ VP9_FRAME_MEM,
+ AV1_CDF_MEM,
+ AV1_IQ_MEM,
+};
/* enum mtk_vcp_ipi_index - index used to separate different hardware */
enum mtk_vcp_ipi_index {
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 756fbb7778b1..4932ef469594 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -765,6 +765,15 @@ static void *vdec_av1_get_ctrl_ptr(struct mtk_vcodec_dec_ctx *ctx, int id)
return ctrl->p_cur.p;
}
+static u32 vdec_av1_get_cdf_table_addr(struct mtk_vcodec_dec_ctx *ctx,
+ struct vdec_av1_slice_init_vsi *vsi)
+{
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ return AV1_CDF_MEM;
+ else
+ return (u32)vsi->cdf_table_addr;
+}
+
static int vdec_av1_slice_init_cdf_table(struct vdec_av1_slice_instance *instance)
{
u8 *remote_cdf_table;
@@ -775,7 +784,7 @@ static int vdec_av1_slice_init_cdf_table(struct vdec_av1_slice_instance *instanc
ctx = instance->ctx;
vsi = instance->vpu.vsi;
remote_cdf_table = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler,
- (u32)vsi->cdf_table_addr);
+ vdec_av1_get_cdf_table_addr(ctx, vsi));
if (IS_ERR(remote_cdf_table)) {
mtk_vdec_err(ctx, "failed to map cdf table\n");
return PTR_ERR(remote_cdf_table);
@@ -796,6 +805,15 @@ static int vdec_av1_slice_init_cdf_table(struct vdec_av1_slice_instance *instanc
return 0;
}
+static u32 vdec_av1_get_iq_table_addr(struct mtk_vcodec_dec_ctx *ctx,
+ struct vdec_av1_slice_init_vsi *vsi)
+{
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ return AV1_IQ_MEM;
+ else
+ return (u32)vsi->iq_table_addr;
+}
+
static int vdec_av1_slice_init_iq_table(struct vdec_av1_slice_instance *instance)
{
u8 *remote_iq_table;
@@ -806,7 +824,7 @@ static int vdec_av1_slice_init_iq_table(struct vdec_av1_slice_instance *instance
ctx = instance->ctx;
vsi = instance->vpu.vsi;
remote_iq_table = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler,
- (u32)vsi->iq_table_addr);
+ vdec_av1_get_iq_table_addr(ctx, vsi));
if (IS_ERR(remote_iq_table)) {
mtk_vdec_err(ctx, "failed to map iq table\n");
return PTR_ERR(remote_iq_table);
@@ -1873,6 +1891,15 @@ static int vdec_av1_slice_update_core(struct vdec_av1_slice_instance *instance,
return 0;
}
+static u32 vdec_av1_get_core_vsi_addr(struct mtk_vcodec_dec_ctx *ctx,
+ struct vdec_av1_slice_init_vsi *vsi)
+{
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ return VCODEC_CORE_MEM;
+ else
+ return (u32)vsi->core_vsi;
+}
+
static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
struct vdec_av1_slice_instance *instance;
@@ -1904,8 +1931,8 @@ static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
goto error_vsi;
}
instance->init_vsi = vsi;
- instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, (u32)vsi->core_vsi);
-
+ instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler,
+ vdec_av1_get_core_vsi_addr(ctx, vsi));
if (!instance->core_vsi) {
mtk_vdec_err(ctx, "failed to get AV1 core vsi\n");
ret = -EINVAL;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
index 69d60717181a..544d3bc06564 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
@@ -1233,7 +1233,11 @@ static int vdec_h264_slice_init(struct mtk_vcodec_dec_ctx *ctx)
vsi_size = round_up(vsi_size, VCODEC_DEC_ALIGNED_64);
inst->vsi_ext = inst->vpu.vsi;
temp = (unsigned char *)inst->vsi_ext;
- inst->vsi_core_ext = (struct vdec_h264_slice_vsi_ext *)(temp + vsi_size);
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ inst->vsi_core_ext =
+ mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, VCODEC_CORE_MEM);
+ else
+ inst->vsi_core_ext = (struct vdec_h264_slice_vsi_ext *)(temp + vsi_size);
if (inst->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE)
inst->decode = vdec_h264_slice_single_decode_ext;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
index dd638ef44083..a5dd42987452 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
@@ -879,8 +879,11 @@ static int vdec_hevc_slice_init(struct mtk_vcodec_dec_ctx *ctx)
vsi_size = round_up(sizeof(struct vdec_hevc_slice_vsi), VCODEC_DEC_ALIGNED_64);
inst->vsi = inst->vpu.vsi;
- inst->vsi_core =
- (struct vdec_hevc_slice_vsi *)(((char *)inst->vpu.vsi) + vsi_size);
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ inst->vsi_core = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, VCODEC_CORE_MEM);
+ else
+ inst->vsi_core =
+ (struct vdec_hevc_slice_vsi *)(((char *)inst->vpu.vsi) + vsi_size);
inst->resolution_changed = true;
inst->realloc_mv_buf = true;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index 1f0479a8f5cb..3f4b70526754 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -500,6 +500,15 @@ static DEFINE_MUTEX(vdec_vp9_slice_frame_ctx_lock);
static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf);
+static u32 vdec_vp9_get_frame_ctx_addr(struct mtk_vcodec_dec_ctx *ctx,
+ struct vdec_vp9_slice_init_vsi *vsi)
+{
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ return VP9_FRAME_MEM;
+ else
+ return (u32)vsi->default_frame_ctx;
+}
+
static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance *instance)
{
struct vdec_vp9_slice_frame_ctx *remote_frame_ctx;
@@ -514,7 +523,7 @@ static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance
return -EINVAL;
remote_frame_ctx = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler,
- (u32)vsi->default_frame_ctx);
+ vdec_vp9_get_frame_ctx_addr(ctx, vsi));
if (!remote_frame_ctx) {
mtk_vdec_err(ctx, "failed to map default frame ctx\n");
return -EINVAL;
@@ -1842,6 +1851,15 @@ static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance,
return 0;
}
+static u32 vdec_vp9_get_core_vsi_addr(struct mtk_vcodec_dec_ctx *ctx,
+ struct vdec_vp9_slice_init_vsi *vsi)
+{
+ if (mtk_vcodec_fw_get_type(ctx->dev->fw_handler) == VCP)
+ return VCODEC_CORE_MEM;
+ else
+ return (u32)vsi->core_vsi;
+}
+
static int vdec_vp9_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
@@ -1875,7 +1893,7 @@ static int vdec_vp9_slice_init(struct mtk_vcodec_dec_ctx *ctx)
}
instance->init_vsi = vsi;
instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler,
- (u32)vsi->core_vsi);
+ vdec_vp9_get_core_vsi_addr(ctx, vsi));
if (!instance->core_vsi) {
mtk_vdec_err(ctx, "failed to get VP9 core vsi\n");
ret = -EINVAL;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
index b35759a0b353..cdb673e6b477 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
@@ -9,6 +9,14 @@
#include "vdec_ipi_msg.h"
#include "vdec_vpu_if.h"
+static u32 vpu_dec_get_vsi_addr(struct vdec_vpu_inst *vpu, const struct vdec_vpu_ipi_init_ack *msg)
+{
+ if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VCP)
+ return VCODEC_LAT_MEM;
+ else
+ return msg->vpu_inst_addr;
+}
+
static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
{
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
@@ -19,7 +27,7 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
/* mapping VPU address to kernel virtual address */
/* the content in vsi is initialized to 0 in VPU */
vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
- msg->vpu_inst_addr);
+ vpu_dec_get_vsi_addr(vpu, msg));
vpu->inst_addr = msg->vpu_inst_addr;
mtk_vdec_debug(vpu->ctx, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
--
2.45.2
^ permalink raw reply related
* [PATCH v4 01/14] media: mediatek: vcodec: add driver to support vcp
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
The processor is changed from scp to vcp in mt8196 platform.
Adding new firmware interface to communicate kernel with vcp
for the communication method is changed.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../media/platform/mediatek/vcodec/Kconfig | 4 +
.../platform/mediatek/vcodec/common/Makefile | 4 +
.../mediatek/vcodec/common/mtk_vcodec_fw.c | 3 +
.../mediatek/vcodec/common/mtk_vcodec_fw.h | 1 +
.../vcodec/common/mtk_vcodec_fw_priv.h | 12 +
.../vcodec/common/mtk_vcodec_fw_vcp.c | 505 ++++++++++++++++++
.../vcodec/common/mtk_vcodec_fw_vcp.h | 139 +++++
7 files changed, 668 insertions(+)
create mode 100644 drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
create mode 100644 drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
diff --git a/drivers/media/platform/mediatek/vcodec/Kconfig b/drivers/media/platform/mediatek/vcodec/Kconfig
index bc8292232530..d23dad5c78ce 100644
--- a/drivers/media/platform/mediatek/vcodec/Kconfig
+++ b/drivers/media/platform/mediatek/vcodec/Kconfig
@@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_MEDIATEK_VCODEC_VCP
+ bool
+
config VIDEO_MEDIATEK_VCODEC_SCP
bool
@@ -21,6 +24,7 @@ config VIDEO_MEDIATEK_VCODEC
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU
select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP
+ select VIDEO_MEDIATEK_VCODEC_VCP if MTK_VCP_RPROC
select V4L2_H264
select V4L2_VP9
select MEDIA_CONTROLLER
diff --git a/drivers/media/platform/mediatek/vcodec/common/Makefile b/drivers/media/platform/mediatek/vcodec/common/Makefile
index d0479914dfb3..2f68692e8c98 100644
--- a/drivers/media/platform/mediatek/vcodec/common/Makefile
+++ b/drivers/media/platform/mediatek/vcodec/common/Makefile
@@ -14,6 +14,10 @@ ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP),)
mtk-vcodec-common-y += mtk_vcodec_fw_scp.o
endif
+ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_VCP),)
+mtk-vcodec-common-y += mtk_vcodec_fw_vcp.o
+endif
+
ifneq ($(CONFIG_DEBUG_FS),)
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dbgfs.o
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
index 08949b08fbc6..fc547afa4ebf 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
@@ -3,6 +3,7 @@
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_fw_priv.h"
+#include "mtk_vcodec_fw_vcp.h"
struct mtk_vcodec_fw *mtk_vcodec_fw_select(void *priv, enum mtk_vcodec_fw_type type,
enum mtk_vcodec_fw_use fw_use)
@@ -19,6 +20,8 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_select(void *priv, enum mtk_vcodec_fw_type t
return mtk_vcodec_fw_vpu_init(priv, fw_use);
case SCP:
return mtk_vcodec_fw_scp_init(priv, fw_use);
+ case VCP:
+ return mtk_vcodec_fw_vcp_init(priv, fw_use);
default:
dev_err(&plat_dev->dev, "Invalid vcodec fw type");
return ERR_PTR(-EINVAL);
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
index 300363a40158..c1642fb09b42 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
@@ -14,6 +14,7 @@ struct mtk_vcodec_enc_dev;
enum mtk_vcodec_fw_type {
VPU,
SCP,
+ VCP,
};
enum mtk_vcodec_fw_use {
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_priv.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_priv.h
index 99603accd82e..0a2a9b010244 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_priv.h
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_priv.h
@@ -4,6 +4,7 @@
#define _MTK_VCODEC_FW_PRIV_H_
#include "mtk_vcodec_fw.h"
+#include "mtk_vcodec_fw_vcp.h"
struct mtk_vcodec_dec_dev;
struct mtk_vcodec_enc_dev;
@@ -13,6 +14,7 @@ struct mtk_vcodec_fw {
const struct mtk_vcodec_fw_ops *ops;
struct platform_device *pdev;
struct mtk_scp *scp;
+ struct mtk_vcp *vcp;
enum mtk_vcodec_fw_use fw_use;
};
@@ -49,4 +51,14 @@ mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use fw_use)
}
#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_SCP */
+#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_VCP)
+struct mtk_vcodec_fw *mtk_vcodec_fw_vcp_init(void *priv, enum mtk_vcodec_fw_use fw_use);
+#else
+static inline struct mtk_vcodec_fw *
+mtk_vcodec_fw_vcp_init(void *priv, enum mtk_vcodec_fw_use fw_use)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_VCP */
+
#endif /* _MTK_VCODEC_FW_PRIV_H_ */
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
new file mode 100644
index 000000000000..9fee52fed181
--- /dev/null
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/remoteproc/mtk_vcp_public.h>
+#include <linux/firmware/mediatek/mtk-vcp-ipc.h>
+
+#include "../decoder/mtk_vcodec_dec_drv.h"
+#include "../decoder/vdec_ipi_msg.h"
+#include "mtk_vcodec_fw_priv.h"
+
+#define IPI_SEND_TIMEOUT_MS 100U
+#define IPI_TIMEOUT_MS 100U
+
+#define VCP_IPI_HEADER_SIZE (sizeof(u32) * 2)
+#define VCP_IPI_ALIGN (4)
+
+static struct mutex *mtk_vcodec_vcp_get_ipi_lock(struct mtk_vcp *vcp, u32 ipi_id)
+{
+ return &vcp->ipi_desc[ipi_id].lock;
+}
+
+static void mtk_vcodec_vcp_ipi_lock(struct mtk_vcp *vcp, u32 ipi_id)
+{
+ struct mutex *lock = mtk_vcodec_vcp_get_ipi_lock(vcp, ipi_id);
+
+ if (!lock)
+ return;
+
+ mutex_lock(lock);
+}
+
+static void mtk_vcodec_vcp_ipi_unlock(struct mtk_vcp *vcp, u32 ipi_id)
+{
+ struct mutex *lock = mtk_vcodec_vcp_get_ipi_lock(vcp, ipi_id);
+
+ if (!lock)
+ return;
+
+ lockdep_assert_held(lock);
+ mutex_unlock(lock);
+}
+
+static spinlock_t *mtk_vcodec_vcp_get_msg_queue_lock(struct mtk_vcodec_fw *fw)
+{
+ return &fw->vcp->msg_queue.lock;
+}
+
+static void mtk_vcodec_vcp_msq_queue_lock(struct mtk_vcodec_fw *fw, unsigned long *flags)
+{
+ spinlock_t *lock = mtk_vcodec_vcp_get_msg_queue_lock(fw);
+
+ if (!lock)
+ return;
+
+ spin_lock_irqsave(lock, *flags);
+}
+
+static void mtk_vcodec_vcp_msq_queue_unlock(struct mtk_vcodec_fw *fw, unsigned long *flags)
+{
+ spinlock_t *lock = mtk_vcodec_vcp_get_msg_queue_lock(fw);
+
+ if (!lock)
+ return;
+
+ spin_unlock_irqrestore(lock, *flags);
+}
+
+static int mtk_vcodec_vcp_notifier(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+ struct mtk_vcp *vcp = container_of(nb, struct mtk_vcp, vcp_notify);
+
+ switch (event) {
+ case VCP_EVENT_SUSPEND:
+ case VCP_EVENT_STOP:
+ dev_dbg(&vcp->pdev->dev, "vcp notifier suspend");
+ break;
+ case VCP_EVENT_READY:
+ case VCP_EVENT_RESUME:
+ dev_dbg(&vcp->pdev->dev, "vcp notifier ready");
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static void mtk_vcodec_vcp_free_msg_node(struct mtk_vcodec_fw *fw,
+ struct mtk_vcp_msg_node *msg_node)
+{
+ unsigned long flags;
+
+ mtk_vcodec_vcp_msq_queue_lock(fw, &flags);
+ list_add(&msg_node->list, &fw->vcp->msg_queue.node_list);
+ mtk_vcodec_vcp_msq_queue_unlock(fw, &flags);
+}
+
+static int mtk_vcodec_vcp_ipi_register(struct mtk_vcp *vcp, u32 ipi_id, vcp_ipi_handler_t handler,
+ void *priv)
+{
+ if (!vcp)
+ return -EPROBE_DEFER;
+
+ if (WARN_ON(ipi_id >= VCP_IPI_MAX) || WARN_ON(!handler))
+ return -EINVAL;
+
+ mtk_vcodec_vcp_ipi_lock(vcp, ipi_id);
+ vcp->ipi_desc[ipi_id].handler = handler;
+ vcp->ipi_desc[ipi_id].priv = priv;
+ mtk_vcodec_vcp_ipi_unlock(vcp, ipi_id);
+
+ return 0;
+}
+
+static int mtk_vcodec_vcp_msg_process_thread(void *arg)
+{
+ struct mtk_vcodec_fw *fw = arg;
+ struct vdec_vpu_ipi_ack *msg = NULL;
+ struct mtk_vcp_share_obj *obj;
+ struct mtk_vcp_msg_node *msg_node;
+ vcp_ipi_handler_t handler;
+ unsigned long flags;
+ int ret = 0;
+
+ do {
+ ret = wait_event_interruptible(fw->vcp->msg_queue.wq,
+ atomic_read(&fw->vcp->msg_queue.cnt) > 0);
+ if (ret < 0) {
+ dev_err(&fw->pdev->dev, "wait msg queue ack timeout %d %d\n",
+ ret, atomic_read(&fw->vcp->msg_queue.cnt));
+ continue;
+ }
+
+ mtk_vcodec_vcp_msq_queue_lock(fw, &flags);
+ msg_node = list_entry(fw->vcp->msg_queue.msg_list.next,
+ struct mtk_vcp_msg_node, list);
+ list_del(&msg_node->list);
+ atomic_dec(&fw->vcp->msg_queue.cnt);
+ mtk_vcodec_vcp_msq_queue_unlock(fw, &flags);
+
+ obj = &msg_node->ipi_data;
+ msg = (struct vdec_vpu_ipi_ack *)obj->share_buf;
+
+ if (!msg->ap_inst_addr) {
+ dev_err(&fw->pdev->dev, "invalid message address\n");
+ mtk_vcodec_vcp_free_msg_node(fw, msg_node);
+ continue;
+ }
+
+ dev_dbg(&fw->pdev->dev, "msg ack id %d len %d msg_id 0x%x\n", obj->id, obj->len,
+ msg->msg_id);
+
+ mtk_vcodec_vcp_ipi_lock(fw->vcp, obj->id);
+ handler = fw->vcp->ipi_desc[obj->id].handler;
+ if (!handler) {
+ dev_err(&fw->pdev->dev, "invalid ack ipi handler id = %d\n", obj->id);
+ mtk_vcodec_vcp_ipi_unlock(fw->vcp, obj->id);
+ mtk_vcodec_vcp_free_msg_node(fw, msg_node);
+ return -EINVAL;
+ }
+
+ handler(msg, obj->len, fw->vcp->ipi_desc[obj->id].priv);
+ mtk_vcodec_vcp_ipi_unlock(fw->vcp, obj->id);
+
+ fw->vcp->msg_signaled[obj->id] = true;
+ wake_up(&fw->vcp->msg_wq[obj->id]);
+
+ mtk_vcodec_vcp_free_msg_node(fw, msg_node);
+ } while (!kthread_should_stop());
+
+ return ret;
+}
+
+static int mtk_vcodec_vcp_msg_ack_isr(unsigned int id, void *prdata, void *data, unsigned int len)
+{
+ struct mtk_vcodec_fw *fw = prdata;
+ struct mtk_vcp_msg_queue *msg_queue = &fw->vcp->msg_queue;
+ struct mtk_vcp_msg_node *msg_node;
+ struct vdec_vpu_ipi_ack *msg = NULL;
+ struct mtk_vcp_share_obj *obj = data;
+ unsigned long flags;
+
+ msg = (struct vdec_vpu_ipi_ack *)obj->share_buf;
+
+ mtk_vcodec_vcp_msq_queue_lock(fw, &flags);
+ if (!list_empty(&msg_queue->node_list)) {
+ msg_node = list_entry(msg_queue->node_list.next, struct mtk_vcp_msg_node, list);
+
+ memcpy(&msg_node->ipi_data, obj, sizeof(*obj));
+ list_move_tail(&msg_node->list, &msg_queue->msg_list);
+ atomic_inc(&msg_queue->cnt);
+ mtk_vcodec_vcp_msq_queue_unlock(fw, &flags);
+
+ dev_dbg(&fw->pdev->dev, "push ipi_id %x msg_id %x, msg cnt %d\n",
+ obj->id, msg->msg_id, atomic_read(&msg_queue->cnt));
+
+ wake_up(&msg_queue->wq);
+ } else {
+ mtk_vcodec_vcp_msq_queue_unlock(fw, &flags);
+ dev_err(&fw->pdev->dev, "no free nodes in msg queue\n");
+ }
+
+ return 0;
+}
+
+static int mtk_vcodec_vcp_msg_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait)
+{
+ struct mtk_vcp *vcp = fw->vcp;
+ struct mtk_vcp_device *vcp_device = vcp->vcp_device;
+ bool *msg_signaled = &vcp->msg_signaled[id];
+ wait_queue_head_t *msg_wq = &vcp->msg_wq[id];
+ int ret, ipi_size, feature_id, mailbox_id, retry_cnt = 0;
+ unsigned long timeout_jiffies = 0;
+ struct mtk_vcp_share_obj obj = {0};
+ unsigned int *data;
+
+ if (!vcp_device) {
+ dev_dbg(&fw->pdev->dev, "vcp device is null\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&vcp->ipi_mutex);
+ feature_id = VDEC_FEATURE_ID;
+ mailbox_id = IPI_OUT_VDEC_1;
+
+ timeout_jiffies = jiffies + msecs_to_jiffies(VCP_SYNC_TIMEOUT_MS);
+ while (!vcp_device->ops->vcp_is_ready(feature_id)) {
+ if (time_after(jiffies, timeout_jiffies)) {
+ vcp->ipi_id_ack[id] = -EINVAL;
+ ret = -EINVAL;
+ goto error;
+ }
+ mdelay(1);
+ }
+
+ if (len > VCP_SHARE_BUF_SIZE) {
+ vcp->ipi_id_ack[id] = -EINVAL;
+ ret = -EINVAL;
+ goto error;
+ }
+
+ obj.id = id;
+ obj.len = len;
+ memcpy(obj.share_buf, buf, len);
+
+ ipi_size = round_up(VCP_IPI_HEADER_SIZE + len, VCP_IPI_ALIGN);
+ data = (unsigned int *)obj.share_buf;
+ dev_dbg(&fw->pdev->dev, "vcp send message: id %d len %d data 0x%x\n",
+ obj.id, obj.len, data[0]);
+
+ ret = mtk_vcp_ipc_send(vcp_get_ipidev(vcp_device), mailbox_id, &obj, ipi_size);
+ if (ret != IPI_ACTION_DONE) {
+ vcp->ipi_id_ack[id] = -EIO;
+ ret = -EIO;
+ goto error;
+ }
+
+wait_ack:
+ /* wait for VCP's ACK */
+ ret = wait_event_timeout(*msg_wq, *msg_signaled, msecs_to_jiffies(IPI_TIMEOUT_MS));
+ if (!ret || retry_cnt > 5) {
+ vcp->ipi_id_ack[id] = VCODEC_IPI_MSG_STATUS_FAIL;
+ dev_err(&fw->pdev->dev, "wait ipi ack timeout! %d %d\n", ret, vcp->ipi_id_ack[id]);
+ } else if (ret == -ERESTARTSYS) {
+ dev_err(&fw->pdev->dev, "wait ipi ack err (%d)\n", vcp->ipi_id_ack[id]);
+ retry_cnt++;
+ goto wait_ack;
+ } else if (ret < 0) {
+ dev_err(&fw->pdev->dev, "wait ipi ack fail ret %d %d\n", ret, vcp->ipi_id_ack[id]);
+ vcp->ipi_id_ack[id] = VCODEC_IPI_MSG_STATUS_FAIL;
+ }
+
+ dev_dbg(&fw->pdev->dev, "receive message: id %d len %d data 0x%x\n",
+ obj.id, obj.len, data[0]);
+
+ *msg_signaled = false;
+ mutex_unlock(&vcp->ipi_mutex);
+
+ return vcp->ipi_id_ack[id];
+
+error:
+ mutex_unlock(&vcp->ipi_mutex);
+ dev_err(&fw->pdev->dev, "send msg error type:%d msg:%d > %d ret:%d\n", fw->type, len,
+ VCP_SHARE_BUF_SIZE, ret);
+
+ return ret;
+}
+
+static int check_vcp_loaded(struct mtk_vcodec_fw *fw)
+{
+ struct device *dev = &fw->pdev->dev;
+ struct device_driver *drv;
+
+ drv = driver_find("mtk-vcp", &platform_bus_type);
+ if (!drv) {
+ dev_err(dev, "find mtk-vcp driver failed, need to reload.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_vcodec_vcp_get_vcp_device(struct mtk_vcodec_fw *fw)
+{
+ struct device *dev = &fw->pdev->dev;
+ int retry = 0, retry_cnt = 10000;
+ phandle vcp_phandle;
+
+ while (try_then_request_module(check_vcp_loaded(fw), "mtk-vcp")) {
+ if (++retry > retry_cnt) {
+ dev_err(dev, "failed to load mtk-vcp module");
+ return -EPROBE_DEFER;
+ }
+ msleep(1);
+ }
+
+ if (of_property_read_u32(dev->of_node, "mediatek,vcp", &vcp_phandle)) {
+ dev_err(dev, "can't get vcp handle.\n");
+ return -ENODEV;
+ }
+
+ fw->vcp->vcp_device = mtk_vcp_get_by_phandle(vcp_phandle);
+ if (!fw->vcp->vcp_device) {
+ dev_err(dev, "get vcp device failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int mtk_vcodec_vcp_load_firmware(struct mtk_vcodec_fw *fw)
+{
+ struct mtk_vcp_device *vcp_device;
+ int ret, feature_id, mem_id, mailbox_id, ipi_id;
+
+ if (fw->vcp->is_init_done) {
+ dev_dbg(&fw->pdev->dev, "vcp has already been initialized done.\n");
+ return 0;
+ }
+
+ if (mtk_vcodec_vcp_get_vcp_device(fw) < 0) {
+ dev_err(&fw->pdev->dev, "vcp device is null.\n");
+ return -EINVAL;
+ }
+
+ vcp_device = fw->vcp->vcp_device;
+
+ feature_id = VDEC_FEATURE_ID;
+ mem_id = VDEC_MEM_ID;
+ mailbox_id = IPI_IN_VDEC_1;
+ ipi_id = VCP_IPI_LAT_DECODER;
+
+ ret = mtk_vcp_mbox_ipc_register(vcp_get_ipidev(vcp_device), mailbox_id,
+ mtk_vcodec_vcp_msg_ack_isr, fw, &fw->vcp->share_data);
+ if (ret) {
+ dev_dbg(&fw->pdev->dev, "ipi register fail %d %d %d %d\n", ret, feature_id,
+ mem_id, mailbox_id);
+ return -EINVAL;
+ }
+
+ fw->vcp->vcp_notify.notifier_call = mtk_vcodec_vcp_notifier;
+ fw->vcp->vcp_notify.priority = 1;
+ vcp_device->ops->vcp_register_notify(feature_id, &fw->vcp->vcp_notify);
+
+ if (!fw->vcp->is_register_done) {
+ ret = vcp_device->ops->vcp_register_feature(vcp_device, feature_id);
+ if (ret < 0) {
+ dev_err(&fw->pdev->dev, "%d register to vcp fail(%d)\n", feature_id, ret);
+ return -EINVAL;
+ }
+
+ fw->vcp->is_register_done = true;
+ }
+
+ fw->vcp->is_init_done = true;
+
+ mutex_init(&fw->vcp->ipi_desc[ipi_id].lock);
+ mutex_init(&fw->vcp->ipi_mutex);
+
+ kthread_run(mtk_vcodec_vcp_msg_process_thread, fw, "vcp_vdec_msq_thread");
+
+ fw->vcp->vsi_addr = vcp_device->ops->vcp_get_mem_virt(mem_id);
+ fw->vcp->vsi_core_addr = fw->vcp->vsi_addr + VCODEC_VSI_LEN;
+ fw->vcp->vsi_size = vcp_device->ops->vcp_get_mem_size(mem_id);
+ fw->vcp->iova_addr = vcp_device->ops->vcp_get_mem_iova(mem_id);
+
+ init_waitqueue_head(&fw->vcp->msg_wq[VCP_IPI_LAT_DECODER]);
+ init_waitqueue_head(&fw->vcp->msg_wq[VCP_IPI_CORE_DECODER]);
+
+ dev_dbg(&fw->pdev->dev, "vdec vcp init done => va: %p size:0x%x iova:%p.\n",
+ fw->vcp->vsi_addr, fw->vcp->vsi_size, &fw->vcp->iova_addr);
+
+ return 0;
+}
+
+static unsigned int mtk_vcodec_vcp_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+ return MTK_VDEC_FORMAT_MM21 | MTK_VDEC_FORMAT_H264_SLICE | MTK_VDEC_FORMAT_VP9_FRAME |
+ MTK_VDEC_FORMAT_AV1_FRAME | MTK_VDEC_FORMAT_HEVC_FRAME |
+ MTK_VDEC_IS_SUPPORT_10BIT | MTK_VDEC_IS_SUPPORT_EXT;
+}
+
+static void *mtk_vcodec_vcp_dm_addr(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr)
+{
+ return NULL;
+}
+
+static int mtk_vcodec_vcp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler,
+ const char *name, void *priv)
+{
+ return mtk_vcodec_vcp_ipi_register(fw->vcp, id, handler, priv);
+}
+
+static int mtk_vcodec_vcp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait)
+{
+ return mtk_vcodec_vcp_msg_ipi_send(fw, id, buf, len, wait);
+}
+
+static void mtk_vcodec_vcp_release(struct mtk_vcodec_fw *fw)
+{
+ struct mtk_vcp_device *vcp_device = fw->vcp->vcp_device;
+ struct device *dev = &fw->pdev->dev;
+ int ret, feature_id;
+
+ if (!fw->vcp->vcp_device) {
+ dev_err(dev, "vcp device is null\n");
+ return;
+ }
+
+ if (!fw->vcp->is_register_done)
+ return;
+
+ feature_id = VDEC_FEATURE_ID;
+ ret = vcp_device->ops->vcp_deregister_feature(vcp_device, VDEC_FEATURE_ID);
+ if (ret < 0) {
+ dev_err(dev, "deregister feature_id(%d) fail(%d)\n", feature_id, ret);
+ return;
+ }
+
+ fw->vcp->is_register_done = false;
+
+}
+
+static const struct mtk_vcodec_fw_ops mtk_vcodec_vcp_msg = {
+ .load_firmware = mtk_vcodec_vcp_load_firmware,
+ .get_vdec_capa = mtk_vcodec_vcp_get_vdec_capa,
+ .map_dm_addr = mtk_vcodec_vcp_dm_addr,
+ .ipi_register = mtk_vcodec_vcp_set_ipi_register,
+ .ipi_send = mtk_vcodec_vcp_ipi_send,
+ .release = mtk_vcodec_vcp_release,
+};
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_vcp_init(void *priv, enum mtk_vcodec_fw_use fw_use)
+{
+ struct mtk_vcp_msg_node *msg_node;
+ struct platform_device *plat_dev;
+ struct mtk_vcodec_fw *fw;
+ int i;
+
+ if (fw_use == DECODER) {
+ struct mtk_vcodec_dec_dev *dec_dev = priv;
+
+ plat_dev = dec_dev->plat_dev;
+ } else {
+ pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use);
+ return ERR_PTR(-EINVAL);
+ }
+
+ fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return ERR_PTR(-ENOMEM);
+
+ fw->type = VCP;
+ fw->pdev = plat_dev;
+ fw->fw_use = fw_use;
+ fw->ops = &mtk_vcodec_vcp_msg;
+ fw->vcp = devm_kzalloc(&plat_dev->dev, sizeof(*fw->vcp), GFP_KERNEL);
+ if (!fw->vcp)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&fw->vcp->msg_queue.msg_list);
+ INIT_LIST_HEAD(&fw->vcp->msg_queue.node_list);
+ spin_lock_init(&fw->vcp->msg_queue.lock);
+ init_waitqueue_head(&fw->vcp->msg_queue.wq);
+ atomic_set(&fw->vcp->msg_queue.cnt, 0);
+ fw->vcp->pdev = plat_dev;
+
+ for (i = 0; i < VCP_MAX_MQ_NODE_CNT; i++) {
+ msg_node = devm_kzalloc(&plat_dev->dev, sizeof(*msg_node), GFP_KERNEL);
+ if (!msg_node)
+ return ERR_PTR(-ENOMEM);
+
+ list_add(&msg_node->list, &fw->vcp->msg_queue.node_list);
+ }
+
+ return fw;
+}
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
new file mode 100644
index 000000000000..fada786124d5
--- /dev/null
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#ifndef _MTK_VCODEC_FW_VCP_H_
+#define _MTK_VCODEC_FW_VCP_H_
+
+typedef void (*vcp_ipi_handler_t) (void *data, unsigned int len, void *priv);
+
+#define VCP_MAX_MQ_NODE_CNT 6
+#define VCP_SHARE_BUF_SIZE 64
+
+#define VCODEC_VSI_LEN (0x2000)
+
+/* enum mtk_vcp_ipi_index - index used to separate different hardware */
+enum mtk_vcp_ipi_index {
+ VCP_IPI_LAT_DECODER,
+ VCP_IPI_CORE_DECODER,
+ VCP_IPI_MAX,
+};
+
+/**
+ * struct mtk_vcp_msg_queue - process the vcp message between kernel with vcp
+ *
+ * @msg_list: store share buffer list which from vcp to kernel
+ * @wq: waitqueue that can be used to wait for vcp message
+ * @lock: protect msg list
+ * @cnt: the count of share obj in msg list
+ * @node_list: share obj list
+ */
+struct mtk_vcp_msg_queue {
+ struct list_head msg_list;
+ wait_queue_head_t wq;
+ spinlock_t lock;
+ atomic_t cnt;
+ struct list_head node_list;
+};
+
+/**
+ * struct mtk_vcp_ipi_desc - store the ack handler
+ *
+ * @lock: protect ack handler data
+ * @handler: calling this handler when kernel receive ack
+ * @priv: private data when calling handler to process
+ */
+struct mtk_vcp_ipi_desc {
+ struct mutex lock;
+ vcp_ipi_handler_t handler;
+ void *priv;
+};
+
+/**
+ * struct mtk_vcp_share_obj - share buffer used to send data to vcp
+ *
+ * @id: message index
+ * @len: message size
+ * @share_buf: message data
+ */
+struct mtk_vcp_share_obj {
+ unsigned int id;
+ unsigned int len;
+ unsigned char share_buf[VCP_SHARE_BUF_SIZE];
+};
+
+/* enum mtk_vcp_ipi_msg_status - the status when send message to vcp */
+enum mtk_vcp_ipi_msg_status {
+ VCODEC_IPI_MSG_STATUS_OK = 0,
+ VCODEC_IPI_MSG_STATUS_FAIL = -1,
+ VCODEC_IPI_MSG_STATUS_MAX_INST = -2,
+ VCODEC_IPI_MSG_STATUS_ILSEQ = -3,
+ VCODEC_IPI_MSG_STATUS_INVALID_ID = -4,
+ VCODEC_IPI_MSG_STATUS_DMA_FAIL = -5,
+};
+
+/**
+ * struct mtk_vcp_msg_node - share buffer used to send data to vcp
+ *
+ * @ipi_data: share obj data
+ * @list: list to store msg node
+ */
+struct mtk_vcp_msg_node {
+ struct mtk_vcp_share_obj ipi_data;
+ struct list_head list;
+};
+
+/**
+ * struct mtk_vcp - vcp firmware private data
+ *
+ * @is_init_done: vcp is ready to use
+ *
+ * @ipi_mutex: used to protect ipi data
+ * @msg_signaled: whether receive ack from vcp
+ * @msg_wq: wake message queue
+ *
+ * @ipi_desc: store ack handler
+ * @ipi_id_ack: the ack handler status
+ *
+ * @msg_queue: process vcp message
+ * @share_data: temp share obj data
+ *
+ * @vcp_notify: register notifier to vcp
+ *
+ * @vsi_addr: vsi virtual data address
+ * @vsi_core_addr: vsi core virtual data address
+ * @iova_addr: vsi iova address
+ * @vsi_size: vsi size
+ *
+ * @pdev: platform device
+ * @vcp_device: vcp private data
+ * @is_register_done: register vcodec to vcp
+ */
+struct mtk_vcp {
+ bool is_init_done;
+
+ struct mutex ipi_mutex;
+ bool msg_signaled[VCP_IPI_MAX];
+ wait_queue_head_t msg_wq[VCP_IPI_MAX];
+
+ struct mtk_vcp_ipi_desc ipi_desc[VCP_IPI_MAX];
+ bool ipi_id_ack[VCP_IPI_MAX];
+
+ struct mtk_vcp_msg_queue msg_queue;
+ struct mtk_vcp_share_obj share_data;
+
+ struct notifier_block vcp_notify;
+
+ void *vsi_addr;
+ void *vsi_core_addr;
+ dma_addr_t iova_addr;
+ int vsi_size;
+
+ struct platform_device *pdev;
+ struct mtk_vcp_device *vcp_device;
+ bool is_register_done;
+};
+
+#endif
--
2.45.2
^ permalink raw reply related
* [PATCH v4 00/14] media: mediatek: vcodec: support video decoder in mt8196
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
This patch set adds support for the video decoder on the MediaTek MT8196
platform, leveraging the VCP microprocessor for enhanced performance. It
introduces new firmware interfaces for kernel-side communication with VCP,
adds MT8196 compatible, codec levels/profiles, and private data. Rewrites
the AV1 driver to support extended VSI structures, then change irq table
and cdf table size.
This patch set depends on "Add VCP support for mt8196"[1]
[1] https://patchwork.kernel.org/project/linux-remoteproc/patch/20250402092134.12293-2-xiangzhi.tang@mediatek.com/
Compliance Test Result:
- v4l2-compliance: 48/49 tests passed, 1 failed (known issue)
- fail: v4l2-test-controls.cpp(981): ret (got 13)
- test VIDIOC_G/S/TRY_EXT_CTRLS: FAIL
Fluster Test Result:
- H264:
- Ran 95/135 tests successfully in 73.540 secs
- H265:
- Ran 142/147 tests successfully in 100.168 secs
- VP9:
- Ran 276/305 tests successfully in 106.804 secs
- AV1:
- Ran 240/242 tests successfully in 23.991 secs
---
Changed in v4:
- Rebase to latest codebase
- Move dt-bindings and compatible to the after of vcp driver ready
- MT8189 base on MT8196 patch set
Changed in v3:
- Depends on change no update
- Add Compliance and Fluster test result
- Re-write the commit message for patch 12
- Change the patches according to review suggestion for patch: 3/4/5/6/14
Changed in v2:
- re-write the commit message for patch 1
---
Yunfei Dong (14):
media: mediatek: vcodec: add driver to support vcp
media: mediatek: vcodec: add driver to support vcp encoder
media: mediatek: vcodec: get different firmware ipi id
media: mediatek: vcodec: get share memory address
media: mediatek: vcodec: define MT8196 vcodec levels.
media: mediatek: vcodec: support vcp architecture
media: mediatek: vcodec: support 36bit iova address
media: mediatek: vcodec: clean xpc status
media: mediatek: vcodec: add debug information
media: mediatek: vcodec: send share memory address to vcp
dt-bindings: media: mediatek: vcodec: add decoder dt-bindings for
mt8196
media: mediatek: vcodec: add decoder compatible to support mt8196
media: mediatek: decoder: fill av1 buffer size with picinfo
media: mediatek: decoder: support av1 extend vsi
.../media/mediatek,vcodec-subdev-decoder.yaml | 1 +
.../media/platform/mediatek/vcodec/Kconfig | 4 +
.../platform/mediatek/vcodec/common/Makefile | 4 +
.../mediatek/vcodec/common/mtk_vcodec_dbgfs.c | 21 +-
.../mediatek/vcodec/common/mtk_vcodec_fw.c | 16 +
.../mediatek/vcodec/common/mtk_vcodec_fw.h | 2 +
.../vcodec/common/mtk_vcodec_fw_priv.h | 12 +
.../vcodec/common/mtk_vcodec_fw_vcp.c | 561 ++++++++++++++++++
.../vcodec/common/mtk_vcodec_fw_vcp.h | 153 +++++
.../vcodec/decoder/mtk_vcodec_dec_drv.c | 16 +
.../vcodec/decoder/mtk_vcodec_dec_drv.h | 1 +
.../vcodec/decoder/mtk_vcodec_dec_hw.c | 28 +
.../vcodec/decoder/mtk_vcodec_dec_hw.h | 13 +-
.../vcodec/decoder/mtk_vcodec_dec_stateless.c | 6 +
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 113 +++-
.../decoder/vdec/vdec_h264_req_multi_if.c | 11 +-
.../decoder/vdec/vdec_hevc_req_multi_if.c | 12 +-
.../vcodec/decoder/vdec/vdec_vp8_req_if.c | 5 +-
.../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 27 +-
.../mediatek/vcodec/decoder/vdec_ipi_msg.h | 2 +
.../mediatek/vcodec/decoder/vdec_vpu_if.c | 12 +-
.../mediatek/vcodec/encoder/mtk_vcodec_enc.c | 1 -
.../mediatek/vcodec/encoder/mtk_vcodec_enc.h | 2 +
23 files changed, 985 insertions(+), 38 deletions(-)
create mode 100644 drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
create mode 100644 drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
--
2.45.2
^ permalink raw reply
* [PATCH v4 06/14] media: mediatek: vcodec: support vcp architecture
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Some platforms expose the video codec through the VCP coprocessor.
Use the VCP architecture when the VCP coprocessor is found.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index e936ed8dffba..d220b645e455 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -379,6 +379,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
} else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
&rproc_phandle)) {
fw_type = SCP;
+ } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vcp",
+ &rproc_phandle)) {
+ fw_type = VCP;
} else {
dev_dbg(&pdev->dev, "Could not get vdec IPI device");
return -ENODEV;
--
2.45.2
^ permalink raw reply related
* [PATCH v4 02/14] media: mediatek: vcodec: add driver to support vcp encoder
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Encoder also need to call vcp interface to communicate with vcp,
add driver to support encoder.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../vcodec/common/mtk_vcodec_fw_vcp.c | 56 ++++++++++++++++---
.../vcodec/common/mtk_vcodec_fw_vcp.h | 1 +
.../mediatek/vcodec/encoder/mtk_vcodec_enc.c | 1 -
.../mediatek/vcodec/encoder/mtk_vcodec_enc.h | 2 +
4 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
index 9fee52fed181..32d4e566f357 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.c
@@ -13,6 +13,8 @@
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../decoder/vdec_ipi_msg.h"
+#include "../encoder/mtk_vcodec_enc.h"
+#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_fw_priv.h"
#define IPI_SEND_TIMEOUT_MS 100U
@@ -226,8 +228,13 @@ static int mtk_vcodec_vcp_msg_ipi_send(struct mtk_vcodec_fw *fw, int id, void *b
}
mutex_lock(&vcp->ipi_mutex);
- feature_id = VDEC_FEATURE_ID;
- mailbox_id = IPI_OUT_VDEC_1;
+ if (fw->fw_use == ENCODER) {
+ feature_id = VENC_FEATURE_ID;
+ mailbox_id = IPI_OUT_VENC_0;
+ } else {
+ feature_id = VDEC_FEATURE_ID;
+ mailbox_id = IPI_OUT_VDEC_1;
+ }
timeout_jiffies = jiffies + msecs_to_jiffies(VCP_SYNC_TIMEOUT_MS);
while (!vcp_device->ops->vcp_is_ready(feature_id)) {
@@ -351,10 +358,17 @@ static int mtk_vcodec_vcp_load_firmware(struct mtk_vcodec_fw *fw)
vcp_device = fw->vcp->vcp_device;
- feature_id = VDEC_FEATURE_ID;
- mem_id = VDEC_MEM_ID;
- mailbox_id = IPI_IN_VDEC_1;
- ipi_id = VCP_IPI_LAT_DECODER;
+ if (fw->fw_use == ENCODER) {
+ feature_id = VENC_FEATURE_ID;
+ mem_id = VENC_MEM_ID;
+ mailbox_id = IPI_IN_VENC_0;
+ ipi_id = VCP_IPI_ENCODER;
+ } else {
+ feature_id = VDEC_FEATURE_ID;
+ mem_id = VDEC_MEM_ID;
+ mailbox_id = IPI_IN_VDEC_1;
+ ipi_id = VCP_IPI_LAT_DECODER;
+ }
ret = mtk_vcp_mbox_ipc_register(vcp_get_ipidev(vcp_device), mailbox_id,
mtk_vcodec_vcp_msg_ack_isr, fw, &fw->vcp->share_data);
@@ -383,6 +397,20 @@ static int mtk_vcodec_vcp_load_firmware(struct mtk_vcodec_fw *fw)
mutex_init(&fw->vcp->ipi_desc[ipi_id].lock);
mutex_init(&fw->vcp->ipi_mutex);
+ if (fw->fw_use == ENCODER) {
+ kthread_run(mtk_vcodec_vcp_msg_process_thread, fw, "vcp_enc_msq_thread");
+
+ fw->vcp->vsi_addr = vcp_device->ops->vcp_get_mem_virt(mem_id);
+ fw->vcp->vsi_size = vcp_device->ops->vcp_get_mem_size(mem_id);
+ fw->vcp->iova_addr = vcp_device->ops->vcp_get_mem_iova(mem_id);
+
+ dev_dbg(&fw->pdev->dev, "enc vcp init done => va: %p size:0x%x iova:%pad.\n",
+ fw->vcp->vsi_addr, fw->vcp->vsi_size, &fw->vcp->iova_addr);
+
+ init_waitqueue_head(&fw->vcp->msg_wq[VCP_IPI_ENCODER]);
+ return 0;
+ }
+
kthread_run(mtk_vcodec_vcp_msg_process_thread, fw, "vcp_vdec_msq_thread");
fw->vcp->vsi_addr = vcp_device->ops->vcp_get_mem_virt(mem_id);
@@ -406,6 +434,11 @@ static unsigned int mtk_vcodec_vcp_get_vdec_capa(struct mtk_vcodec_fw *fw)
MTK_VDEC_IS_SUPPORT_10BIT | MTK_VDEC_IS_SUPPORT_EXT;
}
+static unsigned int mtk_vcodec_vcp_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+ return MTK_VENC_4K_CAPABILITY_ENABLE;
+}
+
static void *mtk_vcodec_vcp_dm_addr(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr)
{
return NULL;
@@ -438,8 +471,8 @@ static void mtk_vcodec_vcp_release(struct mtk_vcodec_fw *fw)
if (!fw->vcp->is_register_done)
return;
- feature_id = VDEC_FEATURE_ID;
- ret = vcp_device->ops->vcp_deregister_feature(vcp_device, VDEC_FEATURE_ID);
+ feature_id = fw->fw_use == ENCODER ? VENC_FEATURE_ID : VDEC_FEATURE_ID;
+ ret = vcp_device->ops->vcp_deregister_feature(vcp_device, feature_id);
if (ret < 0) {
dev_err(dev, "deregister feature_id(%d) fail(%d)\n", feature_id, ret);
return;
@@ -452,6 +485,7 @@ static void mtk_vcodec_vcp_release(struct mtk_vcodec_fw *fw)
static const struct mtk_vcodec_fw_ops mtk_vcodec_vcp_msg = {
.load_firmware = mtk_vcodec_vcp_load_firmware,
.get_vdec_capa = mtk_vcodec_vcp_get_vdec_capa,
+ .get_venc_capa = mtk_vcodec_vcp_get_venc_capa,
.map_dm_addr = mtk_vcodec_vcp_dm_addr,
.ipi_register = mtk_vcodec_vcp_set_ipi_register,
.ipi_send = mtk_vcodec_vcp_ipi_send,
@@ -465,7 +499,11 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vcp_init(void *priv, enum mtk_vcodec_fw_use
struct mtk_vcodec_fw *fw;
int i;
- if (fw_use == DECODER) {
+ if (fw_use == ENCODER) {
+ struct mtk_vcodec_enc_dev *enc_dev = priv;
+
+ plat_dev = enc_dev->plat_dev;
+ } else if (fw_use == DECODER) {
struct mtk_vcodec_dec_dev *dec_dev = priv;
plat_dev = dec_dev->plat_dev;
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
index fada786124d5..c0632a872892 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vcp.h
@@ -16,6 +16,7 @@ typedef void (*vcp_ipi_handler_t) (void *data, unsigned int len, void *priv);
/* enum mtk_vcp_ipi_index - index used to separate different hardware */
enum mtk_vcp_ipi_index {
+ VCP_IPI_ENCODER,
VCP_IPI_LAT_DECODER,
VCP_IPI_CORE_DECODER,
VCP_IPI_MAX,
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
index 0d4e94463685..48cb5dded70a 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
@@ -26,7 +26,6 @@
#define MTK_DEFAULT_FRAMERATE_NUM 1001
#define MTK_DEFAULT_FRAMERATE_DENOM 30000
-#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
static void mtk_venc_worker(struct work_struct *work);
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h
index 908d8179b2d2..84156c102d8d 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h
@@ -23,6 +23,8 @@
#define MTK_VENC_IRQ_STATUS_OFFSET 0x05C
#define MTK_VENC_IRQ_ACK_OFFSET 0x060
+#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
+
/**
* struct mtk_video_enc_buf - Private data related to each VB2 buffer.
* @m2m_buf: M2M buffer
--
2.45.2
^ permalink raw reply related
* [PATCH v4 03/14] media: mediatek: vcodec: get different firmware ipi id
From: Yunfei Dong @ 2026-03-28 5:16 UTC (permalink / raw)
To: Nícolas F . R . A . Prado, Sebastian Fricke,
Nicolas Dufresne, Hans Verkuil, AngeloGioacchino Del Regno,
Benjamin Gaignard, Nathan Hebert, Daniel Almeida
Cc: Hsin-Yi Wang, Fritz Koenig, Daniel Vetter, Steve Cho, Yunfei Dong,
linux-media, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260328051630.7937-1-yunfei.dong@mediatek.com>
Getting ipi(inter-processor interrupt) id according to firmware
type and hardware index for different architecture.
Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
.../platform/mediatek/vcodec/common/mtk_vcodec_fw.c | 13 +++++++++++++
.../platform/mediatek/vcodec/common/mtk_vcodec_fw.h | 1 +
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 5 +++--
.../vcodec/decoder/vdec/vdec_h264_req_multi_if.c | 5 +++--
.../vcodec/decoder/vdec/vdec_hevc_req_multi_if.c | 5 +++--
.../mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c | 5 +++--
.../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 5 +++--
7 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
index fc547afa4ebf..4ed7639dfa30 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.c
@@ -5,6 +5,19 @@
#include "mtk_vcodec_fw_priv.h"
#include "mtk_vcodec_fw_vcp.h"
+int mtk_vcodec_fw_get_ipi(enum mtk_vcodec_fw_type type, int hw_id)
+{
+ switch (type) {
+ case SCP:
+ return hw_id == MTK_VDEC_LAT0 ? SCP_IPI_VDEC_LAT : SCP_IPI_VDEC_CORE;
+ case VCP:
+ return hw_id == MTK_VDEC_LAT0 ? VCP_IPI_LAT_DECODER : VCP_IPI_CORE_DECODER;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_ipi);
+
struct mtk_vcodec_fw *mtk_vcodec_fw_select(void *priv, enum mtk_vcodec_fw_type type,
enum mtk_vcodec_fw_use fw_use)
{
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
index c1642fb09b42..142e2e87905c 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw.h
@@ -41,5 +41,6 @@ int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id,
void *buf, unsigned int len, unsigned int wait);
int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw);
+int mtk_vcodec_fw_get_ipi(enum mtk_vcodec_fw_type type, int hw_id);
#endif /* _MTK_VCODEC_FW_H_ */
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 2d622e85f827..756fbb7778b1 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1877,6 +1877,7 @@ static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
struct vdec_av1_slice_instance *instance;
struct vdec_av1_slice_init_vsi *vsi;
+ enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
int ret;
instance = kzalloc_obj(*instance);
@@ -1884,8 +1885,8 @@ static int vdec_av1_slice_init(struct mtk_vcodec_dec_ctx *ctx)
return -ENOMEM;
instance->ctx = ctx;
- instance->vpu.id = SCP_IPI_VDEC_LAT;
- instance->vpu.core_id = SCP_IPI_VDEC_CORE;
+ instance->vpu.id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_LAT0);
+ instance->vpu.core_id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_CORE);
instance->vpu.ctx = ctx;
instance->vpu.codec_type = ctx->current_codec;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
index 10359ce9b934..69d60717181a 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c
@@ -1204,6 +1204,7 @@ static int vdec_h264_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs
static int vdec_h264_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
+ enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
struct vdec_h264_slice_inst *inst;
int err, vsi_size;
unsigned char *temp;
@@ -1214,8 +1215,8 @@ static int vdec_h264_slice_init(struct mtk_vcodec_dec_ctx *ctx)
inst->ctx = ctx;
- inst->vpu.id = SCP_IPI_VDEC_LAT;
- inst->vpu.core_id = SCP_IPI_VDEC_CORE;
+ inst->vpu.id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_LAT0);
+ inst->vpu.core_id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_CORE);
inst->vpu.ctx = ctx;
inst->vpu.codec_type = ctx->current_codec;
inst->vpu.capture_type = ctx->capture_fourcc;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
index 02f39954a4c2..dd638ef44083 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c
@@ -855,6 +855,7 @@ static int vdec_hevc_slice_setup_core_buffer(struct vdec_hevc_slice_inst *inst,
static int vdec_hevc_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
+ enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
struct vdec_hevc_slice_inst *inst;
int err, vsi_size;
@@ -864,8 +865,8 @@ static int vdec_hevc_slice_init(struct mtk_vcodec_dec_ctx *ctx)
inst->ctx = ctx;
- inst->vpu.id = SCP_IPI_VDEC_LAT;
- inst->vpu.core_id = SCP_IPI_VDEC_CORE;
+ inst->vpu.id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_LAT0);
+ inst->vpu.core_id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_CORE);
inst->vpu.ctx = ctx;
inst->vpu.codec_type = ctx->current_codec;
inst->vpu.capture_type = ctx->capture_fourcc;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c
index 391e789a5a13..d65e276f6cea 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c
@@ -272,6 +272,7 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst
static int vdec_vp8_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
+ enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
struct vdec_vp8_slice_inst *inst;
int err;
@@ -281,8 +282,8 @@ static int vdec_vp8_slice_init(struct mtk_vcodec_dec_ctx *ctx)
inst->ctx = ctx;
- inst->vpu.id = SCP_IPI_VDEC_LAT;
- inst->vpu.core_id = SCP_IPI_VDEC_CORE;
+ inst->vpu.id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_LAT0);
+ inst->vpu.core_id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_CORE);
inst->vpu.ctx = ctx;
inst->vpu.codec_type = ctx->current_codec;
inst->vpu.capture_type = ctx->capture_fourcc;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index adbacabdbebc..1f0479a8f5cb 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -1844,6 +1844,7 @@ static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance,
static int vdec_vp9_slice_init(struct mtk_vcodec_dec_ctx *ctx)
{
+ enum mtk_vcodec_fw_type fw_type = ctx->dev->fw_handler->type;
struct vdec_vp9_slice_instance *instance;
struct vdec_vp9_slice_init_vsi *vsi;
int ret;
@@ -1853,8 +1854,8 @@ static int vdec_vp9_slice_init(struct mtk_vcodec_dec_ctx *ctx)
return -ENOMEM;
instance->ctx = ctx;
- instance->vpu.id = SCP_IPI_VDEC_LAT;
- instance->vpu.core_id = SCP_IPI_VDEC_CORE;
+ instance->vpu.id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_LAT0);
+ instance->vpu.core_id = mtk_vcodec_fw_get_ipi(fw_type, MTK_VDEC_CORE);
instance->vpu.ctx = ctx;
instance->vpu.codec_type = ctx->current_codec;
--
2.45.2
^ permalink raw reply related
* Re: [PATCH 2/2] dt-bindings: Add clock guard DT description
From: Vyacheslav Yurkov @ 2026-03-28 2:58 UTC (permalink / raw)
To: Conor Dooley
Cc: Krzysztof Kozlowski, Rob Herring, Vyacheslav Yurkov,
Michael Turquette, Stephen Boyd, Krzysztof Kozlowski,
Conor Dooley, linux-kernel, linux-clk, devicetree
In-Reply-To: <20260326-nursery-outer-55799f675e14@spud>
On 26.03.2026 19:32, Conor Dooley wrote:
>> I was not sure how to provide a diagram in the mailing list, so I posted in
>> on Github https://github.com/OSS-Keepers/clock-controller-guard/issues/1
>>
>> It is a driver which models dependencies for other drivers. These are soft
>> or "indirect" dependencies, because we cannot access the FPGA unless the
>> FPGA_PLL_locked, and GPIO is telling us we are good to go.
>>
>> Conor, I think this should answer your question as well.
>
> Not really, but it gets part of the way there. I want to know what this
> provider actually is. I now know it is a PLL, not an off-chip
> oscillator, but I know nothing about the interface that you have to it
> (or if you have one at all). What compatible string/kernel driver does
> it use?
>
> Because SoC-FPGAs can route GPIOs from the SoC part to the FPGA fabric
> and use them as if interacting with something off-chip, I'm not sure if
> we are dealing with an separate FPGA or a SoC-FPGA. Which is it?
> Effectively I want to understand why you cannot just read the lock bit
> from the PLL directly. In my experience with *SoC*-FPGAs, things like
> PLLs that must lock for the fabric to be usable have a register
> interface from which the lock bit can be read, that is of course not
> clocked by the PLL output clock and therefore accessible before the
> PLL has locked.
>
> I think more info is needed here to guide you on where such a "helper
> driver" should be located and what the dt represetation should be.
I really appreciate your feedback on this. Here's an attempt to provide
a better exlanation.
We have various use cases. Most of the time it's a PLL in the FPGA but
it can also be some signal from a custom FPGA IP used to indicate if
some preconditions are met and the IP is ready to be used (some kind of
inverted reset but exposed by the IP). For a PLL we typically get the
signal connected either to a GPIO IP block (altr,pio-1.0) OR to a bit in
a custom IP register.
In addition, some of the IPs in our design do not have a proper split
between registers and IP core, which means that if an external clock
and/or PLL lock is missing and we access the registers we won’t ever get
an answer and thus stall the CPU.
We are using a SoC-FPGA and use some GPIO IP within the FPGA
(altr,pio-1.0 for example).
The PLL itself doesn't have any registers but the signal indicating that
it is locked is available and routed to such a GPIO.
The point is that we will have several IPs/drivers that will depend on
the same preconditions (clk, gpios being high or low) and we want to use
this clk_guard driver as an aggregator for those pre-conditions. Define
once, reuse a lot.
Slava
^ permalink raw reply
* Re: [PATCH v3 0/5] SDM670 LPASS LPI pin controller support
From: Richard Acayan @ 2026-03-28 2:14 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Konrad Dybcio, Srinivas Kandagatla, linux-arm-msm,
linux-gpio, devicetree
In-Reply-To: <20260328021036.85945-1-mailingradian@gmail.com>
On Fri, Mar 27, 2026 at 10:10:31PM -0400, Richard Acayan wrote:
> This adds support for the LPASS LPI pin controller on SDM670, which
> controls some audio pins (e.g. TDM or PDM busses). The ADSP patches are
> not sent yet.
>
> Dependencies:
> - SDM670 Basic SoC thermal zones (devicetree nodes are touching)
> https://lore.kernel.org/r/20260310002037.1863-1-mailingradian@gmail.com
> - Support for the Pixel 3a XL with the Tianma panel (for reserved GPIOs)
> https://lore.kernel.org/r/20260310002606.16413-1-mailingradian@gmail.com
>
> Changes since v2 (https://lore.kernel.org/r/20260310012446.32226-1-mailingradian@gmail.com):
> - add minItems and maxItems (1/5)
> - add review tags (2-5/5)
Uh, it seems I dropped them (pun intended).
^ permalink raw reply
* [PATCH v3 5/5] arm64: dts: qcom: sdm670-google: add reserved lpi gpios
From: Richard Acayan @ 2026-03-28 2:10 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Konrad Dybcio, Srinivas Kandagatla, linux-arm-msm,
linux-gpio, devicetree
Cc: Richard Acayan
In-Reply-To: <20260328021036.85945-1-mailingradian@gmail.com>
Some of the GPIOs are reserved for sensors since the ADSP also handles
sensors on SDM670. Add the reserved GPIOs for the LPI pin controller.
Signed-off-by: Richard Acayan <mailingradian@gmail.com>
---
arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
index cf7b130ea0c4..b0da24fd1aee 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
@@ -519,6 +519,10 @@ rmi4_f12: rmi4-f12@12 {
};
};
+&lpi_tlmm {
+ gpio-reserved-ranges = <0 8>, <12 6>;
+};
+
&mdss {
status = "okay";
};
--
2.53.0
^ permalink raw reply related
* [PATCH v3 4/5] arm64: dts: qcom: sdm670: add lpi pinctrl
From: Richard Acayan @ 2026-03-28 2:10 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Konrad Dybcio, Srinivas Kandagatla, linux-arm-msm,
linux-gpio, devicetree
Cc: Richard Acayan
In-Reply-To: <20260328021036.85945-1-mailingradian@gmail.com>
The Snapdragon 670 has a separate TLMM for audio pins. Add the device
node for it.
Signed-off-by: Richard Acayan <mailingradian@gmail.com>
---
arch/arm64/boot/dts/qcom/sdm670.dtsi | 73 ++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index c5f7655421a3..85a34e2f0907 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -2346,6 +2346,79 @@ lmh_cluster0: lmh@17d78800 {
interrupt-controller;
#interrupt-cells = <1>;
};
+
+ lpi_tlmm: pinctrl@62b40000 {
+ compatible = "qcom,sdm670-lpass-lpi-pinctrl";
+ reg = <0 0x62b40000 0 0x20000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&lpi_tlmm 0 0 32>;
+
+ cdc_pdm_default: cdc-pdm-default-state {
+ clk-pins {
+ pins = "gpio18";
+ function = "slimbus_clk";
+ drive-strength = <4>;
+ output-low;
+ };
+
+ sync-pins {
+ pins = "gpio19";
+ function = "pdm_sync";
+ drive-strength = <4>;
+ output-low;
+ };
+
+ tx-pins {
+ pins = "gpio20";
+ function = "pdm_tx";
+ drive-strength = <8>;
+ };
+
+ rx-pins {
+ pins = "gpio21", "gpio23", "gpio25";
+ function = "pdm_rx";
+ drive-strength = <4>;
+ output-low;
+ };
+ };
+
+ cdc_comp_default: cdc-comp-default-state {
+ pins = "gpio22", "gpio24";
+ function = "comp_rx";
+ drive-strength = <4>;
+ };
+
+ cdc_dmic_default: cdc-dmic-default-state {
+ clk1-pins {
+ pins = "gpio26";
+ function = "dmic1_clk";
+ drive-strength = <8>;
+ output-high;
+ };
+
+ clk2-pins {
+ pins = "gpio28";
+ function = "dmic2_clk";
+ drive-strength = <8>;
+ output-high;
+ };
+
+ data1-pins {
+ pins = "gpio27";
+ function = "dmic1_data";
+ drive-strength = <8>;
+ input-enable;
+ };
+
+ data2-pins {
+ pins = "gpio29";
+ function = "dmic2_data";
+ drive-strength = <8>;
+ input-enable;
+ };
+ };
+ };
};
thermal-zones {
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox