* [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-10 17:24 ` Krzysztof Kozlowski
2025-02-10 9:07 ` [PATCH 2/8] media: v4l2-common: Add YUV24 format info Nas Chung
` (8 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
The existing Kconfig parameter VIDEO_WAVE_VPU is ambiguous,
as it does not clearly indicate that it is specific to the Wave5 IP.
Rename VIDEO_WAVE_VPU to VIDEO_WAVE5_VPU to make it explicit
that the parameter is specific to the Wave5 IP.
No functional changes, only the parameter name is updated.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
arch/arm64/configs/defconfig | 2 +-
drivers/media/platform/chips-media/wave5/Kconfig | 6 +++---
drivers/media/platform/chips-media/wave5/Makefile | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index cb7da4415599..d904d4dc4f0d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -837,7 +837,7 @@ CONFIG_VIDEO_AMPHION_VPU=m
CONFIG_VIDEO_CADENCE_CSI2RX=m
CONFIG_VIDEO_MEDIATEK_JPEG=m
CONFIG_VIDEO_MEDIATEK_VCODEC=m
-CONFIG_VIDEO_WAVE_VPU=m
+CONFIG_VIDEO_WAVE5_VPU=m
CONFIG_VIDEO_E5010_JPEG_ENC=m
CONFIG_VIDEO_IMX7_CSI=m
CONFIG_VIDEO_IMX_MIPI_CSIS=m
diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig
index f1bcef5177bd..914720a35de8 100644
--- a/drivers/media/platform/chips-media/wave5/Kconfig
+++ b/drivers/media/platform/chips-media/wave5/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-config VIDEO_WAVE_VPU
- tristate "Chips&Media Wave Codec Driver"
+config VIDEO_WAVE5_VPU
+ tristate "Chips&Media Wave5 Codec Driver"
depends on V4L_MEM2MEM_DRIVERS
depends on VIDEO_DEV && OF
depends on ARCH_K3 || COMPILE_TEST
@@ -9,7 +9,7 @@ config VIDEO_WAVE_VPU
select V4L2_MEM2MEM_DEV
select GENERIC_ALLOCATOR
help
- Chips&Media stateful encoder and decoder driver.
+ Chips&Media Wave5 stateful encoder and decoder driver.
The driver supports HEVC and H264 formats.
To compile this driver as modules, choose M here: the
modules will be called wave5.
diff --git a/drivers/media/platform/chips-media/wave5/Makefile b/drivers/media/platform/chips-media/wave5/Makefile
index 3d738a03bd8e..81be0e1dcebd 100644
--- a/drivers/media/platform/chips-media/wave5/Makefile
+++ b/drivers/media/platform/chips-media/wave5/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o
+obj-$(CONFIG_VIDEO_WAVE5_VPU) += wave5.o
wave5-objs += wave5-hw.o \
wave5-vpuapi.o \
wave5-vdi.o \
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter
2025-02-10 9:07 ` [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter Nas Chung
@ 2025-02-10 17:24 ` Krzysztof Kozlowski
2025-02-11 4:23 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-10 17:24 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim
On 10/02/2025 10:07, Nas Chung wrote:
> The existing Kconfig parameter VIDEO_WAVE_VPU is ambiguous,
> as it does not clearly indicate that it is specific to the Wave5 IP.
>
> Rename VIDEO_WAVE_VPU to VIDEO_WAVE5_VPU to make it explicit
> that the parameter is specific to the Wave5 IP.
>
> No functional changes, only the parameter name is updated.
That's unnecessary churn. Old name was fine. Kconfig does not match
hardware 1-to-1 but represents only the driver name (or not even that...).
If you solve any particular problem, then explain it. Otherwise this is
just unnecessarily affecting users and backports.
>
> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
> ---
> arch/arm64/configs/defconfig | 2 +-
That's a SoC patch, don't mix up subsystems.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* RE: [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter
2025-02-10 17:24 ` Krzysztof Kozlowski
@ 2025-02-11 4:23 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-11 4:23 UTC (permalink / raw)
To: Krzysztof Kozlowski, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Tuesday, February 11, 2025 2:24 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; sebastian.fricke@collabora.com; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 1/8] media: platform: chips-media: wave5: Rename
>Kconfig parameter
>
>On 10/02/2025 10:07, Nas Chung wrote:
>> The existing Kconfig parameter VIDEO_WAVE_VPU is ambiguous,
>> as it does not clearly indicate that it is specific to the Wave5 IP.
>>
>> Rename VIDEO_WAVE_VPU to VIDEO_WAVE5_VPU to make it explicit
>> that the parameter is specific to the Wave5 IP.
>>
>> No functional changes, only the parameter name is updated.
>
>
>That's unnecessary churn. Old name was fine. Kconfig does not match
>hardware 1-to-1 but represents only the driver name (or not even that...).
>
>If you solve any particular problem, then explain it. Otherwise this is
>just unnecessarily affecting users and backports.
I understand your point.
To avoid unnecessary changes, I'll drop this patch.
Thank you for your feedback.
Thanks.
Nas.
>
>>
>> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>> ---
>> arch/arm64/configs/defconfig | 2 +-
>
>That's a SoC patch, don't mix up subsystems.
>
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 2/8] media: v4l2-common: Add YUV24 format info
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
2025-02-10 9:07 ` [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-10 14:00 ` Sebastian Fricke
2025-02-10 9:07 ` [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device Nas Chung
` (7 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
The YUV24 format is missing an entry in the v4l2_format_info().
The YUV24 format is the packed YUV 4:4:4 formats with 8 bits
per component.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
drivers/media/v4l2-core/v4l2-common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 0a2f4f0d0a07..de3636f1cdf1 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -269,6 +269,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_Y216, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_YUV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
.block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
{ .format = V4L2_PIX_FMT_MT2110R, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 2/8] media: v4l2-common: Add YUV24 format info
2025-02-10 9:07 ` [PATCH 2/8] media: v4l2-common: Add YUV24 format info Nas Chung
@ 2025-02-10 14:00 ` Sebastian Fricke
2025-02-11 1:58 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Sebastian Fricke @ 2025-02-10 14:00 UTC (permalink / raw)
To: Nas Chung
Cc: mchehab, hverkuil, robh, krzk+dt, conor+dt, linux-media,
devicetree, linux-kernel, linux-imx, linux-arm-kernel,
jackson.lee, lafley.kim
Hey Nas,
On 10.02.2025 18:07, Nas Chung wrote:
>The YUV24 format is missing an entry in the v4l2_format_info().
>The YUV24 format is the packed YUV 4:4:4 formats with 8 bits
>per component.
>
That means that 0376a51fbe5e1 was incomplete, I think you should add a
fixes tag to this commit, to highlight that you basically complete the
previous commit.
Regards,
Sebastian
>Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>---
> drivers/media/v4l2-core/v4l2-common.c | 1 +
> 1 file changed, 1 insertion(+)
>
>diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
>index 0a2f4f0d0a07..de3636f1cdf1 100644
>--- a/drivers/media/v4l2-core/v4l2-common.c
>+++ b/drivers/media/v4l2-core/v4l2-common.c
>@@ -269,6 +269,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
> { .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
> { .format = V4L2_PIX_FMT_Y216, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
> { .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>+ { .format = V4L2_PIX_FMT_YUV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
> { .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
> .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
> { .format = V4L2_PIX_FMT_MT2110R, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
>--
>2.31.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 2/8] media: v4l2-common: Add YUV24 format info
2025-02-10 14:00 ` Sebastian Fricke
@ 2025-02-11 1:58 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-11 1:58 UTC (permalink / raw)
To: Sebastian Fricke
Cc: mchehab@kernel.org, hverkuil@xs4all.nl, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Sebastian!
>-----Original Message-----
>From: Sebastian Fricke <sebastian.fricke@collabora.com>
>Sent: Monday, February 10, 2025 11:00 PM
>To: Nas Chung <nas.chung@chipsnmedia.com>
>Cc: mchehab@kernel.org; hverkuil@xs4all.nl; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org; linux-media@vger.kernel.org;
>devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-imx@nxp.com;
>linux-arm-kernel@lists.infradead.org; jackson.lee
><jackson.lee@chipsnmedia.com>; lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 2/8] media: v4l2-common: Add YUV24 format info
>
>Hey Nas,
>
>On 10.02.2025 18:07, Nas Chung wrote:
>>The YUV24 format is missing an entry in the v4l2_format_info().
>>The YUV24 format is the packed YUV 4:4:4 formats with 8 bits
>>per component.
>>
>
>That means that 0376a51fbe5e1 was incomplete, I think you should add a
>fixes tag to this commit, to highlight that you basically complete the
>previous commit.
I agree. I will add the fixes tag in v2.
Thanks.
Nas.
>
>Regards,
>Sebastian
>
>>Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>>---
>> drivers/media/v4l2-core/v4l2-common.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>>diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-
>core/v4l2-common.c
>>index 0a2f4f0d0a07..de3636f1cdf1 100644
>>--- a/drivers/media/v4l2-core/v4l2-common.c
>>+++ b/drivers/media/v4l2-core/v4l2-common.c
>>@@ -269,6 +269,7 @@ const struct v4l2_format_info *v4l2_format_info(u32
>format)
>> { .format = V4L2_PIX_FMT_Y212, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0,
>0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
>> { .format = V4L2_PIX_FMT_Y216, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0,
>0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
>> { .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0,
>0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>>+ { .format = V4L2_PIX_FMT_YUV24, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0,
>0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
>> { .format = V4L2_PIX_FMT_MT2110T, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0,
>0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
>> .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
>> { .format = V4L2_PIX_FMT_MT2110R, .pixel_enc =
>V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0,
>0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
>>--
>>2.31.1
>>
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
2025-02-10 9:07 ` [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter Nas Chung
2025-02-10 9:07 ` [PATCH 2/8] media: v4l2-common: Add YUV24 format info Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-10 17:30 ` Krzysztof Kozlowski
2025-02-10 9:07 ` [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver Nas Chung
` (6 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Add documents for the Wave6 video codec on NXP i.MX SoCs.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../bindings/media/nxp,wave633c.yaml | 202 ++++++++++++++++++
MAINTAINERS | 8 +
2 files changed, 210 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/nxp,wave633c.yaml
diff --git a/Documentation/devicetree/bindings/media/nxp,wave633c.yaml b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
new file mode 100644
index 000000000000..99c3008314c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
@@ -0,0 +1,202 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/nxp,wave633c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Chips&Media Wave6 Series multi-standard codec IP on NXP i.MX SoCs.
+
+maintainers:
+ - Nas Chung <nas.chung@chipsnmedia.com>
+ - Jackson Lee <jackson.lee@chipsnmedia.com>
+
+description:
+ The Chips&Media Wave6 codec IP is a multi-standard video encoder/decoder.
+ On NXP i.MX SoCs, Wave6 codec IP functionality is split between the VPU control device
+ (vpu-ctrl) and the VPU device (vpu). The VPU control device manages shared resources
+ such as firmware access and power domains, while the VPU device provides encoding
+ and decoding capabilities. The VPU devie cannot operate independently
+ without the VPU control device.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - nxp,imx95-wave633c-ctrl
+ - nxp,imx95-wave633c
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: VPU clock
+ - description: VPU associated block clock
+
+ clock-names:
+ items:
+ - const: vpu
+ - const: vpublk_wave
+
+ power-domains:
+ minItems: 1
+ items:
+ - description: Main VPU power domain
+ - description: Performance power domain
+
+ power-domain-names:
+ items:
+ - const: vpumix
+ - const: vpuperf
+
+ cnm,ctrl:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle of the VPU control device node. Required for VPU operation.
+
+ boot:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle of the boot memory region node for the VPU control device.
+
+ sram:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle of the SRAM memory region node for the VPU control device.
+
+ '#cooling-cells':
+ const: 2
+
+ support-follower:
+ type: boolean
+ description: Indicates whether the VPU domain power always on.
+
+patternProperties:
+ "^vpu-ctrl@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ items:
+ - enum:
+ - nxp,imx95-wave633c-ctrl
+ reg: true
+ clocks: true
+ clock-names: true
+ power-domains:
+ items:
+ - description: Main VPU power domain
+ - description: Performance power domain
+ power-domain-names:
+ items:
+ - const: vpumix
+ - const: vpuperf
+ sram: true
+ boot: true
+ '#cooling-cells': true
+ support-follower: true
+ required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - power-domains
+ - power-domain-names
+ - sram
+ - boot
+
+ additionalProperties: false
+
+ "^vpu@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ items:
+ - enum:
+ - nxp,imx95-wave633c
+ reg: true
+ interrupts: true
+ clocks: true
+ clock-names: true
+ power-domains:
+ maxItems: 1
+ description: Main VPU power domain
+ cnm,ctrl: true
+ required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - power-domains
+ - cnm,ctrl
+
+ additionalProperties: false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ vpuctrl: vpu-ctrl@4c4c0000 {
+ compatible = "nxp,imx95-wave633c-ctrl";
+ reg = <0x0 0x4c4c0000 0x0 0x10000>;
+ clocks = <&scmi_clk 115>,
+ <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
+ clock-names = "vpu", "vpublk_wave";
+ power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
+ power-domain-names = "vpumix", "vpuperf";
+ #cooling-cells = <2>;
+ boot = <&vpu_boot>;
+ sram = <&sram1>;
+ };
+
+ vpu0: vpu@4c480000 {
+ compatible = "nxp,imx95-wave633c";
+ reg = <0x0 0x4c480000 0x0 0x10000>;
+ interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scmi_clk 115>,
+ <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
+ clock-names = "vpu", "vpublk_wave";
+ power-domains = <&scmi_devpd 21>;
+ cnm,ctrl = <&vpuctrl>;
+ };
+
+ vpu1: vpu@4c490000 {
+ compatible = "nxp,imx95-wave633c";
+ reg = <0x0 0x4c490000 0x0 0x10000>;
+ interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scmi_clk 115>,
+ <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
+ clock-names = "vpu", "vpublk_wave";
+ power-domains = <&scmi_devpd 21>;
+ cnm,ctrl = <&vpuctrl>;
+ };
+
+ vpu2: vpu@4c4a0000 {
+ compatible = "nxp,imx95-wave633c";
+ reg = <0x0 0x4c4a0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scmi_clk 115>,
+ <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
+ clock-names = "vpu", "vpublk_wave";
+ power-domains = <&scmi_devpd 21>;
+ cnm,ctrl = <&vpuctrl>;
+ };
+
+ vpu3: vpu@4c4b0000 {
+ compatible = "nxp,imx95-wave633c";
+ reg = <0x0 0x4c4b0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scmi_clk 115>,
+ <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
+ clock-names = "vpu", "vpublk_wave";
+ power-domains = <&scmi_devpd 21>;
+ cnm,ctrl = <&vpuctrl>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 896a307fa065..5ff5b1f1ced2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25462,6 +25462,14 @@ S: Maintained
F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
F: drivers/media/platform/chips-media/wave5/
+WAVE6 VPU CODEC DRIVER
+M: Nas Chung <nas.chung@chipsnmedia.com>
+M: Jackson Lee <jackson.lee@chipsnmedia.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml
+F: drivers/media/platform/chips-media/wave6/
+
WHISKEYCOVE PMIC GPIO DRIVER
M: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
L: linux-gpio@vger.kernel.org
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-10 9:07 ` [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device Nas Chung
@ 2025-02-10 17:30 ` Krzysztof Kozlowski
2025-02-13 7:50 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-10 17:30 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim
On 10/02/2025 10:07, Nas Chung wrote:
> Add documents for the Wave6 video codec on NXP i.MX SoCs.
>
> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
> ---
> .../bindings/media/nxp,wave633c.yaml | 202 ++++++++++++++++++
> MAINTAINERS | 8 +
> 2 files changed, 210 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>
> diff --git a/Documentation/devicetree/bindings/media/nxp,wave633c.yaml b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
> new file mode 100644
> index 000000000000..99c3008314c5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
Filename matching compatible.
> @@ -0,0 +1,202 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/nxp,wave633c.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Chips&Media Wave6 Series multi-standard codec IP on NXP i.MX SoCs.
> +
> +maintainers:
> + - Nas Chung <nas.chung@chipsnmedia.com>
> + - Jackson Lee <jackson.lee@chipsnmedia.com>
> +
> +description:
> + The Chips&Media Wave6 codec IP is a multi-standard video encoder/decoder.
> + On NXP i.MX SoCs, Wave6 codec IP functionality is split between the VPU control device
> + (vpu-ctrl) and the VPU device (vpu). The VPU control device manages shared resources
> + such as firmware access and power domains, while the VPU device provides encoding
> + and decoding capabilities. The VPU devie cannot operate independently
Typo
> + without the VPU control device.
> +
Please wrap code according to the preferred limit expressed in Kernel
coding style (checkpatch is not a coding style description, but only a
tool). Bindings use strict rule here.
> +properties:
> + compatible:
> + items:
> + - enum:
> + - nxp,imx95-wave633c-ctrl
> + - nxp,imx95-wave633c
I don't understand why you duplicated compatibles. You split this for
driver? That's a no. There are no two hardwares.
These compatibles are anyway weird - why imx95 is in chipmedia product?
Is this part of a SoC?
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: VPU clock
> + - description: VPU associated block clock
> +
> + clock-names:
> + items:
> + - const: vpu
> + - const: vpublk_wave
> +
> + power-domains:
> + minItems: 1
> + items:
> + - description: Main VPU power domain
> + - description: Performance power domain
> +
> + power-domain-names:
> + items:
> + - const: vpumix
> + - const: vpuperf
> +
> + cnm,ctrl:
What is this prefix about? Is this nxp or something else?
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: phandle of the VPU control device node. Required for VPU operation.
Explain - required for what. Operation is too generic.
If this is phandle to second device, then it's proof your split is
really wrong.
> +
> + boot:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: phandle of the boot memory region node for the VPU control device.
No clue what is this... if memory region then use existing bindings.
Anyway, wrap your code correctly.
> +
> + sram:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: phandle of the SRAM memory region node for the VPU control device.
> +
> + '#cooling-cells':
> + const: 2
> +
> + support-follower:
> + type: boolean
> + description: Indicates whether the VPU domain power always on.
You cannot add new common properties in random way. Missing vendor
prefix but more important: does not look at all as hardware property but
OS policy.
> +
> +patternProperties:
> + "^vpu-ctrl@[0-9a-f]+$":
> + type: object
> + properties:
> + compatible:
> + items:
> + - enum:
> + - nxp,imx95-wave633c-ctrl
Really, what? How nxp,imx95-wave633c-ctrl node can have a child with
nxp,imx95-wave633c-ctrl compatible?
NAK.
> + reg: true
> + clocks: true
> + clock-names: true
> + power-domains:
> + items:
> + - description: Main VPU power domain
> + - description: Performance power domain
> + power-domain-names:
> + items:
> + - const: vpumix
> + - const: vpuperf
> + sram: true
> + boot: true
> + '#cooling-cells': true
> + support-follower: true
> + required:
> + - compatible
> + - reg
> + - clocks
> + - clock-names
> + - power-domains
> + - power-domain-names
> + - sram
> + - boot
> +
> + additionalProperties: false
> +
> + "^vpu@[0-9a-f]+$":
> + type: object
> + properties:
> + compatible:
> + items:
> + - enum:
> + - nxp,imx95-wave633c
> + reg: true
> + interrupts: true
> + clocks: true
> + clock-names: true
> + power-domains:
> + maxItems: 1
> + description: Main VPU power domain
> + cnm,ctrl: true
> + required:
> + - compatible
> + - reg
> + - interrupts
> + - clocks
> + - clock-names
> + - power-domains
> + - cnm,ctrl
All this is just incorrect.
> +
> + additionalProperties: false
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/clock/nxp,imx95-clock.h>
> +
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + vpuctrl: vpu-ctrl@4c4c0000 {
> + compatible = "nxp,imx95-wave633c-ctrl";
> + reg = <0x0 0x4c4c0000 0x0 0x10000>;
> + clocks = <&scmi_clk 115>,
> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> + clock-names = "vpu", "vpublk_wave";
> + power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
> + power-domain-names = "vpumix", "vpuperf";
> + #cooling-cells = <2>;
> + boot = <&vpu_boot>;
> + sram = <&sram1>;
> + };
> +
> + vpu0: vpu@4c480000 {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> + compatible = "nxp,imx95-wave633c";
> + reg = <0x0 0x4c480000 0x0 0x10000>;
> + interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&scmi_clk 115>,
> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> + clock-names = "vpu", "vpublk_wave";
> + power-domains = <&scmi_devpd 21>;
> + cnm,ctrl = <&vpuctrl>;
> + };
> +
> + vpu1: vpu@4c490000 {
> + compatible = "nxp,imx95-wave633c";
Drop all duplicated examples.
> + reg = <0x0 0x4c490000 0x0 0x10000>;
> + interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&scmi_clk 115>,
> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> + clock-names = "vpu", "vpublk_wave";
> + power-domains = <&scmi_devpd 21>;
> + cnm,ctrl = <&vpuctrl>;
> + };
> +
> + vpu2: vpu@4c4a0000 {
> + compatible = "nxp,imx95-wave633c";
> + reg = <0x0 0x4c4a0000 0x0 0x10000>;
> + interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&scmi_clk 115>,
> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> + clock-names = "vpu", "vpublk_wave";
> + power-domains = <&scmi_devpd 21>;
> + cnm,ctrl = <&vpuctrl>;
> + };
> +
> + vpu3: vpu@4c4b0000 {
> + compatible = "nxp,imx95-wave633c";
> + reg = <0x0 0x4c4b0000 0x0 0x10000>;
> + interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&scmi_clk 115>,
> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> + clock-names = "vpu", "vpublk_wave";
> + power-domains = <&scmi_devpd 21>;
> + cnm,ctrl = <&vpuctrl>;
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 896a307fa065..5ff5b1f1ced2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25462,6 +25462,14 @@ S: Maintained
> F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
> F: drivers/media/platform/chips-media/wave5/
>
> +WAVE6 VPU CODEC DRIVER
> +M: Nas Chung <nas.chung@chipsnmedia.com>
> +M: Jackson Lee <jackson.lee@chipsnmedia.com>
> +L: linux-media@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml
> +F: drivers/media/platform/chips-media/wave6/
There is no such file/directory.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-10 17:30 ` Krzysztof Kozlowski
@ 2025-02-13 7:50 ` Nas Chung
2025-02-13 8:49 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-13 7:50 UTC (permalink / raw)
To: Krzysztof Kozlowski, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Tuesday, February 11, 2025 2:31 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; sebastian.fricke@collabora.com; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>device
>
>On 10/02/2025 10:07, Nas Chung wrote:
>> Add documents for the Wave6 video codec on NXP i.MX SoCs.
>>
>> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>> ---
>> .../bindings/media/nxp,wave633c.yaml | 202 ++++++++++++++++++
>> MAINTAINERS | 8 +
>> 2 files changed, 210 insertions(+)
>> create mode 100644
>Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>> new file mode 100644
>> index 000000000000..99c3008314c5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>
>Filename matching compatible.
>
>> @@ -0,0 +1,202 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/media/nxp,wave633c.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Chips&Media Wave6 Series multi-standard codec IP on NXP i.MX SoCs.
>> +
>> +maintainers:
>> + - Nas Chung <nas.chung@chipsnmedia.com>
>> + - Jackson Lee <jackson.lee@chipsnmedia.com>
>> +
>> +description:
>> + The Chips&Media Wave6 codec IP is a multi-standard video
>encoder/decoder.
>> + On NXP i.MX SoCs, Wave6 codec IP functionality is split between the
>VPU control device
>> + (vpu-ctrl) and the VPU device (vpu). The VPU control device manages
>shared resources
>> + such as firmware access and power domains, while the VPU device
>provides encoding
>> + and decoding capabilities. The VPU devie cannot operate independently
>
>Typo
I'll fix it in v2.
>
>> + without the VPU control device.
>> +
>
>Please wrap code according to the preferred limit expressed in Kernel
>coding style (checkpatch is not a coding style description, but only a
>tool). Bindings use strict rule here.
I'll address this in v2.
>
>
>
>> +properties:
>> + compatible:
>> + items:
>> + - enum:
>> + - nxp,imx95-wave633c-ctrl
>> + - nxp,imx95-wave633c
>
>I don't understand why you duplicated compatibles. You split this for
>driver? That's a no. There are no two hardwares.
Yes, I want to introduce two different devices and drivers,
even though there is only one hardware.
Wave6 IP has five independent register regions:
One register region is dedicated to the control device,
which manages shared resources such as firmware loading and power domains.
The remaining four register regions are assigned to
four independent VPU devices, each accessing its own dedicated region.
(to support 4 vms)
Would it be reasonable to split the YAML into separate files
for the VPU control device and the VPU device ?
(like nxp,wave633c-ctrl.yaml)
>
>These compatibles are anyway weird - why imx95 is in chipmedia product?
>Is this part of a SoC?
I want to represent that the Wave633 is part of the i.MX95.
Chips&Media's Wave633 can also be integrated into SoCs from other vendors.
By using the compatible name, the same Wave6 driver can distinguish
different implementations.
However, I agree that "imx95" is not strictly necessary in current status.
So, using "nxp,wave633c" would be a better choice, right ?
>
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + clocks:
>> + items:
>> + - description: VPU clock
>> + - description: VPU associated block clock
>> +
>> + clock-names:
>> + items:
>> + - const: vpu
>> + - const: vpublk_wave
>> +
>> + power-domains:
>> + minItems: 1
>> + items:
>> + - description: Main VPU power domain
>> + - description: Performance power domain
>> +
>> + power-domain-names:
>> + items:
>> + - const: vpumix
>> + - const: vpuperf
>> +
>> + cnm,ctrl:
>
>What is this prefix about? Is this nxp or something else?
Yes, using "nxp" as the prefix seems more appropriate.
>
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: phandle of the VPU control device node. Required for VPU
>operation.
>
>Explain - required for what. Operation is too generic.
phandle of the VPU control device node, which manages shared resources
such as firmware access and power domains.
>
>If this is phandle to second device, then it's proof your split is
>really wrong.
Are you suggesting that I should separate them into two YAML files,
or that I should structure them in a parent-child hierarchy
within the same YAML file ?
I appreciate any guidance on the best approach to structure this in line
with existing bindings.
>
>> +
>> + boot:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: phandle of the boot memory region node for the VPU
>control device.
>
>No clue what is this... if memory region then use existing bindings.
Boot is a memory region used for firmware upload.
Only the control device can access this region.
By "existing bindings," do you mean I should use "memory-region" instead ?
>
>Anyway, wrap your code correctly.
Okay.
>
>> +
>> + sram:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: phandle of the SRAM memory region node for the VPU
>control device.
>> +
>> + '#cooling-cells':
>> + const: 2
>> +
>> + support-follower:
>> + type: boolean
>> + description: Indicates whether the VPU domain power always on.
>
>You cannot add new common properties in random way. Missing vendor
>prefix but more important: does not look at all as hardware property but
>OS policy.
I agree with you.
I'll remove it in v2.
>
>> +
>> +patternProperties:
>> + "^vpu-ctrl@[0-9a-f]+$":
>> + type: object
>> + properties:
>> + compatible:
>> + items:
>> + - enum:
>> + - nxp,imx95-wave633c-ctrl
>
>Really, what? How nxp,imx95-wave633c-ctrl node can have a child with
>nxp,imx95-wave633c-ctrl compatible?
>
>NAK.
Apologies, I misunderstood the meaning of 'patternProperties'.
I'll remove it in v2.
>
>
>> + reg: true
>> + clocks: true
>> + clock-names: true
>> + power-domains:
>> + items:
>> + - description: Main VPU power domain
>> + - description: Performance power domain
>> + power-domain-names:
>> + items:
>> + - const: vpumix
>> + - const: vpuperf
>> + sram: true
>> + boot: true
>> + '#cooling-cells': true
>> + support-follower: true
>> + required:
>> + - compatible
>> + - reg
>> + - clocks
>> + - clock-names
>> + - power-domains
>> + - power-domain-names
>> + - sram
>> + - boot
>> +
>> + additionalProperties: false
>> +
>> + "^vpu@[0-9a-f]+$":
>> + type: object
>> + properties:
>> + compatible:
>> + items:
>> + - enum:
>> + - nxp,imx95-wave633c
>> + reg: true
>> + interrupts: true
>> + clocks: true
>> + clock-names: true
>> + power-domains:
>> + maxItems: 1
>> + description: Main VPU power domain
>> + cnm,ctrl: true
>> + required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - clocks
>> + - clock-names
>> + - power-domains
>> + - cnm,ctrl
>
>All this is just incorrect.
I'll remove it in v2.
>
>> +
>> + additionalProperties: false
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/clock/nxp,imx95-clock.h>
>> +
>> + soc {
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> +
>> + vpuctrl: vpu-ctrl@4c4c0000 {
>> + compatible = "nxp,imx95-wave633c-ctrl";
>> + reg = <0x0 0x4c4c0000 0x0 0x10000>;
>> + clocks = <&scmi_clk 115>,
>> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> + clock-names = "vpu", "vpublk_wave";
>> + power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
>> + power-domain-names = "vpumix", "vpuperf";
>> + #cooling-cells = <2>;
>> + boot = <&vpu_boot>;
>> + sram = <&sram1>;
>> + };
>> +
>> + vpu0: vpu@4c480000 {
>
>Node names should be generic. See also an explanation and list of
>examples (not exhaustive) in DT specification:
>https://devicetree-specification.readthedocs.io/en/latest/chapter2-
>devicetree-basics.html#generic-names-recommendation
Thanks for sharing the link.
I'll use "video-codec" as the node name in v2.
>
>
>> + compatible = "nxp,imx95-wave633c";
>> + reg = <0x0 0x4c480000 0x0 0x10000>;
>> + interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
>> + clocks = <&scmi_clk 115>,
>> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> + clock-names = "vpu", "vpublk_wave";
>> + power-domains = <&scmi_devpd 21>;
>> + cnm,ctrl = <&vpuctrl>;
>> + };
>> +
>> + vpu1: vpu@4c490000 {
>> + compatible = "nxp,imx95-wave633c";
>
>Drop all duplicated examples.
Wave6 HW is designed for simultaneous access,
as each VPU device has its own separate register space.
Therefore, I defined the 4 VPU devices as independent nodes in the example
to reflect this.
>
>
>> + reg = <0x0 0x4c490000 0x0 0x10000>;
>> + interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
>> + clocks = <&scmi_clk 115>,
>> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> + clock-names = "vpu", "vpublk_wave";
>> + power-domains = <&scmi_devpd 21>;
>> + cnm,ctrl = <&vpuctrl>;
>> + };
>> +
>> + vpu2: vpu@4c4a0000 {
>> + compatible = "nxp,imx95-wave633c";
>> + reg = <0x0 0x4c4a0000 0x0 0x10000>;
>> + interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
>> + clocks = <&scmi_clk 115>,
>> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> + clock-names = "vpu", "vpublk_wave";
>> + power-domains = <&scmi_devpd 21>;
>> + cnm,ctrl = <&vpuctrl>;
>> + };
>> +
>> + vpu3: vpu@4c4b0000 {
>> + compatible = "nxp,imx95-wave633c";
>> + reg = <0x0 0x4c4b0000 0x0 0x10000>;
>> + interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
>> + clocks = <&scmi_clk 115>,
>> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> + clock-names = "vpu", "vpublk_wave";
>> + power-domains = <&scmi_devpd 21>;
>> + cnm,ctrl = <&vpuctrl>;
>> + };
>> + };
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 896a307fa065..5ff5b1f1ced2 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -25462,6 +25462,14 @@ S: Maintained
>> F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
>> F: drivers/media/platform/chips-media/wave5/
>>
>> +WAVE6 VPU CODEC DRIVER
>> +M: Nas Chung <nas.chung@chipsnmedia.com>
>> +M: Jackson Lee <jackson.lee@chipsnmedia.com>
>> +L: linux-media@vger.kernel.org
>> +S: Maintained
>> +F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>> +F: drivers/media/platform/chips-media/wave6/
>
>There is no such file/directory.
Understood. I'll move the MAINTAINERS update to the last patch in v2.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-13 7:50 ` Nas Chung
@ 2025-02-13 8:49 ` Krzysztof Kozlowski
2025-02-18 9:21 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13 8:49 UTC (permalink / raw)
To: Nas Chung
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
On Thu, Feb 13, 2025 at 07:50:53AM +0000, Nas Chung wrote:
> >> + items:
> >> + - enum:
> >> + - nxp,imx95-wave633c-ctrl
> >> + - nxp,imx95-wave633c
> >
> >I don't understand why you duplicated compatibles. You split this for
> >driver? That's a no. There are no two hardwares.
>
> Yes, I want to introduce two different devices and drivers,
> even though there is only one hardware.
That's a no. Bindings are for hardware, not drivers.
Linux driver design is independent of bindings.
>
> Wave6 IP has five independent register regions:
>
> One register region is dedicated to the control device,
> which manages shared resources such as firmware loading and power domains.
>
> The remaining four register regions are assigned to
> four independent VPU devices, each accessing its own dedicated region.
> (to support 4 vms)
This could be, but your binding said something completely opposite. Look
how other bindings do it, first.
>
> Would it be reasonable to split the YAML into separate files
> for the VPU control device and the VPU device ?
> (like nxp,wave633c-ctrl.yaml)
No, it changes nothing.
>
> >
> >These compatibles are anyway weird - why imx95 is in chipmedia product?
> >Is this part of a SoC?
>
> I want to represent that the Wave633 is part of the i.MX95.
> Chips&Media's Wave633 can also be integrated into SoCs from other vendors.
OK
> By using the compatible name, the same Wave6 driver can distinguish
> different implementations.
So you tell DT maintainer how DT works, brilliant...
>
> However, I agree that "imx95" is not strictly necessary in current status.
> So, using "nxp,wave633c" would be a better choice, right ?
No, NXP did not create wave633c. SoC components must have SoC prefix,
assuming this is a Soc component.
>
> >
> >> +
> >> + reg:
> >> + maxItems: 1
> >> +
> >> + interrupts:
> >> + maxItems: 1
> >> +
> >> + clocks:
> >> + items:
> >> + - description: VPU clock
> >> + - description: VPU associated block clock
> >> +
> >> + clock-names:
> >> + items:
> >> + - const: vpu
> >> + - const: vpublk_wave
> >> +
> >> + power-domains:
> >> + minItems: 1
> >> + items:
> >> + - description: Main VPU power domain
> >> + - description: Performance power domain
> >> +
> >> + power-domain-names:
> >> + items:
> >> + - const: vpumix
> >> + - const: vpuperf
> >> +
> >> + cnm,ctrl:
> >
> >What is this prefix about? Is this nxp or something else?
>
> Yes, using "nxp" as the prefix seems more appropriate.
>
> >
> >> + $ref: /schemas/types.yaml#/definitions/phandle
> >> + description: phandle of the VPU control device node. Required for VPU
> >operation.
> >
> >Explain - required for what. Operation is too generic.
>
> phandle of the VPU control device node, which manages shared resources
> such as firmware access and power domains.
Then NAK.
Use proper bindings for this, e.g. power-domains.
>
> >
> >If this is phandle to second device, then it's proof your split is
> >really wrong.
>
> Are you suggesting that I should separate them into two YAML files,
No. Splitting into separate files would change nothing - you still would
have here a phandle, right?
> or that I should structure them in a parent-child hierarchy
> within the same YAML file ?
You did not try hard enough to find similar devices, which there is a
ton of.
>
> I appreciate any guidance on the best approach to structure this in line
> with existing bindings.
Then look for them.
You have one device. If you have sub-blocks with their own
distinguishable address space, then they can be children. But you did
not write it that way. Just look at your example DTS - no children at
all!
>
> >
> >> +
> >> + boot:
> >> + $ref: /schemas/types.yaml#/definitions/phandle
> >> + description: phandle of the boot memory region node for the VPU
> >control device.
> >
> >No clue what is this... if memory region then use existing bindings.
>
> Boot is a memory region used for firmware upload.
> Only the control device can access this region.
> By "existing bindings," do you mean I should use "memory-region" instead ?
Look how other bindings do this and what property they use. Yes,
memory-region.
>
> >
> >Anyway, wrap your code correctly.
>
> Okay.
>
> >
> >> +
> >> + sram:
> >> + $ref: /schemas/types.yaml#/definitions/phandle
> >> + description: phandle of the SRAM memory region node for the VPU
> >control device.
> >> +
> >> + '#cooling-cells':
> >> + const: 2
> >> +
> >> + support-follower:
> >> + type: boolean
> >> + description: Indicates whether the VPU domain power always on.
> >
> >You cannot add new common properties in random way. Missing vendor
> >prefix but more important: does not look at all as hardware property but
> >OS policy.
>
> I agree with you.
> I'll remove it in v2.
>
> >
> >> +
> >> +patternProperties:
> >> + "^vpu-ctrl@[0-9a-f]+$":
> >> + type: object
> >> + properties:
> >> + compatible:
> >> + items:
> >> + - enum:
> >> + - nxp,imx95-wave633c-ctrl
> >
> >Really, what? How nxp,imx95-wave633c-ctrl node can have a child with
> >nxp,imx95-wave633c-ctrl compatible?
> >
> >NAK.
>
> Apologies, I misunderstood the meaning of 'patternProperties'.
> I'll remove it in v2.
>
> >
> >
> >> + reg: true
> >> + clocks: true
> >> + clock-names: true
> >> + power-domains:
> >> + items:
> >> + - description: Main VPU power domain
> >> + - description: Performance power domain
> >> + power-domain-names:
> >> + items:
> >> + - const: vpumix
> >> + - const: vpuperf
> >> + sram: true
> >> + boot: true
> >> + '#cooling-cells': true
> >> + support-follower: true
> >> + required:
> >> + - compatible
> >> + - reg
> >> + - clocks
> >> + - clock-names
> >> + - power-domains
> >> + - power-domain-names
> >> + - sram
> >> + - boot
> >> +
> >> + additionalProperties: false
> >> +
> >> + "^vpu@[0-9a-f]+$":
> >> + type: object
> >> + properties:
> >> + compatible:
> >> + items:
> >> + - enum:
> >> + - nxp,imx95-wave633c
> >> + reg: true
> >> + interrupts: true
> >> + clocks: true
> >> + clock-names: true
> >> + power-domains:
> >> + maxItems: 1
> >> + description: Main VPU power domain
> >> + cnm,ctrl: true
> >> + required:
> >> + - compatible
> >> + - reg
> >> + - interrupts
> >> + - clocks
> >> + - clock-names
> >> + - power-domains
> >> + - cnm,ctrl
> >
> >All this is just incorrect.
>
> I'll remove it in v2.
>
> >
> >> +
> >> + additionalProperties: false
> >> +
> >> +additionalProperties: false
> >> +
> >> +examples:
> >> + - |
> >> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> >> + #include <dt-bindings/clock/nxp,imx95-clock.h>
> >> +
> >> + soc {
> >> + #address-cells = <2>;
> >> + #size-cells = <2>;
> >> +
> >> + vpuctrl: vpu-ctrl@4c4c0000 {
So this is the parent device...
> >> + compatible = "nxp,imx95-wave633c-ctrl";
> >> + reg = <0x0 0x4c4c0000 0x0 0x10000>;
> >> + clocks = <&scmi_clk 115>,
> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> >> + clock-names = "vpu", "vpublk_wave";
> >> + power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
> >> + power-domain-names = "vpumix", "vpuperf";
> >> + #cooling-cells = <2>;
> >> + boot = <&vpu_boot>;
> >> + sram = <&sram1>;
> >> + };
> >> +
> >> + vpu0: vpu@4c480000 {
And here you have child which is not a child? Your binding and DTS
neither match nor make any sense.
> >
> >Node names should be generic. See also an explanation and list of
> >examples (not exhaustive) in DT specification:
> >https://devicetree-specification.readthedocs.io/en/latest/chapter2-
> >devicetree-basics.html#generic-names-recommendation
>
> Thanks for sharing the link.
> I'll use "video-codec" as the node name in v2.
>
> >
> >
> >> + compatible = "nxp,imx95-wave633c";
> >> + reg = <0x0 0x4c480000 0x0 0x10000>;
> >> + interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
> >> + clocks = <&scmi_clk 115>,
> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> >> + clock-names = "vpu", "vpublk_wave";
> >> + power-domains = <&scmi_devpd 21>;
> >> + cnm,ctrl = <&vpuctrl>;
> >> + };
> >> +
> >> + vpu1: vpu@4c490000 {
> >> + compatible = "nxp,imx95-wave633c";
> >
> >Drop all duplicated examples.
>
> Wave6 HW is designed for simultaneous access,
> as each VPU device has its own separate register space.
> Therefore, I defined the 4 VPU devices as independent nodes in the example
> to reflect this.
They are redundant in this example. Unless you wanted to express
something else, but you did not.
>
> >
> >
> >> + reg = <0x0 0x4c490000 0x0 0x10000>;
> >> + interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
> >> + clocks = <&scmi_clk 115>,
> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> >> + clock-names = "vpu", "vpublk_wave";
> >> + power-domains = <&scmi_devpd 21>;
> >> + cnm,ctrl = <&vpuctrl>;
> >> + };
> >> +
> >> + vpu2: vpu@4c4a0000 {
> >> + compatible = "nxp,imx95-wave633c";
> >> + reg = <0x0 0x4c4a0000 0x0 0x10000>;
> >> + interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
> >> + clocks = <&scmi_clk 115>,
> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> >> + clock-names = "vpu", "vpublk_wave";
> >> + power-domains = <&scmi_devpd 21>;
> >> + cnm,ctrl = <&vpuctrl>;
> >> + };
> >> +
> >> + vpu3: vpu@4c4b0000 {
> >> + compatible = "nxp,imx95-wave633c";
> >> + reg = <0x0 0x4c4b0000 0x0 0x10000>;
> >> + interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
> >> + clocks = <&scmi_clk 115>,
> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> >> + clock-names = "vpu", "vpublk_wave";
> >> + power-domains = <&scmi_devpd 21>;
> >> + cnm,ctrl = <&vpuctrl>;
> >> + };
> >> + };
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 896a307fa065..5ff5b1f1ced2 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -25462,6 +25462,14 @@ S: Maintained
> >> F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
> >> F: drivers/media/platform/chips-media/wave5/
> >>
> >> +WAVE6 VPU CODEC DRIVER
> >> +M: Nas Chung <nas.chung@chipsnmedia.com>
> >> +M: Jackson Lee <jackson.lee@chipsnmedia.com>
> >> +L: linux-media@vger.kernel.org
> >> +S: Maintained
> >> +F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml
> >> +F: drivers/media/platform/chips-media/wave6/
> >
> >There is no such file/directory.
>
> Understood. I'll move the MAINTAINERS update to the last patch in v2.
No, just add entry per entry.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-13 8:49 ` Krzysztof Kozlowski
@ 2025-02-18 9:21 ` Nas Chung
2025-02-19 12:31 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-18 9:21 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Thursday, February 13, 2025 5:50 PM
>To: Nas Chung <nas.chung@chipsnmedia.com>
>Cc: mchehab@kernel.org; hverkuil@xs4all.nl; sebastian.fricke@collabora.com;
>robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; linux-
>media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>device
>
>On Thu, Feb 13, 2025 at 07:50:53AM +0000, Nas Chung wrote:
>> >> + items:
>> >> + - enum:
>> >> + - nxp,imx95-wave633c-ctrl
>> >> + - nxp,imx95-wave633c
>> >
>> >I don't understand why you duplicated compatibles. You split this for
>> >driver? That's a no. There are no two hardwares.
>>
>> Yes, I want to introduce two different devices and drivers,
>> even though there is only one hardware.
>
>That's a no. Bindings are for hardware, not drivers.
>Linux driver design is independent of bindings.
>
>>
>> Wave6 IP has five independent register regions:
>>
>> One register region is dedicated to the control device,
>> which manages shared resources such as firmware loading and power domains.
>>
>> The remaining four register regions are assigned to
>> four independent VPU devices, each accessing its own dedicated region.
>> (to support 4 vms)
>
>This could be, but your binding said something completely opposite. Look
>how other bindings do it, first.
>
>>
>> Would it be reasonable to split the YAML into separate files
>> for the VPU control device and the VPU device ?
>> (like nxp,wave633c-ctrl.yaml)
>
>No, it changes nothing.
>
>>
>> >
>> >These compatibles are anyway weird - why imx95 is in chipmedia product?
>> >Is this part of a SoC?
>>
>> I want to represent that the Wave633 is part of the i.MX95.
>> Chips&Media's Wave633 can also be integrated into SoCs from other vendors.
>
>OK
>
>
>> By using the compatible name, the same Wave6 driver can distinguish
>> different implementations.
>
>So you tell DT maintainer how DT works, brilliant...
>
>>
>> However, I agree that "imx95" is not strictly necessary in current status.
>> So, using "nxp,wave633c" would be a better choice, right ?
>
>No, NXP did not create wave633c. SoC components must have SoC prefix,
>assuming this is a Soc component.
Ah, I had completely misunderstood the purpose and role of DT.
My apologies for that.
Would it be okay to modify it as follows ?
items:
- enum:
- nxp,imx95-vpu
- const: cnm,wave633c
>
>>
>> >
>> >> +
>> >> + reg:
>> >> + maxItems: 1
>> >> +
>> >> + interrupts:
>> >> + maxItems: 1
>> >> +
>> >> + clocks:
>> >> + items:
>> >> + - description: VPU clock
>> >> + - description: VPU associated block clock
>> >> +
>> >> + clock-names:
>> >> + items:
>> >> + - const: vpu
>> >> + - const: vpublk_wave
>> >> +
>> >> + power-domains:
>> >> + minItems: 1
>> >> + items:
>> >> + - description: Main VPU power domain
>> >> + - description: Performance power domain
>> >> +
>> >> + power-domain-names:
>> >> + items:
>> >> + - const: vpumix
>> >> + - const: vpuperf
>> >> +
>> >> + cnm,ctrl:
>> >
>> >What is this prefix about? Is this nxp or something else?
>>
>> Yes, using "nxp" as the prefix seems more appropriate.
>>
>> >
>> >> + $ref: /schemas/types.yaml#/definitions/phandle
>> >> + description: phandle of the VPU control device node. Required for
>VPU
>> >operation.
>> >
>> >Explain - required for what. Operation is too generic.
>>
>> phandle of the VPU control device node, which manages shared resources
>> such as firmware access and power domains.
>
>Then NAK.
>
>Use proper bindings for this, e.g. power-domains.
>
>
>>
>> >
>> >If this is phandle to second device, then it's proof your split is
>> >really wrong.
>>
>> Are you suggesting that I should separate them into two YAML files,
>
>No. Splitting into separate files would change nothing - you still would
>have here a phandle, right?
>
>> or that I should structure them in a parent-child hierarchy
>> within the same YAML file ?
>
>You did not try hard enough to find similar devices, which there is a
>ton of.
>
>>
>> I appreciate any guidance on the best approach to structure this in line
>> with existing bindings.
>
>Then look for them.
>
>You have one device. If you have sub-blocks with their own
>distinguishable address space, then they can be children. But you did
>not write it that way. Just look at your example DTS - no children at
>all!
I see that I didn't review similar devices thoroughly enough.
Thanks for pointing this out.
Okay, I will remove the phandle for second device and handle it in
parent node.
I have left the modified structure in the example below.
>
>>
>> >
>> >> +
>> >> + boot:
>> >> + $ref: /schemas/types.yaml#/definitions/phandle
>> >> + description: phandle of the boot memory region node for the VPU
>> >control device.
>> >
>> >No clue what is this... if memory region then use existing bindings.
>>
>> Boot is a memory region used for firmware upload.
>> Only the control device can access this region.
>> By "existing bindings," do you mean I should use "memory-region" instead ?
>
>Look how other bindings do this and what property they use. Yes,
>memory-region.
>
>>
>> >
>> >Anyway, wrap your code correctly.
>>
>> Okay.
>>
>> >
>> >> +
>> >> + sram:
>> >> + $ref: /schemas/types.yaml#/definitions/phandle
>> >> + description: phandle of the SRAM memory region node for the VPU
>> >control device.
>> >> +
>> >> + '#cooling-cells':
>> >> + const: 2
>> >> +
>> >> + support-follower:
>> >> + type: boolean
>> >> + description: Indicates whether the VPU domain power always on.
>> >
>> >You cannot add new common properties in random way. Missing vendor
>> >prefix but more important: does not look at all as hardware property but
>> >OS policy.
>>
>> I agree with you.
>> I'll remove it in v2.
>>
>> >
>> >> +
>> >> +patternProperties:
>> >> + "^vpu-ctrl@[0-9a-f]+$":
>> >> + type: object
>> >> + properties:
>> >> + compatible:
>> >> + items:
>> >> + - enum:
>> >> + - nxp,imx95-wave633c-ctrl
>> >
>> >Really, what? How nxp,imx95-wave633c-ctrl node can have a child with
>> >nxp,imx95-wave633c-ctrl compatible?
>> >
>> >NAK.
>>
>> Apologies, I misunderstood the meaning of 'patternProperties'.
>> I'll remove it in v2.
>>
>> >
>> >
>> >> + reg: true
>> >> + clocks: true
>> >> + clock-names: true
>> >> + power-domains:
>> >> + items:
>> >> + - description: Main VPU power domain
>> >> + - description: Performance power domain
>> >> + power-domain-names:
>> >> + items:
>> >> + - const: vpumix
>> >> + - const: vpuperf
>> >> + sram: true
>> >> + boot: true
>> >> + '#cooling-cells': true
>> >> + support-follower: true
>> >> + required:
>> >> + - compatible
>> >> + - reg
>> >> + - clocks
>> >> + - clock-names
>> >> + - power-domains
>> >> + - power-domain-names
>> >> + - sram
>> >> + - boot
>> >> +
>> >> + additionalProperties: false
>> >> +
>> >> + "^vpu@[0-9a-f]+$":
>> >> + type: object
>> >> + properties:
>> >> + compatible:
>> >> + items:
>> >> + - enum:
>> >> + - nxp,imx95-wave633c
>> >> + reg: true
>> >> + interrupts: true
>> >> + clocks: true
>> >> + clock-names: true
>> >> + power-domains:
>> >> + maxItems: 1
>> >> + description: Main VPU power domain
>> >> + cnm,ctrl: true
>> >> + required:
>> >> + - compatible
>> >> + - reg
>> >> + - interrupts
>> >> + - clocks
>> >> + - clock-names
>> >> + - power-domains
>> >> + - cnm,ctrl
>> >
>> >All this is just incorrect.
>>
>> I'll remove it in v2.
>>
>> >
>> >> +
>> >> + additionalProperties: false
>> >> +
>> >> +additionalProperties: false
>> >> +
>> >> +examples:
>> >> + - |
>> >> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> >> + #include <dt-bindings/clock/nxp,imx95-clock.h>
>> >> +
>> >> + soc {
>> >> + #address-cells = <2>;
>> >> + #size-cells = <2>;
>> >> +
>> >> + vpuctrl: vpu-ctrl@4c4c0000 {
>
>So this is the parent device...
>
>> >> + compatible = "nxp,imx95-wave633c-ctrl";
>> >> + reg = <0x0 0x4c4c0000 0x0 0x10000>;
>> >> + clocks = <&scmi_clk 115>,
>> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> >> + clock-names = "vpu", "vpublk_wave";
>> >> + power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
>> >> + power-domain-names = "vpumix", "vpuperf";
>> >> + #cooling-cells = <2>;
>> >> + boot = <&vpu_boot>;
>> >> + sram = <&sram1>;
>> >> + };
>> >> +
>> >> + vpu0: vpu@4c480000 {
>
>
>And here you have child which is not a child? Your binding and DTS
>neither match nor make any sense.
Would it be reasonable to modify it as follows ?
For example:
vpu: video-codec@4c480000 {
compatible = "nxp,imx95-vpu";
reg = <0x0 0x4c480000 0x0 0x50000>;
ranges = <0x0 0x0 0x4c480000 0x50000>;
vpuctrl: vpu-ctrl@40000 {
compatible = "nxp,imx95-vpu-ctrl";
reg = <0x40000 0x10000>;
};
vpucore0: vpu-core@00000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x00000 0x10000>;
};
vpucore1: vpu-core@10000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x10000 0x10000>;
};
vpucore2: vpu-core@20000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x20000 0x10000>;
};
vpucore3: vpu-core@30000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x30000 0x10000>;
};
};
>
>> >
>> >Node names should be generic. See also an explanation and list of
>> >examples (not exhaustive) in DT specification:
>> >https://devicetree-specification.readthedocs.io/en/latest/chapter2-
>> >devicetree-basics.html#generic-names-recommendation
>>
>> Thanks for sharing the link.
>> I'll use "video-codec" as the node name in v2.
>>
>> >
>> >
>> >> + compatible = "nxp,imx95-wave633c";
>> >> + reg = <0x0 0x4c480000 0x0 0x10000>;
>> >> + interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
>> >> + clocks = <&scmi_clk 115>,
>> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> >> + clock-names = "vpu", "vpublk_wave";
>> >> + power-domains = <&scmi_devpd 21>;
>> >> + cnm,ctrl = <&vpuctrl>;
>> >> + };
>> >> +
>> >> + vpu1: vpu@4c490000 {
>> >> + compatible = "nxp,imx95-wave633c";
>> >
>> >Drop all duplicated examples.
>>
>> Wave6 HW is designed for simultaneous access,
>> as each VPU device has its own separate register space.
>> Therefore, I defined the 4 VPU devices as independent nodes in the
>example
>> to reflect this.
>
>They are redundant in this example. Unless you wanted to express
>something else, but you did not.
Got it.
>
>
>>
>> >
>> >
>> >> + reg = <0x0 0x4c490000 0x0 0x10000>;
>> >> + interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
>> >> + clocks = <&scmi_clk 115>,
>> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> >> + clock-names = "vpu", "vpublk_wave";
>> >> + power-domains = <&scmi_devpd 21>;
>> >> + cnm,ctrl = <&vpuctrl>;
>> >> + };
>> >> +
>> >> + vpu2: vpu@4c4a0000 {
>> >> + compatible = "nxp,imx95-wave633c";
>> >> + reg = <0x0 0x4c4a0000 0x0 0x10000>;
>> >> + interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
>> >> + clocks = <&scmi_clk 115>,
>> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> >> + clock-names = "vpu", "vpublk_wave";
>> >> + power-domains = <&scmi_devpd 21>;
>> >> + cnm,ctrl = <&vpuctrl>;
>> >> + };
>> >> +
>> >> + vpu3: vpu@4c4b0000 {
>> >> + compatible = "nxp,imx95-wave633c";
>> >> + reg = <0x0 0x4c4b0000 0x0 0x10000>;
>> >> + interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
>> >> + clocks = <&scmi_clk 115>,
>> >> + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> >> + clock-names = "vpu", "vpublk_wave";
>> >> + power-domains = <&scmi_devpd 21>;
>> >> + cnm,ctrl = <&vpuctrl>;
>> >> + };
>> >> + };
>> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> index 896a307fa065..5ff5b1f1ced2 100644
>> >> --- a/MAINTAINERS
>> >> +++ b/MAINTAINERS
>> >> @@ -25462,6 +25462,14 @@ S: Maintained
>> >> F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
>> >> F: drivers/media/platform/chips-media/wave5/
>> >>
>> >> +WAVE6 VPU CODEC DRIVER
>> >> +M: Nas Chung <nas.chung@chipsnmedia.com>
>> >> +M: Jackson Lee <jackson.lee@chipsnmedia.com>
>> >> +L: linux-media@vger.kernel.org
>> >> +S: Maintained
>> >> +F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>> >> +F: drivers/media/platform/chips-media/wave6/
>> >
>> >There is no such file/directory.
>>
>> Understood. I'll move the MAINTAINERS update to the last patch in v2.
>
>No, just add entry per entry.
I'll add each entry separately in v2.
Thanks.
Nas.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-18 9:21 ` Nas Chung
@ 2025-02-19 12:31 ` Krzysztof Kozlowski
2025-02-20 7:35 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-19 12:31 UTC (permalink / raw)
To: Nas Chung
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
On 18/02/2025 10:21, Nas Chung wrote:
> For example:
> vpu: video-codec@4c480000 {
> compatible = "nxp,imx95-vpu";
> reg = <0x0 0x4c480000 0x0 0x50000>;
> ranges = <0x0 0x0 0x4c480000 0x50000>;
>
> vpuctrl: vpu-ctrl@40000 {
> compatible = "nxp,imx95-vpu-ctrl";
> reg = <0x40000 0x10000>;
> };
>
> vpucore0: vpu-core@00000 {
> compatible = "nxp,imx95-vpu-core";
> reg = <0x00000 0x10000>;
> };
>
> vpucore1: vpu-core@10000 {
> compatible = "nxp,imx95-vpu-core";
> reg = <0x10000 0x10000>;
> };
>
> vpucore2: vpu-core@20000 {
> compatible = "nxp,imx95-vpu-core";
> reg = <0x20000 0x10000>;
> };
>
> vpucore3: vpu-core@30000 {
> compatible = "nxp,imx95-vpu-core";
Why do you need compatible here? Could it be anything else?
> reg = <0x30000 0x10000>;
Where is the rest of resources? You created children only for one
resource - address space?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-19 12:31 ` Krzysztof Kozlowski
@ 2025-02-20 7:35 ` Nas Chung
2025-02-20 8:32 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-20 7:35 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Wednesday, February 19, 2025 9:32 PM
>To: Nas Chung <nas.chung@chipsnmedia.com>
>Cc: mchehab@kernel.org; hverkuil@xs4all.nl; sebastian.fricke@collabora.com;
>robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; linux-
>media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>device
>
>On 18/02/2025 10:21, Nas Chung wrote:
>> For example:
>> vpu: video-codec@4c480000 {
>> compatible = "nxp,imx95-vpu";
>> reg = <0x0 0x4c480000 0x0 0x50000>;
>> ranges = <0x0 0x0 0x4c480000 0x50000>;
>>
>> vpuctrl: vpu-ctrl@40000 {
>> compatible = "nxp,imx95-vpu-ctrl";
>> reg = <0x40000 0x10000>;
>> };
>>
>> vpucore0: vpu-core@00000 {
>> compatible = "nxp,imx95-vpu-core";
>> reg = <0x00000 0x10000>;
>> };
>>
>> vpucore1: vpu-core@10000 {
>> compatible = "nxp,imx95-vpu-core";
>> reg = <0x10000 0x10000>;
>> };
>>
>> vpucore2: vpu-core@20000 {
>> compatible = "nxp,imx95-vpu-core";
>> reg = <0x20000 0x10000>;
>> };
>>
>> vpucore3: vpu-core@30000 {
>> compatible = "nxp,imx95-vpu-core";
>
>Why do you need compatible here? Could it be anything else?
I will update the driver based on the final DT.
>
>> reg = <0x30000 0x10000>;
>
>Where is the rest of resources? You created children only for one
>resource - address space?
Sorry for the confusion.
I believe the final example looks like the one below.
vpu: video-codec@4c480000 {
compatible = "nxp,imx95-vpu";
reg = <0x0 0x4c480000 0x0 0x50000>;
ranges = <0x0 0x0 0x4c480000 0x50000>;
vpuctrl: vpu-ctrl@40000 {
compatible = "nxp,imx95-vpu-ctrl";
reg = <0x40000 0x10000>;
clocks = <&scmi_clk 115>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
power-domain-names = "vpumix", "vpuperf";
memory-region = <&vpu_boot>;
#cooling-cells = <2>;
sram = <&sram1>;
};
vpucore0: vpu-core@00000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x00000 0x10000>;
interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scmi_clk 115>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd 21>;
};
vpucore1: vpu-core@10000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x10000 0x10000>;
interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scmi_clk 115>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd 21>;
};
vpucore2: vpu-core@20000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x20000 0x10000>;
interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scmi_clk 115>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd 21>;
};
vpucore3: vpu-core@30000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x30000 0x10000>;
interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scmi_clk 115>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd 21>;
};
};
Thanks.
Nas.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-20 7:35 ` Nas Chung
@ 2025-02-20 8:32 ` Krzysztof Kozlowski
2025-02-21 8:29 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-20 8:32 UTC (permalink / raw)
To: Nas Chung
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
On 20/02/2025 08:35, Nas Chung wrote:
> Hi, Krzysztof.
>
>> -----Original Message-----
>> From: Krzysztof Kozlowski <krzk@kernel.org>
>> Sent: Wednesday, February 19, 2025 9:32 PM
>> To: Nas Chung <nas.chung@chipsnmedia.com>
>> Cc: mchehab@kernel.org; hverkuil@xs4all.nl; sebastian.fricke@collabora.com;
>> robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; linux-
>> media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>> kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>> kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>> lafley.kim <lafley.kim@chipsnmedia.com>
>> Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>> device
>>
>> On 18/02/2025 10:21, Nas Chung wrote:
>>> For example:
>>> vpu: video-codec@4c480000 {
>>> compatible = "nxp,imx95-vpu";
>>> reg = <0x0 0x4c480000 0x0 0x50000>;
>>> ranges = <0x0 0x0 0x4c480000 0x50000>;
>>>
>>> vpuctrl: vpu-ctrl@40000 {
>>> compatible = "nxp,imx95-vpu-ctrl";
>>> reg = <0x40000 0x10000>;
>>> };
>>>
>>> vpucore0: vpu-core@00000 {
>>> compatible = "nxp,imx95-vpu-core";
>>> reg = <0x00000 0x10000>;
>>> };
>>>
>>> vpucore1: vpu-core@10000 {
>>> compatible = "nxp,imx95-vpu-core";
>>> reg = <0x10000 0x10000>;
>>> };
>>>
>>> vpucore2: vpu-core@20000 {
>>> compatible = "nxp,imx95-vpu-core";
>>> reg = <0x20000 0x10000>;
>>> };
>>>
>>> vpucore3: vpu-core@30000 {
>>> compatible = "nxp,imx95-vpu-core";
>>
>> Why do you need compatible here? Could it be anything else?
>
> I will update the driver based on the final DT.
>
>>
>>> reg = <0x30000 0x10000>;
>>
>> Where is the rest of resources? You created children only for one
>> resource - address space?
>
> Sorry for the confusion.
> I believe the final example looks like the one below.
>
> vpu: video-codec@4c480000 {
> compatible = "nxp,imx95-vpu";
> reg = <0x0 0x4c480000 0x0 0x50000>;
> ranges = <0x0 0x0 0x4c480000 0x50000>;
>
> vpuctrl: vpu-ctrl@40000 {
> compatible = "nxp,imx95-vpu-ctrl";
> reg = <0x40000 0x10000>;
> clocks = <&scmi_clk 115>,
> <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
> clock-names = "vpu", "vpublk_wave";
> power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
> power-domain-names = "vpumix", "vpuperf";
> memory-region = <&vpu_boot>;
> #cooling-cells = <2>;
> sram = <&sram1>;
> };
>
> vpucore0: vpu-core@00000 {
> compatible = "nxp,imx95-vpu-core";
> reg = <0x00000 0x10000>;
> interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&scmi_clk 115>,
> <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
These are the same resources for every block so for entire device. Why
they are no in top level node?
> clock-names = "vpu", "vpublk_wave";
> power-domains = <&scmi_devpd 21>;
Same here
Everything else also looks duplicated... All my previous comments - from
first email - stand. Don't design DT to match your Linu driver structure.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device
2025-02-20 8:32 ` Krzysztof Kozlowski
@ 2025-02-21 8:29 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-21 8:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Thursday, February 20, 2025 5:32 PM
>To: Nas Chung <nas.chung@chipsnmedia.com>
>Cc: mchehab@kernel.org; hverkuil@xs4all.nl; sebastian.fricke@collabora.com;
>robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; linux-
>media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>device
>
>On 20/02/2025 08:35, Nas Chung wrote:
>> Hi, Krzysztof.
>>
>>> -----Original Message-----
>>> From: Krzysztof Kozlowski <krzk@kernel.org>
>>> Sent: Wednesday, February 19, 2025 9:32 PM
>>> To: Nas Chung <nas.chung@chipsnmedia.com>
>>> Cc: mchehab@kernel.org; hverkuil@xs4all.nl;
>sebastian.fricke@collabora.com;
>>> robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; linux-
>>> media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>>> kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>>> kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>>> lafley.kim <lafley.kim@chipsnmedia.com>
>>> Subject: Re: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec
>>> device
>>>
>>> On 18/02/2025 10:21, Nas Chung wrote:
>>>> For example:
>>>> vpu: video-codec@4c480000 {
>>>> compatible = "nxp,imx95-vpu";
>>>> reg = <0x0 0x4c480000 0x0 0x50000>;
>>>> ranges = <0x0 0x0 0x4c480000 0x50000>;
>>>>
>>>> vpuctrl: vpu-ctrl@40000 {
>>>> compatible = "nxp,imx95-vpu-ctrl";
>>>> reg = <0x40000 0x10000>;
>>>> };
>>>>
>>>> vpucore0: vpu-core@00000 {
>>>> compatible = "nxp,imx95-vpu-core";
>>>> reg = <0x00000 0x10000>;
>>>> };
>>>>
>>>> vpucore1: vpu-core@10000 {
>>>> compatible = "nxp,imx95-vpu-core";
>>>> reg = <0x10000 0x10000>;
>>>> };
>>>>
>>>> vpucore2: vpu-core@20000 {
>>>> compatible = "nxp,imx95-vpu-core";
>>>> reg = <0x20000 0x10000>;
>>>> };
>>>>
>>>> vpucore3: vpu-core@30000 {
>>>> compatible = "nxp,imx95-vpu-core";
>>>
>>> Why do you need compatible here? Could it be anything else?
>>
>> I will update the driver based on the final DT.
>>
>>>
>>>> reg = <0x30000 0x10000>;
>>>
>>> Where is the rest of resources? You created children only for one
>>> resource - address space?
>>
>> Sorry for the confusion.
>> I believe the final example looks like the one below.
>>
>> vpu: video-codec@4c480000 {
>> compatible = "nxp,imx95-vpu";
>> reg = <0x0 0x4c480000 0x0 0x50000>;
>> ranges = <0x0 0x0 0x4c480000 0x50000>;
>>
>> vpuctrl: vpu-ctrl@40000 {
>> compatible = "nxp,imx95-vpu-ctrl";
>> reg = <0x40000 0x10000>;
>> clocks = <&scmi_clk 115>,
>> <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>> clock-names = "vpu", "vpublk_wave";
>> power-domains = <&scmi_devpd 21>, <&scmi_perf 10>;
>> power-domain-names = "vpumix", "vpuperf";
>> memory-region = <&vpu_boot>;
>> #cooling-cells = <2>;
>> sram = <&sram1>;
>> };
>>
>> vpucore0: vpu-core@00000 {
>> compatible = "nxp,imx95-vpu-core";
>> reg = <0x00000 0x10000>;
>> interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
>> clocks = <&scmi_clk 115>,
>> <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
>
>
>These are the same resources for every block so for entire device. Why
>they are no in top level node?
>
>> clock-names = "vpu", "vpublk_wave";
>> power-domains = <&scmi_devpd 21>;
>
>Same here
>
>Everything else also looks duplicated... All my previous comments - from
>first email - stand. Don't design DT to match your Linu driver structure.
I agree with you. Thanks again for your feedback.
I've moved the shared resources to the parent node while keeping the
independent resources within their respective child nodes, as shown below.
vpu: video-codec@4c480000 {
compatible = "nxp,imx95-vpu";
reg = <0x0 0x4c480000 0x0 0x50000>;
ranges = <0x0 0x0 0x4c480000 0x50000>;
clocks = <&scmi_clk IMX95_CLK_VPU>,
<&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>;
clock-names = "vpu", "vpublk_wave";
power-domains = <&scmi_devpd IMX95_PD_VPU>;
vpucore0: vpu-core@00000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x00000 0x10000>;
interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
};
vpucore1: vpu-core@10000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x10000 0x10000>;
interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
};
vpucore2: vpu-core@20000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x20000 0x10000>;
interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>;
};
vpucore3: vpu-core@30000 {
compatible = "nxp,imx95-vpu-core";
reg = <0x30000 0x10000>;
interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
};
vpuctrl: vpu-ctrl@40000 {
compatible = "nxp,imx95-vpu-ctrl";
reg = <0x40000 0x10000>;
power-domains = <&scmi_perf IMX95_PERF_VPU>;
memory-region = <&vpu_boot>;
#cooling-cells = <2>;
sram = <&sram1>;
};
};
Thanks.
Nas.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (2 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-10 17:40 ` Krzysztof Kozlowski
2025-02-10 9:07 ` [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver Nas Chung
` (5 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Chips&Media Wave6 stateful codec driver.
The codec driver provides encoding and decoding capabilities
for H.264, HEVC, and other video formats.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
drivers/media/platform/chips-media/Kconfig | 1 +
drivers/media/platform/chips-media/Makefile | 1 +
.../media/platform/chips-media/wave6/Kconfig | 26 +
.../media/platform/chips-media/wave6/Makefile | 17 +
.../platform/chips-media/wave6/wave6-vpu.c | 487 ++++++++++++++++++
.../platform/chips-media/wave6/wave6-vpu.h | 106 ++++
6 files changed, 638 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig
create mode 100644 drivers/media/platform/chips-media/wave6/Makefile
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h
diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig
index ad350eb6b1fc..8ef7fc8029a4 100644
--- a/drivers/media/platform/chips-media/Kconfig
+++ b/drivers/media/platform/chips-media/Kconfig
@@ -4,3 +4,4 @@ comment "Chips&Media media platform drivers"
source "drivers/media/platform/chips-media/coda/Kconfig"
source "drivers/media/platform/chips-media/wave5/Kconfig"
+source "drivers/media/platform/chips-media/wave6/Kconfig"
diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile
index 6b5d99de8b54..b9a07a91c9d6 100644
--- a/drivers/media/platform/chips-media/Makefile
+++ b/drivers/media/platform/chips-media/Makefile
@@ -2,3 +2,4 @@
obj-y += coda/
obj-y += wave5/
+obj-y += wave6/
diff --git a/drivers/media/platform/chips-media/wave6/Kconfig b/drivers/media/platform/chips-media/wave6/Kconfig
new file mode 100644
index 000000000000..0f45581ff273
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_WAVE6_VPU
+ tristate "Chips&Media Wave6 Codec Driver"
+ depends on V4L_MEM2MEM_DRIVERS
+ depends on VIDEO_DEV && OF
+ depends on ARCH_MXC || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ select GENERIC_ALLOCATOR
+ help
+ Chips&Media Wave6 stateful codec driver.
+ The codec driver provides encoding and decoding capabilities
+ for H.264, HEVC, and other video formats.
+ To compile this driver as modules, choose M here: the
+ modules will be called wave6.
+
+config VIDEO_WAVE6_VPU_CTRL
+ tristate "Chips&Media Wave6 Codec Control Driver"
+ depends on VIDEO_WAVE6_VPU
+ default VIDEO_WAVE6_VPU if ARCH_MXC || COMPILE_TEST
+ help
+ Chips&Media Wave6 control driver.
+ The control driver manages shared resources such as firmware
+ access and power domains and clock.
+ To compile this driver as modules, choose M here: the
+ modules will be called wave6-ctrl.
diff --git a/drivers/media/platform/chips-media/wave6/Makefile b/drivers/media/platform/chips-media/wave6/Makefile
new file mode 100644
index 000000000000..c2180406c193
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# tell define_trace.h where to find the trace header
+CFLAGS_wave6-vpu.o := -I$(src)
+
+wave6-ctrl-objs += wave6-vpu-ctrl.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU_CTRL) += wave6-ctrl.o
+
+wave6-objs += wave6-vpu.o \
+ wave6-vpu-v4l2.o \
+ wave6-vpu-dbg.o \
+ wave6-vdi.o \
+ wave6-vpuapi.o \
+ wave6-vpu-dec.o \
+ wave6-vpu-enc.o \
+ wave6-hw.o
+obj-$(CONFIG_VIDEO_WAVE6_VPU) += wave6.o
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.c b/drivers/media/platform/chips-media/wave6/wave6-vpu.c
new file mode 100644
index 000000000000..470d22489ecc
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 codec driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
+#include <linux/debugfs.h>
+#include "wave6-vpu.h"
+#include "wave6-regdefine.h"
+#include "wave6-vpuconfig.h"
+#include "wave6-hw.h"
+#include "wave6-vpu-ctrl.h"
+#include "wave6-vpu-dbg.h"
+
+#define CREATE_TRACE_POINTS
+#include "wave6-trace.h"
+
+#define VPU_PLATFORM_DEVICE_NAME "wave6-vpu"
+#define VPU_CLK_NAME "vcodec"
+#define WAVE6_VPU_DEBUGFS_DIR "wave6"
+
+#define WAVE6_IS_ENC BIT(0)
+#define WAVE6_IS_DEC BIT(1)
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+
+struct wave6_match_data {
+ int codec_types;
+ u32 compatible_fw_version;
+};
+
+static const struct wave6_match_data wave633c_data = {
+ .codec_types = WAVE6_IS_ENC | WAVE6_IS_DEC,
+ .compatible_fw_version = 0x3000000,
+};
+
+unsigned int wave6_vpu_debug(void)
+{
+ return debug;
+}
+
+static void wave6_vpu_get_clk(struct vpu_device *vpu_dev)
+{
+ int i;
+
+ if (!vpu_dev || !vpu_dev->num_clks || vpu_dev->clk_vpu)
+ return;
+
+ for (i = 0; i < vpu_dev->num_clks; i++) {
+ if (vpu_dev->clks[i].id && !strcmp(vpu_dev->clks[i].id, "vpu")) {
+ vpu_dev->clk_vpu = vpu_dev->clks[i].clk;
+ return;
+ }
+ }
+
+ vpu_dev->clk_vpu = vpu_dev->clks[0].clk;
+}
+
+static irqreturn_t wave6_vpu_irq(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
+ u32 irq_status;
+
+ if (wave6_vdi_readl(dev, W6_VPU_VPU_INT_STS)) {
+ irq_status = wave6_vdi_readl(dev, W6_VPU_VINT_REASON);
+
+ wave6_vdi_writel(dev, W6_VPU_VINT_REASON_CLR, irq_status);
+ wave6_vdi_writel(dev, W6_VPU_VINT_CLEAR, 0x1);
+
+ trace_irq(dev, irq_status);
+
+ kfifo_in(&dev->irq_status, &irq_status, sizeof(int));
+
+ return IRQ_WAKE_THREAD;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wave6_vpu_irq_thread(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
+ struct vpu_instance *inst;
+ int irq_status, ret;
+
+ while (kfifo_len(&dev->irq_status)) {
+ bool error = false;
+
+ ret = kfifo_out(&dev->irq_status, &irq_status, sizeof(int));
+ if (!ret)
+ break;
+
+ if (irq_status & BIT(W6_INT_BIT_REQ_WORK_BUF)) {
+ if (!dev->ctrl)
+ continue;
+
+ wave6_vpu_ctrl_require_buffer(dev->ctrl, &dev->entity);
+ continue;
+ }
+
+ if ((irq_status & BIT(W6_INT_BIT_INIT_SEQ)) ||
+ (irq_status & BIT(W6_INT_BIT_ENC_SET_PARAM))) {
+ complete(&dev->irq_done);
+ continue;
+ }
+
+ if (irq_status & BIT(W6_INT_BIT_BSBUF_ERROR))
+ error = true;
+
+ inst = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (inst)
+ inst->ops->finish_process(inst, error);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static u32 wave6_vpu_read_reg(struct device *dev, u32 addr)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ return wave6_vdi_readl(vpu_dev, addr);
+}
+
+static void wave6_vpu_write_reg(struct device *dev, u32 addr, u32 data)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ wave6_vdi_writel(vpu_dev, addr, data);
+}
+
+static void wave6_vpu_on_boot(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ u32 product_code;
+ u32 version;
+ u32 revision;
+ u32 hw_version;
+ int ret;
+
+ product_code = wave6_vdi_readl(vpu_dev, W6_VPU_RET_PRODUCT_VERSION);
+
+ wave6_vpu_enable_interrupt(vpu_dev);
+ ret = wave6_vpu_get_version(vpu_dev, &version, &revision);
+ if (ret) {
+ dev_err(dev, "wave6_vpu_get_version fail\n");
+ return;
+ }
+
+ hw_version = wave6_vdi_readl(vpu_dev, W6_RET_CONF_REVISION);
+
+ if (vpu_dev->product_code != product_code ||
+ vpu_dev->fw_version != version ||
+ vpu_dev->fw_revision != revision ||
+ vpu_dev->hw_version != hw_version) {
+ vpu_dev->product_code = product_code;
+ vpu_dev->fw_version = version;
+ vpu_dev->fw_revision = revision;
+ vpu_dev->hw_version = hw_version;
+ dev_info(dev, "product: %08x, fw_version : %d.%d.%d(r%d), hw_version : 0x%x\n",
+ vpu_dev->product_code,
+ (version >> 24) & 0xFF,
+ (version >> 16) & 0xFF,
+ (version >> 0) & 0xFFFF,
+ revision,
+ vpu_dev->hw_version);
+ }
+
+ if (vpu_dev->res->compatible_fw_version > version)
+ dev_err(dev, "compatible firmware version is v%d.%d.%d or higher, but only v%d.%d.%d\n",
+ (vpu_dev->res->compatible_fw_version >> 24) & 0xFF,
+ (vpu_dev->res->compatible_fw_version >> 16) & 0xFF,
+ vpu_dev->res->compatible_fw_version & 0xFFFF,
+ (version >> 24) & 0xFF,
+ (version >> 16) & 0xFF,
+ version & 0xFFFF);
+
+ wave6_vpu_get_clk(vpu_dev);
+}
+
+void wave6_vpu_pause(struct device *dev, int resume)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ mutex_lock(&vpu_dev->pause_lock);
+ if (resume) {
+ vpu_dev->pause_request--;
+ if (!vpu_dev->pause_request)
+ v4l2_m2m_resume(vpu_dev->m2m_dev);
+ } else {
+ if (!vpu_dev->pause_request)
+ v4l2_m2m_suspend(vpu_dev->m2m_dev);
+ vpu_dev->pause_request++;
+ }
+ mutex_unlock(&vpu_dev->pause_lock);
+}
+
+void wave6_vpu_activate(struct vpu_device *dev)
+{
+ dev->active = true;
+}
+
+void wave6_vpu_wait_activated(struct vpu_device *dev)
+{
+ wave6_vpu_check_state(dev);
+}
+
+static int wave6_vpu_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct vpu_device *dev;
+ const struct wave6_match_data *match_data;
+ struct device_node *np;
+ struct platform_device *pctrl;
+
+ match_data = device_get_match_data(&pdev->dev);
+ if (!match_data) {
+ dev_err(&pdev->dev, "missing match_data\n");
+ return -EINVAL;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "dma_set_mask_and_coherent failed: %d\n", ret);
+ return ret;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mutex_init(&dev->dev_lock);
+ mutex_init(&dev->hw_lock);
+ mutex_init(&dev->pause_lock);
+ init_completion(&dev->irq_done);
+ dev_set_drvdata(&pdev->dev, dev);
+ dev->dev = &pdev->dev;
+ dev->res = match_data;
+
+ dev->entity.dev = dev->dev;
+ dev->entity.read_reg = wave6_vpu_read_reg;
+ dev->entity.write_reg = wave6_vpu_write_reg;
+ dev->entity.on_boot = wave6_vpu_on_boot;
+ dev->entity.pause = wave6_vpu_pause;
+
+ dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dev->reg_base))
+ return PTR_ERR(dev->reg_base);
+
+ np = of_parse_phandle(pdev->dev.of_node, "cnm,ctrl", 0);
+ if (np) {
+ pctrl = of_find_device_by_node(np);
+ of_node_put(np);
+ if (pctrl) {
+ dev->ctrl = &pctrl->dev;
+ if (wave6_vpu_ctrl_get_state(dev->ctrl) < 0) {
+ dev_info(&pdev->dev, "vpu ctrl is not ready, defer probe\n");
+ return -EPROBE_DEFER;
+ }
+ } else {
+ dev_info(&pdev->dev, "vpu ctrl is not found\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "unable to get clocks: %d\n", ret);
+ ret = 0;
+ }
+ dev->num_clks = ret;
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "v4l2_device_register fail: %d\n", ret);
+ return ret;
+ }
+
+ ret = wave6_vpu_init_m2m_dev(dev);
+ if (ret)
+ goto err_v4l2_unregister;
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ ret = -ENXIO;
+ goto err_m2m_dev_release;
+ }
+
+ if (kfifo_alloc(&dev->irq_status, 16 * sizeof(int), GFP_KERNEL)) {
+ dev_err(&pdev->dev, "failed to allocate fifo\n");
+ goto err_m2m_dev_release;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, dev->irq, wave6_vpu_irq,
+ wave6_vpu_irq_thread, 0, "vpu_irq", dev);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to register interrupt handler: %d\n", ret);
+ goto err_kfifo_free;
+ }
+
+ dev->temp_vbuf.size = ALIGN(WAVE6_TEMPBUF_SIZE, 4096);
+ ret = wave6_alloc_dma(dev->dev, &dev->temp_vbuf);
+ if (ret) {
+ dev_err(&pdev->dev, "alloc temp of size %zu failed\n",
+ dev->temp_vbuf.size);
+ goto err_kfifo_free;
+ }
+
+ dev->debugfs = debugfs_lookup(WAVE6_VPU_DEBUGFS_DIR, NULL);
+ if (IS_ERR_OR_NULL(dev->debugfs))
+ dev->debugfs = debugfs_create_dir(WAVE6_VPU_DEBUGFS_DIR, NULL);
+
+ pm_runtime_enable(&pdev->dev);
+
+ if (dev->res->codec_types & WAVE6_IS_DEC) {
+ ret = wave6_vpu_dec_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave6_vpu_dec_register_device fail: %d\n", ret);
+ goto err_temp_vbuf_free;
+ }
+ }
+ if (dev->res->codec_types & WAVE6_IS_ENC) {
+ ret = wave6_vpu_enc_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave6_vpu_enc_register_device fail: %d\n", ret);
+ goto err_dec_unreg;
+ }
+ }
+
+ if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
+ wave6_vpu_activate(dev);
+ ret = pm_runtime_resume_and_get(dev->dev);
+ if (ret)
+ goto err_enc_unreg;
+ }
+
+ dev_dbg(&pdev->dev, "Added wave6 driver with caps %s %s\n",
+ dev->res->codec_types & WAVE6_IS_ENC ? "'ENCODE'" : "",
+ dev->res->codec_types & WAVE6_IS_DEC ? "'DECODE'" : "");
+
+ return 0;
+
+err_enc_unreg:
+ if (dev->res->codec_types & WAVE6_IS_ENC)
+ wave6_vpu_enc_unregister_device(dev);
+err_dec_unreg:
+ if (dev->res->codec_types & WAVE6_IS_DEC)
+ wave6_vpu_dec_unregister_device(dev);
+err_temp_vbuf_free:
+ wave6_free_dma(&dev->temp_vbuf);
+err_kfifo_free:
+ kfifo_free(&dev->irq_status);
+err_m2m_dev_release:
+ wave6_vpu_release_m2m_dev(dev);
+err_v4l2_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return ret;
+}
+
+static void wave6_vpu_remove(struct platform_device *pdev)
+{
+ struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
+
+ if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put_sync(&pdev->dev);
+ }
+ pm_runtime_disable(&pdev->dev);
+
+ wave6_vpu_enc_unregister_device(dev);
+ wave6_vpu_dec_unregister_device(dev);
+ wave6_free_dma(&dev->temp_vbuf);
+ kfifo_free(&dev->irq_status);
+ wave6_vpu_release_m2m_dev(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+static int wave6_vpu_runtime_suspend(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ if (!vpu_dev)
+ return -ENODEV;
+
+ dprintk(dev, "runtime suspend\n");
+ if (vpu_dev->ctrl && vpu_dev->active)
+ wave6_vpu_ctrl_put_sync(vpu_dev->ctrl, &vpu_dev->entity);
+ if (vpu_dev->num_clks)
+ clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
+
+ return 0;
+}
+
+static int wave6_vpu_runtime_resume(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (!vpu_dev)
+ return -ENODEV;
+
+ dprintk(dev, "runtime resume\n");
+ if (vpu_dev->num_clks) {
+ ret = clk_bulk_prepare_enable(vpu_dev->num_clks, vpu_dev->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (vpu_dev->ctrl && vpu_dev->active) {
+ ret = wave6_vpu_ctrl_resume_and_get(vpu_dev->ctrl, &vpu_dev->entity);
+ if (ret && vpu_dev->num_clks)
+ clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
+ } else {
+ wave6_vpu_check_state(vpu_dev);
+ }
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int wave6_vpu_suspend(struct device *dev)
+{
+ int ret;
+
+ dprintk(dev, "suspend\n");
+ wave6_vpu_pause(dev, 0);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ wave6_vpu_pause(dev, 1);
+
+ return ret;
+}
+
+static int wave6_vpu_resume(struct device *dev)
+{
+ int ret;
+
+ dprintk(dev, "resume\n");
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ wave6_vpu_pause(dev, 1);
+ return 0;
+}
+#endif
+static const struct dev_pm_ops wave6_vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend, wave6_vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_suspend, wave6_vpu_resume)
+};
+
+static const struct of_device_id wave6_dt_ids[] = {
+ { .compatible = "nxp,imx95-wave633c", .data = &wave633c_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wave6_dt_ids);
+
+static struct platform_driver wave6_vpu_driver = {
+ .driver = {
+ .name = VPU_PLATFORM_DEVICE_NAME,
+ .of_match_table = of_match_ptr(wave6_dt_ids),
+ .pm = &wave6_vpu_pm_ops,
+ },
+ .probe = wave6_vpu_probe,
+ .remove = wave6_vpu_remove,
+};
+
+module_platform_driver(wave6_vpu_driver);
+MODULE_DESCRIPTION("chips&media VPU V4L2 driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.h b/drivers/media/platform/chips-media/wave6/wave6-vpu.h
new file mode 100644
index 000000000000..51cda07863a4
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 codec driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPU_H__
+#define __WAVE6_VPU_H__
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include "wave6-vpuconfig.h"
+#include "wave6-vpuapi.h"
+
+struct vpu_buffer {
+ struct v4l2_m2m_buffer v4l2_m2m_buf;
+ bool consumed;
+ bool used;
+ bool error;
+ bool force_key_frame;
+ bool force_frame_qp;
+ u32 force_i_frame_qp;
+ u32 force_p_frame_qp;
+ u32 force_b_frame_qp;
+ ktime_t ts_input;
+ ktime_t ts_start;
+ ktime_t ts_finish;
+ ktime_t ts_output;
+ u64 hw_time;
+ u32 average_qp;
+};
+
+enum vpu_fmt_type {
+ VPU_FMT_TYPE_CODEC = 0,
+ VPU_FMT_TYPE_RAW = 1
+};
+
+struct vpu_format {
+ unsigned int v4l2_pix_fmt;
+ unsigned int max_width;
+ unsigned int min_width;
+ unsigned int max_height;
+ unsigned int min_height;
+ unsigned int num_planes;
+};
+
+static inline struct vpu_instance *wave6_to_vpu_inst(struct v4l2_fh *vfh)
+{
+ return container_of(vfh, struct vpu_instance, v4l2_fh);
+}
+
+static inline struct vpu_instance *wave6_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl)
+{
+ return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl);
+}
+
+static inline struct vpu_buffer *wave6_to_vpu_buf(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct vpu_buffer, v4l2_m2m_buf.vb);
+}
+
+static inline bool wave6_vpu_both_queues_are_streaming(struct vpu_instance *inst)
+{
+ struct vb2_queue *vq_cap = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx);
+ struct vb2_queue *vq_out = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx);
+
+ return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out);
+}
+
+u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst);
+u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst);
+void wave6_vpu_pause(struct device *dev, int resume);
+void wave6_vpu_activate(struct vpu_device *dev);
+void wave6_vpu_wait_activated(struct vpu_device *dev);
+void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ unsigned int width,
+ unsigned int height);
+struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct vpu_instance *inst,
+ dma_addr_t addr);
+dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf,
+ unsigned int plane_no);
+enum codec_std wave6_to_codec_std(enum vpu_instance_type type, unsigned int v4l2_pix_fmt);
+const char *wave6_vpu_instance_state_name(u32 state);
+void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32 state);
+u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle);
+int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout);
+int wave6_vpu_dec_register_device(struct vpu_device *dev);
+void wave6_vpu_dec_unregister_device(struct vpu_device *dev);
+int wave6_vpu_enc_register_device(struct vpu_device *dev);
+void wave6_vpu_enc_unregister_device(struct vpu_device *dev);
+void wave6_vpu_finish_job(struct vpu_instance *inst);
+void wave6_vpu_handle_performance(struct vpu_instance *inst, struct vpu_buffer *vpu_buf);
+void wave6_vpu_reset_performance(struct vpu_instance *inst);
+int wave6_vpu_init_m2m_dev(struct vpu_device *dev);
+void wave6_vpu_release_m2m_dev(struct vpu_device *dev);
+int wave6_vpu_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub);
+void wave6_vpu_return_buffers(struct vpu_instance *inst,
+ unsigned int type, enum vb2_buffer_state state);
+
+#endif /* __WAVE6_VPU_H__ */
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver
2025-02-10 9:07 ` [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver Nas Chung
@ 2025-02-10 17:40 ` Krzysztof Kozlowski
2025-02-11 8:28 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-10 17:40 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim
On 10/02/2025 10:07, Nas Chung wrote:
> +
> + dev->debugfs = debugfs_lookup(WAVE6_VPU_DEBUGFS_DIR, NULL);
> + if (IS_ERR_OR_NULL(dev->debugfs))
> + dev->debugfs = debugfs_create_dir(WAVE6_VPU_DEBUGFS_DIR, NULL);
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + if (dev->res->codec_types & WAVE6_IS_DEC) {
> + ret = wave6_vpu_dec_register_device(dev);
> + if (ret) {
> + dev_err(&pdev->dev, "wave6_vpu_dec_register_device fail: %d\n", ret);
> + goto err_temp_vbuf_free;
> + }
> + }
> + if (dev->res->codec_types & WAVE6_IS_ENC) {
> + ret = wave6_vpu_enc_register_device(dev);
> + if (ret) {
> + dev_err(&pdev->dev, "wave6_vpu_enc_register_device fail: %d\n", ret);
> + goto err_dec_unreg;
> + }
> + }
> +
> + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
> + wave6_vpu_activate(dev);
> + ret = pm_runtime_resume_and_get(dev->dev);
> + if (ret)
> + goto err_enc_unreg;
> + }
> +
> + dev_dbg(&pdev->dev, "Added wave6 driver with caps %s %s\n",
> + dev->res->codec_types & WAVE6_IS_ENC ? "'ENCODE'" : "",
> + dev->res->codec_types & WAVE6_IS_DEC ? "'DECODE'" : "");
> +
> + return 0;
> +
> +err_enc_unreg:
> + if (dev->res->codec_types & WAVE6_IS_ENC)
> + wave6_vpu_enc_unregister_device(dev);
> +err_dec_unreg:
> + if (dev->res->codec_types & WAVE6_IS_DEC)
> + wave6_vpu_dec_unregister_device(dev);
> +err_temp_vbuf_free:
> + wave6_free_dma(&dev->temp_vbuf);
> +err_kfifo_free:
> + kfifo_free(&dev->irq_status);
> +err_m2m_dev_release:
> + wave6_vpu_release_m2m_dev(dev);
> +err_v4l2_unregister:
> + v4l2_device_unregister(&dev->v4l2_dev);
> +
> + return ret;
> +}
> +
> +static void wave6_vpu_remove(struct platform_device *pdev)
> +{
> + struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
> +
> + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
> + if (!pm_runtime_suspended(&pdev->dev))
> + pm_runtime_put_sync(&pdev->dev);
> + }
> + pm_runtime_disable(&pdev->dev);
> +
> + wave6_vpu_enc_unregister_device(dev);
> + wave6_vpu_dec_unregister_device(dev);
> + wave6_free_dma(&dev->temp_vbuf);
> + kfifo_free(&dev->irq_status);
> + wave6_vpu_release_m2m_dev(dev);
> + v4l2_device_unregister(&dev->v4l2_dev);
> +}
> +
> +#ifdef CONFIG_PM
> +static int wave6_vpu_runtime_suspend(struct device *dev)
> +{
> + struct vpu_device *vpu_dev = dev_get_drvdata(dev);
> +
> + if (!vpu_dev)
> + return -ENODEV;
> +
> + dprintk(dev, "runtime suspend\n");
Drop
> + if (vpu_dev->ctrl && vpu_dev->active)
> + wave6_vpu_ctrl_put_sync(vpu_dev->ctrl, &vpu_dev->entity);
> + if (vpu_dev->num_clks)
> + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_runtime_resume(struct device *dev)
> +{
> + struct vpu_device *vpu_dev = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + if (!vpu_dev)
> + return -ENODEV;
> +
> + dprintk(dev, "runtime resume\n");
Drop
> + if (vpu_dev->num_clks) {
> + ret = clk_bulk_prepare_enable(vpu_dev->num_clks, vpu_dev->clks);
> + if (ret) {
> + dev_err(dev, "failed to enable clocks: %d\n", ret);
> + return ret;
> + }
> + }
> +
> + if (vpu_dev->ctrl && vpu_dev->active) {
> + ret = wave6_vpu_ctrl_resume_and_get(vpu_dev->ctrl, &vpu_dev->entity);
> + if (ret && vpu_dev->num_clks)
> + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
> + } else {
> + wave6_vpu_check_state(vpu_dev);
> + }
> +
> + return ret;
> +}
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int wave6_vpu_suspend(struct device *dev)
> +{
> + int ret;
> +
> + dprintk(dev, "suspend\n");
Drop. Don't re-implement existing tracing.
> + wave6_vpu_pause(dev, 0);
> +
> + ret = pm_runtime_force_suspend(dev);
> + if (ret)
> + wave6_vpu_pause(dev, 1);
> +
> + return ret;
> +}
> +
> +static int wave6_vpu_resume(struct device *dev)
> +{
> + int ret;
> +
> + dprintk(dev, "resume\n");
Drop, useless.
> + ret = pm_runtime_force_resume(dev);
> + if (ret)
> + return ret;
> +
> + wave6_vpu_pause(dev, 1);
> + return 0;
> +}
> +#endif
> +static const struct dev_pm_ops wave6_vpu_pm_ops = {
> + SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend, wave6_vpu_runtime_resume, NULL)
> + SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_suspend, wave6_vpu_resume)
> +};
> +
> +static const struct of_device_id wave6_dt_ids[] = {
> + { .compatible = "nxp,imx95-wave633c", .data = &wave633c_data },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, wave6_dt_ids);
> +
> +static struct platform_driver wave6_vpu_driver = {
> + .driver = {
> + .name = VPU_PLATFORM_DEVICE_NAME,
> + .of_match_table = of_match_ptr(wave6_dt_ids),
Drop of_match_ptr, you have here warnings.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver
2025-02-10 17:40 ` Krzysztof Kozlowski
@ 2025-02-11 8:28 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-11 8:28 UTC (permalink / raw)
To: Krzysztof Kozlowski, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Tuesday, February 11, 2025 2:41 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; sebastian.fricke@collabora.com; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver
>
>On 10/02/2025 10:07, Nas Chung wrote:
>> +
>> + dev->debugfs = debugfs_lookup(WAVE6_VPU_DEBUGFS_DIR, NULL);
>> + if (IS_ERR_OR_NULL(dev->debugfs))
>> + dev->debugfs = debugfs_create_dir(WAVE6_VPU_DEBUGFS_DIR,
>NULL);
>> +
>> + pm_runtime_enable(&pdev->dev);
>> +
>> + if (dev->res->codec_types & WAVE6_IS_DEC) {
>> + ret = wave6_vpu_dec_register_device(dev);
>> + if (ret) {
>> + dev_err(&pdev->dev, "wave6_vpu_dec_register_device
>fail: %d\n", ret);
>> + goto err_temp_vbuf_free;
>> + }
>> + }
>> + if (dev->res->codec_types & WAVE6_IS_ENC) {
>> + ret = wave6_vpu_enc_register_device(dev);
>> + if (ret) {
>> + dev_err(&pdev->dev, "wave6_vpu_enc_register_device
>fail: %d\n", ret);
>> + goto err_dec_unreg;
>> + }
>> + }
>> +
>> + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
>> + wave6_vpu_activate(dev);
>> + ret = pm_runtime_resume_and_get(dev->dev);
>> + if (ret)
>> + goto err_enc_unreg;
>> + }
>> +
>> + dev_dbg(&pdev->dev, "Added wave6 driver with caps %s %s\n",
>> + dev->res->codec_types & WAVE6_IS_ENC ? "'ENCODE'" : "",
>> + dev->res->codec_types & WAVE6_IS_DEC ? "'DECODE'" : "");
>> +
>> + return 0;
>> +
>> +err_enc_unreg:
>> + if (dev->res->codec_types & WAVE6_IS_ENC)
>> + wave6_vpu_enc_unregister_device(dev);
>> +err_dec_unreg:
>> + if (dev->res->codec_types & WAVE6_IS_DEC)
>> + wave6_vpu_dec_unregister_device(dev);
>> +err_temp_vbuf_free:
>> + wave6_free_dma(&dev->temp_vbuf);
>> +err_kfifo_free:
>> + kfifo_free(&dev->irq_status);
>> +err_m2m_dev_release:
>> + wave6_vpu_release_m2m_dev(dev);
>> +err_v4l2_unregister:
>> + v4l2_device_unregister(&dev->v4l2_dev);
>> +
>> + return ret;
>> +}
>> +
>> +static void wave6_vpu_remove(struct platform_device *pdev)
>> +{
>> + struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
>> +
>> + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) {
>> + if (!pm_runtime_suspended(&pdev->dev))
>> + pm_runtime_put_sync(&pdev->dev);
>> + }
>> + pm_runtime_disable(&pdev->dev);
>> +
>> + wave6_vpu_enc_unregister_device(dev);
>> + wave6_vpu_dec_unregister_device(dev);
>> + wave6_free_dma(&dev->temp_vbuf);
>> + kfifo_free(&dev->irq_status);
>> + wave6_vpu_release_m2m_dev(dev);
>> + v4l2_device_unregister(&dev->v4l2_dev);
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int wave6_vpu_runtime_suspend(struct device *dev)
>> +{
>> + struct vpu_device *vpu_dev = dev_get_drvdata(dev);
>> +
>> + if (!vpu_dev)
>> + return -ENODEV;
>> +
>> + dprintk(dev, "runtime suspend\n");
>
>Drop
>
>> + if (vpu_dev->ctrl && vpu_dev->active)
>> + wave6_vpu_ctrl_put_sync(vpu_dev->ctrl, &vpu_dev->entity);
>> + if (vpu_dev->num_clks)
>> + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_runtime_resume(struct device *dev)
>> +{
>> + struct vpu_device *vpu_dev = dev_get_drvdata(dev);
>> + int ret = 0;
>> +
>> + if (!vpu_dev)
>> + return -ENODEV;
>> +
>> + dprintk(dev, "runtime resume\n");
>
>Drop
>
>> + if (vpu_dev->num_clks) {
>> + ret = clk_bulk_prepare_enable(vpu_dev->num_clks, vpu_dev-
>>clks);
>> + if (ret) {
>> + dev_err(dev, "failed to enable clocks: %d\n", ret);
>> + return ret;
>> + }
>> + }
>> +
>> + if (vpu_dev->ctrl && vpu_dev->active) {
>> + ret = wave6_vpu_ctrl_resume_and_get(vpu_dev->ctrl, &vpu_dev-
>>entity);
>> + if (ret && vpu_dev->num_clks)
>> + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev-
>>clks);
>> + } else {
>> + wave6_vpu_check_state(vpu_dev);
>> + }
>> +
>> + return ret;
>> +}
>> +#endif
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int wave6_vpu_suspend(struct device *dev)
>> +{
>> + int ret;
>> +
>> + dprintk(dev, "suspend\n");
>
>Drop. Don't re-implement existing tracing.
>
>> + wave6_vpu_pause(dev, 0);
>> +
>> + ret = pm_runtime_force_suspend(dev);
>> + if (ret)
>> + wave6_vpu_pause(dev, 1);
>> +
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_resume(struct device *dev)
>> +{
>> + int ret;
>> +
>> + dprintk(dev, "resume\n");
>
>Drop, useless.
Okay. I will remove the redundant debug message and dprintk in v2.
>
>> + ret = pm_runtime_force_resume(dev);
>> + if (ret)
>> + return ret;
>> +
>> + wave6_vpu_pause(dev, 1);
>> + return 0;
>> +}
>> +#endif
>> +static const struct dev_pm_ops wave6_vpu_pm_ops = {
>> + SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend,
>wave6_vpu_runtime_resume, NULL)
>> + SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_suspend, wave6_vpu_resume)
>> +};
>> +
>> +static const struct of_device_id wave6_dt_ids[] = {
>> + { .compatible = "nxp,imx95-wave633c", .data = &wave633c_data },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, wave6_dt_ids);
>> +
>> +static struct platform_driver wave6_vpu_driver = {
>> + .driver = {
>> + .name = VPU_PLATFORM_DEVICE_NAME,
>> + .of_match_table = of_match_ptr(wave6_dt_ids),
>
>
>Drop of_match_ptr, you have here warnings.
I will address this in v2.
Thanks.
Nas.
>
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (3 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-17 18:33 ` Nicolas Dufresne
2025-02-10 9:07 ` [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface Nas Chung
` (4 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Add v4l2 m2m drivers which support stateful decoder and encoder.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++++
.../chips-media/wave6/wave6-vpu-enc.c | 2698 +++++++++++++++++
.../chips-media/wave6/wave6-vpu-v4l2.c | 381 +++
3 files changed, 4962 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
new file mode 100644
index 000000000000..f6ed078a2824
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
@@ -0,0 +1,1883 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - v4l2 stateful decoder interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include "wave6-vpu.h"
+#include "wave6-vpu-dbg.h"
+#include "wave6-trace.h"
+
+#define VPU_DEC_DEV_NAME "C&M Wave6 VPU decoder"
+#define VPU_DEC_DRV_NAME "wave6-dec"
+#define V4L2_CID_VPU_THUMBNAIL_MODE (V4L2_CID_USER_BASE + 0x1001)
+
+static const struct vpu_format wave6_vpu_dec_fmt_list[2][6] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 3,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
+ .max_width = W6_MAX_DEC_PIC_WIDTH,
+ .min_width = W6_MIN_DEC_PIC_WIDTH,
+ .max_height = W6_MAX_DEC_PIC_HEIGHT,
+ .min_height = W6_MIN_DEC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ }
+};
+
+static int wave6_vpu_dec_seek_header(struct vpu_instance *inst);
+
+static const struct vpu_format *wave6_find_vpu_fmt(unsigned int v4l2_pix_fmt,
+ enum vpu_fmt_type type)
+{
+ unsigned int index;
+
+ for (index = 0; index < ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]); index++) {
+ if (wave6_vpu_dec_fmt_list[type][index].v4l2_pix_fmt == v4l2_pix_fmt)
+ return &wave6_vpu_dec_fmt_list[type][index];
+ }
+
+ return NULL;
+}
+
+static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned int idx,
+ enum vpu_fmt_type type)
+{
+ if (idx >= ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]))
+ return NULL;
+
+ if (!wave6_vpu_dec_fmt_list[type][idx].v4l2_pix_fmt)
+ return NULL;
+
+ return &wave6_vpu_dec_fmt_list[type][idx];
+}
+
+static void wave6_vpu_dec_release_fb(struct vpu_instance *inst)
+{
+ int i;
+
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ wave6_free_dma(&inst->frame_vbuf[i]);
+ memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer));
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
+ }
+}
+
+static void wave6_vpu_dec_destroy_instance(struct vpu_instance *inst)
+{
+ u32 fail_res;
+ int ret;
+
+ dprintk(inst->dev->dev, "[%d] destroy instance\n", inst->id);
+ wave6_vpu_remove_dbgfs_file(inst);
+
+ ret = wave6_vpu_dec_close(inst, &fail_res);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed destroy instance: %d (%d)\n",
+ ret, fail_res);
+ }
+
+ wave6_vpu_dec_release_fb(inst);
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
+
+ if (!pm_runtime_suspended(inst->dev->dev))
+ pm_runtime_put_sync(inst->dev->dev);
+}
+
+static void wave6_handle_bitstream_buffer(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *src_buf;
+ u32 src_size = 0;
+ int ret;
+
+ src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
+ if (src_buf) {
+ struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(src_buf);
+ dma_addr_t rd_ptr = wave6_get_dma_addr(src_buf, 0);
+
+ if (vpu_buf->consumed) {
+ dev_dbg(inst->dev->dev, "%s: Already consumed buffer\n",
+ __func__);
+ return;
+ }
+
+ vpu_buf->ts_start = ktime_get_raw();
+ vpu_buf->consumed = true;
+ wave6_vpu_dec_set_rd_ptr(inst, rd_ptr, true);
+
+ src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+ }
+
+ if (!src_size) {
+ dma_addr_t rd = 0, wr = 0;
+
+ wave6_vpu_dec_get_bitstream_buffer(inst, &rd, &wr);
+ wave6_vpu_dec_set_rd_ptr(inst, wr, true);
+ }
+
+ trace_dec_pic(inst, src_buf ? src_buf->vb2_buf.index : -1, src_size);
+
+ ret = wave6_vpu_dec_update_bitstream_buffer(inst, src_size);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Update bitstream buffer fail %d\n",
+ __func__, ret);
+ return;
+ }
+}
+
+static void wave6_update_pix_fmt_cap(struct v4l2_pix_format_mplane *pix_mp,
+ unsigned int width,
+ unsigned int height,
+ bool new_resolution)
+{
+ unsigned int aligned_width;
+
+ if (new_resolution)
+ pix_mp->plane_fmt[0].bytesperline = 0;
+
+ aligned_width = round_up(width, 32);
+ wave6_update_pix_fmt(pix_mp, aligned_width, height);
+}
+
+static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
+ enum aux_buffer_type type,
+ int num)
+{
+ struct aux_buffer buf[WAVE6_MAX_FBS];
+ struct aux_buffer_info buf_info;
+ struct dec_aux_buffer_size_info size_info;
+ unsigned int size;
+ int i, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ size_info.width = inst->src_fmt.width;
+ size_info.height = inst->src_fmt.height;
+ size_info.type = type;
+
+ ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info, &size);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Get size fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ num = min_t(u32, num, WAVE6_MAX_FBS);
+ for (i = 0; i < num; i++) {
+ inst->aux_vbuf[type][i].size = size;
+ ret = wave6_alloc_dma(inst->dev->dev, &inst->aux_vbuf[type][i]);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Alloc fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ buf[i].index = i;
+ buf[i].addr = inst->aux_vbuf[type][i].daddr;
+ buf[i].size = inst->aux_vbuf[type][i].size;
+ }
+
+ buf_info.type = type;
+ buf_info.num = num;
+ buf_info.buf_array = buf;
+
+ ret = wave6_vpu_dec_register_aux_buffer(inst, buf_info);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Register fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void wave6_vpu_dec_handle_dst_buffer(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *dst_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf;
+ dma_addr_t buf_addr_y, buf_addr_cb, buf_addr_cr;
+ u32 buf_size;
+ u32 fb_stride = inst->dst_fmt.plane_fmt[0].bytesperline;
+ u32 luma_size = fb_stride * inst->dst_fmt.height;
+ u32 chroma_size = (fb_stride / 2) * (inst->dst_fmt.height / 2);
+ struct frame_buffer disp_buffer = {0};
+ struct dec_initial_info initial_info = {0};
+ int consumed_num = wave6_vpu_get_consumed_fb_num(inst);
+ int ret;
+
+ wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info);
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ dst_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(dst_buf);
+
+ if (vpu_buf->consumed)
+ continue;
+
+ if (consumed_num >= WAVE6_MAX_FBS)
+ break;
+
+ if (inst->dst_fmt.num_planes == 1) {
+ buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
+ buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
+ buf_addr_cb = buf_addr_y + luma_size;
+ buf_addr_cr = buf_addr_cb + chroma_size;
+ } else if (inst->dst_fmt.num_planes == 2) {
+ buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) +
+ vb2_plane_size(&dst_buf->vb2_buf, 1);
+ buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
+ buf_addr_cb = wave6_get_dma_addr(dst_buf, 1);
+ buf_addr_cr = buf_addr_cb + chroma_size;
+ } else if (inst->dst_fmt.num_planes == 3) {
+ buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) +
+ vb2_plane_size(&dst_buf->vb2_buf, 1) +
+ vb2_plane_size(&dst_buf->vb2_buf, 2);
+ buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
+ buf_addr_cb = wave6_get_dma_addr(dst_buf, 1);
+ buf_addr_cr = wave6_get_dma_addr(dst_buf, 2);
+ }
+ disp_buffer.buf_y = buf_addr_y;
+ disp_buffer.buf_cb = buf_addr_cb;
+ disp_buffer.buf_cr = buf_addr_cr;
+ disp_buffer.width = inst->src_fmt.width;
+ disp_buffer.height = inst->src_fmt.height;
+ disp_buffer.stride = fb_stride;
+ disp_buffer.map_type = LINEAR_FRAME_MAP;
+ disp_buffer.luma_bitdepth = initial_info.luma_bitdepth;
+ disp_buffer.chroma_bitdepth = initial_info.chroma_bitdepth;
+ disp_buffer.chroma_format_idc = initial_info.chroma_format_idc;
+
+ ret = wave6_vpu_dec_register_display_buffer_ex(inst, disp_buffer);
+ if (ret) {
+ dev_err(inst->dev->dev, "fail register display buffer %d", ret);
+ break;
+ }
+
+ vpu_buf->consumed = true;
+ consumed_num++;
+ }
+}
+
+static enum v4l2_quantization to_v4l2_quantization(u32 video_full_range_flag)
+{
+ switch (video_full_range_flag) {
+ case 0:
+ return V4L2_QUANTIZATION_LIM_RANGE;
+ case 1:
+ return V4L2_QUANTIZATION_FULL_RANGE;
+ default:
+ return V4L2_QUANTIZATION_DEFAULT;
+ }
+}
+
+static enum v4l2_colorspace to_v4l2_colorspace(u32 colour_primaries)
+{
+ switch (colour_primaries) {
+ case 1:
+ return V4L2_COLORSPACE_REC709;
+ case 4:
+ return V4L2_COLORSPACE_470_SYSTEM_M;
+ case 5:
+ return V4L2_COLORSPACE_470_SYSTEM_BG;
+ case 6:
+ return V4L2_COLORSPACE_SMPTE170M;
+ case 7:
+ return V4L2_COLORSPACE_SMPTE240M;
+ case 9:
+ return V4L2_COLORSPACE_BT2020;
+ case 11:
+ return V4L2_COLORSPACE_DCI_P3;
+ default:
+ return V4L2_COLORSPACE_DEFAULT;
+ }
+}
+
+static enum v4l2_xfer_func to_v4l2_xfer_func(u32 transfer_characteristics)
+{
+ switch (transfer_characteristics) {
+ case 1:
+ return V4L2_XFER_FUNC_709;
+ case 6:
+ return V4L2_XFER_FUNC_709;
+ case 7:
+ return V4L2_XFER_FUNC_SMPTE240M;
+ case 8:
+ return V4L2_XFER_FUNC_NONE;
+ case 13:
+ return V4L2_XFER_FUNC_SRGB;
+ case 14:
+ return V4L2_XFER_FUNC_709;
+ case 16:
+ return V4L2_XFER_FUNC_SMPTE2084;
+ default:
+ return V4L2_XFER_FUNC_DEFAULT;
+ }
+}
+
+static enum v4l2_ycbcr_encoding to_v4l2_ycbcr_encoding(u32 matrix_coeffs)
+{
+ switch (matrix_coeffs) {
+ case 1:
+ return V4L2_YCBCR_ENC_709;
+ case 5:
+ return V4L2_YCBCR_ENC_601;
+ case 6:
+ return V4L2_YCBCR_ENC_601;
+ case 7:
+ return V4L2_YCBCR_ENC_SMPTE240M;
+ case 9:
+ return V4L2_YCBCR_ENC_BT2020;
+ case 10:
+ return V4L2_YCBCR_ENC_BT2020_CONST_LUM;
+ default:
+ return V4L2_YCBCR_ENC_DEFAULT;
+ }
+}
+
+static void wave6_update_color_info(struct vpu_instance *inst,
+ struct dec_initial_info *initial_info)
+{
+ struct color_param *color = &initial_info->color;
+
+ if (!color->video_signal_type_present)
+ goto set_default_all;
+
+ inst->quantization = to_v4l2_quantization(color->color_range);
+
+ if (!color->color_description_present)
+ goto set_default_color;
+
+ inst->colorspace = to_v4l2_colorspace(color->color_primaries);
+ inst->xfer_func = to_v4l2_xfer_func(color->transfer_characteristics);
+ inst->ycbcr_enc = to_v4l2_ycbcr_encoding(color->matrix_coefficients);
+
+ return;
+
+set_default_all:
+ inst->quantization = V4L2_QUANTIZATION_DEFAULT;
+set_default_color:
+ inst->colorspace = V4L2_COLORSPACE_DEFAULT;
+ inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static enum v4l2_mpeg_video_hevc_profile to_v4l2_hevc_profile(u32 profile)
+{
+ switch (profile) {
+ case HEVC_PROFILE_MAIN:
+ return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
+ default:
+ return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
+ }
+}
+
+static enum v4l2_mpeg_video_h264_profile to_v4l2_h264_profile(u32 profile)
+{
+ switch (profile) {
+ case H264_PROFILE_BP:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+ case H264_PROFILE_MP:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+ case H264_PROFILE_EXTENDED:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
+ case H264_PROFILE_HP:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+ default:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+ }
+}
+
+static void wave6_update_v4l2_ctrls(struct vpu_instance *inst,
+ struct dec_initial_info *info)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 min_disp_cnt;
+
+ min_disp_cnt = info->frame_buf_delay + 1;
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, min_disp_cnt);
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_HEVC) {
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MPEG_VIDEO_HEVC_PROFILE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, to_v4l2_hevc_profile(info->profile));
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_H264) {
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, to_v4l2_h264_profile(info->profile));
+ }
+}
+
+static int wave6_vpu_dec_start_decode(struct vpu_instance *inst)
+{
+ struct dec_param pic_param;
+ int ret;
+ u32 fail_res = 0;
+
+ memset(&pic_param, 0, sizeof(struct dec_param));
+
+ wave6_handle_bitstream_buffer(inst);
+ if (inst->state == VPU_INST_STATE_OPEN) {
+ ret = wave6_vpu_dec_seek_header(inst);
+ if (ret) {
+ vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx));
+ vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx));
+ }
+ return -EAGAIN;
+ }
+
+ wave6_vpu_dec_handle_dst_buffer(inst);
+
+ ret = wave6_vpu_dec_start_one_frame(inst, &pic_param, &fail_res);
+ if (ret) {
+ struct vb2_v4l2_buffer *src_buf = NULL;
+
+ dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst->id, __func__, ret);
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP);
+
+ src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (src_buf) {
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ inst->sequence++;
+ inst->processed_buf_num++;
+ inst->error_buf_num++;
+ }
+ }
+
+ return ret;
+}
+
+static void wave6_handle_decoded_frame(struct vpu_instance *inst,
+ struct dec_output_info *info)
+{
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ struct vpu_buffer *vpu_buf;
+ enum vb2_buffer_state state;
+
+ state = info->decoding_success ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
+ if (!src_buf) {
+ dev_err(inst->dev->dev, "[%d] decoder can't find src buffer\n", inst->id);
+ return;
+ }
+
+ vpu_buf = wave6_to_vpu_buf(src_buf);
+ if (!vpu_buf || !vpu_buf->consumed) {
+ dev_err(inst->dev->dev, "[%d] src buffer is not consumed\n", inst->id);
+ return;
+ }
+
+ dst_buf = wave6_get_dst_buf_by_addr(inst, info->frame_decoded_addr);
+ if (dst_buf) {
+ struct vpu_buffer *dst_vpu_buf = wave6_to_vpu_buf(dst_buf);
+
+ if (wave6_to_vpu_buf(dst_buf)->used) {
+ dev_warn(inst->dev->dev, "[%d] duplication frame buffer\n", inst->id);
+ inst->sequence++;
+ }
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+ dst_vpu_buf->used = true;
+ if (state == VB2_BUF_STATE_ERROR)
+ dst_vpu_buf->error = true;
+ dst_vpu_buf->ts_input = vpu_buf->ts_input;
+ dst_vpu_buf->ts_start = vpu_buf->ts_start;
+ dst_vpu_buf->ts_finish = ktime_get_raw();
+ dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev, info->cycle.frame_cycle);
+ }
+
+ v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, src_buf);
+ if (state == VB2_BUF_STATE_ERROR) {
+ dprintk(inst->dev->dev, "[%d] error frame %d\n", inst->id, inst->sequence);
+ inst->error_buf_num++;
+ }
+ v4l2_m2m_buf_done(src_buf, state);
+ inst->processed_buf_num++;
+}
+
+static void wave6_handle_skipped_frame(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *src_buf;
+ struct vpu_buffer *vpu_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
+ if (!src_buf)
+ return;
+
+ vpu_buf = wave6_to_vpu_buf(src_buf);
+ if (!vpu_buf || !vpu_buf->consumed)
+ return;
+
+ dprintk(inst->dev->dev, "[%d] skip frame %d\n", inst->id, inst->sequence);
+
+ inst->sequence++;
+ inst->processed_buf_num++;
+ inst->error_buf_num++;
+ v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, src_buf);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+}
+
+static void wave6_handle_display_frame(struct vpu_instance *inst,
+ dma_addr_t addr, enum vb2_buffer_state state)
+{
+ struct vb2_v4l2_buffer *dst_buf;
+ struct vpu_buffer *vpu_buf;
+
+ dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
+ if (!dst_buf)
+ return;
+
+ vpu_buf = wave6_to_vpu_buf(dst_buf);
+ if (!vpu_buf->used) {
+ dprintk(inst->dev->dev, "[%d] recycle display buffer\n", inst->id);
+ vpu_buf->consumed = false;
+ return;
+ }
+
+ if (inst->dst_fmt.num_planes == 1) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ } else if (inst->dst_fmt.num_planes == 2) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
+ inst->dst_fmt.plane_fmt[1].sizeimage);
+ } else if (inst->dst_fmt.num_planes == 3) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
+ inst->dst_fmt.plane_fmt[1].sizeimage);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 2,
+ inst->dst_fmt.plane_fmt[2].sizeimage);
+ }
+
+ vpu_buf->ts_output = ktime_get_raw();
+ wave6_vpu_handle_performance(inst, vpu_buf);
+
+ if (vpu_buf->error)
+ state = VB2_BUF_STATE_ERROR;
+ dst_buf->sequence = inst->sequence++;
+ dst_buf->field = V4L2_FIELD_NONE;
+ if (state == VB2_BUF_STATE_ERROR)
+ dprintk(inst->dev->dev, "[%d] discard frame %d\n", inst->id, dst_buf->sequence);
+ v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf);
+ v4l2_m2m_buf_done(dst_buf, state);
+}
+
+static void wave6_handle_display_frames(struct vpu_instance *inst,
+ struct dec_output_info *info)
+{
+ int i;
+
+ for (i = 0; i < info->disp_frame_num; i++)
+ wave6_handle_display_frame(inst,
+ info->disp_frame_addr[i],
+ VB2_BUF_STATE_DONE);
+}
+
+static void wave6_handle_discard_frames(struct vpu_instance *inst,
+ struct dec_output_info *info)
+{
+ int i;
+
+ for (i = 0; i < info->release_disp_frame_num; i++)
+ wave6_handle_display_frame(inst,
+ info->release_disp_frame_addr[i],
+ VB2_BUF_STATE_ERROR);
+}
+
+static void wave6_handle_last_frame(struct vpu_instance *inst,
+ struct vb2_v4l2_buffer *dst_buf)
+{
+ if (!dst_buf) {
+ dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (!dst_buf) {
+ inst->next_buf_last = true;
+ return;
+ }
+ }
+
+ if (inst->dst_fmt.num_planes == 1) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ } else if (inst->dst_fmt.num_planes == 2) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+ } else if (inst->dst_fmt.num_planes == 3) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 2, 0);
+ }
+
+ dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ dst_buf->field = V4L2_FIELD_NONE;
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+ if (inst->state != VPU_INST_STATE_INIT_SEQ) {
+ dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
+ inst->eos = true;
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
+ }
+}
+
+static void wave6_vpu_dec_retry_one_frame(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *src_buf;
+ struct vpu_buffer *vpu_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
+ if (!src_buf)
+ return;
+
+ vpu_buf = wave6_to_vpu_buf(src_buf);
+ vpu_buf->consumed = false;
+}
+
+static void wave6_vpu_dec_handle_source_change(struct vpu_instance *inst,
+ struct dec_initial_info *info)
+{
+ static const struct v4l2_event vpu_event_src_ch = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
+
+ dprintk(inst->dev->dev, "pic size %dx%d profile %d, min_fb_cnt : %d | min_disp_cnt : %d\n",
+ info->pic_width, info->pic_height,
+ info->profile, info->min_frame_buffer_count, info->frame_buf_delay);
+
+ wave6_vpu_dec_retry_one_frame(inst);
+ wave6_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO, NULL);
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
+
+ inst->crop.left = info->pic_crop_rect.left;
+ inst->crop.top = info->pic_crop_rect.top;
+ inst->crop.width = info->pic_crop_rect.right - inst->crop.left;
+ inst->crop.height = info->pic_crop_rect.bottom - inst->crop.top;
+
+ wave6_update_v4l2_ctrls(inst, info);
+ wave6_update_color_info(inst, info);
+ wave6_update_pix_fmt(&inst->src_fmt, info->pic_width, info->pic_height);
+ wave6_update_pix_fmt_cap(&inst->dst_fmt,
+ info->pic_width, info->pic_height,
+ true);
+
+ trace_source_change(inst, info);
+
+ v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_src_ch);
+}
+
+static void wave6_vpu_dec_handle_decoding_warn_error(struct vpu_instance *inst,
+ struct dec_output_info *info)
+{
+ if (info->warn_info)
+ dev_dbg(inst->dev->dev, "[%d] decoding %d warning 0x%x\n",
+ inst->id, inst->processed_buf_num, info->warn_info);
+
+ if (info->error_reason)
+ dev_err(inst->dev->dev, "[%d] decoding %d error 0x%x\n",
+ inst->id, inst->processed_buf_num, info->error_reason);
+}
+
+static void wave6_vpu_dec_finish_decode(struct vpu_instance *inst, bool error)
+{
+ struct dec_output_info info;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+
+ ret = wave6_vpu_dec_get_output_info(inst, &info);
+ if (ret)
+ goto finish_decode;
+
+ trace_dec_done(inst, &info);
+
+ dev_dbg(inst->dev->dev, "dec %d dis %d noti_flag %d stream_end %d\n",
+ info.frame_decoded, info.frame_display,
+ info.notification_flags, info.stream_end);
+
+ if (info.notification_flags & DEC_NOTI_FLAG_NO_FB) {
+ wave6_vpu_dec_retry_one_frame(inst);
+ goto finish_decode;
+ }
+
+ if (info.notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) {
+ struct dec_initial_info initial_info = {0};
+
+ v4l2_m2m_mark_stopped(m2m_ctx);
+
+ if (info.frame_display)
+ wave6_handle_display_frames(inst, &info);
+
+ if (info.release_disp_frame_num)
+ wave6_handle_discard_frames(inst, &info);
+
+ wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info);
+ wave6_vpu_dec_handle_source_change(inst, &initial_info);
+
+ wave6_handle_last_frame(inst, NULL);
+
+ goto finish_decode;
+ }
+
+ wave6_vpu_dec_handle_decoding_warn_error(inst, &info);
+
+ if (info.frame_decoded)
+ wave6_handle_decoded_frame(inst, &info);
+ else
+ wave6_handle_skipped_frame(inst);
+
+ if (info.frame_display)
+ wave6_handle_display_frames(inst, &info);
+
+ if (info.release_disp_frame_num)
+ wave6_handle_discard_frames(inst, &info);
+
+ if (info.stream_end && !inst->eos)
+ wave6_handle_last_frame(inst, NULL);
+
+finish_decode:
+ wave6_vpu_finish_job(inst);
+}
+
+static int wave6_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:" VPU_DEC_DRV_NAME, sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static int wave6_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+ const struct vpu_format *vpu_fmt;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt) {
+ vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt)
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = vpu_fmt->min_width;
+ fsize->stepwise.max_width = vpu_fmt->max_width;
+ fsize->stepwise.step_width = W6_DEC_PIC_SIZE_STEP;
+ fsize->stepwise.min_height = vpu_fmt->min_height;
+ fsize->stepwise.max_height = vpu_fmt->max_height;
+ fsize->stepwise.step_height = W6_DEC_PIC_SIZE_STEP;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ const struct vpu_format *vpu_fmt;
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct vpu_format *vpu_fmt;
+ int width, height;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ if (!V4L2_TYPE_IS_CAPTURE(f->type))
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
+ pix_mp->pixelformat = inst->dst_fmt.pixelformat;
+ pix_mp->num_planes = inst->dst_fmt.num_planes;
+ } else {
+ width = clamp(pix_mp->width,
+ vpu_fmt->min_width, round_up(inst->src_fmt.width, 32));
+ height = clamp(pix_mp->height,
+ vpu_fmt->min_height, inst->src_fmt.height);
+ pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ pix_mp->num_planes = vpu_fmt->num_planes;
+ }
+
+ if (inst->state >= VPU_INST_STATE_INIT_SEQ) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
+ }
+
+ wave6_update_pix_fmt_cap(pix_mp, width, height, false);
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ ret = wave6_vpu_dec_try_fmt_cap(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->dst_fmt.width = pix_mp->width;
+ inst->dst_fmt.height = pix_mp->height;
+ inst->dst_fmt.pixelformat = pix_mp->pixelformat;
+ inst->dst_fmt.field = pix_mp->field;
+ inst->dst_fmt.flags = pix_mp->flags;
+ inst->dst_fmt.num_planes = pix_mp->num_planes;
+ for (i = 0; i < inst->dst_fmt.num_planes; i++) {
+ inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline;
+ inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage;
+ }
+
+ if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = false;
+ } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = true;
+ } else {
+ inst->cbcr_interleave = false;
+ inst->nv21 = false;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i;
+
+ pix_mp->width = inst->dst_fmt.width;
+ pix_mp->height = inst->dst_fmt.height;
+ pix_mp->pixelformat = inst->dst_fmt.pixelformat;
+ pix_mp->field = inst->dst_fmt.field;
+ pix_mp->flags = inst->dst_fmt.flags;
+ pix_mp->num_planes = inst->dst_fmt.num_planes;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline;
+ pix_mp->plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage;
+ }
+
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f->index);
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+ f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct vpu_format *vpu_fmt;
+ int width, height;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ if (!V4L2_TYPE_IS_OUTPUT(f->type))
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
+ pix_mp->pixelformat = inst->src_fmt.pixelformat;
+ pix_mp->num_planes = inst->src_fmt.num_planes;
+ } else {
+ width = pix_mp->width;
+ height = pix_mp->height;
+ pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ pix_mp->num_planes = vpu_fmt->num_planes;
+ }
+
+ wave6_update_pix_fmt(pix_mp, width, height);
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane in_pix_mp = f->fmt.pix_mp;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ ret = wave6_vpu_dec_try_fmt_out(file, fh, f);
+ if (ret)
+ return ret;
+
+ pix_mp->colorspace = in_pix_mp.colorspace;
+ pix_mp->ycbcr_enc = in_pix_mp.ycbcr_enc;
+ pix_mp->quantization = in_pix_mp.quantization;
+ pix_mp->xfer_func = in_pix_mp.xfer_func;
+
+ inst->src_fmt.width = pix_mp->width;
+ inst->src_fmt.height = pix_mp->height;
+ inst->src_fmt.pixelformat = pix_mp->pixelformat;
+ inst->src_fmt.field = pix_mp->field;
+ inst->src_fmt.flags = pix_mp->flags;
+ inst->src_fmt.num_planes = pix_mp->num_planes;
+ for (i = 0; i < inst->src_fmt.num_planes; i++) {
+ inst->src_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline;
+ inst->src_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage;
+ }
+
+ inst->colorspace = pix_mp->colorspace;
+ inst->ycbcr_enc = pix_mp->ycbcr_enc;
+ inst->quantization = pix_mp->quantization;
+ inst->xfer_func = pix_mp->xfer_func;
+
+ wave6_update_pix_fmt_cap(&inst->dst_fmt,
+ pix_mp->width, pix_mp->height,
+ true);
+
+ return 0;
+}
+
+static int wave6_vpu_dec_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i;
+
+ pix_mp->width = inst->src_fmt.width;
+ pix_mp->height = inst->src_fmt.height;
+ pix_mp->pixelformat = inst->src_fmt.pixelformat;
+ pix_mp->field = inst->src_fmt.field;
+ pix_mp->flags = inst->src_fmt.flags;
+ pix_mp->num_planes = inst->src_fmt.num_planes;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
+ pix_mp->plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
+ }
+
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
+ __func__, s->type, s->target);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->dst_fmt.width;
+ s->r.height = inst->dst_fmt.height;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ case V4L2_SEL_TGT_COMPOSE:
+ s->r.left = 0;
+ s->r.top = 0;
+ if (inst->scaler_info.enable) {
+ s->r.width = inst->scaler_info.width;
+ s->r.height = inst->scaler_info.height;
+ } else if (inst->crop.width && inst->crop.height) {
+ s->r = inst->crop;
+ } else {
+ s->r.width = inst->src_fmt.width;
+ s->r.height = inst->src_fmt.height;
+ }
+ break;
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->src_fmt.width;
+ s->r.height = inst->src_fmt.height;
+ if (inst->crop.width && inst->crop.height)
+ s->r = inst->crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ int step = 4;
+ int scale_width, scale_height;
+ int min_scale_width, min_scale_height;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ if (s->target != V4L2_SEL_TGT_COMPOSE)
+ return -EINVAL;
+
+ if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
+ s->flags |= V4L2_SEL_FLAG_LE;
+
+ scale_width = clamp(s->r.width, W6_MIN_DEC_PIC_WIDTH,
+ round_up(inst->src_fmt.width, 32));
+ scale_height = clamp(s->r.height, W6_MIN_DEC_PIC_HEIGHT,
+ inst->src_fmt.height);
+ if (s->flags & V4L2_SEL_FLAG_GE) {
+ scale_width = round_up(scale_width, step);
+ scale_height = round_up(scale_height, step);
+ }
+ if (s->flags & V4L2_SEL_FLAG_LE) {
+ scale_width = round_down(scale_width, step);
+ scale_height = round_down(scale_height, step);
+ }
+
+ if (scale_width < inst->src_fmt.width ||
+ scale_height < inst->src_fmt.height)
+ inst->scaler_info.enable = true;
+
+ if (inst->scaler_info.enable) {
+ min_scale_width = ALIGN((inst->src_fmt.width / 8), step);
+ min_scale_height = ALIGN((inst->src_fmt.height / 8), step);
+
+ if (scale_width < W6_MIN_DEC_PIC_WIDTH)
+ scale_width = W6_MIN_DEC_PIC_WIDTH;
+ if (scale_width < min_scale_width)
+ scale_width = min_scale_width;
+ if (scale_height < W6_MIN_DEC_PIC_HEIGHT)
+ scale_height = W6_MIN_DEC_PIC_HEIGHT;
+ if (scale_height < min_scale_height)
+ scale_height = min_scale_height;
+
+ inst->scaler_info.width = scale_width;
+ inst->scaler_info.height = scale_height;
+ }
+
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = scale_width;
+ s->r.height = scale_height;
+
+ return 0;
+}
+
+static int wave6_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ int ret;
+
+ dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, dc->cmd);
+
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
+ if (ret)
+ return ret;
+
+ switch (dc->cmd) {
+ case V4L2_DEC_CMD_STOP:
+ dprintk(inst->dev->dev, "[%d] drain\n", inst->id);
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true);
+ v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
+ break;
+ case V4L2_DEC_CMD_START:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops wave6_vpu_dec_ioctl_ops = {
+ .vidioc_querycap = wave6_vpu_dec_querycap,
+ .vidioc_enum_framesizes = wave6_vpu_dec_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = wave6_vpu_dec_enum_fmt_cap,
+ .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_dec_s_fmt_cap,
+ .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_dec_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_dec_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = wave6_vpu_dec_enum_fmt_out,
+ .vidioc_s_fmt_vid_out_mplane = wave6_vpu_dec_s_fmt_out,
+ .vidioc_g_fmt_vid_out_mplane = wave6_vpu_dec_g_fmt_out,
+ .vidioc_try_fmt_vid_out_mplane = wave6_vpu_dec_try_fmt_out,
+
+ .vidioc_g_selection = wave6_vpu_dec_g_selection,
+ .vidioc_s_selection = wave6_vpu_dec_s_selection,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
+ .vidioc_decoder_cmd = wave6_vpu_dec_decoder_cmd,
+
+ .vidioc_subscribe_event = wave6_vpu_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int wave6_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
+
+ trace_s_ctrl(inst, ctrl);
+
+ dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
+ __func__, ctrl->name, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VPU_THUMBNAIL_MODE:
+ inst->thumbnail_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
+ inst->disp_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops wave6_vpu_dec_ctrl_ops = {
+ .s_ctrl = wave6_vpu_dec_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config wave6_vpu_thumbnail_mode = {
+ .ops = &wave6_vpu_dec_ctrl_ops,
+ .id = V4L2_CID_VPU_THUMBNAIL_MODE,
+ .name = "thumbnail mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .def = 0,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_WRITE_ONLY,
+};
+
+static void wave6_set_dec_openparam(struct dec_open_param *open_param,
+ struct vpu_instance *inst)
+{
+ open_param->inst_buffer.temp_base = inst->dev->temp_vbuf.daddr;
+ open_param->inst_buffer.temp_size = inst->dev->temp_vbuf.size;
+ open_param->bs_mode = BS_MODE_PIC_END;
+ open_param->stream_endian = VPU_STREAM_ENDIAN;
+ open_param->frame_endian = VPU_FRAME_ENDIAN;
+ open_param->disp_mode = inst->disp_mode;
+}
+
+static int wave6_vpu_dec_create_instance(struct vpu_instance *inst)
+{
+ int ret;
+ struct dec_open_param open_param;
+
+ memset(&open_param, 0, sizeof(struct dec_open_param));
+
+ wave6_vpu_activate(inst->dev);
+ ret = pm_runtime_resume_and_get(inst->dev->dev);
+ if (ret) {
+ dev_err(inst->dev->dev, "runtime_resume failed %d\n", ret);
+ return ret;
+ }
+
+ wave6_vpu_wait_activated(inst->dev);
+
+ inst->std = wave6_to_codec_std(inst->type, inst->src_fmt.pixelformat);
+ if (inst->std == STD_UNKNOWN) {
+ dev_err(inst->dev->dev, "unsupported pixelformat: %.4s\n",
+ (char *)&inst->src_fmt.pixelformat);
+ ret = -EINVAL;
+ goto error_pm;
+ }
+
+ wave6_set_dec_openparam(&open_param, inst);
+
+ ret = wave6_vpu_dec_open(inst, &open_param);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed create instance : %d\n", ret);
+ goto error_pm;
+ }
+
+ dprintk(inst->dev->dev, "[%d] decoder\n", inst->id);
+
+ if (inst->thumbnail_mode)
+ wave6_vpu_dec_give_command(inst, ENABLE_DEC_THUMBNAIL_MODE, NULL);
+
+ wave6_vpu_create_dbgfs_file(inst);
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
+ inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = true;
+ v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, true);
+
+ return 0;
+
+error_pm:
+ pm_runtime_put_sync(inst->dev->dev);
+
+ return ret;
+}
+
+static int wave6_vpu_dec_prepare_fb(struct vpu_instance *inst)
+{
+ int ret;
+ unsigned int i;
+ unsigned int fb_num;
+ unsigned int mv_num;
+ unsigned int fb_stride;
+ unsigned int fb_height;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ fb_num = p_dec_info->initial_info.min_frame_buffer_count;
+ mv_num = p_dec_info->initial_info.req_mv_buffer_count;
+
+ fb_stride = ALIGN(inst->src_fmt.width, 32);
+ fb_height = ALIGN(inst->src_fmt.height, 32);
+
+ for (i = 0; i < fb_num; i++) {
+ struct frame_buffer *frame = &inst->frame_buf[i];
+ struct vpu_buf *vframe = &inst->frame_vbuf[i];
+ unsigned int l_size = fb_stride * fb_height;
+ unsigned int ch_size = ALIGN(fb_stride / 2, 32) * fb_height;
+
+ vframe->size = l_size + ch_size;
+ ret = wave6_alloc_dma(inst->dev->dev, vframe);
+ if (ret) {
+ dev_err(inst->dev->dev, "alloc FBC buffer fail : %zu\n",
+ vframe->size);
+ goto error;
+ }
+
+ frame->buf_y = vframe->daddr;
+ frame->buf_cb = vframe->daddr + l_size;
+ frame->buf_cr = (dma_addr_t)-1;
+ frame->width = inst->src_fmt.width;
+ frame->stride = fb_stride;
+ frame->height = fb_height;
+ frame->map_type = COMPRESSED_FRAME_MAP;
+ }
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL, fb_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL, fb_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL, mv_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_vpu_dec_register_frame_buffer_ex(inst, fb_num, fb_stride,
+ fb_height,
+ COMPRESSED_FRAME_MAP);
+ if (ret) {
+ dev_err(inst->dev->dev, "register frame buffer fail %d\n", ret);
+ goto error;
+ }
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
+
+ return 0;
+
+error:
+ wave6_vpu_dec_release_fb(inst);
+ return ret;
+}
+
+static int wave6_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane inst_format =
+ (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
+
+ dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d type %d\n",
+ __func__, *num_buffers, *num_planes, q->type);
+
+ if (*num_planes) {
+ if (inst_format.num_planes != *num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < inst_format.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = inst_format.num_planes;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "size[%d] : %d\n", i, sizes[i]);
+ }
+
+ if (V4L2_TYPE_IS_CAPTURE(q->type)) {
+ struct v4l2_ctrl *ctrl;
+ unsigned int min_disp_cnt = 0;
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
+ if (ctrl)
+ min_disp_cnt = v4l2_ctrl_g_ctrl(ctrl);
+
+ *num_buffers = max(*num_buffers, min_disp_cnt);
+
+ if (*num_buffers > WAVE6_MAX_FBS)
+ *num_buffers = min_disp_cnt;
+ }
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type) &&
+ inst->state == VPU_INST_STATE_SEEK) {
+ wave6_vpu_pause(inst->dev->dev, 0);
+ wave6_vpu_dec_destroy_instance(inst);
+ wave6_vpu_pause(inst->dev->dev, 1);
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_dec_seek_header(struct vpu_instance *inst)
+{
+ struct dec_initial_info initial_info;
+ int ret;
+
+ memset(&initial_info, 0, sizeof(struct dec_initial_info));
+
+ ret = wave6_vpu_dec_issue_seq_init(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed wave6_vpu_dec_issue_seq_init %d\n", ret);
+ return ret;
+ }
+
+ if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0)
+ dev_err(inst->dev->dev, "failed to call vpu_wait_interrupt()\n");
+
+ ret = wave6_vpu_dec_complete_seq_init(inst, &initial_info);
+ if (ret) {
+ dev_err(inst->dev->dev, "vpu_dec_complete_seq_init: %d, reason : 0x%x\n",
+ ret, initial_info.err_reason);
+ if ((initial_info.err_reason & WAVE6_SYSERR_NOT_SUPPORT) ||
+ (initial_info.err_reason & WAVE6_SYSERR_NOT_SUPPORT_PROFILE)) {
+ ret = -EINVAL;
+ } else if ((initial_info.err_reason & HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND) ||
+ (initial_info.err_reason & AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND)) {
+ wave6_handle_skipped_frame(inst);
+ ret = 0;
+ }
+ } else {
+ wave6_vpu_dec_handle_source_change(inst, &initial_info);
+ inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = false;
+ v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, false);
+ if (vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx)))
+ wave6_handle_last_frame(inst, NULL);
+ }
+
+ return ret;
+}
+
+static void wave6_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+
+ dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n",
+ vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ vbuf->sequence = inst->queued_src_buf_num++;
+ vpu_buf->ts_input = ktime_get_raw();
+
+ v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
+}
+
+static void wave6_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+
+ dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n",
+ vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ inst->queued_dst_buf_num++;
+ if (inst->next_buf_last) {
+ wave6_handle_last_frame(inst, vbuf);
+ inst->next_buf_last = false;
+ } else {
+ v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
+ }
+}
+
+static void wave6_vpu_dec_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
+
+ vpu_buf->consumed = false;
+ vpu_buf->used = false;
+ vpu_buf->error = false;
+ if (V4L2_TYPE_IS_OUTPUT(vb->type))
+ wave6_vpu_dec_buf_queue_src(vb);
+ else
+ wave6_vpu_dec_buf_queue_dst(vb);
+}
+
+static int wave6_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane *fmt;
+ int ret = 0;
+
+ trace_start_streaming(inst, q->type);
+
+ wave6_vpu_pause(inst->dev->dev, 0);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ fmt = &inst->src_fmt;
+ if (inst->state == VPU_INST_STATE_NONE) {
+ ret = wave6_vpu_dec_create_instance(inst);
+ if (ret)
+ goto exit;
+ }
+
+ if (inst->state == VPU_INST_STATE_SEEK)
+ wave6_vpu_set_instance_state(inst, inst->state_in_seek);
+ } else {
+ fmt = &inst->dst_fmt;
+ if (inst->state == VPU_INST_STATE_INIT_SEQ) {
+ ret = wave6_vpu_dec_prepare_fb(inst);
+ if (ret)
+ goto exit;
+ }
+ }
+
+exit:
+ wave6_vpu_pause(inst->dev->dev, 1);
+ if (ret)
+ wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_QUEUED);
+
+ dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers, ret = %d\n",
+ inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture",
+ fmt->pixelformat,
+ fmt->pixelformat >> 8,
+ fmt->pixelformat >> 16,
+ fmt->pixelformat >> 24,
+ fmt->width, fmt->height, vb2_get_num_buffers(q), ret);
+
+ return ret;
+}
+
+static void wave6_vpu_dec_stop_streaming(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ trace_stop_streaming(inst, q->type);
+
+ dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d error %d\n",
+ inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture",
+ inst->queued_src_buf_num, inst->processed_buf_num, inst->error_buf_num);
+
+ if (inst->state == VPU_INST_STATE_NONE)
+ goto exit;
+
+ wave6_vpu_pause(inst->dev->dev, 0);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ wave6_vpu_reset_performance(inst);
+ inst->queued_src_buf_num = 0;
+ inst->processed_buf_num = 0;
+ inst->error_buf_num = 0;
+ inst->state_in_seek = inst->state;
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_SEEK);
+ inst->sequence = 0;
+ } else {
+ if (v4l2_m2m_has_stopped(m2m_ctx))
+ v4l2_m2m_clear_state(m2m_ctx);
+
+ inst->eos = false;
+ inst->queued_dst_buf_num = 0;
+ inst->sequence = 0;
+ wave6_vpu_dec_flush_instance(inst);
+ }
+
+ wave6_vpu_pause(inst->dev->dev, 1);
+
+exit:
+ wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_ERROR);
+}
+
+static int wave6_vpu_dec_buf_init(struct vb2_buffer *vb)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct dec_initial_info initial_info = {0};
+ int i;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->type))
+ return 0;
+
+ wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info);
+ if (initial_info.chroma_format_idc != YUV400)
+ return 0;
+
+ for (i = 0; i < inst->dst_fmt.num_planes; i++) {
+ void *vaddr = vb2_plane_vaddr(vb, i);
+
+ if (vaddr)
+ memset(vaddr, 0x80, vb2_plane_size(vb, i));
+ }
+
+ return 0;
+}
+
+static const struct vb2_ops wave6_vpu_dec_vb2_ops = {
+ .queue_setup = wave6_vpu_dec_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = wave6_vpu_dec_buf_queue,
+ .start_streaming = wave6_vpu_dec_start_streaming,
+ .stop_streaming = wave6_vpu_dec_stop_streaming,
+ .buf_init = wave6_vpu_dec_buf_init,
+};
+
+static void wave6_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
+ struct v4l2_pix_format_mplane *dst_fmt)
+{
+ const struct vpu_format *vpu_fmt;
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
+ if (vpu_fmt) {
+ src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ src_fmt->num_planes = vpu_fmt->num_planes;
+ wave6_update_pix_fmt(src_fmt,
+ W6_DEF_DEC_PIC_WIDTH, W6_DEF_DEC_PIC_HEIGHT);
+ }
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
+ if (vpu_fmt) {
+ dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ dst_fmt->num_planes = vpu_fmt->num_planes;
+ wave6_update_pix_fmt_cap(dst_fmt,
+ W6_DEF_DEC_PIC_WIDTH, W6_DEF_DEC_PIC_HEIGHT,
+ true);
+ }
+}
+
+static int wave6_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct vpu_instance *inst = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->ops = &wave6_vpu_dec_vb2_ops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->buf_struct_size = sizeof(struct vpu_buffer);
+ src_vq->min_queued_buffers = 1;
+ src_vq->drv_priv = inst;
+ src_vq->lock = &inst->dev->dev_lock;
+ src_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->ops = &wave6_vpu_dec_vb2_ops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
+ dst_vq->min_queued_buffers = 1;
+ dst_vq->drv_priv = inst;
+ dst_vq->lock = &inst->dev->dev_lock;
+ dst_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(dst_vq);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct vpu_instance_ops wave6_vpu_dec_inst_ops = {
+ .start_process = wave6_vpu_dec_start_decode,
+ .finish_process = wave6_vpu_dec_finish_decode,
+};
+
+static int wave6_vpu_open_dec(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_device *dev = video_drvdata(filp);
+ struct vpu_instance *inst = NULL;
+ int ret;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->dev = dev;
+ inst->type = VPU_INST_TYPE_DEC;
+ inst->ops = &wave6_vpu_dec_inst_ops;
+
+ v4l2_fh_init(&inst->v4l2_fh, vdev);
+ filp->private_data = &inst->v4l2_fh;
+ v4l2_fh_add(&inst->v4l2_fh);
+
+ inst->v4l2_fh.m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev, inst, wave6_vpu_dec_queue_init);
+ if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
+ ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
+ goto free_inst;
+ }
+
+ v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10);
+ v4l2_ctrl_new_custom(&inst->v4l2_ctrl_hdl, &wave6_vpu_thumbnail_mode, NULL);
+ v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1);
+ v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
+ 0, 0, 1, 0);
+ v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
+ v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+
+ if (inst->v4l2_ctrl_hdl.error) {
+ ret = -ENODEV;
+ goto err_m2m_release;
+ }
+
+ inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl;
+ v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl);
+
+ wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ inst->colorspace = V4L2_COLORSPACE_DEFAULT;
+ inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ inst->quantization = V4L2_QUANTIZATION_DEFAULT;
+ inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ return 0;
+
+err_m2m_release:
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+free_inst:
+ kfree(inst);
+ return ret;
+}
+
+static int wave6_vpu_dec_release(struct file *filp)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(filp->private_data);
+
+ dprintk(inst->dev->dev, "[%d] release\n", inst->id);
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+
+ mutex_lock(&inst->dev->dev_lock);
+ if (inst->state != VPU_INST_STATE_NONE) {
+ wave6_vpu_pause(inst->dev->dev, 0);
+ wave6_vpu_dec_destroy_instance(inst);
+ wave6_vpu_pause(inst->dev->dev, 1);
+ }
+ mutex_unlock(&inst->dev->dev_lock);
+
+ v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
+ v4l2_fh_del(&inst->v4l2_fh);
+ v4l2_fh_exit(&inst->v4l2_fh);
+ kfree(inst);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations wave6_vpu_dec_fops = {
+ .owner = THIS_MODULE,
+ .open = wave6_vpu_open_dec,
+ .release = wave6_vpu_dec_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+int wave6_vpu_dec_register_device(struct vpu_device *dev)
+{
+ struct video_device *vdev_dec;
+ int ret;
+
+ vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL);
+ if (!vdev_dec)
+ return -ENOMEM;
+
+ dev->video_dev_dec = vdev_dec;
+
+ strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec->name));
+ vdev_dec->fops = &wave6_vpu_dec_fops;
+ vdev_dec->ioctl_ops = &wave6_vpu_dec_ioctl_ops;
+ vdev_dec->release = video_device_release_empty;
+ vdev_dec->v4l2_dev = &dev->v4l2_dev;
+ vdev_dec->vfl_dir = VFL_DIR_M2M;
+ vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ vdev_dec->lock = &dev->dev_lock;
+ video_set_drvdata(vdev_dec, dev);
+
+ ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void wave6_vpu_dec_unregister_device(struct vpu_device *dev)
+{
+ video_unregister_device(dev->video_dev_dec);
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
new file mode 100644
index 000000000000..36417a7fef99
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
@@ -0,0 +1,2698 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - v4l2 stateful encoder interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/pm_runtime.h>
+#include "wave6-vpu.h"
+#include "wave6-vpu-dbg.h"
+#include "wave6-trace.h"
+
+#define VPU_ENC_DEV_NAME "C&M Wave6 VPU encoder"
+#define VPU_ENC_DRV_NAME "wave6-enc"
+
+static const struct vpu_format wave6_vpu_enc_fmt_list[2][23] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUYV,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV24,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV24,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV42,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 3,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 3,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 2,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_RGB24,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_P010,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB32,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_XRGB32,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_RGBA32,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_RGBX32,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB2101010,
+ .max_width = W6_MAX_ENC_PIC_WIDTH,
+ .min_width = W6_MIN_ENC_PIC_WIDTH,
+ .max_height = W6_MAX_ENC_PIC_HEIGHT,
+ .min_height = W6_MIN_ENC_PIC_HEIGHT,
+ .num_planes = 1,
+ },
+ }
+};
+
+static const struct vpu_format *wave6_find_vpu_fmt(unsigned int v4l2_pix_fmt,
+ enum vpu_fmt_type type)
+{
+ unsigned int index;
+
+ for (index = 0; index < ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]); index++) {
+ if (wave6_vpu_enc_fmt_list[type][index].v4l2_pix_fmt == v4l2_pix_fmt)
+ return &wave6_vpu_enc_fmt_list[type][index];
+ }
+
+ return NULL;
+}
+
+static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned int idx,
+ enum vpu_fmt_type type)
+{
+ if (idx >= ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]))
+ return NULL;
+
+ if (!wave6_vpu_enc_fmt_list[type][idx].v4l2_pix_fmt)
+ return NULL;
+
+ return &wave6_vpu_enc_fmt_list[type][idx];
+}
+
+static u32 wave6_cpb_size_msec(u32 cpb_size_kb, u32 bitrate)
+{
+ u64 cpb_size_bit;
+ u64 cpb_size_msec;
+
+ cpb_size_bit = (u64)cpb_size_kb * 1000 * BITS_PER_BYTE;
+ cpb_size_msec = (cpb_size_bit * 1000) / bitrate;
+
+ if (cpb_size_msec < 10 || cpb_size_msec > 100000)
+ cpb_size_msec = 10000;
+
+ return cpb_size_msec;
+}
+
+static void wave6_vpu_enc_release_fb(struct vpu_instance *inst)
+{
+ int i;
+
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ wave6_free_dma(&inst->frame_vbuf[i]);
+ memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer));
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_SUB_SAMPLE][i]);
+ }
+}
+
+static void wave6_vpu_enc_destroy_instance(struct vpu_instance *inst)
+{
+ u32 fail_res;
+ int ret;
+
+ dprintk(inst->dev->dev, "[%d] destroy instance\n", inst->id);
+ wave6_vpu_remove_dbgfs_file(inst);
+
+ ret = wave6_vpu_enc_close(inst, &fail_res);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed destroy instance: %d (%d)\n",
+ ret, fail_res);
+ }
+
+ wave6_vpu_enc_release_fb(inst);
+ wave6_free_dma(&inst->ar_vbuf);
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
+
+ if (!pm_runtime_suspended(inst->dev->dev))
+ pm_runtime_put_sync(inst->dev->dev);
+}
+
+static struct vb2_v4l2_buffer *wave6_get_valid_src_buf(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf = NULL;
+
+ v4l2_m2m_for_each_src_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
+
+ if (!vpu_buf->consumed) {
+ dev_dbg(inst->dev->dev, "no consumed src idx : %d\n",
+ vb2_v4l2_buf->vb2_buf.index);
+ return vb2_v4l2_buf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct vb2_v4l2_buffer *wave6_get_valid_dst_buf(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf;
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
+
+ if (!vpu_buf->consumed) {
+ dev_dbg(inst->dev->dev, "no consumed dst idx : %d\n",
+ vb2_v4l2_buf->vb2_buf.index);
+ return vb2_v4l2_buf;
+ }
+ }
+
+ return NULL;
+}
+
+static void wave6_set_csc(struct vpu_instance *inst, struct enc_param *pic_param)
+{
+ bool is_10bit = false;
+
+ if (!(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) &&
+ !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32) &&
+ !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32) &&
+ !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32) &&
+ !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) &&
+ !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010))
+ return;
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010)
+ is_10bit = true;
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32)
+ pic_param->csc.format_order = 8;
+
+ if (inst->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT ||
+ inst->ycbcr_enc == V4L2_YCBCR_ENC_601) {
+ if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) {
+ /*
+ * Y 0.299(R) 0.587(G) 0.114(B)
+ * Cb -0.16874(R) -0.33126(G) 0.5(B)
+ * Cr 0.5(R) -0.41869(G) -0.08131(B)
+ */
+ pic_param->csc.coef_ry = 0x099;
+ pic_param->csc.coef_gy = 0x12d;
+ pic_param->csc.coef_by = 0x03a;
+ pic_param->csc.coef_rcb = 0xffffffaa;
+ pic_param->csc.coef_gcb = 0xffffff56;
+ pic_param->csc.coef_bcb = 0x100;
+ pic_param->csc.coef_rcr = 0x100;
+ pic_param->csc.coef_gcr = 0xffffff2a;
+ pic_param->csc.coef_bcr = 0xffffffd6;
+ pic_param->csc.offset_y = 0x0;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ } else {
+ /*
+ * Y 0.258(R) 0.504(G) 0.098(B)
+ * Cb -0.1484(R) -0.2891(G) 0.4375(B)
+ * Cr 0.4375(R) -0.3672(G) -0.0703(B)
+ */
+ pic_param->csc.coef_ry = 0x084;
+ pic_param->csc.coef_gy = 0x102;
+ pic_param->csc.coef_by = 0x032;
+ pic_param->csc.coef_rcb = 0xffffffb4;
+ pic_param->csc.coef_gcb = 0xffffff6c;
+ pic_param->csc.coef_bcb = 0x0e0;
+ pic_param->csc.coef_rcr = 0x0e0;
+ pic_param->csc.coef_gcr = 0xffffff44;
+ pic_param->csc.coef_bcr = 0xffffffdc;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ }
+ } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) {
+ /*
+ * Y 0.2126(R) 0.7152(G) 0.0722(B)
+ * Cb -0.11457(R) -0.38543(G) 0.5(B)
+ * Cr 0.5(R) -0.45415(G) -0.04585(B)
+ */
+ pic_param->csc.coef_ry = 0x06d;
+ pic_param->csc.coef_gy = 0x16e;
+ pic_param->csc.coef_by = 0x025;
+ pic_param->csc.coef_rcb = 0xffffffc5;
+ pic_param->csc.coef_gcb = 0xffffff3b;
+ pic_param->csc.coef_bcb = 0x100;
+ pic_param->csc.coef_rcr = 0x100;
+ pic_param->csc.coef_gcr = 0xffffff17;
+ pic_param->csc.coef_bcr = 0xffffffe9;
+ pic_param->csc.offset_y = 0x0;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ } else {
+ pic_param->csc.coef_ry = 0x05e;
+ pic_param->csc.coef_gy = 0x13b;
+ pic_param->csc.coef_by = 0x020;
+ pic_param->csc.coef_rcb = 0xffffffcc;
+ pic_param->csc.coef_gcb = 0xffffff53;
+ pic_param->csc.coef_bcb = 0x0e1;
+ pic_param->csc.coef_rcr = 0x0e1;
+ pic_param->csc.coef_gcr = 0xffffff34;
+ pic_param->csc.coef_bcr = 0xffffffeb;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ }
+ } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
+ if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) {
+ /*
+ * Y 0.2627(R) 0.678(G) 0.0593(B)
+ * Cb -0.13963(R) -0.36037(G) 0.5(B)
+ * Cr 0.5(R) -0.45979(G) -0.04021(B)
+ */
+ pic_param->csc.coef_ry = 0x087;
+ pic_param->csc.coef_gy = 0x15b;
+ pic_param->csc.coef_by = 0x01e;
+ pic_param->csc.coef_rcb = 0xffffffb9;
+ pic_param->csc.coef_gcb = 0xffffff47;
+ pic_param->csc.coef_bcb = 0x100;
+ pic_param->csc.coef_rcr = 0x100;
+ pic_param->csc.coef_gcr = 0xffffff15;
+ pic_param->csc.coef_bcr = 0xffffffeb;
+ pic_param->csc.offset_y = 0x0;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ } else {
+ pic_param->csc.coef_ry = 0x074;
+ pic_param->csc.coef_gy = 0x12a;
+ pic_param->csc.coef_by = 0x01a;
+ pic_param->csc.coef_rcb = 0xffffffc1;
+ pic_param->csc.coef_gcb = 0xffffff5e;
+ pic_param->csc.coef_bcb = 0x0e1;
+ pic_param->csc.coef_rcr = 0x0e1;
+ pic_param->csc.coef_gcr = 0xffffff31;
+ pic_param->csc.coef_bcr = 0xffffffee;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ }
+ } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_SMPTE240M) {
+ if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) {
+ /*
+ * Y 0.2122(R) 0.7013(G) 0.0865(B)
+ * Cb -0.1161(R) -0.3839(G) 0.5(B)
+ * Cr 0.5(R) -0.4451(G) -0.0549(B)
+ */
+ pic_param->csc.coef_ry = 0x06d;
+ pic_param->csc.coef_gy = 0x167;
+ pic_param->csc.coef_by = 0x02c;
+ pic_param->csc.coef_rcb = 0xffffffc5;
+ pic_param->csc.coef_gcb = 0xffffff3b;
+ pic_param->csc.coef_bcb = 0x100;
+ pic_param->csc.coef_rcr = 0x100;
+ pic_param->csc.coef_gcr = 0xffffff1c;
+ pic_param->csc.coef_bcr = 0xffffffe4;
+ pic_param->csc.offset_y = 0x0;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ } else {
+ pic_param->csc.coef_ry = 0x05d;
+ pic_param->csc.coef_gy = 0x134;
+ pic_param->csc.coef_by = 0x026;
+ pic_param->csc.coef_rcb = 0xffffffcc;
+ pic_param->csc.coef_gcb = 0xffffff53;
+ pic_param->csc.coef_bcb = 0x0e1;
+ pic_param->csc.coef_rcr = 0x0e1;
+ pic_param->csc.coef_gcr = 0xffffff38;
+ pic_param->csc.coef_bcr = 0xffffffe7;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80;
+ pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80;
+ }
+ } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
+ if (inst->quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+ /*
+ * Y 0.2558(R) 0.5021(G) 0.0975(B)
+ * Cb -0.1476(R) -0.2899(G) 0.4375(B)
+ * Cr 0.4375(R) -0.3664(G) -0.0711(B)
+ */
+ pic_param->csc.coef_ry = 0x083;
+ pic_param->csc.coef_gy = 0x101;
+ pic_param->csc.coef_by = 0x032;
+ pic_param->csc.coef_rcb = 0xffffffb4;
+ pic_param->csc.coef_gcb = 0xffffff6c;
+ pic_param->csc.coef_bcb = 0x0e0;
+ pic_param->csc.coef_rcr = 0x0e0;
+ pic_param->csc.coef_gcr = 0xffffff44;
+ pic_param->csc.coef_bcr = 0xffffffdc;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = 0x0;
+ pic_param->csc.offset_cr = 0x0;
+ }
+ } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
+ if (inst->quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+ /*
+ * Y 0.1819(R) 0.6118(G) 0.0618(B)
+ * Cb -0.1003(R) -0.3372(G) 0.4375(B)
+ * Cr 0.4375(R) -0.3974(G) -0.0401(B)
+ */
+ pic_param->csc.coef_ry = 0x05d;
+ pic_param->csc.coef_gy = 0x139;
+ pic_param->csc.coef_by = 0x020;
+ pic_param->csc.coef_rcb = 0xffffffcd;
+ pic_param->csc.coef_gcb = 0xffffff53;
+ pic_param->csc.coef_bcb = 0x0e0;
+ pic_param->csc.coef_rcr = 0x0e0;
+ pic_param->csc.coef_gcr = 0xffffff35;
+ pic_param->csc.coef_bcr = 0xffffffeb;
+ pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10;
+ pic_param->csc.offset_cb = 0x0;
+ pic_param->csc.offset_cr = 0x0;
+ }
+ }
+}
+
+static void wave6_update_crop_info(struct vpu_instance *inst,
+ u32 left, u32 top, u32 width, u32 height)
+{
+ u32 enc_pic_width, enc_pic_height;
+
+ inst->crop.left = left;
+ inst->crop.top = top;
+ inst->crop.width = width;
+ inst->crop.height = height;
+
+ inst->codec_rect.left = round_down(left, W6_ENC_CROP_X_POS_STEP);
+ inst->codec_rect.top = round_down(top, W6_ENC_CROP_Y_POS_STEP);
+
+ enc_pic_width = width + left - inst->codec_rect.left;
+ inst->codec_rect.width = round_up(enc_pic_width, W6_ENC_PIC_SIZE_STEP);
+
+ enc_pic_height = height + top - inst->codec_rect.top;
+ inst->codec_rect.height = round_up(enc_pic_height, W6_ENC_PIC_SIZE_STEP);
+}
+
+static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
+ enum aux_buffer_type type,
+ int num)
+{
+ struct aux_buffer buf[WAVE6_MAX_FBS];
+ struct aux_buffer_info buf_info;
+ struct enc_aux_buffer_size_info size_info;
+ unsigned int size;
+ int i, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ size_info.width = inst->codec_rect.width;
+ size_info.height = inst->codec_rect.height;
+ size_info.type = type;
+ size_info.mirror_direction = inst->enc_ctrls.mirror_direction;
+ size_info.rotation_angle = inst->enc_ctrls.rot_angle;
+
+ ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info, &size);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Get size fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ inst->aux_vbuf[type][i].size = size;
+ ret = wave6_alloc_dma(inst->dev->dev, &inst->aux_vbuf[type][i]);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Alloc fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ buf[i].index = i;
+ buf[i].addr = inst->aux_vbuf[type][i].daddr;
+ buf[i].size = inst->aux_vbuf[type][i].size;
+ }
+
+ buf_info.type = type;
+ buf_info.num = num;
+ buf_info.buf_array = buf;
+
+ ret = wave6_vpu_enc_register_aux_buffer(inst, buf_info);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: Register fail (type %d)\n", __func__, type);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void wave6_update_frame_buf_addr(struct vpu_instance *inst,
+ struct frame_buffer *frame_buf)
+{
+ const struct v4l2_format_info *fmt_info;
+ u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
+ u32 offset;
+
+ fmt_info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!fmt_info)
+ return;
+
+ offset = inst->codec_rect.top * stride + inst->codec_rect.left * fmt_info->bpp[0];
+ frame_buf->buf_y += offset;
+
+ stride = DIV_ROUND_UP(stride, fmt_info->bpp[0]) * fmt_info->bpp[1];
+ offset = inst->codec_rect.top * stride / fmt_info->vdiv / fmt_info->hdiv
+ + inst->codec_rect.left * fmt_info->bpp[1] / fmt_info->hdiv;
+ frame_buf->buf_cb += offset;
+ frame_buf->buf_cr += offset;
+}
+
+static int wave6_update_seq_param(struct vpu_instance *inst)
+{
+ struct enc_initial_info initial_info;
+ bool changed = false;
+ int ret;
+
+ ret = wave6_vpu_enc_issue_seq_change(inst, &changed);
+ if (ret) {
+ dev_err(inst->dev->dev, "seq change fail %d\n", ret);
+ return ret;
+ }
+
+ if (!changed)
+ return 0;
+
+ if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
+ dev_err(inst->dev->dev, "seq change timeout\n");
+ return ret;
+ }
+
+ wave6_vpu_enc_complete_seq_init(inst, &initial_info);
+ if (ret) {
+ dev_err(inst->dev->dev, "seq change error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_start_encode(struct vpu_instance *inst)
+{
+ int ret = -EINVAL;
+ struct vb2_v4l2_buffer *src_buf = NULL;
+ struct vb2_v4l2_buffer *dst_buf = NULL;
+ struct vpu_buffer *src_vbuf = NULL;
+ struct vpu_buffer *dst_vbuf = NULL;
+ struct frame_buffer frame_buf;
+ struct enc_param pic_param;
+ u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
+ u32 luma_size = (stride * inst->src_fmt.height);
+ u32 chroma_size;
+ u32 fail_res;
+
+ memset(&pic_param, 0, sizeof(struct enc_param));
+ memset(&frame_buf, 0, sizeof(struct frame_buffer));
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M)
+ chroma_size = ((stride / 2) * (inst->src_fmt.height / 2));
+ else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M)
+ chroma_size = ((stride) * (inst->src_fmt.height / 2));
+ else
+ chroma_size = 0;
+
+ ret = wave6_update_seq_param(inst);
+ if (ret)
+ goto exit;
+
+ src_buf = wave6_get_valid_src_buf(inst);
+ dst_buf = wave6_get_valid_dst_buf(inst);
+
+ if (!dst_buf) {
+ dev_dbg(inst->dev->dev, "no valid dst buf\n");
+ goto exit;
+ }
+
+ dst_vbuf = wave6_to_vpu_buf(dst_buf);
+ pic_param.pic_stream_buffer_addr = wave6_get_dma_addr(dst_buf, 0);
+ pic_param.pic_stream_buffer_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
+ if (!src_buf) {
+ dev_dbg(inst->dev->dev, "no valid src buf\n");
+ if (inst->state == VPU_INST_STATE_STOP)
+ pic_param.src_end = true;
+ else
+ goto exit;
+ } else {
+ src_vbuf = wave6_to_vpu_buf(src_buf);
+ if (inst->src_fmt.num_planes == 1) {
+ frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0);
+ frame_buf.buf_cb = frame_buf.buf_y + luma_size;
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 2) {
+ frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0);
+ frame_buf.buf_cb = wave6_get_dma_addr(src_buf, 1);
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 3) {
+ frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0);
+ frame_buf.buf_cb = wave6_get_dma_addr(src_buf, 1);
+ frame_buf.buf_cr = wave6_get_dma_addr(src_buf, 2);
+ }
+ wave6_update_frame_buf_addr(inst, &frame_buf);
+ frame_buf.stride = stride;
+ pic_param.src_idx = src_buf->vb2_buf.index;
+ if (src_vbuf->force_key_frame || inst->error_recovery) {
+ pic_param.force_pic_type_enable = true;
+ pic_param.force_pic_type = ENC_FORCE_PIC_TYPE_IDR;
+ inst->error_recovery = false;
+ }
+ if (src_vbuf->force_frame_qp) {
+ pic_param.force_pic_qp_enable = true;
+ pic_param.force_pic_qp_i = src_vbuf->force_i_frame_qp;
+ pic_param.force_pic_qp_p = src_vbuf->force_p_frame_qp;
+ pic_param.force_pic_qp_b = src_vbuf->force_b_frame_qp;
+ }
+ src_vbuf->ts_start = ktime_get_raw();
+ }
+
+ pic_param.source_frame = &frame_buf;
+ wave6_set_csc(inst, &pic_param);
+
+ if (src_vbuf)
+ src_vbuf->consumed = true;
+ if (dst_vbuf) {
+ dst_vbuf->consumed = true;
+ dst_vbuf->used = true;
+ }
+
+ trace_enc_pic(inst, &pic_param);
+
+ ret = wave6_vpu_enc_start_one_frame(inst, &pic_param, &fail_res);
+ if (ret) {
+ dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst->id, __func__, ret);
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP);
+
+ dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (dst_buf) {
+ dst_buf->sequence = inst->sequence;
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (src_buf) {
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ inst->sequence++;
+ inst->processed_buf_num++;
+ inst->error_buf_num++;
+ }
+ } else {
+ dev_dbg(inst->dev->dev, "%s: success\n", __func__);
+ }
+
+exit:
+ return ret;
+}
+
+static void wave6_handle_encoded_frame(struct vpu_instance *inst,
+ struct enc_output_info *info)
+{
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ struct vpu_buffer *vpu_buf;
+ struct vpu_buffer *dst_vpu_buf;
+ enum vb2_buffer_state state;
+
+ state = info->encoding_success ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ src_buf = v4l2_m2m_src_buf_remove_by_idx(inst->v4l2_fh.m2m_ctx,
+ info->enc_src_idx);
+ if (!src_buf) {
+ dev_err(inst->dev->dev, "[%d] encoder can't find src buffer\n", inst->id);
+ return;
+ }
+
+ vpu_buf = wave6_to_vpu_buf(src_buf);
+ if (!vpu_buf || !vpu_buf->consumed) {
+ dev_err(inst->dev->dev, "[%d] src buffer is not consumed\n", inst->id);
+ return;
+ }
+
+ dst_buf = wave6_get_dst_buf_by_addr(inst, info->bitstream_buffer);
+ if (!dst_buf) {
+ dev_err(inst->dev->dev, "[%d] encoder can't find dst buffer\n", inst->id);
+ return;
+ }
+
+ dst_vpu_buf = wave6_to_vpu_buf(dst_buf);
+
+ dst_vpu_buf->average_qp = info->avg_ctu_qp;
+ dst_vpu_buf->ts_input = vpu_buf->ts_input;
+ dst_vpu_buf->ts_start = vpu_buf->ts_start;
+ dst_vpu_buf->ts_finish = ktime_get_raw();
+ dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev, info->cycle.frame_cycle);
+ dst_vpu_buf->ts_output = ktime_get_raw();
+ wave6_vpu_handle_performance(inst, dst_vpu_buf);
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
+ v4l2_m2m_buf_done(src_buf, state);
+
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, info->bitstream_size);
+ dst_buf->sequence = inst->sequence++;
+ dst_buf->field = V4L2_FIELD_NONE;
+ if (info->pic_type == PIC_TYPE_I)
+ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else if (info->pic_type == PIC_TYPE_P)
+ dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ else if (info->pic_type == PIC_TYPE_B)
+ dst_buf->flags |= V4L2_BUF_FLAG_BFRAME;
+
+ v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf);
+ if (state == VB2_BUF_STATE_ERROR) {
+ dprintk(inst->dev->dev, "[%d] error frame %d\n", inst->id, inst->sequence);
+ inst->error_recovery = true;
+ inst->error_buf_num++;
+ }
+ v4l2_m2m_buf_done(dst_buf, state);
+ inst->processed_buf_num++;
+}
+
+static void wave6_handle_last_frame(struct vpu_instance *inst,
+ dma_addr_t addr)
+{
+ struct vb2_v4l2_buffer *dst_buf;
+
+ dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
+ if (!dst_buf)
+ return;
+
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ dst_buf->field = V4L2_FIELD_NONE;
+ dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
+
+ dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
+ inst->eos = true;
+
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
+}
+
+static void wave6_vpu_enc_finish_encode(struct vpu_instance *inst, bool error)
+{
+ int ret;
+ struct enc_output_info info;
+
+ if (error) {
+ vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx));
+ vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx));
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP);
+ inst->eos = true;
+
+ goto finish_encode;
+ }
+
+ ret = wave6_vpu_enc_get_output_info(inst, &info);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "vpu_enc_get_output_info fail %d reason: %d | info : %d\n",
+ ret, info.error_reason, info.warn_info);
+ goto finish_encode;
+ }
+
+ trace_enc_done(inst, &info);
+
+ if (info.enc_src_idx >= 0 && info.recon_frame_index >= 0)
+ wave6_handle_encoded_frame(inst, &info);
+ else if (info.recon_frame_index == RECON_IDX_FLAG_ENC_END)
+ wave6_handle_last_frame(inst, info.bitstream_buffer);
+
+finish_encode:
+ wave6_vpu_finish_job(inst);
+}
+
+static int wave6_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:" VPU_ENC_DRV_NAME, sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static int wave6_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+ const struct vpu_format *vpu_fmt;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt) {
+ vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt)
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = vpu_fmt->min_width;
+ fsize->stepwise.max_width = vpu_fmt->max_width;
+ fsize->stepwise.step_width = W6_ENC_PIC_SIZE_STEP;
+ fsize->stepwise.min_height = vpu_fmt->min_height;
+ fsize->stepwise.max_height = vpu_fmt->max_height;
+ fsize->stepwise.step_height = W6_ENC_PIC_SIZE_STEP;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "index : %d\n", f->index);
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct vpu_format *vpu_fmt;
+ int width, height;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ if (!V4L2_TYPE_IS_CAPTURE(f->type))
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_CODEC);
+ if (!vpu_fmt) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
+ pix_mp->pixelformat = inst->dst_fmt.pixelformat;
+ pix_mp->num_planes = inst->dst_fmt.num_planes;
+ } else {
+ width = pix_mp->width;
+ height = pix_mp->height;
+ pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ pix_mp->num_planes = vpu_fmt->num_planes;
+ }
+
+ wave6_update_pix_fmt(pix_mp, width, height);
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ ret = wave6_vpu_enc_try_fmt_cap(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->std = wave6_to_codec_std(inst->type, pix_mp->pixelformat);
+ if (inst->std == STD_UNKNOWN) {
+ dev_err(inst->dev->dev, "unsupported pixelformat: %.4s\n",
+ (char *)&pix_mp->pixelformat);
+ return -EINVAL;
+ }
+
+ inst->dst_fmt.width = pix_mp->width;
+ inst->dst_fmt.height = pix_mp->height;
+ inst->dst_fmt.pixelformat = pix_mp->pixelformat;
+ inst->dst_fmt.field = pix_mp->field;
+ inst->dst_fmt.flags = pix_mp->flags;
+ inst->dst_fmt.num_planes = pix_mp->num_planes;
+ for (i = 0; i < inst->dst_fmt.num_planes; i++) {
+ inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline;
+ inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i;
+
+ pix_mp->width = inst->dst_fmt.width;
+ pix_mp->height = inst->dst_fmt.height;
+ pix_mp->pixelformat = inst->dst_fmt.pixelformat;
+ pix_mp->field = inst->dst_fmt.field;
+ pix_mp->flags = inst->dst_fmt.flags;
+ pix_mp->num_planes = inst->dst_fmt.num_planes;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline;
+ pix_mp->plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage;
+ }
+
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f->index);
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct vpu_format *vpu_fmt;
+ int width, height;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ if (!V4L2_TYPE_IS_OUTPUT(f->type))
+ return -EINVAL;
+
+ vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_RAW);
+ if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
+ pix_mp->pixelformat = inst->src_fmt.pixelformat;
+ pix_mp->num_planes = inst->src_fmt.num_planes;
+ } else {
+ width = clamp(pix_mp->width,
+ vpu_fmt->min_width, vpu_fmt->max_width);
+ height = clamp(pix_mp->height,
+ vpu_fmt->min_height, vpu_fmt->max_height);
+
+ pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ pix_mp->num_planes = vpu_fmt->num_planes;
+ }
+
+ wave6_update_pix_fmt(pix_mp, width, height);
+
+ if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
+ pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
+ if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV601 ||
+ pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
+ if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ pix_mp->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n",
+ __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height,
+ pix_mp->num_planes, pix_mp->colorspace);
+
+ ret = wave6_vpu_enc_try_fmt_out(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->src_fmt.width = pix_mp->width;
+ inst->src_fmt.height = pix_mp->height;
+ inst->src_fmt.pixelformat = pix_mp->pixelformat;
+ inst->src_fmt.field = pix_mp->field;
+ inst->src_fmt.flags = pix_mp->flags;
+ inst->src_fmt.num_planes = pix_mp->num_planes;
+ for (i = 0; i < inst->src_fmt.num_planes; i++) {
+ inst->src_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline;
+ inst->src_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage;
+ }
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = false;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = true;
+ } else {
+ inst->cbcr_interleave = false;
+ inst->nv21 = false;
+ }
+
+ inst->colorspace = pix_mp->colorspace;
+ inst->ycbcr_enc = pix_mp->ycbcr_enc;
+ inst->quantization = pix_mp->quantization;
+ inst->xfer_func = pix_mp->xfer_func;
+
+ wave6_update_pix_fmt(&inst->dst_fmt, pix_mp->width, pix_mp->height);
+ wave6_update_crop_info(inst, 0, 0, pix_mp->width, pix_mp->height);
+
+ return 0;
+}
+
+static int wave6_vpu_enc_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i;
+
+ dev_dbg(inst->dev->dev, "\n");
+
+ pix_mp->width = inst->src_fmt.width;
+ pix_mp->height = inst->src_fmt.height;
+ pix_mp->pixelformat = inst->src_fmt.pixelformat;
+ pix_mp->field = inst->src_fmt.field;
+ pix_mp->flags = inst->src_fmt.flags;
+ pix_mp->num_planes = inst->src_fmt.num_planes;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
+ pix_mp->plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
+ }
+
+ pix_mp->colorspace = inst->colorspace;
+ pix_mp->ycbcr_enc = inst->ycbcr_enc;
+ pix_mp->quantization = inst->quantization;
+ pix_mp->xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave6_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
+ __func__, s->type, s->target);
+
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->src_fmt.width;
+ s->r.height = inst->src_fmt.height;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ s->r = inst->crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ u32 max_crop_w, max_crop_h;
+
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
+ return -EINVAL;
+
+ if (s->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
+ s->flags |= V4L2_SEL_FLAG_LE;
+
+ if (s->flags & V4L2_SEL_FLAG_GE) {
+ s->r.left = round_up(s->r.left, W6_ENC_CROP_STEP);
+ s->r.top = round_up(s->r.top, W6_ENC_CROP_STEP);
+ s->r.width = round_up(s->r.width, W6_ENC_CROP_STEP);
+ s->r.height = round_up(s->r.height, W6_ENC_CROP_STEP);
+ }
+ if (s->flags & V4L2_SEL_FLAG_LE) {
+ s->r.left = round_down(s->r.left, W6_ENC_CROP_STEP);
+ s->r.top = round_down(s->r.top, W6_ENC_CROP_STEP);
+ s->r.width = round_down(s->r.width, W6_ENC_CROP_STEP);
+ s->r.height = round_down(s->r.height, W6_ENC_CROP_STEP);
+ }
+
+ max_crop_w = inst->src_fmt.width - s->r.left;
+ max_crop_h = inst->src_fmt.height - s->r.top;
+
+ if (!s->r.width || !s->r.height)
+ return 0;
+ if (max_crop_w < W6_MIN_ENC_PIC_WIDTH)
+ return 0;
+ if (max_crop_h < W6_MIN_ENC_PIC_HEIGHT)
+ return 0;
+
+ s->r.width = clamp(s->r.width, W6_MIN_ENC_PIC_WIDTH, max_crop_w);
+ s->r.height = clamp(s->r.height, W6_MIN_ENC_PIC_HEIGHT, max_crop_h);
+
+ wave6_update_pix_fmt(&inst->dst_fmt, s->r.width, s->r.height);
+ wave6_update_crop_info(inst, s->r.left, s->r.top, s->r.width, s->r.height);
+
+ dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_CROP %dx%dx%dx%d\n",
+ s->r.left, s->r.top, s->r.width, s->r.height);
+
+ return 0;
+}
+
+static int wave6_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ int ret;
+
+ dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, ec->cmd);
+
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
+ if (ret)
+ return ret;
+
+ if (!wave6_vpu_both_queues_are_streaming(inst))
+ return 0;
+
+ switch (ec->cmd) {
+ case V4L2_ENC_CMD_STOP:
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP);
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true);
+ v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
+ break;
+ case V4L2_ENC_CMD_START:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
+
+ if (!V4L2_TYPE_IS_OUTPUT(a->type))
+ return -EINVAL;
+
+ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ a->parm.output.timeperframe.numerator = 1;
+ a->parm.output.timeperframe.denominator = inst->frame_rate;
+
+ dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator : %d\n",
+ __func__,
+ a->parm.output.timeperframe.numerator,
+ a->parm.output.timeperframe.denominator);
+
+ return 0;
+}
+
+static int wave6_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
+
+ if (!V4L2_TYPE_IS_OUTPUT(a->type))
+ return -EINVAL;
+
+ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) {
+ inst->frame_rate = a->parm.output.timeperframe.denominator /
+ a->parm.output.timeperframe.numerator;
+ } else {
+ a->parm.output.timeperframe.numerator = 1;
+ a->parm.output.timeperframe.denominator = inst->frame_rate;
+ }
+
+ dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator : %d\n",
+ __func__,
+ a->parm.output.timeperframe.numerator,
+ a->parm.output.timeperframe.denominator);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops wave6_vpu_enc_ioctl_ops = {
+ .vidioc_querycap = wave6_vpu_enc_querycap,
+ .vidioc_enum_framesizes = wave6_vpu_enc_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = wave6_vpu_enc_enum_fmt_cap,
+ .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_enc_s_fmt_cap,
+ .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_enc_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_enc_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = wave6_vpu_enc_enum_fmt_out,
+ .vidioc_s_fmt_vid_out_mplane = wave6_vpu_enc_s_fmt_out,
+ .vidioc_g_fmt_vid_out_mplane = wave6_vpu_enc_g_fmt_out,
+ .vidioc_try_fmt_vid_out_mplane = wave6_vpu_enc_try_fmt_out,
+
+ .vidioc_g_selection = wave6_vpu_enc_g_selection,
+ .vidioc_s_selection = wave6_vpu_enc_s_selection,
+
+ .vidioc_g_parm = wave6_vpu_enc_g_parm,
+ .vidioc_s_parm = wave6_vpu_enc_s_parm,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+ .vidioc_encoder_cmd = wave6_vpu_enc_encoder_cmd,
+
+ .vidioc_subscribe_event = wave6_vpu_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int wave6_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
+ struct enc_controls *p = &inst->enc_ctrls;
+
+ trace_s_ctrl(inst, ctrl);
+
+ dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
+ __func__, ctrl->name, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ p->mirror_direction |= (ctrl->val << 1);
+ break;
+ case V4L2_CID_VFLIP:
+ p->mirror_direction |= ctrl->val;
+ break;
+ case V4L2_CID_ROTATE:
+ p->rot_angle = ctrl->val;
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ p->gop_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ p->slice_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ p->slice_max_mb = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ p->bitrate_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ p->bitrate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ p->frame_rc_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ p->mb_rc_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+ p->force_key_frame = true;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
+ p->prepend_spspps_to_idr = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE:
+ break;
+ case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
+ p->intra_refresh_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+ p->frame_skip_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ p->hevc.profile = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ p->hevc.level = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ p->hevc.min_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ p->hevc.max_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
+ p->hevc.i_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
+ p->hevc.p_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
+ p->hevc.b_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ p->hevc.loop_filter_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
+ p->hevc.lf_beta_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
+ p->hevc.lf_tc_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ p->hevc.refresh_type = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
+ p->hevc.refresh_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
+ p->hevc.const_intra_pred = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
+ p->hevc.strong_smoothing = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
+ p->hevc.tmv_prediction = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ p->h264.profile = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ p->h264.level = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ p->h264.min_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ p->h264.max_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ p->h264.i_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ p->h264.p_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ p->h264.b_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ p->h264.loop_filter_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ p->h264.loop_filter_beta = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ p->h264.loop_filter_alpha = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ p->h264._8x8_transform = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
+ p->h264.constrained_intra_prediction = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:
+ p->h264.chroma_qp_index_offset = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ p->h264.entropy_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ p->h264.i_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+ p->h264.vui_sar_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+ p->h264.vui_sar_idc = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+ p->h264.vui_ext_sar_width = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+ p->h264.vui_ext_sar_height = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+ p->h264.cpb_size = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops wave6_vpu_enc_ctrl_ops = {
+ .s_ctrl = wave6_vpu_enc_s_ctrl,
+};
+
+static u32 to_video_full_range_flag(enum v4l2_quantization quantization)
+{
+ switch (quantization) {
+ case V4L2_QUANTIZATION_FULL_RANGE:
+ return 1;
+ case V4L2_QUANTIZATION_LIM_RANGE:
+ default:
+ return 0;
+ }
+}
+
+static u32 to_colour_primaries(enum v4l2_colorspace colorspace)
+{
+ switch (colorspace) {
+ case V4L2_COLORSPACE_SMPTE170M:
+ return 6;
+ case V4L2_COLORSPACE_REC709:
+ case V4L2_COLORSPACE_SRGB:
+ case V4L2_COLORSPACE_JPEG:
+ return 1;
+ case V4L2_COLORSPACE_BT2020:
+ return 9;
+ case V4L2_COLORSPACE_DCI_P3:
+ return 11;
+ case V4L2_COLORSPACE_SMPTE240M:
+ return 7;
+ case V4L2_COLORSPACE_470_SYSTEM_M:
+ return 4;
+ case V4L2_COLORSPACE_470_SYSTEM_BG:
+ return 5;
+ case V4L2_COLORSPACE_RAW:
+ default:
+ return 2;
+ }
+}
+
+static u32 to_transfer_characteristics(enum v4l2_colorspace colorspace,
+ enum v4l2_xfer_func xfer_func)
+{
+ if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
+ xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
+
+ switch (xfer_func) {
+ case V4L2_XFER_FUNC_709:
+ if (colorspace == V4L2_COLORSPACE_SMPTE170M)
+ return 6;
+ else if (colorspace == V4L2_COLORSPACE_BT2020)
+ return 14;
+ else
+ return 1;
+ case V4L2_XFER_FUNC_SRGB:
+ return 13;
+ case V4L2_XFER_FUNC_SMPTE240M:
+ return 7;
+ case V4L2_XFER_FUNC_NONE:
+ return 8;
+ case V4L2_XFER_FUNC_SMPTE2084:
+ return 16;
+ case V4L2_XFER_FUNC_DCI_P3:
+ default:
+ return 2;
+ }
+}
+
+static u32 to_matrix_coeffs(enum v4l2_colorspace colorspace,
+ enum v4l2_ycbcr_encoding ycbcr_enc)
+{
+ if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+ ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
+
+ switch (ycbcr_enc) {
+ case V4L2_YCBCR_ENC_601:
+ case V4L2_YCBCR_ENC_XV601:
+ if (colorspace == V4L2_COLORSPACE_SMPTE170M)
+ return 6;
+ else
+ return 5;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_XV709:
+ return 1;
+ case V4L2_YCBCR_ENC_BT2020:
+ return 9;
+ case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+ return 10;
+ case V4L2_YCBCR_ENC_SMPTE240M:
+ return 7;
+ default:
+ return 2;
+ }
+}
+
+static void wave6_set_enc_h264_param(struct enc_codec_param *output,
+ struct h264_enc_controls *ctrls)
+{
+ switch (ctrls->profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ output->profile = H264_PROFILE_BP;
+ output->internal_bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ output->profile = H264_PROFILE_MP;
+ output->internal_bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ output->profile = H264_PROFILE_EXTENDED;
+ output->internal_bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ output->profile = H264_PROFILE_HP;
+ output->internal_bit_depth = 8;
+ break;
+ default:
+ break;
+ }
+ switch (ctrls->level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ output->level = 10;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ output->level = 9;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ output->level = 11;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ output->level = 12;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ output->level = 13;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ output->level = 20;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ output->level = 21;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ output->level = 22;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ output->level = 30;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ output->level = 31;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ output->level = 32;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ output->level = 40;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ output->level = 41;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ output->level = 42;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ output->level = 50;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ output->level = 51;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+ output->level = 52;
+ break;
+ default:
+ break;
+ }
+ output->qp = ctrls->i_frame_qp;
+ output->min_qp_i = ctrls->min_qp;
+ output->max_qp_i = ctrls->max_qp;
+ output->min_qp_p = ctrls->min_qp;
+ output->max_qp_p = ctrls->max_qp;
+ output->min_qp_b = ctrls->min_qp;
+ output->max_qp_b = ctrls->max_qp;
+ switch (ctrls->loop_filter_mode) {
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+ output->en_dbk = 0;
+ output->en_lf_cross_slice_boundary = 0;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+ output->en_dbk = 1;
+ output->en_lf_cross_slice_boundary = 1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
+ output->en_dbk = 1;
+ output->en_lf_cross_slice_boundary = 0;
+ break;
+ default:
+ break;
+ }
+ output->intra_period = ctrls->i_period;
+ output->beta_offset_div2 = ctrls->loop_filter_beta;
+ output->tc_offset_div2 = ctrls->loop_filter_alpha;
+ if (output->profile >= H264_PROFILE_HP)
+ output->en_transform8x8 = ctrls->_8x8_transform;
+ output->en_constrained_intra_pred = ctrls->constrained_intra_prediction;
+ output->cb_qp_offset = ctrls->chroma_qp_index_offset;
+ output->cr_qp_offset = ctrls->chroma_qp_index_offset;
+ if (output->profile >= H264_PROFILE_MP)
+ output->en_cabac = ctrls->entropy_mode;
+ output->en_auto_level_adjusting = DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
+}
+
+static void wave6_set_enc_hevc_param(struct enc_codec_param *output,
+ struct hevc_enc_controls *ctrls)
+{
+ switch (ctrls->profile) {
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
+ output->profile = HEVC_PROFILE_MAIN;
+ output->internal_bit_depth = 8;
+ break;
+ default:
+ break;
+ }
+ switch (ctrls->level) {
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
+ output->level = 10 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
+ output->level = 20 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
+ output->level = 21 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
+ output->level = 30 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
+ output->level = 31 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
+ output->level = 40 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
+ output->level = 41 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
+ output->level = 50 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
+ output->level = 51 * 3;
+ break;
+ default:
+ break;
+ }
+ output->qp = ctrls->i_frame_qp;
+ output->min_qp_i = ctrls->min_qp;
+ output->max_qp_i = ctrls->max_qp;
+ output->min_qp_p = ctrls->min_qp;
+ output->max_qp_p = ctrls->max_qp;
+ output->min_qp_b = ctrls->min_qp;
+ output->max_qp_b = ctrls->max_qp;
+ switch (ctrls->loop_filter_mode) {
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
+ output->en_dbk = 0;
+ output->en_sao = 0;
+ output->en_lf_cross_slice_boundary = 0;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
+ output->en_dbk = 1;
+ output->en_sao = 1;
+ output->en_lf_cross_slice_boundary = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
+ output->en_dbk = 1;
+ output->en_sao = 1;
+ output->en_lf_cross_slice_boundary = 0;
+ break;
+ default:
+ break;
+ }
+ switch (ctrls->refresh_type) {
+ case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE:
+ output->decoding_refresh_type = DEC_REFRESH_TYPE_NON_IRAP;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR:
+ output->decoding_refresh_type = DEC_REFRESH_TYPE_IDR;
+ break;
+ default:
+ break;
+ }
+ output->intra_period = ctrls->refresh_period;
+ if (output->idr_period) {
+ output->decoding_refresh_type = DEC_REFRESH_TYPE_IDR;
+ output->intra_period = output->idr_period;
+ output->idr_period = 0;
+ }
+ output->beta_offset_div2 = ctrls->lf_beta_offset_div2;
+ output->tc_offset_div2 = ctrls->lf_tc_offset_div2;
+ output->en_constrained_intra_pred = ctrls->const_intra_pred;
+ output->en_strong_intra_smoothing = ctrls->strong_smoothing;
+ output->en_temporal_mvp = ctrls->tmv_prediction;
+ output->num_ticks_poc_diff_one = DEFAULT_NUM_TICKS_POC_DIFF;
+ output->en_auto_level_adjusting = DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
+ output->en_intra_trans_skip = DEFAULT_EN_INTRA_TRANS_SKIP;
+ output->en_me_center = DEFAULT_EN_ME_CENTER;
+ output->intra_4x4 = DEFAULT_INTRA_4X4;
+}
+
+static void wave6_set_enc_open_param(struct enc_open_param *open_param,
+ struct vpu_instance *inst)
+{
+ struct enc_controls *ctrls = &inst->enc_ctrls;
+ struct enc_codec_param *output = &open_param->codec_param;
+ u32 ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
+ u32 num_ctu_row = ALIGN(inst->src_fmt.height, ctu_size) / ctu_size;
+
+ open_param->source_endian = VPU_SOURCE_ENDIAN;
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
+ open_param->src_format = FORMAT_420;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M) {
+ open_param->src_format = FORMAT_422;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42) {
+ open_param->src_format = FORMAT_YUV444_24BIT;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24) {
+ open_param->src_format = FORMAT_YUV444_24BIT_PACKED;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUYV) {
+ open_param->src_format = FORMAT_YUYV;
+ open_param->packed_format = PACKED_YUYV;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) {
+ open_param->src_format = FORMAT_RGB_24BIT_PACKED;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010) {
+ open_param->src_format = FORMAT_420_P10_16BIT_MSB;
+ open_param->source_endian = VDI_128BIT_LE_BYTE_SWAP;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) {
+ open_param->src_format = FORMAT_RGB_32BIT_PACKED;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) {
+ open_param->src_format = FORMAT_RGB_P10_32BIT_PACKED;
+ open_param->source_endian = VDI_128BIT_LE_WORD_BYTE_SWAP;
+ }
+ open_param->line_buf_int_en = true;
+ open_param->stream_endian = VPU_STREAM_ENDIAN;
+ open_param->inst_buffer.temp_base = inst->dev->temp_vbuf.daddr;
+ open_param->inst_buffer.temp_size = inst->dev->temp_vbuf.size;
+ open_param->inst_buffer.ar_base = inst->ar_vbuf.daddr;
+ open_param->pic_width = inst->codec_rect.width;
+ open_param->pic_height = inst->codec_rect.height;
+
+ output->custom_map_endian = VPU_USER_DATA_ENDIAN;
+ output->gop_preset_idx = PRESET_IDX_IPP_SINGLE;
+ output->temp_layer_cnt = DEFAULT_TEMP_LAYER_CNT;
+ output->rc_initial_level = DEFAULT_RC_INITIAL_LEVEL;
+ output->pic_rc_max_dqp = DEFAULT_PIC_RC_MAX_DQP;
+ output->rc_initial_qp = DEFAULT_RC_INITIAL_QP;
+ output->en_adaptive_round = DEFAULT_EN_ADAPTIVE_ROUND;
+ output->q_round_inter = DEFAULT_Q_ROUND_INTER;
+ output->q_round_intra = DEFAULT_Q_ROUND_INTRA;
+
+ output->frame_rate = inst->frame_rate;
+ output->idr_period = ctrls->gop_size;
+ output->rc_mode = ctrls->bitrate_mode;
+ output->rc_update_speed = (ctrls->bitrate_mode) ? DEFAULT_RC_UPDATE_SPEED_CBR :
+ DEFAULT_RC_UPDATE_SPEED_VBR;
+ output->en_rate_control = ctrls->frame_rc_enable;
+ output->en_cu_level_rate_control = ctrls->mb_rc_enable;
+ output->max_intra_pic_bit = inst->dst_fmt.plane_fmt[0].sizeimage * 8;
+ output->max_inter_pic_bit = inst->dst_fmt.plane_fmt[0].sizeimage * 8;
+ output->bitrate = ctrls->bitrate;
+ output->cpb_size = wave6_cpb_size_msec(ctrls->h264.cpb_size, ctrls->bitrate);
+ output->slice_mode = ctrls->slice_mode;
+ output->slice_arg = ctrls->slice_max_mb;
+ output->forced_idr_header = ctrls->prepend_spspps_to_idr;
+ output->en_vbv_overflow_drop_frame = (ctrls->frame_skip_mode) ? 1 : 0;
+ if (ctrls->intra_refresh_period) {
+ output->intra_refresh_mode = INTRA_REFRESH_ROW;
+ if (ctrls->intra_refresh_period < num_ctu_row) {
+ output->intra_refresh_arg = (num_ctu_row + ctrls->intra_refresh_period - 1)
+ / ctrls->intra_refresh_period;
+ } else {
+ output->intra_refresh_arg = 1;
+ }
+ }
+ output->sar.enable = ctrls->h264.vui_sar_enable;
+ output->sar.idc = ctrls->h264.vui_sar_idc;
+ if (output->sar.idc == V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED)
+ output->sar.idc = H264_VUI_SAR_IDC_EXTENDED;
+ output->sar.width = ctrls->h264.vui_ext_sar_width;
+ output->sar.height = ctrls->h264.vui_ext_sar_height;
+ output->color.video_signal_type_present = DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG;
+ output->color.color_range = to_video_full_range_flag(inst->quantization);
+ output->color.color_description_present = DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG;
+ output->color.color_primaries = to_colour_primaries(inst->colorspace);
+ output->color.transfer_characteristics = to_transfer_characteristics(inst->colorspace,
+ inst->xfer_func);
+ output->color.matrix_coefficients = to_matrix_coeffs(inst->colorspace, inst->ycbcr_enc);
+ output->conf_win.left = inst->crop.left - inst->codec_rect.left;
+ output->conf_win.top = inst->crop.top - inst->codec_rect.top;
+ output->conf_win.right = inst->codec_rect.width
+ - inst->crop.width - output->conf_win.left;
+ output->conf_win.bottom = inst->codec_rect.height
+ - inst->crop.height - output->conf_win.top;
+
+ switch (inst->std) {
+ case W_AVC_ENC:
+ wave6_set_enc_h264_param(output, &ctrls->h264);
+ break;
+ case W_HEVC_ENC:
+ wave6_set_enc_hevc_param(output, &ctrls->hevc);
+ break;
+ default:
+ break;
+ }
+}
+
+static int wave6_vpu_enc_create_instance(struct vpu_instance *inst)
+{
+ int ret;
+ struct enc_open_param open_param;
+
+ memset(&open_param, 0, sizeof(struct enc_open_param));
+
+ wave6_vpu_activate(inst->dev);
+ ret = pm_runtime_resume_and_get(inst->dev->dev);
+ if (ret) {
+ dev_err(inst->dev->dev, "runtime_resume failed %d\n", ret);
+ return ret;
+ }
+
+ wave6_vpu_wait_activated(inst->dev);
+
+ inst->ar_vbuf.size = ALIGN(WAVE6_ARBUF_SIZE, 4096);
+ ret = wave6_alloc_dma(inst->dev->dev, &inst->ar_vbuf);
+ if (ret) {
+ dev_err(inst->dev->dev, "alloc ar of size %zu failed\n",
+ inst->ar_vbuf.size);
+ goto error_pm;
+ }
+
+ wave6_set_enc_open_param(&open_param, inst);
+
+ ret = wave6_vpu_enc_open(inst, &open_param);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed create instance : %d\n", ret);
+ goto error_open;
+ }
+
+ dprintk(inst->dev->dev, "[%d] encoder\n", inst->id);
+ wave6_vpu_create_dbgfs_file(inst);
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
+
+ return 0;
+
+error_open:
+ wave6_free_dma(&inst->ar_vbuf);
+error_pm:
+ pm_runtime_put_sync(inst->dev->dev);
+ return ret;
+}
+
+static int wave6_vpu_enc_initialize_instance(struct vpu_instance *inst)
+{
+ int ret;
+ struct enc_initial_info initial_info;
+ struct v4l2_ctrl *ctrl;
+
+ if (inst->enc_ctrls.mirror_direction) {
+ wave6_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL);
+ wave6_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION,
+ &inst->enc_ctrls.mirror_direction);
+ }
+ if (inst->enc_ctrls.rot_angle) {
+ wave6_vpu_enc_give_command(inst, ENABLE_ROTATION, NULL);
+ wave6_vpu_enc_give_command(inst, SET_ROTATION_ANGLE,
+ &inst->enc_ctrls.rot_angle);
+ }
+
+ ret = wave6_vpu_enc_issue_seq_init(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "seq init fail %d\n", ret);
+ return ret;
+ }
+
+ if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
+ dev_err(inst->dev->dev, "seq init timeout\n");
+ return ret;
+ }
+
+ ret = wave6_vpu_enc_complete_seq_init(inst, &initial_info);
+ if (ret) {
+ dev_err(inst->dev->dev, "seq init error\n");
+ return ret;
+ }
+
+ dev_dbg(inst->dev->dev, "min_fb_cnt : %d | min_src_cnt : %d\n",
+ initial_info.min_frame_buffer_count,
+ initial_info.min_src_frame_count);
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, initial_info.min_src_frame_count);
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
+
+ return 0;
+}
+
+static int wave6_vpu_enc_prepare_fb(struct vpu_instance *inst)
+{
+ int ret;
+ unsigned int i;
+ unsigned int fb_num;
+ unsigned int mv_num;
+ unsigned int fb_stride;
+ unsigned int fb_height;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+
+ fb_num = p_enc_info->initial_info.min_frame_buffer_count;
+ mv_num = p_enc_info->initial_info.req_mv_buffer_count;
+
+ fb_stride = ALIGN(inst->codec_rect.width, 32);
+ fb_height = ALIGN(inst->codec_rect.height, 32);
+
+ for (i = 0; i < fb_num; i++) {
+ struct frame_buffer *frame = &inst->frame_buf[i];
+ struct vpu_buf *vframe = &inst->frame_vbuf[i];
+ unsigned int l_size = fb_stride * fb_height;
+ unsigned int ch_size = ALIGN(fb_stride / 2, 32) * fb_height;
+
+ vframe->size = l_size + ch_size;
+ ret = wave6_alloc_dma(inst->dev->dev, vframe);
+ if (ret) {
+ dev_err(inst->dev->dev, "alloc FBC buffer fail : %zu\n",
+ vframe->size);
+ goto error;
+ }
+
+ frame->buf_y = vframe->daddr;
+ frame->buf_cb = vframe->daddr + l_size;
+ frame->buf_cr = (dma_addr_t)-1;
+ frame->stride = fb_stride;
+ frame->height = fb_height;
+ frame->map_type = COMPRESSED_FRAME_MAP;
+ }
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL, fb_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL, fb_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL, mv_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_allocate_aux_buffer(inst, AUX_BUF_SUB_SAMPLE, fb_num);
+ if (ret)
+ goto error;
+
+ ret = wave6_vpu_enc_register_frame_buffer_ex(inst, fb_num, fb_stride,
+ fb_height,
+ COMPRESSED_FRAME_MAP);
+ if (ret) {
+ dev_err(inst->dev->dev, "register frame buffer fail %d\n", ret);
+ goto error;
+ }
+
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
+
+ return 0;
+
+error:
+ wave6_vpu_enc_release_fb(inst);
+ return ret;
+}
+
+static int wave6_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane inst_format =
+ (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
+
+ dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d type %d\n",
+ __func__, *num_buffers, *num_planes, q->type);
+
+ if (*num_planes) {
+ if (inst_format.num_planes != *num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < inst_format.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = inst_format.num_planes;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "size[%d] : %d\n", i, sizes[i]);
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ struct v4l2_ctrl *ctrl;
+ unsigned int min_src_frame_count = 0;
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
+ if (ctrl)
+ min_src_frame_count = v4l2_ctrl_g_ctrl(ctrl);
+
+ *num_buffers = max(*num_buffers, min_src_frame_count);
+ }
+ }
+
+ return 0;
+}
+
+static void wave6_vpu_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
+
+ dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n",
+ vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
+ vbuf->sequence = inst->queued_src_buf_num++;
+
+ vpu_buf->ts_input = ktime_get_raw();
+ vpu_buf->force_key_frame = inst->enc_ctrls.force_key_frame;
+ inst->enc_ctrls.force_key_frame = false;
+ vpu_buf->force_frame_qp = (!inst->enc_ctrls.frame_rc_enable) ? true : false;
+ if (vpu_buf->force_frame_qp) {
+ if (inst->std == W_AVC_ENC) {
+ vpu_buf->force_i_frame_qp = inst->enc_ctrls.h264.i_frame_qp;
+ vpu_buf->force_p_frame_qp = inst->enc_ctrls.h264.p_frame_qp;
+ vpu_buf->force_b_frame_qp = inst->enc_ctrls.h264.b_frame_qp;
+ } else if (inst->std == W_HEVC_ENC) {
+ vpu_buf->force_i_frame_qp = inst->enc_ctrls.hevc.i_frame_qp;
+ vpu_buf->force_p_frame_qp = inst->enc_ctrls.hevc.p_frame_qp;
+ vpu_buf->force_b_frame_qp = inst->enc_ctrls.hevc.b_frame_qp;
+ }
+ }
+ } else {
+ inst->queued_dst_buf_num++;
+ }
+
+ vpu_buf->consumed = false;
+ vpu_buf->used = false;
+ v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
+}
+
+static void wave6_vpu_enc_buf_finish(struct vb2_buffer *vb)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
+ struct v4l2_ctrl *ctrl;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->type))
+ return;
+
+ ctrl = v4l2_ctrl_find(inst->v4l2_fh.ctrl_handler, V4L2_CID_MPEG_VIDEO_AVERAGE_QP);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp);
+}
+
+static int wave6_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane *fmt;
+ struct vb2_queue *vq_peer;
+ int ret = 0;
+
+ trace_start_streaming(inst, q->type);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ fmt = &inst->src_fmt;
+ vq_peer = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx);
+ } else {
+ fmt = &inst->dst_fmt;
+ vq_peer = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx);
+ }
+
+ dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers\n",
+ inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture",
+ fmt->pixelformat,
+ fmt->pixelformat >> 8,
+ fmt->pixelformat >> 16,
+ fmt->pixelformat >> 24,
+ fmt->width, fmt->height, vb2_get_num_buffers(q));
+
+ if (!vb2_is_streaming(vq_peer))
+ return 0;
+
+ wave6_vpu_pause(inst->dev->dev, 0);
+
+ if (inst->state == VPU_INST_STATE_NONE) {
+ ret = wave6_vpu_enc_create_instance(inst);
+ if (ret)
+ goto exit;
+ }
+
+ if (inst->state == VPU_INST_STATE_OPEN) {
+ ret = wave6_vpu_enc_initialize_instance(inst);
+ if (ret) {
+ wave6_vpu_enc_destroy_instance(inst);
+ goto exit;
+ }
+ }
+
+ if (inst->state == VPU_INST_STATE_INIT_SEQ) {
+ ret = wave6_vpu_enc_prepare_fb(inst);
+ if (ret) {
+ wave6_vpu_enc_destroy_instance(inst);
+ goto exit;
+ }
+ }
+
+exit:
+ wave6_vpu_pause(inst->dev->dev, 1);
+ if (ret)
+ wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_QUEUED);
+
+ return ret;
+}
+
+static void wave6_vpu_enc_stop_streaming(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct vb2_queue *vq_peer;
+
+ trace_stop_streaming(inst, q->type);
+
+ dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d\n",
+ inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture",
+ inst->queued_src_buf_num, inst->sequence);
+
+ if (inst->state == VPU_INST_STATE_NONE)
+ goto exit;
+
+ if (wave6_vpu_both_queues_are_streaming(inst))
+ wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP);
+
+ wave6_vpu_pause(inst->dev->dev, 0);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ wave6_vpu_reset_performance(inst);
+ inst->queued_src_buf_num = 0;
+ inst->processed_buf_num = 0;
+ inst->error_buf_num = 0;
+ inst->sequence = 0;
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
+ } else {
+ inst->eos = false;
+ inst->queued_dst_buf_num = 0;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ vq_peer = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx);
+ else
+ vq_peer = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx);
+
+ if (!vb2_is_streaming(vq_peer) && inst->state != VPU_INST_STATE_NONE)
+ wave6_vpu_enc_destroy_instance(inst);
+
+ wave6_vpu_pause(inst->dev->dev, 1);
+
+exit:
+ wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops wave6_vpu_enc_vb2_ops = {
+ .queue_setup = wave6_vpu_enc_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = wave6_vpu_enc_buf_queue,
+ .buf_finish = wave6_vpu_enc_buf_finish,
+ .start_streaming = wave6_vpu_enc_start_streaming,
+ .stop_streaming = wave6_vpu_enc_stop_streaming,
+};
+
+static void wave6_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
+ struct v4l2_pix_format_mplane *dst_fmt)
+{
+ const struct vpu_format *vpu_fmt;
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
+ if (vpu_fmt) {
+ src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ src_fmt->num_planes = vpu_fmt->num_planes;
+ wave6_update_pix_fmt(src_fmt,
+ W6_DEF_ENC_PIC_WIDTH, W6_DEF_ENC_PIC_HEIGHT);
+ }
+
+ vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
+ if (vpu_fmt) {
+ dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ dst_fmt->num_planes = vpu_fmt->num_planes;
+ wave6_update_pix_fmt(dst_fmt,
+ W6_DEF_ENC_PIC_WIDTH, W6_DEF_ENC_PIC_HEIGHT);
+ }
+}
+
+static int wave6_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct vpu_instance *inst = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->ops = &wave6_vpu_enc_vb2_ops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->buf_struct_size = sizeof(struct vpu_buffer);
+ src_vq->drv_priv = inst;
+ src_vq->lock = &inst->dev->dev_lock;
+ src_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->ops = &wave6_vpu_enc_vb2_ops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
+ dst_vq->drv_priv = inst;
+ dst_vq->lock = &inst->dev->dev_lock;
+ dst_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(dst_vq);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct vpu_instance_ops wave6_vpu_enc_inst_ops = {
+ .start_process = wave6_vpu_enc_start_encode,
+ .finish_process = wave6_vpu_enc_finish_encode,
+};
+
+static int wave6_vpu_open_enc(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_device *dev = video_drvdata(filp);
+ struct vpu_instance *inst = NULL;
+ struct v4l2_ctrl_handler *v4l2_ctrl_hdl;
+ int ret;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+ v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl;
+
+ inst->dev = dev;
+ inst->type = VPU_INST_TYPE_ENC;
+ inst->ops = &wave6_vpu_enc_inst_ops;
+
+ v4l2_fh_init(&inst->v4l2_fh, vdev);
+ filp->private_data = &inst->v4l2_fh;
+ v4l2_fh_add(&inst->v4l2_fh);
+
+ inst->v4l2_fh.m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev, inst, wave6_vpu_enc_queue_init);
+ if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
+ ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
+ goto free_inst;
+ }
+
+ v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ 0, 51, 1, 8);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+ 0, 51, 1, 51);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR,
+ BIT(V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA),
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
+ 0, 2047, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_2, 0,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ 0, 51, 1, 8);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ 0, 51, 1, 51);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ 0, 51, 1, 30);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
+ -12, 12, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0,
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ 0, 2047, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, 0, 1, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, 0,
+ V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+ 0, 0xFFFF, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+ 0, 0xFFFF, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_ROTATE,
+ 0, 270, 90, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+ 0, 18750000, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 1, 1500000000, 1, 2097152);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 0, 2047, 1, 30);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ 0, 0x3FFFF, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
+ V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
+ BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM),
+ V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
+ 0, 2160, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
+ V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT),
+ V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1, 0);
+
+ if (v4l2_ctrl_hdl->error) {
+ ret = -ENODEV;
+ goto err_m2m_release;
+ }
+
+ inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl;
+ v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
+
+ wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ wave6_update_crop_info(inst, 0, 0, inst->dst_fmt.width, inst->dst_fmt.height);
+ inst->colorspace = V4L2_COLORSPACE_DEFAULT;
+ inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ inst->quantization = V4L2_QUANTIZATION_DEFAULT;
+ inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ inst->frame_rate = 30;
+
+ return 0;
+
+err_m2m_release:
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+free_inst:
+ kfree(inst);
+ return ret;
+}
+
+static int wave6_vpu_enc_release(struct file *filp)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(filp->private_data);
+
+ dprintk(inst->dev->dev, "[%d] release\n", inst->id);
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+
+ mutex_lock(&inst->dev->dev_lock);
+ if (inst->state != VPU_INST_STATE_NONE) {
+ wave6_vpu_pause(inst->dev->dev, 0);
+ wave6_vpu_enc_destroy_instance(inst);
+ wave6_vpu_pause(inst->dev->dev, 1);
+ }
+ mutex_unlock(&inst->dev->dev_lock);
+
+ v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
+ v4l2_fh_del(&inst->v4l2_fh);
+ v4l2_fh_exit(&inst->v4l2_fh);
+ kfree(inst);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations wave6_vpu_enc_fops = {
+ .owner = THIS_MODULE,
+ .open = wave6_vpu_open_enc,
+ .release = wave6_vpu_enc_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+int wave6_vpu_enc_register_device(struct vpu_device *dev)
+{
+ struct video_device *vdev_enc;
+ int ret;
+
+ vdev_enc = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_enc), GFP_KERNEL);
+ if (!vdev_enc)
+ return -ENOMEM;
+
+ dev->video_dev_enc = vdev_enc;
+
+ strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name));
+ vdev_enc->fops = &wave6_vpu_enc_fops;
+ vdev_enc->ioctl_ops = &wave6_vpu_enc_ioctl_ops;
+ vdev_enc->release = video_device_release_empty;
+ vdev_enc->v4l2_dev = &dev->v4l2_dev;
+ vdev_enc->vfl_dir = VFL_DIR_M2M;
+ vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ vdev_enc->lock = &dev->dev_lock;
+ video_set_drvdata(vdev_enc, dev);
+
+ ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void wave6_vpu_enc_unregister_device(struct vpu_device *dev)
+{
+ video_unregister_device(dev->video_dev_enc);
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
new file mode 100644
index 000000000000..e614eda01a5a
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - v4l2 driver helper interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/clk.h>
+#include <linux/math64.h>
+#include "wave6-vpu.h"
+#include "wave6-vpu-dbg.h"
+#include "wave6-trace.h"
+
+void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ unsigned int width,
+ unsigned int height)
+{
+ const struct v4l2_format_info *fmt_info;
+ unsigned int stride_y;
+ int i;
+
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->flags = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+ memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+
+ fmt_info = v4l2_format_info(pix_mp->pixelformat);
+ if (!fmt_info) {
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ if (!pix_mp->plane_fmt[0].sizeimage)
+ pix_mp->plane_fmt[0].sizeimage = width * height;
+
+ return;
+ }
+
+ stride_y = width * fmt_info->bpp[0];
+ if (pix_mp->plane_fmt[0].bytesperline <= W6_MAX_PIC_STRIDE)
+ stride_y = max(stride_y, pix_mp->plane_fmt[0].bytesperline);
+ stride_y = round_up(stride_y, 32);
+ pix_mp->plane_fmt[0].bytesperline = stride_y;
+ pix_mp->plane_fmt[0].sizeimage = stride_y * height;
+
+ stride_y = DIV_ROUND_UP(stride_y, fmt_info->bpp[0]);
+
+ for (i = 1; i < fmt_info->comp_planes; i++) {
+ unsigned int stride_c, sizeimage_c;
+
+ stride_c = DIV_ROUND_UP(stride_y, fmt_info->hdiv) *
+ fmt_info->bpp[i];
+ sizeimage_c = stride_c * DIV_ROUND_UP(height, fmt_info->vdiv);
+
+ if (fmt_info->mem_planes == 1) {
+ pix_mp->plane_fmt[0].sizeimage += sizeimage_c;
+ } else {
+ pix_mp->plane_fmt[i].bytesperline = stride_c;
+ pix_mp->plane_fmt[i].sizeimage = sizeimage_c;
+ }
+ }
+}
+
+dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf, unsigned int plane_no)
+{
+ return vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, plane_no) +
+ buf->planes[plane_no].data_offset;
+}
+
+struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct vpu_instance *inst,
+ dma_addr_t addr)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vb2_v4l2_buffer *dst_buf = NULL;
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ if (addr == wave6_get_dma_addr(vb2_v4l2_buf, 0)) {
+ dst_buf = vb2_v4l2_buf;
+ break;
+ }
+ }
+
+ return dst_buf;
+}
+
+enum codec_std wave6_to_codec_std(enum vpu_instance_type type, unsigned int v4l2_pix_fmt)
+{
+ enum codec_std std = STD_UNKNOWN;
+
+ if (v4l2_pix_fmt == V4L2_PIX_FMT_H264)
+ std = (type == VPU_INST_TYPE_DEC) ? W_AVC_DEC : W_AVC_ENC;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_HEVC)
+ std = (type == VPU_INST_TYPE_DEC) ? W_HEVC_DEC : W_HEVC_ENC;
+
+ return std;
+}
+
+const char *wave6_vpu_instance_state_name(u32 state)
+{
+ switch (state) {
+ case VPU_INST_STATE_NONE: return "none";
+ case VPU_INST_STATE_OPEN: return "open";
+ case VPU_INST_STATE_INIT_SEQ: return "init_seq";
+ case VPU_INST_STATE_PIC_RUN: return "pic_run";
+ case VPU_INST_STATE_SEEK: return "seek";
+ case VPU_INST_STATE_STOP: return "stop";
+ }
+ return "unknown";
+}
+
+void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32 state)
+{
+ trace_set_state(inst, state);
+
+ dprintk(inst->dev->dev, "[%d] %s -> %s\n",
+ inst->id,
+ wave6_vpu_instance_state_name(inst->state),
+ wave6_vpu_instance_state_name(state));
+
+ inst->state = state;
+ if (state == VPU_INST_STATE_PIC_RUN && !inst->performance.ts_first)
+ inst->performance.ts_first = ktime_get_raw();
+}
+
+u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle)
+{
+ if (!vpu_dev || !vpu_dev->clk_vpu || !clk_get_rate(vpu_dev->clk_vpu))
+ return 0;
+
+ return (cycle * NSEC_PER_SEC) / clk_get_rate(vpu_dev->clk_vpu);
+}
+
+int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout)
+{
+ int ret;
+
+ ret = wait_for_completion_timeout(&inst->dev->irq_done,
+ msecs_to_jiffies(timeout));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ reinit_completion(&inst->dev->irq_done);
+
+ return 0;
+}
+
+int wave6_vpu_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ struct vpu_instance *inst = wave6_to_vpu_inst(fh);
+ bool is_decoder = (inst->type == VPU_INST_TYPE_DEC) ? true : false;
+
+ dev_dbg(inst->dev->dev, "%s: [%s] type: %d id: %d | flags: %d\n",
+ __func__, is_decoder ? "decoder" : "encoder", sub->type,
+ sub->id, sub->flags);
+
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ if (is_decoder)
+ return v4l2_src_change_event_subscribe(fh, sub);
+ return -EINVAL;
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+void wave6_vpu_return_buffers(struct vpu_instance *inst,
+ unsigned int type, enum vb2_buffer_state state)
+{
+ struct vb2_v4l2_buffer *buf;
+ int i;
+
+ if (V4L2_TYPE_IS_OUTPUT(type)) {
+ while ((buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buf, state);
+ } else {
+ while ((buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx))) {
+ for (i = 0; i < inst->dst_fmt.num_planes; i++)
+ vb2_set_plane_payload(&buf->vb2_buf, i, 0);
+ v4l2_m2m_buf_done(buf, state);
+ }
+ }
+}
+
+u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf;
+ u32 num = 0;
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
+ if (vpu_buf->consumed)
+ num++;
+ }
+
+ return num;
+}
+
+u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf;
+ u32 num = 0;
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
+ if (vpu_buf->used)
+ num++;
+ }
+
+ return num;
+}
+
+static bool wave6_vpu_check_fb_available(struct vpu_instance *inst)
+{
+ struct vb2_v4l2_buffer *vb2_v4l2_buf;
+ struct v4l2_m2m_buffer *v4l2_m2m_buf;
+ struct vpu_buffer *vpu_buf;
+
+ v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
+ vb2_v4l2_buf = &v4l2_m2m_buf->vb;
+ vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
+
+ if (!vpu_buf->used)
+ return true;
+ }
+
+ return false;
+}
+
+static int wave6_vpu_job_ready(void *priv)
+{
+ struct vpu_instance *inst = priv;
+
+ dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
+ inst->id, __func__, inst->state);
+
+ if (inst->type == VPU_INST_TYPE_DEC && inst->state == VPU_INST_STATE_OPEN)
+ return 1;
+ if (inst->state < VPU_INST_STATE_PIC_RUN)
+ return 0;
+ if (inst->state == VPU_INST_STATE_STOP && inst->eos)
+ return 0;
+ if (!wave6_vpu_check_fb_available(inst))
+ return 0;
+
+ return 1;
+}
+
+static void wave6_vpu_device_run_timeout(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct vpu_device *dev = container_of(dwork, struct vpu_device, task_timer);
+ struct vpu_instance *inst = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ struct vb2_v4l2_buffer *src_buf = NULL;
+ struct vb2_v4l2_buffer *dst_buf = NULL;
+
+ if (!inst)
+ return;
+
+ dev_err(inst->dev->dev, "[%d] sequence %d timeout\n", inst->id, inst->sequence);
+ src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (src_buf) {
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ if (inst->type == VPU_INST_TYPE_DEC)
+ inst->processed_buf_num++;
+ inst->error_buf_num++;
+ }
+
+ dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
+ if (dst_buf)
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+
+ vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx));
+ vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx));
+
+ v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx);
+}
+
+static void wave6_vpu_device_run(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ int ret;
+
+ dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
+ inst->id, __func__, inst->state);
+
+ ret = inst->ops->start_process(inst);
+ if (!ret)
+ schedule_delayed_work(&inst->dev->task_timer, msecs_to_jiffies(W6_VPU_TIMEOUT));
+ else
+ v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx);
+}
+
+void wave6_vpu_finish_job(struct vpu_instance *inst)
+{
+ cancel_delayed_work(&inst->dev->task_timer);
+ v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx);
+}
+
+void wave6_vpu_handle_performance(struct vpu_instance *inst, struct vpu_buffer *vpu_buf)
+{
+ s64 latency, time_spent;
+
+ if (!inst || !vpu_buf)
+ return;
+
+ inst->performance.ts_last = vpu_buf->ts_output;
+
+ latency = vpu_buf->ts_output - vpu_buf->ts_input;
+ time_spent = vpu_buf->ts_finish - vpu_buf->ts_start;
+
+ if (!inst->performance.latency_first)
+ inst->performance.latency_first = latency;
+ inst->performance.latency_max = max_t(s64, latency, inst->performance.latency_max);
+
+ if (!inst->performance.min_process_time)
+ inst->performance.min_process_time = time_spent;
+ else if (inst->performance.min_process_time > time_spent)
+ inst->performance.min_process_time = time_spent;
+
+ if (inst->performance.max_process_time < time_spent)
+ inst->performance.max_process_time = time_spent;
+
+ inst->performance.total_sw_time += time_spent;
+ inst->performance.total_hw_time += vpu_buf->hw_time;
+}
+
+void wave6_vpu_reset_performance(struct vpu_instance *inst)
+{
+ if (!inst)
+ return;
+
+ if (inst->processed_buf_num) {
+ s64 tmp;
+ s64 fps_act, fps_sw, fps_hw;
+ struct vpu_performance_info *perf = &inst->performance;
+
+ tmp = MSEC_PER_SEC * inst->processed_buf_num;
+ fps_act = DIV_ROUND_CLOSEST(tmp, (perf->ts_last - perf->ts_first) / NSEC_PER_MSEC);
+ fps_sw = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time / NSEC_PER_MSEC);
+ fps_hw = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time / NSEC_PER_MSEC);
+ dprintk(inst->dev->dev,
+ "[%d] fps actual: %lld, sw: %lld, hw: %lld, latency(ms) %llu.%06llu\n",
+ inst->id, fps_act, fps_sw, fps_hw,
+ perf->latency_first / NSEC_PER_MSEC,
+ perf->latency_first % NSEC_PER_MSEC);
+ }
+
+ memset(&inst->performance, 0, sizeof(inst->performance));
+}
+
+static const struct v4l2_m2m_ops wave6_vpu_m2m_ops = {
+ .device_run = wave6_vpu_device_run,
+ .job_ready = wave6_vpu_job_ready,
+};
+
+int wave6_vpu_init_m2m_dev(struct vpu_device *dev)
+{
+ dev->m2m_dev = v4l2_m2m_init(&wave6_vpu_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ dev_err(dev->dev, "v4l2_m2m_init fail: %ld\n", PTR_ERR(dev->m2m_dev));
+ return PTR_ERR(dev->m2m_dev);
+ }
+
+ INIT_DELAYED_WORK(&dev->task_timer, wave6_vpu_device_run_timeout);
+
+ return 0;
+}
+
+void wave6_vpu_release_m2m_dev(struct vpu_device *dev)
+{
+ v4l2_m2m_release(dev->m2m_dev);
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver
2025-02-10 9:07 ` [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver Nas Chung
@ 2025-02-17 18:33 ` Nicolas Dufresne
2025-02-19 4:36 ` Nas Chung
0 siblings, 1 reply; 34+ messages in thread
From: Nicolas Dufresne @ 2025-02-17 18:33 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim
Hi Nas.
Le lundi 10 février 2025 à 18:07 +0900, Nas Chung a écrit :
> Add v4l2 m2m drivers which support stateful decoder and encoder.
Before sending updates, note that this is quite short of a commit
message for a newly introduce driver. Your readers would certainly like
to know what feature have been included, what is not, etc. My
understanding from the discussion is that the Wave6 design can be
configured with a lot more features then what this driver covers.
I know you have placed some of that in the cover letter, but no one
will find it when later doing git blame.
regards,
Nicolas
>
> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
> ---
> .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++++
> .../chips-media/wave6/wave6-vpu-enc.c | 2698
> +++++++++++++++++
> .../chips-media/wave6/wave6-vpu-v4l2.c | 381 +++
> 3 files changed, 4962 insertions(+)
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
> vpu-dec.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
> vpu-enc.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
> vpu-v4l2.c
>
> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
> b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
> new file mode 100644
> index 000000000000..f6ed078a2824
> --- /dev/null
> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
> @@ -0,0 +1,1883 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Wave6 series multi-standard codec IP - v4l2 stateful decoder
> interface
> + *
> + * Copyright (C) 2025 CHIPS&MEDIA INC
> + */
> +
> +#include <linux/pm_runtime.h>
> +#include <linux/delay.h>
> +#include "wave6-vpu.h"
> +#include "wave6-vpu-dbg.h"
> +#include "wave6-trace.h"
> +
> +#define VPU_DEC_DEV_NAME "C&M Wave6 VPU decoder"
> +#define VPU_DEC_DRV_NAME "wave6-dec"
> +#define V4L2_CID_VPU_THUMBNAIL_MODE (V4L2_CID_USER_BASE + 0x1001)
> +
> +static const struct vpu_format wave6_vpu_dec_fmt_list[2][6] = {
> + [VPU_FMT_TYPE_CODEC] = {
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + },
> + [VPU_FMT_TYPE_RAW] = {
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 3,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
> + .max_width = W6_MAX_DEC_PIC_WIDTH,
> + .min_width = W6_MIN_DEC_PIC_WIDTH,
> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + }
> +};
> +
> +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst);
> +
> +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int
> v4l2_pix_fmt,
> + enum vpu_fmt_type
> type)
> +{
> + unsigned int index;
> +
> + for (index = 0; index <
> ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]); index++) {
> + if (wave6_vpu_dec_fmt_list[type][index].v4l2_pix_fmt
> == v4l2_pix_fmt)
> + return &wave6_vpu_dec_fmt_list[type][index];
> + }
> +
> + return NULL;
> +}
> +
> +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned
> int idx,
> + enum
> vpu_fmt_type type)
> +{
> + if (idx >= ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]))
> + return NULL;
> +
> + if (!wave6_vpu_dec_fmt_list[type][idx].v4l2_pix_fmt)
> + return NULL;
> +
> + return &wave6_vpu_dec_fmt_list[type][idx];
> +}
> +
> +static void wave6_vpu_dec_release_fb(struct vpu_instance *inst)
> +{
> + int i;
> +
> + for (i = 0; i < WAVE6_MAX_FBS; i++) {
> + wave6_free_dma(&inst->frame_vbuf[i]);
> + memset(&inst->frame_buf[i], 0, sizeof(struct
> frame_buffer));
> + wave6_free_dma(&inst-
> >aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
> + wave6_free_dma(&inst-
> >aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
> + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
> + }
> +}
> +
> +static void wave6_vpu_dec_destroy_instance(struct vpu_instance
> *inst)
> +{
> + u32 fail_res;
> + int ret;
> +
> + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst-
> >id);
> + wave6_vpu_remove_dbgfs_file(inst);
> +
> + ret = wave6_vpu_dec_close(inst, &fail_res);
> + if (ret) {
> + dev_err(inst->dev->dev, "failed destroy instance: %d
> (%d)\n",
> + ret, fail_res);
> + }
> +
> + wave6_vpu_dec_release_fb(inst);
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
> +
> + if (!pm_runtime_suspended(inst->dev->dev))
> + pm_runtime_put_sync(inst->dev->dev);
> +}
> +
> +static void wave6_handle_bitstream_buffer(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *src_buf;
> + u32 src_size = 0;
> + int ret;
> +
> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
> + if (src_buf) {
> + struct vpu_buffer *vpu_buf =
> wave6_to_vpu_buf(src_buf);
> + dma_addr_t rd_ptr = wave6_get_dma_addr(src_buf, 0);
> +
> + if (vpu_buf->consumed) {
> + dev_dbg(inst->dev->dev, "%s: Already
> consumed buffer\n",
> + __func__);
> + return;
> + }
> +
> + vpu_buf->ts_start = ktime_get_raw();
> + vpu_buf->consumed = true;
> + wave6_vpu_dec_set_rd_ptr(inst, rd_ptr, true);
> +
> + src_size = vb2_get_plane_payload(&src_buf->vb2_buf,
> 0);
> + }
> +
> + if (!src_size) {
> + dma_addr_t rd = 0, wr = 0;
> +
> + wave6_vpu_dec_get_bitstream_buffer(inst, &rd, &wr);
> + wave6_vpu_dec_set_rd_ptr(inst, wr, true);
> + }
> +
> + trace_dec_pic(inst, src_buf ? src_buf->vb2_buf.index : -1,
> src_size);
> +
> + ret = wave6_vpu_dec_update_bitstream_buffer(inst, src_size);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Update bitstream buffer
> fail %d\n",
> + __func__, ret);
> + return;
> + }
> +}
> +
> +static void wave6_update_pix_fmt_cap(struct v4l2_pix_format_mplane
> *pix_mp,
> + unsigned int width,
> + unsigned int height,
> + bool new_resolution)
> +{
> + unsigned int aligned_width;
> +
> + if (new_resolution)
> + pix_mp->plane_fmt[0].bytesperline = 0;
> +
> + aligned_width = round_up(width, 32);
> + wave6_update_pix_fmt(pix_mp, aligned_width, height);
> +}
> +
> +static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
> + enum aux_buffer_type type,
> + int num)
> +{
> + struct aux_buffer buf[WAVE6_MAX_FBS];
> + struct aux_buffer_info buf_info;
> + struct dec_aux_buffer_size_info size_info;
> + unsigned int size;
> + int i, ret;
> +
> + memset(buf, 0, sizeof(buf));
> +
> + size_info.width = inst->src_fmt.width;
> + size_info.height = inst->src_fmt.height;
> + size_info.type = type;
> +
> + ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info,
> &size);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Get size fail (type
> %d)\n", __func__, type);
> + return ret;
> + }
> +
> + num = min_t(u32, num, WAVE6_MAX_FBS);
> + for (i = 0; i < num; i++) {
> + inst->aux_vbuf[type][i].size = size;
> + ret = wave6_alloc_dma(inst->dev->dev, &inst-
> >aux_vbuf[type][i]);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Alloc fail
> (type %d)\n", __func__, type);
> + return ret;
> + }
> +
> + buf[i].index = i;
> + buf[i].addr = inst->aux_vbuf[type][i].daddr;
> + buf[i].size = inst->aux_vbuf[type][i].size;
> + }
> +
> + buf_info.type = type;
> + buf_info.num = num;
> + buf_info.buf_array = buf;
> +
> + ret = wave6_vpu_dec_register_aux_buffer(inst, buf_info);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Register fail (type
> %d)\n", __func__, type);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void wave6_vpu_dec_handle_dst_buffer(struct vpu_instance
> *inst)
> +{
> + struct vb2_v4l2_buffer *dst_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf;
> + dma_addr_t buf_addr_y, buf_addr_cb, buf_addr_cr;
> + u32 buf_size;
> + u32 fb_stride = inst->dst_fmt.plane_fmt[0].bytesperline;
> + u32 luma_size = fb_stride * inst->dst_fmt.height;
> + u32 chroma_size = (fb_stride / 2) * (inst->dst_fmt.height /
> 2);
> + struct frame_buffer disp_buffer = {0};
> + struct dec_initial_info initial_info = {0};
> + int consumed_num = wave6_vpu_get_consumed_fb_num(inst);
> + int ret;
> +
> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
> &initial_info);
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + dst_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(dst_buf);
> +
> + if (vpu_buf->consumed)
> + continue;
> +
> + if (consumed_num >= WAVE6_MAX_FBS)
> + break;
> +
> + if (inst->dst_fmt.num_planes == 1) {
> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
> 0);
> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
> + buf_addr_cb = buf_addr_y + luma_size;
> + buf_addr_cr = buf_addr_cb + chroma_size;
> + } else if (inst->dst_fmt.num_planes == 2) {
> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
> 0) +
> + vb2_plane_size(&dst_buf->vb2_buf,
> 1);
> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
> + buf_addr_cb = wave6_get_dma_addr(dst_buf,
> 1);
> + buf_addr_cr = buf_addr_cb + chroma_size;
> + } else if (inst->dst_fmt.num_planes == 3) {
> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
> 0) +
> + vb2_plane_size(&dst_buf->vb2_buf,
> 1) +
> + vb2_plane_size(&dst_buf->vb2_buf,
> 2);
> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
> + buf_addr_cb = wave6_get_dma_addr(dst_buf,
> 1);
> + buf_addr_cr = wave6_get_dma_addr(dst_buf,
> 2);
> + }
> + disp_buffer.buf_y = buf_addr_y;
> + disp_buffer.buf_cb = buf_addr_cb;
> + disp_buffer.buf_cr = buf_addr_cr;
> + disp_buffer.width = inst->src_fmt.width;
> + disp_buffer.height = inst->src_fmt.height;
> + disp_buffer.stride = fb_stride;
> + disp_buffer.map_type = LINEAR_FRAME_MAP;
> + disp_buffer.luma_bitdepth =
> initial_info.luma_bitdepth;
> + disp_buffer.chroma_bitdepth =
> initial_info.chroma_bitdepth;
> + disp_buffer.chroma_format_idc =
> initial_info.chroma_format_idc;
> +
> + ret = wave6_vpu_dec_register_display_buffer_ex(inst,
> disp_buffer);
> + if (ret) {
> + dev_err(inst->dev->dev, "fail register
> display buffer %d", ret);
> + break;
> + }
> +
> + vpu_buf->consumed = true;
> + consumed_num++;
> + }
> +}
> +
> +static enum v4l2_quantization to_v4l2_quantization(u32
> video_full_range_flag)
> +{
> + switch (video_full_range_flag) {
> + case 0:
> + return V4L2_QUANTIZATION_LIM_RANGE;
> + case 1:
> + return V4L2_QUANTIZATION_FULL_RANGE;
> + default:
> + return V4L2_QUANTIZATION_DEFAULT;
> + }
> +}
> +
> +static enum v4l2_colorspace to_v4l2_colorspace(u32 colour_primaries)
> +{
> + switch (colour_primaries) {
> + case 1:
> + return V4L2_COLORSPACE_REC709;
> + case 4:
> + return V4L2_COLORSPACE_470_SYSTEM_M;
> + case 5:
> + return V4L2_COLORSPACE_470_SYSTEM_BG;
> + case 6:
> + return V4L2_COLORSPACE_SMPTE170M;
> + case 7:
> + return V4L2_COLORSPACE_SMPTE240M;
> + case 9:
> + return V4L2_COLORSPACE_BT2020;
> + case 11:
> + return V4L2_COLORSPACE_DCI_P3;
> + default:
> + return V4L2_COLORSPACE_DEFAULT;
> + }
> +}
> +
> +static enum v4l2_xfer_func to_v4l2_xfer_func(u32
> transfer_characteristics)
> +{
> + switch (transfer_characteristics) {
> + case 1:
> + return V4L2_XFER_FUNC_709;
> + case 6:
> + return V4L2_XFER_FUNC_709;
> + case 7:
> + return V4L2_XFER_FUNC_SMPTE240M;
> + case 8:
> + return V4L2_XFER_FUNC_NONE;
> + case 13:
> + return V4L2_XFER_FUNC_SRGB;
> + case 14:
> + return V4L2_XFER_FUNC_709;
> + case 16:
> + return V4L2_XFER_FUNC_SMPTE2084;
> + default:
> + return V4L2_XFER_FUNC_DEFAULT;
> + }
> +}
> +
> +static enum v4l2_ycbcr_encoding to_v4l2_ycbcr_encoding(u32
> matrix_coeffs)
> +{
> + switch (matrix_coeffs) {
> + case 1:
> + return V4L2_YCBCR_ENC_709;
> + case 5:
> + return V4L2_YCBCR_ENC_601;
> + case 6:
> + return V4L2_YCBCR_ENC_601;
> + case 7:
> + return V4L2_YCBCR_ENC_SMPTE240M;
> + case 9:
> + return V4L2_YCBCR_ENC_BT2020;
> + case 10:
> + return V4L2_YCBCR_ENC_BT2020_CONST_LUM;
> + default:
> + return V4L2_YCBCR_ENC_DEFAULT;
> + }
> +}
> +
> +static void wave6_update_color_info(struct vpu_instance *inst,
> + struct dec_initial_info
> *initial_info)
> +{
> + struct color_param *color = &initial_info->color;
> +
> + if (!color->video_signal_type_present)
> + goto set_default_all;
> +
> + inst->quantization = to_v4l2_quantization(color-
> >color_range);
> +
> + if (!color->color_description_present)
> + goto set_default_color;
> +
> + inst->colorspace = to_v4l2_colorspace(color-
> >color_primaries);
> + inst->xfer_func = to_v4l2_xfer_func(color-
> >transfer_characteristics);
> + inst->ycbcr_enc = to_v4l2_ycbcr_encoding(color-
> >matrix_coefficients);
> +
> + return;
> +
> +set_default_all:
> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
> +set_default_color:
> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +}
> +
> +static enum v4l2_mpeg_video_hevc_profile to_v4l2_hevc_profile(u32
> profile)
> +{
> + switch (profile) {
> + case HEVC_PROFILE_MAIN:
> + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
> + default:
> + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
> + }
> +}
> +
> +static enum v4l2_mpeg_video_h264_profile to_v4l2_h264_profile(u32
> profile)
> +{
> + switch (profile) {
> + case H264_PROFILE_BP:
> + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
> + case H264_PROFILE_MP:
> + return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
> + case H264_PROFILE_EXTENDED:
> + return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
> + case H264_PROFILE_HP:
> + return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
> + default:
> + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
> + }
> +}
> +
> +static void wave6_update_v4l2_ctrls(struct vpu_instance *inst,
> + struct dec_initial_info *info)
> +{
> + struct v4l2_ctrl *ctrl;
> + u32 min_disp_cnt;
> +
> + min_disp_cnt = info->frame_buf_delay + 1;
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
> + if (ctrl)
> + v4l2_ctrl_s_ctrl(ctrl, min_disp_cnt);
> +
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_HEVC) {
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> +
> V4L2_CID_MPEG_VIDEO_HEVC_PROFILE);
> + if (ctrl)
> + v4l2_ctrl_s_ctrl(ctrl,
> to_v4l2_hevc_profile(info->profile));
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_H264) {
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> +
> V4L2_CID_MPEG_VIDEO_H264_PROFILE);
> + if (ctrl)
> + v4l2_ctrl_s_ctrl(ctrl,
> to_v4l2_h264_profile(info->profile));
> + }
> +}
> +
> +static int wave6_vpu_dec_start_decode(struct vpu_instance *inst)
> +{
> + struct dec_param pic_param;
> + int ret;
> + u32 fail_res = 0;
> +
> + memset(&pic_param, 0, sizeof(struct dec_param));
> +
> + wave6_handle_bitstream_buffer(inst);
> + if (inst->state == VPU_INST_STATE_OPEN) {
> + ret = wave6_vpu_dec_seek_header(inst);
> + if (ret) {
> + vb2_queue_error(v4l2_m2m_get_src_vq(inst-
> >v4l2_fh.m2m_ctx));
> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst-
> >v4l2_fh.m2m_ctx));
> + }
> + return -EAGAIN;
> + }
> +
> + wave6_vpu_dec_handle_dst_buffer(inst);
> +
> + ret = wave6_vpu_dec_start_one_frame(inst, &pic_param,
> &fail_res);
> + if (ret) {
> + struct vb2_v4l2_buffer *src_buf = NULL;
> +
> + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst-
> >id, __func__, ret);
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_STOP);
> +
> + src_buf = v4l2_m2m_src_buf_remove(inst-
> >v4l2_fh.m2m_ctx);
> + if (src_buf) {
> + v4l2_m2m_buf_done(src_buf,
> VB2_BUF_STATE_ERROR);
> + inst->sequence++;
> + inst->processed_buf_num++;
> + inst->error_buf_num++;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void wave6_handle_decoded_frame(struct vpu_instance *inst,
> + struct dec_output_info *info)
> +{
> + struct vb2_v4l2_buffer *src_buf;
> + struct vb2_v4l2_buffer *dst_buf;
> + struct vpu_buffer *vpu_buf;
> + enum vb2_buffer_state state;
> +
> + state = info->decoding_success ? VB2_BUF_STATE_DONE :
> VB2_BUF_STATE_ERROR;
> +
> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
> + if (!src_buf) {
> + dev_err(inst->dev->dev, "[%d] decoder can't find src
> buffer\n", inst->id);
> + return;
> + }
> +
> + vpu_buf = wave6_to_vpu_buf(src_buf);
> + if (!vpu_buf || !vpu_buf->consumed) {
> + dev_err(inst->dev->dev, "[%d] src buffer is not
> consumed\n", inst->id);
> + return;
> + }
> +
> + dst_buf = wave6_get_dst_buf_by_addr(inst, info-
> >frame_decoded_addr);
> + if (dst_buf) {
> + struct vpu_buffer *dst_vpu_buf =
> wave6_to_vpu_buf(dst_buf);
> +
> + if (wave6_to_vpu_buf(dst_buf)->used) {
> + dev_warn(inst->dev->dev, "[%d] duplication
> frame buffer\n", inst->id);
> + inst->sequence++;
> + }
> + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> + dst_vpu_buf->used = true;
> + if (state == VB2_BUF_STATE_ERROR)
> + dst_vpu_buf->error = true;
> + dst_vpu_buf->ts_input = vpu_buf->ts_input;
> + dst_vpu_buf->ts_start = vpu_buf->ts_start;
> + dst_vpu_buf->ts_finish = ktime_get_raw();
> + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst-
> >dev, info->cycle.frame_cycle);
> + }
> +
> + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
> src_buf);
> + if (state == VB2_BUF_STATE_ERROR) {
> + dprintk(inst->dev->dev, "[%d] error frame %d\n",
> inst->id, inst->sequence);
> + inst->error_buf_num++;
> + }
> + v4l2_m2m_buf_done(src_buf, state);
> + inst->processed_buf_num++;
> +}
> +
> +static void wave6_handle_skipped_frame(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *src_buf;
> + struct vpu_buffer *vpu_buf;
> +
> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
> + if (!src_buf)
> + return;
> +
> + vpu_buf = wave6_to_vpu_buf(src_buf);
> + if (!vpu_buf || !vpu_buf->consumed)
> + return;
> +
> + dprintk(inst->dev->dev, "[%d] skip frame %d\n", inst->id,
> inst->sequence);
> +
> + inst->sequence++;
> + inst->processed_buf_num++;
> + inst->error_buf_num++;
> + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
> src_buf);
> + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
> +}
> +
> +static void wave6_handle_display_frame(struct vpu_instance *inst,
> + dma_addr_t addr, enum
> vb2_buffer_state state)
> +{
> + struct vb2_v4l2_buffer *dst_buf;
> + struct vpu_buffer *vpu_buf;
> +
> + dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
> + if (!dst_buf)
> + return;
> +
> + vpu_buf = wave6_to_vpu_buf(dst_buf);
> + if (!vpu_buf->used) {
> + dprintk(inst->dev->dev, "[%d] recycle display
> buffer\n", inst->id);
> + vpu_buf->consumed = false;
> + return;
> + }
> +
> + if (inst->dst_fmt.num_planes == 1) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
> + inst-
> >dst_fmt.plane_fmt[0].sizeimage);
> + } else if (inst->dst_fmt.num_planes == 2) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
> + inst-
> >dst_fmt.plane_fmt[0].sizeimage);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
> + inst-
> >dst_fmt.plane_fmt[1].sizeimage);
> + } else if (inst->dst_fmt.num_planes == 3) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
> + inst-
> >dst_fmt.plane_fmt[0].sizeimage);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
> + inst-
> >dst_fmt.plane_fmt[1].sizeimage);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 2,
> + inst-
> >dst_fmt.plane_fmt[2].sizeimage);
> + }
> +
> + vpu_buf->ts_output = ktime_get_raw();
> + wave6_vpu_handle_performance(inst, vpu_buf);
> +
> + if (vpu_buf->error)
> + state = VB2_BUF_STATE_ERROR;
> + dst_buf->sequence = inst->sequence++;
> + dst_buf->field = V4L2_FIELD_NONE;
> + if (state == VB2_BUF_STATE_ERROR)
> + dprintk(inst->dev->dev, "[%d] discard frame %d\n",
> inst->id, dst_buf->sequence);
> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
> dst_buf);
> + v4l2_m2m_buf_done(dst_buf, state);
> +}
> +
> +static void wave6_handle_display_frames(struct vpu_instance *inst,
> + struct dec_output_info
> *info)
> +{
> + int i;
> +
> + for (i = 0; i < info->disp_frame_num; i++)
> + wave6_handle_display_frame(inst,
> + info->disp_frame_addr[i],
> + VB2_BUF_STATE_DONE);
> +}
> +
> +static void wave6_handle_discard_frames(struct vpu_instance *inst,
> + struct dec_output_info
> *info)
> +{
> + int i;
> +
> + for (i = 0; i < info->release_disp_frame_num; i++)
> + wave6_handle_display_frame(inst,
> + info-
> >release_disp_frame_addr[i],
> + VB2_BUF_STATE_ERROR);
> +}
> +
> +static void wave6_handle_last_frame(struct vpu_instance *inst,
> + struct vb2_v4l2_buffer *dst_buf)
> +{
> + if (!dst_buf) {
> + dst_buf = v4l2_m2m_dst_buf_remove(inst-
> >v4l2_fh.m2m_ctx);
> + if (!dst_buf) {
> + inst->next_buf_last = true;
> + return;
> + }
> + }
> +
> + if (inst->dst_fmt.num_planes == 1) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
> + } else if (inst->dst_fmt.num_planes == 2) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
> + } else if (inst->dst_fmt.num_planes == 3) {
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 2, 0);
> + }
> +
> + dst_buf->flags |= V4L2_BUF_FLAG_LAST;
> + dst_buf->field = V4L2_FIELD_NONE;
> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
> +
> + if (inst->state != VPU_INST_STATE_INIT_SEQ) {
> + dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
> + inst->eos = true;
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
> false);
> + }
> +}
> +
> +static void wave6_vpu_dec_retry_one_frame(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *src_buf;
> + struct vpu_buffer *vpu_buf;
> +
> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
> + if (!src_buf)
> + return;
> +
> + vpu_buf = wave6_to_vpu_buf(src_buf);
> + vpu_buf->consumed = false;
> +}
> +
> +static void wave6_vpu_dec_handle_source_change(struct vpu_instance
> *inst,
> + struct
> dec_initial_info *info)
> +{
> + static const struct v4l2_event vpu_event_src_ch = {
> + .type = V4L2_EVENT_SOURCE_CHANGE,
> + .u.src_change.changes =
> V4L2_EVENT_SRC_CH_RESOLUTION,
> + };
> +
> + dprintk(inst->dev->dev, "pic size %dx%d profile %d,
> min_fb_cnt : %d | min_disp_cnt : %d\n",
> + info->pic_width, info->pic_height,
> + info->profile, info->min_frame_buffer_count, info-
> >frame_buf_delay);
> +
> + wave6_vpu_dec_retry_one_frame(inst);
> + wave6_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO,
> NULL);
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
> +
> + inst->crop.left = info->pic_crop_rect.left;
> + inst->crop.top = info->pic_crop_rect.top;
> + inst->crop.width = info->pic_crop_rect.right - inst-
> >crop.left;
> + inst->crop.height = info->pic_crop_rect.bottom - inst-
> >crop.top;
> +
> + wave6_update_v4l2_ctrls(inst, info);
> + wave6_update_color_info(inst, info);
> + wave6_update_pix_fmt(&inst->src_fmt, info->pic_width, info-
> >pic_height);
> + wave6_update_pix_fmt_cap(&inst->dst_fmt,
> + info->pic_width, info->pic_height,
> + true);
> +
> + trace_source_change(inst, info);
> +
> + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_src_ch);
> +}
> +
> +static void wave6_vpu_dec_handle_decoding_warn_error(struct
> vpu_instance *inst,
> + struct
> dec_output_info *info)
> +{
> + if (info->warn_info)
> + dev_dbg(inst->dev->dev, "[%d] decoding %d warning
> 0x%x\n",
> + inst->id, inst->processed_buf_num, info-
> >warn_info);
> +
> + if (info->error_reason)
> + dev_err(inst->dev->dev, "[%d] decoding %d error
> 0x%x\n",
> + inst->id, inst->processed_buf_num, info-
> >error_reason);
> +}
> +
> +static void wave6_vpu_dec_finish_decode(struct vpu_instance *inst,
> bool error)
> +{
> + struct dec_output_info info;
> + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
> + int ret;
> +
> + ret = wave6_vpu_dec_get_output_info(inst, &info);
> + if (ret)
> + goto finish_decode;
> +
> + trace_dec_done(inst, &info);
> +
> + dev_dbg(inst->dev->dev, "dec %d dis %d noti_flag %d
> stream_end %d\n",
> + info.frame_decoded, info.frame_display,
> + info.notification_flags, info.stream_end);
> +
> + if (info.notification_flags & DEC_NOTI_FLAG_NO_FB) {
> + wave6_vpu_dec_retry_one_frame(inst);
> + goto finish_decode;
> + }
> +
> + if (info.notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) {
> + struct dec_initial_info initial_info = {0};
> +
> + v4l2_m2m_mark_stopped(m2m_ctx);
> +
> + if (info.frame_display)
> + wave6_handle_display_frames(inst, &info);
> +
> + if (info.release_disp_frame_num)
> + wave6_handle_discard_frames(inst, &info);
> +
> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
> &initial_info);
> + wave6_vpu_dec_handle_source_change(inst,
> &initial_info);
> +
> + wave6_handle_last_frame(inst, NULL);
> +
> + goto finish_decode;
> + }
> +
> + wave6_vpu_dec_handle_decoding_warn_error(inst, &info);
> +
> + if (info.frame_decoded)
> + wave6_handle_decoded_frame(inst, &info);
> + else
> + wave6_handle_skipped_frame(inst);
> +
> + if (info.frame_display)
> + wave6_handle_display_frames(inst, &info);
> +
> + if (info.release_disp_frame_num)
> + wave6_handle_discard_frames(inst, &info);
> +
> + if (info.stream_end && !inst->eos)
> + wave6_handle_last_frame(inst, NULL);
> +
> +finish_decode:
> + wave6_vpu_finish_job(inst);
> +}
> +
> +static int wave6_vpu_dec_querycap(struct file *file, void *fh,
> struct v4l2_capability *cap)
> +{
> + strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver));
> + strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card));
> + strscpy(cap->bus_info, "platform:" VPU_DEC_DRV_NAME,
> sizeof(cap->bus_info));
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_enum_framesizes(struct file *f, void *fh,
> struct v4l2_frmsizeenum *fsize)
> +{
> + const struct vpu_format *vpu_fmt;
> +
> + if (fsize->index)
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt) {
> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt)
> + return -EINVAL;
> + }
> +
> + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
> + fsize->stepwise.min_width = vpu_fmt->min_width;
> + fsize->stepwise.max_width = vpu_fmt->max_width;
> + fsize->stepwise.step_width = W6_DEC_PIC_SIZE_STEP;
> + fsize->stepwise.min_height = vpu_fmt->min_height;
> + fsize->stepwise.max_height = vpu_fmt->max_height;
> + fsize->stepwise.step_height = W6_DEC_PIC_SIZE_STEP;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_enum_fmt_cap(struct file *file, void *fh,
> struct v4l2_fmtdesc *f)
> +{
> + const struct vpu_format *vpu_fmt;
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt)
> + return -EINVAL;
> +
> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + f->flags = 0;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_try_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + const struct vpu_format *vpu_fmt;
> + int width, height;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + if (!V4L2_TYPE_IS_CAPTURE(f->type))
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt) {
> + width = inst->dst_fmt.width;
> + height = inst->dst_fmt.height;
> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
> + pix_mp->num_planes = inst->dst_fmt.num_planes;
> + } else {
> + width = clamp(pix_mp->width,
> + vpu_fmt->min_width, round_up(inst-
> >src_fmt.width, 32));
> + height = clamp(pix_mp->height,
> + vpu_fmt->min_height, inst-
> >src_fmt.height);
> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + pix_mp->num_planes = vpu_fmt->num_planes;
> + }
> +
> + if (inst->state >= VPU_INST_STATE_INIT_SEQ) {
> + width = inst->dst_fmt.width;
> + height = inst->dst_fmt.height;
> + }
> +
> + wave6_update_pix_fmt_cap(pix_mp, width, height, false);
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_s_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i, ret;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + ret = wave6_vpu_dec_try_fmt_cap(file, fh, f);
> + if (ret)
> + return ret;
> +
> + inst->dst_fmt.width = pix_mp->width;
> + inst->dst_fmt.height = pix_mp->height;
> + inst->dst_fmt.pixelformat = pix_mp->pixelformat;
> + inst->dst_fmt.field = pix_mp->field;
> + inst->dst_fmt.flags = pix_mp->flags;
> + inst->dst_fmt.num_planes = pix_mp->num_planes;
> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
> + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp-
> >plane_fmt[i].bytesperline;
> + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp-
> >plane_fmt[i].sizeimage;
> + }
> +
> + if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
> + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
> + inst->cbcr_interleave = true;
> + inst->nv21 = false;
> + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
> + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M)
> {
> + inst->cbcr_interleave = true;
> + inst->nv21 = true;
> + } else {
> + inst->cbcr_interleave = false;
> + inst->nv21 = false;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_g_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i;
> +
> + pix_mp->width = inst->dst_fmt.width;
> + pix_mp->height = inst->dst_fmt.height;
> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
> + pix_mp->field = inst->dst_fmt.field;
> + pix_mp->flags = inst->dst_fmt.flags;
> + pix_mp->num_planes = inst->dst_fmt.num_planes;
> + for (i = 0; i < pix_mp->num_planes; i++) {
> + pix_mp->plane_fmt[i].bytesperline = inst-
> >dst_fmt.plane_fmt[i].bytesperline;
> + pix_mp->plane_fmt[i].sizeimage = inst-
> >dst_fmt.plane_fmt[i].sizeimage;
> + }
> +
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_enum_fmt_out(struct file *file, void *fh,
> struct v4l2_fmtdesc *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + const struct vpu_format *vpu_fmt;
> +
> + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f-
> >index);
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt)
> + return -EINVAL;
> +
> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + f->flags = 0;
> + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
> V4L2_FMT_FLAG_COMPRESSED;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_try_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + const struct vpu_format *vpu_fmt;
> + int width, height;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + if (!V4L2_TYPE_IS_OUTPUT(f->type))
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt) {
> + width = inst->src_fmt.width;
> + height = inst->src_fmt.height;
> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
> + pix_mp->num_planes = inst->src_fmt.num_planes;
> + } else {
> + width = pix_mp->width;
> + height = pix_mp->height;
> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + pix_mp->num_planes = vpu_fmt->num_planes;
> + }
> +
> + wave6_update_pix_fmt(pix_mp, width, height);
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_s_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane in_pix_mp = f->fmt.pix_mp;
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i, ret;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + ret = wave6_vpu_dec_try_fmt_out(file, fh, f);
> + if (ret)
> + return ret;
> +
> + pix_mp->colorspace = in_pix_mp.colorspace;
> + pix_mp->ycbcr_enc = in_pix_mp.ycbcr_enc;
> + pix_mp->quantization = in_pix_mp.quantization;
> + pix_mp->xfer_func = in_pix_mp.xfer_func;
> +
> + inst->src_fmt.width = pix_mp->width;
> + inst->src_fmt.height = pix_mp->height;
> + inst->src_fmt.pixelformat = pix_mp->pixelformat;
> + inst->src_fmt.field = pix_mp->field;
> + inst->src_fmt.flags = pix_mp->flags;
> + inst->src_fmt.num_planes = pix_mp->num_planes;
> + for (i = 0; i < inst->src_fmt.num_planes; i++) {
> + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp-
> >plane_fmt[i].bytesperline;
> + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp-
> >plane_fmt[i].sizeimage;
> + }
> +
> + inst->colorspace = pix_mp->colorspace;
> + inst->ycbcr_enc = pix_mp->ycbcr_enc;
> + inst->quantization = pix_mp->quantization;
> + inst->xfer_func = pix_mp->xfer_func;
> +
> + wave6_update_pix_fmt_cap(&inst->dst_fmt,
> + pix_mp->width, pix_mp->height,
> + true);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_g_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i;
> +
> + pix_mp->width = inst->src_fmt.width;
> + pix_mp->height = inst->src_fmt.height;
> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
> + pix_mp->field = inst->src_fmt.field;
> + pix_mp->flags = inst->src_fmt.flags;
> + pix_mp->num_planes = inst->src_fmt.num_planes;
> + for (i = 0; i < pix_mp->num_planes; i++) {
> + pix_mp->plane_fmt[i].bytesperline = inst-
> >src_fmt.plane_fmt[i].bytesperline;
> + pix_mp->plane_fmt[i].sizeimage = inst-
> >src_fmt.plane_fmt[i].sizeimage;
> + }
> +
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_g_selection(struct file *file, void *fh,
> struct v4l2_selection *s)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> +
> + dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
> + __func__, s->type, s->target);
> +
> + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
> + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> + return -EINVAL;
> +
> + switch (s->target) {
> + case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> + s->r.left = 0;
> + s->r.top = 0;
> + s->r.width = inst->dst_fmt.width;
> + s->r.height = inst->dst_fmt.height;
> + break;
> + case V4L2_SEL_TGT_COMPOSE_PADDED:
> + case V4L2_SEL_TGT_COMPOSE:
> + s->r.left = 0;
> + s->r.top = 0;
> + if (inst->scaler_info.enable) {
> + s->r.width = inst->scaler_info.width;
> + s->r.height = inst->scaler_info.height;
> + } else if (inst->crop.width && inst->crop.height) {
> + s->r = inst->crop;
> + } else {
> + s->r.width = inst->src_fmt.width;
> + s->r.height = inst->src_fmt.height;
> + }
> + break;
> + case V4L2_SEL_TGT_CROP:
> + case V4L2_SEL_TGT_CROP_DEFAULT:
> + case V4L2_SEL_TGT_CROP_BOUNDS:
> + case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> + s->r.left = 0;
> + s->r.top = 0;
> + s->r.width = inst->src_fmt.width;
> + s->r.height = inst->src_fmt.height;
> + if (inst->crop.width && inst->crop.height)
> + s->r = inst->crop;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_s_selection(struct file *file, void *fh,
> struct v4l2_selection *s)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + int step = 4;
> + int scale_width, scale_height;
> + int min_scale_width, min_scale_height;
> +
> + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
> + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> + return -EINVAL;
> +
> + if (s->target != V4L2_SEL_TGT_COMPOSE)
> + return -EINVAL;
> +
> + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
> + s->flags |= V4L2_SEL_FLAG_LE;
> +
> + scale_width = clamp(s->r.width, W6_MIN_DEC_PIC_WIDTH,
> + round_up(inst->src_fmt.width, 32));
> + scale_height = clamp(s->r.height, W6_MIN_DEC_PIC_HEIGHT,
> + inst->src_fmt.height);
> + if (s->flags & V4L2_SEL_FLAG_GE) {
> + scale_width = round_up(scale_width, step);
> + scale_height = round_up(scale_height, step);
> + }
> + if (s->flags & V4L2_SEL_FLAG_LE) {
> + scale_width = round_down(scale_width, step);
> + scale_height = round_down(scale_height, step);
> + }
> +
> + if (scale_width < inst->src_fmt.width ||
> + scale_height < inst->src_fmt.height)
> + inst->scaler_info.enable = true;
> +
> + if (inst->scaler_info.enable) {
> + min_scale_width = ALIGN((inst->src_fmt.width / 8),
> step);
> + min_scale_height = ALIGN((inst->src_fmt.height / 8),
> step);
> +
> + if (scale_width < W6_MIN_DEC_PIC_WIDTH)
> + scale_width = W6_MIN_DEC_PIC_WIDTH;
> + if (scale_width < min_scale_width)
> + scale_width = min_scale_width;
> + if (scale_height < W6_MIN_DEC_PIC_HEIGHT)
> + scale_height = W6_MIN_DEC_PIC_HEIGHT;
> + if (scale_height < min_scale_height)
> + scale_height = min_scale_height;
> +
> + inst->scaler_info.width = scale_width;
> + inst->scaler_info.height = scale_height;
> + }
> +
> + s->r.left = 0;
> + s->r.top = 0;
> + s->r.width = scale_width;
> + s->r.height = scale_height;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_decoder_cmd(struct file *file, void *fh,
> struct v4l2_decoder_cmd *dc)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + int ret;
> +
> + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, dc->cmd);
> +
> + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
> + if (ret)
> + return ret;
> +
> + switch (dc->cmd) {
> + case V4L2_DEC_CMD_STOP:
> + dprintk(inst->dev->dev, "[%d] drain\n", inst->id);
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
> true);
> + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
> + break;
> + case V4L2_DEC_CMD_START:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops wave6_vpu_dec_ioctl_ops = {
> + .vidioc_querycap = wave6_vpu_dec_querycap,
> + .vidioc_enum_framesizes = wave6_vpu_dec_enum_framesizes,
> +
> + .vidioc_enum_fmt_vid_cap = wave6_vpu_dec_enum_fmt_cap,
> + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_dec_s_fmt_cap,
> + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_dec_g_fmt_cap,
> + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_dec_try_fmt_cap,
> +
> + .vidioc_enum_fmt_vid_out = wave6_vpu_dec_enum_fmt_out,
> + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_dec_s_fmt_out,
> + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_dec_g_fmt_out,
> + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_dec_try_fmt_out,
> +
> + .vidioc_g_selection = wave6_vpu_dec_g_selection,
> + .vidioc_s_selection = wave6_vpu_dec_s_selection,
> +
> + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
> + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
> + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
> + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
> + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
> + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
> + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
> + .vidioc_streamon = v4l2_m2m_ioctl_streamon,
> + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
> +
> + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
> + .vidioc_decoder_cmd = wave6_vpu_dec_decoder_cmd,
> +
> + .vidioc_subscribe_event = wave6_vpu_subscribe_event,
> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +};
> +
> +static int wave6_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
> +
> + trace_s_ctrl(inst, ctrl);
> +
> + dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
> + __func__, ctrl->name, ctrl->val);
> +
> + switch (ctrl->id) {
> + case V4L2_CID_VPU_THUMBNAIL_MODE:
> + inst->thumbnail_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
> + inst->disp_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
> + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
> + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
> + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops wave6_vpu_dec_ctrl_ops = {
> + .s_ctrl = wave6_vpu_dec_s_ctrl,
> +};
> +
> +static const struct v4l2_ctrl_config wave6_vpu_thumbnail_mode = {
> + .ops = &wave6_vpu_dec_ctrl_ops,
> + .id = V4L2_CID_VPU_THUMBNAIL_MODE,
> + .name = "thumbnail mode",
> + .type = V4L2_CTRL_TYPE_BOOLEAN,
> + .def = 0,
> + .min = 0,
> + .max = 1,
> + .step = 1,
> + .flags = V4L2_CTRL_FLAG_WRITE_ONLY,
> +};
> +
> +static void wave6_set_dec_openparam(struct dec_open_param
> *open_param,
> + struct vpu_instance *inst)
> +{
> + open_param->inst_buffer.temp_base = inst->dev-
> >temp_vbuf.daddr;
> + open_param->inst_buffer.temp_size = inst->dev-
> >temp_vbuf.size;
> + open_param->bs_mode = BS_MODE_PIC_END;
> + open_param->stream_endian = VPU_STREAM_ENDIAN;
> + open_param->frame_endian = VPU_FRAME_ENDIAN;
> + open_param->disp_mode = inst->disp_mode;
> +}
> +
> +static int wave6_vpu_dec_create_instance(struct vpu_instance *inst)
> +{
> + int ret;
> + struct dec_open_param open_param;
> +
> + memset(&open_param, 0, sizeof(struct dec_open_param));
> +
> + wave6_vpu_activate(inst->dev);
> + ret = pm_runtime_resume_and_get(inst->dev->dev);
> + if (ret) {
> + dev_err(inst->dev->dev, "runtime_resume failed
> %d\n", ret);
> + return ret;
> + }
> +
> + wave6_vpu_wait_activated(inst->dev);
> +
> + inst->std = wave6_to_codec_std(inst->type, inst-
> >src_fmt.pixelformat);
> + if (inst->std == STD_UNKNOWN) {
> + dev_err(inst->dev->dev, "unsupported pixelformat:
> %.4s\n",
> + (char *)&inst->src_fmt.pixelformat);
> + ret = -EINVAL;
> + goto error_pm;
> + }
> +
> + wave6_set_dec_openparam(&open_param, inst);
> +
> + ret = wave6_vpu_dec_open(inst, &open_param);
> + if (ret) {
> + dev_err(inst->dev->dev, "failed create instance :
> %d\n", ret);
> + goto error_pm;
> + }
> +
> + dprintk(inst->dev->dev, "[%d] decoder\n", inst->id);
> +
> + if (inst->thumbnail_mode)
> + wave6_vpu_dec_give_command(inst,
> ENABLE_DEC_THUMBNAIL_MODE, NULL);
> +
> + wave6_vpu_create_dbgfs_file(inst);
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
> + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = true;
> + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, true);
> +
> + return 0;
> +
> +error_pm:
> + pm_runtime_put_sync(inst->dev->dev);
> +
> + return ret;
> +}
> +
> +static int wave6_vpu_dec_prepare_fb(struct vpu_instance *inst)
> +{
> + int ret;
> + unsigned int i;
> + unsigned int fb_num;
> + unsigned int mv_num;
> + unsigned int fb_stride;
> + unsigned int fb_height;
> + struct dec_info *p_dec_info = &inst->codec_info->dec_info;
> +
> + fb_num = p_dec_info->initial_info.min_frame_buffer_count;
> + mv_num = p_dec_info->initial_info.req_mv_buffer_count;
> +
> + fb_stride = ALIGN(inst->src_fmt.width, 32);
> + fb_height = ALIGN(inst->src_fmt.height, 32);
> +
> + for (i = 0; i < fb_num; i++) {
> + struct frame_buffer *frame = &inst->frame_buf[i];
> + struct vpu_buf *vframe = &inst->frame_vbuf[i];
> + unsigned int l_size = fb_stride * fb_height;
> + unsigned int ch_size = ALIGN(fb_stride / 2, 32) *
> fb_height;
> +
> + vframe->size = l_size + ch_size;
> + ret = wave6_alloc_dma(inst->dev->dev, vframe);
> + if (ret) {
> + dev_err(inst->dev->dev, "alloc FBC buffer
> fail : %zu\n",
> + vframe->size);
> + goto error;
> + }
> +
> + frame->buf_y = vframe->daddr;
> + frame->buf_cb = vframe->daddr + l_size;
> + frame->buf_cr = (dma_addr_t)-1;
> + frame->width = inst->src_fmt.width;
> + frame->stride = fb_stride;
> + frame->height = fb_height;
> + frame->map_type = COMPRESSED_FRAME_MAP;
> + }
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL,
> fb_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL,
> fb_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL,
> mv_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_vpu_dec_register_frame_buffer_ex(inst, fb_num,
> fb_stride,
> + fb_height,
> +
> COMPRESSED_FRAME_MAP);
> + if (ret) {
> + dev_err(inst->dev->dev, "register frame buffer fail
> %d\n", ret);
> + goto error;
> + }
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
> +
> + return 0;
> +
> +error:
> + wave6_vpu_dec_release_fb(inst);
> + return ret;
> +}
> +
> +static int wave6_vpu_dec_queue_setup(struct vb2_queue *q, unsigned
> int *num_buffers,
> + unsigned int *num_planes,
> unsigned int sizes[],
> + struct device *alloc_devs[])
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct v4l2_pix_format_mplane inst_format =
> + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt :
> inst->dst_fmt;
> + unsigned int i;
> +
> + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d
> type %d\n",
> + __func__, *num_buffers, *num_planes, q->type);
> +
> + if (*num_planes) {
> + if (inst_format.num_planes != *num_planes)
> + return -EINVAL;
> +
> + for (i = 0; i < *num_planes; i++) {
> + if (sizes[i] <
> inst_format.plane_fmt[i].sizeimage)
> + return -EINVAL;
> + }
> + } else {
> + *num_planes = inst_format.num_planes;
> + for (i = 0; i < *num_planes; i++) {
> + sizes[i] =
> inst_format.plane_fmt[i].sizeimage;
> + dev_dbg(inst->dev->dev, "size[%d] : %d\n",
> i, sizes[i]);
> + }
> +
> + if (V4L2_TYPE_IS_CAPTURE(q->type)) {
> + struct v4l2_ctrl *ctrl;
> + unsigned int min_disp_cnt = 0;
> +
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> +
> V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
> + if (ctrl)
> + min_disp_cnt =
> v4l2_ctrl_g_ctrl(ctrl);
> +
> + *num_buffers = max(*num_buffers,
> min_disp_cnt);
> +
> + if (*num_buffers > WAVE6_MAX_FBS)
> + *num_buffers = min_disp_cnt;
> + }
> + }
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type) &&
> + inst->state == VPU_INST_STATE_SEEK) {
> + wave6_vpu_pause(inst->dev->dev, 0);
> + wave6_vpu_dec_destroy_instance(inst);
> + wave6_vpu_pause(inst->dev->dev, 1);
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst)
> +{
> + struct dec_initial_info initial_info;
> + int ret;
> +
> + memset(&initial_info, 0, sizeof(struct dec_initial_info));
> +
> + ret = wave6_vpu_dec_issue_seq_init(inst);
> + if (ret) {
> + dev_err(inst->dev->dev, "failed
> wave6_vpu_dec_issue_seq_init %d\n", ret);
> + return ret;
> + }
> +
> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0)
> + dev_err(inst->dev->dev, "failed to call
> vpu_wait_interrupt()\n");
> +
> + ret = wave6_vpu_dec_complete_seq_init(inst, &initial_info);
> + if (ret) {
> + dev_err(inst->dev->dev, "vpu_dec_complete_seq_init:
> %d, reason : 0x%x\n",
> + ret, initial_info.err_reason);
> + if ((initial_info.err_reason &
> WAVE6_SYSERR_NOT_SUPPORT) ||
> + (initial_info.err_reason &
> WAVE6_SYSERR_NOT_SUPPORT_PROFILE)) {
> + ret = -EINVAL;
> + } else if ((initial_info.err_reason &
> HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND) ||
> + (initial_info.err_reason &
> AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND)) {
> + wave6_handle_skipped_frame(inst);
> + ret = 0;
> + }
> + } else {
> + wave6_vpu_dec_handle_source_change(inst,
> &initial_info);
> + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = false;
> + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx,
> false);
> + if (vb2_is_streaming(v4l2_m2m_get_dst_vq(inst-
> >v4l2_fh.m2m_ctx)))
> + wave6_handle_last_frame(inst, NULL);
> + }
> +
> + return ret;
> +}
> +
> +static void wave6_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
> +{
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
> +
> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
> size[1] : %4ld | size[2] : %4ld\n",
> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
> 0),
> + vb2_plane_size(&vbuf->vb2_buf, 1),
> vb2_plane_size(&vbuf->vb2_buf, 2));
> +
> + vbuf->sequence = inst->queued_src_buf_num++;
> + vpu_buf->ts_input = ktime_get_raw();
> +
> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
> +}
> +
> +static void wave6_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
> +{
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
> +
> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
> size[1] : %4ld | size[2] : %4ld\n",
> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
> 0),
> + vb2_plane_size(&vbuf->vb2_buf, 1),
> vb2_plane_size(&vbuf->vb2_buf, 2));
> +
> + inst->queued_dst_buf_num++;
> + if (inst->next_buf_last) {
> + wave6_handle_last_frame(inst, vbuf);
> + inst->next_buf_last = false;
> + } else {
> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
> + }
> +}
> +
> +static void wave6_vpu_dec_buf_queue(struct vb2_buffer *vb)
> +{
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
> +
> + vpu_buf->consumed = false;
> + vpu_buf->used = false;
> + vpu_buf->error = false;
> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
> + wave6_vpu_dec_buf_queue_src(vb);
> + else
> + wave6_vpu_dec_buf_queue_dst(vb);
> +}
> +
> +static int wave6_vpu_dec_start_streaming(struct vb2_queue *q,
> unsigned int count)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct v4l2_pix_format_mplane *fmt;
> + int ret = 0;
> +
> + trace_start_streaming(inst, q->type);
> +
> + wave6_vpu_pause(inst->dev->dev, 0);
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> + fmt = &inst->src_fmt;
> + if (inst->state == VPU_INST_STATE_NONE) {
> + ret = wave6_vpu_dec_create_instance(inst);
> + if (ret)
> + goto exit;
> + }
> +
> + if (inst->state == VPU_INST_STATE_SEEK)
> + wave6_vpu_set_instance_state(inst, inst-
> >state_in_seek);
> + } else {
> + fmt = &inst->dst_fmt;
> + if (inst->state == VPU_INST_STATE_INIT_SEQ) {
> + ret = wave6_vpu_dec_prepare_fb(inst);
> + if (ret)
> + goto exit;
> + }
> + }
> +
> +exit:
> + wave6_vpu_pause(inst->dev->dev, 1);
> + if (ret)
> + wave6_vpu_return_buffers(inst, q->type,
> VB2_BUF_STATE_QUEUED);
> +
> + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers,
> ret = %d\n",
> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
> "capture",
> + fmt->pixelformat,
> + fmt->pixelformat >> 8,
> + fmt->pixelformat >> 16,
> + fmt->pixelformat >> 24,
> + fmt->width, fmt->height, vb2_get_num_buffers(q),
> ret);
> +
> + return ret;
> +}
> +
> +static void wave6_vpu_dec_stop_streaming(struct vb2_queue *q)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
> +
> + trace_stop_streaming(inst, q->type);
> +
> + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d error
> %d\n",
> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
> "capture",
> + inst->queued_src_buf_num, inst->processed_buf_num,
> inst->error_buf_num);
> +
> + if (inst->state == VPU_INST_STATE_NONE)
> + goto exit;
> +
> + wave6_vpu_pause(inst->dev->dev, 0);
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> + wave6_vpu_reset_performance(inst);
> + inst->queued_src_buf_num = 0;
> + inst->processed_buf_num = 0;
> + inst->error_buf_num = 0;
> + inst->state_in_seek = inst->state;
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
> false);
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_SEEK);
> + inst->sequence = 0;
> + } else {
> + if (v4l2_m2m_has_stopped(m2m_ctx))
> + v4l2_m2m_clear_state(m2m_ctx);
> +
> + inst->eos = false;
> + inst->queued_dst_buf_num = 0;
> + inst->sequence = 0;
> + wave6_vpu_dec_flush_instance(inst);
> + }
> +
> + wave6_vpu_pause(inst->dev->dev, 1);
> +
> +exit:
> + wave6_vpu_return_buffers(inst, q->type,
> VB2_BUF_STATE_ERROR);
> +}
> +
> +static int wave6_vpu_dec_buf_init(struct vb2_buffer *vb)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
> + struct dec_initial_info initial_info = {0};
> + int i;
> +
> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
> + return 0;
> +
> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
> &initial_info);
> + if (initial_info.chroma_format_idc != YUV400)
> + return 0;
> +
> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
> + void *vaddr = vb2_plane_vaddr(vb, i);
> +
> + if (vaddr)
> + memset(vaddr, 0x80, vb2_plane_size(vb, i));
> + }
> +
> + return 0;
> +}
> +
> +static const struct vb2_ops wave6_vpu_dec_vb2_ops = {
> + .queue_setup = wave6_vpu_dec_queue_setup,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
> + .buf_queue = wave6_vpu_dec_buf_queue,
> + .start_streaming = wave6_vpu_dec_start_streaming,
> + .stop_streaming = wave6_vpu_dec_stop_streaming,
> + .buf_init = wave6_vpu_dec_buf_init,
> +};
> +
> +static void wave6_set_default_format(struct v4l2_pix_format_mplane
> *src_fmt,
> + struct v4l2_pix_format_mplane
> *dst_fmt)
> +{
> + const struct vpu_format *vpu_fmt;
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
> + if (vpu_fmt) {
> + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + src_fmt->num_planes = vpu_fmt->num_planes;
> + wave6_update_pix_fmt(src_fmt,
> + W6_DEF_DEC_PIC_WIDTH,
> W6_DEF_DEC_PIC_HEIGHT);
> + }
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
> + if (vpu_fmt) {
> + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + dst_fmt->num_planes = vpu_fmt->num_planes;
> + wave6_update_pix_fmt_cap(dst_fmt,
> + W6_DEF_DEC_PIC_WIDTH,
> W6_DEF_DEC_PIC_HEIGHT,
> + true);
> + }
> +}
> +
> +static int wave6_vpu_dec_queue_init(void *priv, struct vb2_queue
> *src_vq, struct vb2_queue *dst_vq)
> +{
> + struct vpu_instance *inst = priv;
> + int ret;
> +
> + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> + src_vq->mem_ops = &vb2_dma_contig_memops;
> + src_vq->ops = &wave6_vpu_dec_vb2_ops;
> + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> + src_vq->buf_struct_size = sizeof(struct vpu_buffer);
> + src_vq->min_queued_buffers = 1;
> + src_vq->drv_priv = inst;
> + src_vq->lock = &inst->dev->dev_lock;
> + src_vq->dev = inst->dev->v4l2_dev.dev;
> + ret = vb2_queue_init(src_vq);
> + if (ret)
> + return ret;
> +
> + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> + dst_vq->mem_ops = &vb2_dma_contig_memops;
> + dst_vq->ops = &wave6_vpu_dec_vb2_ops;
> + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> + dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
> + dst_vq->min_queued_buffers = 1;
> + dst_vq->drv_priv = inst;
> + dst_vq->lock = &inst->dev->dev_lock;
> + dst_vq->dev = inst->dev->v4l2_dev.dev;
> + ret = vb2_queue_init(dst_vq);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static const struct vpu_instance_ops wave6_vpu_dec_inst_ops = {
> + .start_process = wave6_vpu_dec_start_decode,
> + .finish_process = wave6_vpu_dec_finish_decode,
> +};
> +
> +static int wave6_vpu_open_dec(struct file *filp)
> +{
> + struct video_device *vdev = video_devdata(filp);
> + struct vpu_device *dev = video_drvdata(filp);
> + struct vpu_instance *inst = NULL;
> + int ret;
> +
> + inst = kzalloc(sizeof(*inst), GFP_KERNEL);
> + if (!inst)
> + return -ENOMEM;
> +
> + inst->dev = dev;
> + inst->type = VPU_INST_TYPE_DEC;
> + inst->ops = &wave6_vpu_dec_inst_ops;
> +
> + v4l2_fh_init(&inst->v4l2_fh, vdev);
> + filp->private_data = &inst->v4l2_fh;
> + v4l2_fh_add(&inst->v4l2_fh);
> +
> + inst->v4l2_fh.m2m_ctx =
> + v4l2_m2m_ctx_init(dev->m2m_dev, inst,
> wave6_vpu_dec_queue_init);
> + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
> + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
> + goto free_inst;
> + }
> +
> + v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10);
> + v4l2_ctrl_new_custom(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_thumbnail_mode, NULL);
> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_dec_ctrl_ops,
> + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32,
> 1, 1);
> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_dec_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
> + 0, 0, 1, 0);
> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_dec_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_dec_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
> + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl,
> &wave6_vpu_dec_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
> +
> V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
> +
> + if (inst->v4l2_ctrl_hdl.error) {
> + ret = -ENODEV;
> + goto err_m2m_release;
> + }
> +
> + inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl;
> + v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl);
> +
> + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +
> + return 0;
> +
> +err_m2m_release:
> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
> +free_inst:
> + kfree(inst);
> + return ret;
> +}
> +
> +static int wave6_vpu_dec_release(struct file *filp)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(filp-
> >private_data);
> +
> + dprintk(inst->dev->dev, "[%d] release\n", inst->id);
> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
> +
> + mutex_lock(&inst->dev->dev_lock);
> + if (inst->state != VPU_INST_STATE_NONE) {
> + wave6_vpu_pause(inst->dev->dev, 0);
> + wave6_vpu_dec_destroy_instance(inst);
> + wave6_vpu_pause(inst->dev->dev, 1);
> + }
> + mutex_unlock(&inst->dev->dev_lock);
> +
> + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
> + v4l2_fh_del(&inst->v4l2_fh);
> + v4l2_fh_exit(&inst->v4l2_fh);
> + kfree(inst);
> +
> + return 0;
> +}
> +
> +static const struct v4l2_file_operations wave6_vpu_dec_fops = {
> + .owner = THIS_MODULE,
> + .open = wave6_vpu_open_dec,
> + .release = wave6_vpu_dec_release,
> + .unlocked_ioctl = video_ioctl2,
> + .poll = v4l2_m2m_fop_poll,
> + .mmap = v4l2_m2m_fop_mmap,
> +};
> +
> +int wave6_vpu_dec_register_device(struct vpu_device *dev)
> +{
> + struct video_device *vdev_dec;
> + int ret;
> +
> + vdev_dec = devm_kzalloc(dev->v4l2_dev.dev,
> sizeof(*vdev_dec), GFP_KERNEL);
> + if (!vdev_dec)
> + return -ENOMEM;
> +
> + dev->video_dev_dec = vdev_dec;
> +
> + strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec-
> >name));
> + vdev_dec->fops = &wave6_vpu_dec_fops;
> + vdev_dec->ioctl_ops = &wave6_vpu_dec_ioctl_ops;
> + vdev_dec->release = video_device_release_empty;
> + vdev_dec->v4l2_dev = &dev->v4l2_dev;
> + vdev_dec->vfl_dir = VFL_DIR_M2M;
> + vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
> V4L2_CAP_STREAMING;
> + vdev_dec->lock = &dev->dev_lock;
> + video_set_drvdata(vdev_dec, dev);
> +
> + ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +void wave6_vpu_dec_unregister_device(struct vpu_device *dev)
> +{
> + video_unregister_device(dev->video_dev_dec);
> +}
> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
> b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
> new file mode 100644
> index 000000000000..36417a7fef99
> --- /dev/null
> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
> @@ -0,0 +1,2698 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Wave6 series multi-standard codec IP - v4l2 stateful encoder
> interface
> + *
> + * Copyright (C) 2025 CHIPS&MEDIA INC
> + */
> +
> +#include <linux/pm_runtime.h>
> +#include "wave6-vpu.h"
> +#include "wave6-vpu-dbg.h"
> +#include "wave6-trace.h"
> +
> +#define VPU_ENC_DEV_NAME "C&M Wave6 VPU encoder"
> +#define VPU_ENC_DRV_NAME "wave6-enc"
> +
> +static const struct vpu_format wave6_vpu_enc_fmt_list[2][23] = {
> + [VPU_FMT_TYPE_CODEC] = {
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + },
> + [VPU_FMT_TYPE_RAW] = {
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUYV,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV24,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV24,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV42,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 3,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 3,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 2,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGB24,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_P010,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB32,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_XRGB32,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBA32,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBX32,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + {
> + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB2101010,
> + .max_width = W6_MAX_ENC_PIC_WIDTH,
> + .min_width = W6_MIN_ENC_PIC_WIDTH,
> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
> + .num_planes = 1,
> + },
> + }
> +};
> +
> +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int
> v4l2_pix_fmt,
> + enum vpu_fmt_type
> type)
> +{
> + unsigned int index;
> +
> + for (index = 0; index <
> ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]); index++) {
> + if (wave6_vpu_enc_fmt_list[type][index].v4l2_pix_fmt
> == v4l2_pix_fmt)
> + return &wave6_vpu_enc_fmt_list[type][index];
> + }
> +
> + return NULL;
> +}
> +
> +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned
> int idx,
> + enum
> vpu_fmt_type type)
> +{
> + if (idx >= ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]))
> + return NULL;
> +
> + if (!wave6_vpu_enc_fmt_list[type][idx].v4l2_pix_fmt)
> + return NULL;
> +
> + return &wave6_vpu_enc_fmt_list[type][idx];
> +}
> +
> +static u32 wave6_cpb_size_msec(u32 cpb_size_kb, u32 bitrate)
> +{
> + u64 cpb_size_bit;
> + u64 cpb_size_msec;
> +
> + cpb_size_bit = (u64)cpb_size_kb * 1000 * BITS_PER_BYTE;
> + cpb_size_msec = (cpb_size_bit * 1000) / bitrate;
> +
> + if (cpb_size_msec < 10 || cpb_size_msec > 100000)
> + cpb_size_msec = 10000;
> +
> + return cpb_size_msec;
> +}
> +
> +static void wave6_vpu_enc_release_fb(struct vpu_instance *inst)
> +{
> + int i;
> +
> + for (i = 0; i < WAVE6_MAX_FBS; i++) {
> + wave6_free_dma(&inst->frame_vbuf[i]);
> + memset(&inst->frame_buf[i], 0, sizeof(struct
> frame_buffer));
> + wave6_free_dma(&inst-
> >aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
> + wave6_free_dma(&inst-
> >aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
> + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
> + wave6_free_dma(&inst-
> >aux_vbuf[AUX_BUF_SUB_SAMPLE][i]);
> + }
> +}
> +
> +static void wave6_vpu_enc_destroy_instance(struct vpu_instance
> *inst)
> +{
> + u32 fail_res;
> + int ret;
> +
> + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst-
> >id);
> + wave6_vpu_remove_dbgfs_file(inst);
> +
> + ret = wave6_vpu_enc_close(inst, &fail_res);
> + if (ret) {
> + dev_err(inst->dev->dev, "failed destroy instance: %d
> (%d)\n",
> + ret, fail_res);
> + }
> +
> + wave6_vpu_enc_release_fb(inst);
> + wave6_free_dma(&inst->ar_vbuf);
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
> +
> + if (!pm_runtime_suspended(inst->dev->dev))
> + pm_runtime_put_sync(inst->dev->dev);
> +}
> +
> +static struct vb2_v4l2_buffer *wave6_get_valid_src_buf(struct
> vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf = NULL;
> +
> + v4l2_m2m_for_each_src_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
> +
> + if (!vpu_buf->consumed) {
> + dev_dbg(inst->dev->dev, "no consumed src idx
> : %d\n",
> + vb2_v4l2_buf->vb2_buf.index);
> + return vb2_v4l2_buf;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static struct vb2_v4l2_buffer *wave6_get_valid_dst_buf(struct
> vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf;
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
> +
> + if (!vpu_buf->consumed) {
> + dev_dbg(inst->dev->dev, "no consumed dst idx
> : %d\n",
> + vb2_v4l2_buf->vb2_buf.index);
> + return vb2_v4l2_buf;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static void wave6_set_csc(struct vpu_instance *inst, struct
> enc_param *pic_param)
> +{
> + bool is_10bit = false;
> +
> + if (!(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) &&
> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32) &&
> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32) &&
> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32) &&
> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) &&
> + !(inst->src_fmt.pixelformat ==
> V4L2_PIX_FMT_ARGB2101010))
> + return;
> +
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010)
> + is_10bit = true;
> +
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32)
> + pic_param->csc.format_order = 8;
> +
> + if (inst->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT ||
> + inst->ycbcr_enc == V4L2_YCBCR_ENC_601) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_FULL_RANGE) {
> + /*
> + * Y 0.299(R) 0.587(G) 0.114(B)
> + * Cb -0.16874(R) -0.33126(G) 0.5(B)
> + * Cr 0.5(R) -0.41869(G) -0.08131(B)
> + */
> + pic_param->csc.coef_ry = 0x099;
> + pic_param->csc.coef_gy = 0x12d;
> + pic_param->csc.coef_by = 0x03a;
> + pic_param->csc.coef_rcb = 0xffffffaa;
> + pic_param->csc.coef_gcb = 0xffffff56;
> + pic_param->csc.coef_bcb = 0x100;
> + pic_param->csc.coef_rcr = 0x100;
> + pic_param->csc.coef_gcr = 0xffffff2a;
> + pic_param->csc.coef_bcr = 0xffffffd6;
> + pic_param->csc.offset_y = 0x0;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + } else {
> + /*
> + * Y 0.258(R) 0.504(G) 0.098(B)
> + * Cb -0.1484(R) -0.2891(G) 0.4375(B)
> + * Cr 0.4375(R) -0.3672(G) -0.0703(B)
> + */
> + pic_param->csc.coef_ry = 0x084;
> + pic_param->csc.coef_gy = 0x102;
> + pic_param->csc.coef_by = 0x032;
> + pic_param->csc.coef_rcb = 0xffffffb4;
> + pic_param->csc.coef_gcb = 0xffffff6c;
> + pic_param->csc.coef_bcb = 0x0e0;
> + pic_param->csc.coef_rcr = 0x0e0;
> + pic_param->csc.coef_gcr = 0xffffff44;
> + pic_param->csc.coef_bcr = 0xffffffdc;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + }
> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_709) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_FULL_RANGE) {
> + /*
> + * Y 0.2126(R) 0.7152(G) 0.0722(B)
> + * Cb -0.11457(R) -0.38543(G) 0.5(B)
> + * Cr 0.5(R) -0.45415(G) -0.04585(B)
> + */
> + pic_param->csc.coef_ry = 0x06d;
> + pic_param->csc.coef_gy = 0x16e;
> + pic_param->csc.coef_by = 0x025;
> + pic_param->csc.coef_rcb = 0xffffffc5;
> + pic_param->csc.coef_gcb = 0xffffff3b;
> + pic_param->csc.coef_bcb = 0x100;
> + pic_param->csc.coef_rcr = 0x100;
> + pic_param->csc.coef_gcr = 0xffffff17;
> + pic_param->csc.coef_bcr = 0xffffffe9;
> + pic_param->csc.offset_y = 0x0;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + } else {
> + pic_param->csc.coef_ry = 0x05e;
> + pic_param->csc.coef_gy = 0x13b;
> + pic_param->csc.coef_by = 0x020;
> + pic_param->csc.coef_rcb = 0xffffffcc;
> + pic_param->csc.coef_gcb = 0xffffff53;
> + pic_param->csc.coef_bcb = 0x0e1;
> + pic_param->csc.coef_rcr = 0x0e1;
> + pic_param->csc.coef_gcr = 0xffffff34;
> + pic_param->csc.coef_bcr = 0xffffffeb;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + }
> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_FULL_RANGE) {
> + /*
> + * Y 0.2627(R) 0.678(G) 0.0593(B)
> + * Cb -0.13963(R) -0.36037(G) 0.5(B)
> + * Cr 0.5(R) -0.45979(G) -0.04021(B)
> + */
> + pic_param->csc.coef_ry = 0x087;
> + pic_param->csc.coef_gy = 0x15b;
> + pic_param->csc.coef_by = 0x01e;
> + pic_param->csc.coef_rcb = 0xffffffb9;
> + pic_param->csc.coef_gcb = 0xffffff47;
> + pic_param->csc.coef_bcb = 0x100;
> + pic_param->csc.coef_rcr = 0x100;
> + pic_param->csc.coef_gcr = 0xffffff15;
> + pic_param->csc.coef_bcr = 0xffffffeb;
> + pic_param->csc.offset_y = 0x0;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + } else {
> + pic_param->csc.coef_ry = 0x074;
> + pic_param->csc.coef_gy = 0x12a;
> + pic_param->csc.coef_by = 0x01a;
> + pic_param->csc.coef_rcb = 0xffffffc1;
> + pic_param->csc.coef_gcb = 0xffffff5e;
> + pic_param->csc.coef_bcb = 0x0e1;
> + pic_param->csc.coef_rcr = 0x0e1;
> + pic_param->csc.coef_gcr = 0xffffff31;
> + pic_param->csc.coef_bcr = 0xffffffee;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + }
> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_SMPTE240M) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_FULL_RANGE) {
> + /*
> + * Y 0.2122(R) 0.7013(G) 0.0865(B)
> + * Cb -0.1161(R) -0.3839(G) 0.5(B)
> + * Cr 0.5(R) -0.4451(G) -0.0549(B)
> + */
> + pic_param->csc.coef_ry = 0x06d;
> + pic_param->csc.coef_gy = 0x167;
> + pic_param->csc.coef_by = 0x02c;
> + pic_param->csc.coef_rcb = 0xffffffc5;
> + pic_param->csc.coef_gcb = 0xffffff3b;
> + pic_param->csc.coef_bcb = 0x100;
> + pic_param->csc.coef_rcr = 0x100;
> + pic_param->csc.coef_gcr = 0xffffff1c;
> + pic_param->csc.coef_bcr = 0xffffffe4;
> + pic_param->csc.offset_y = 0x0;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + } else {
> + pic_param->csc.coef_ry = 0x05d;
> + pic_param->csc.coef_gy = 0x134;
> + pic_param->csc.coef_by = 0x026;
> + pic_param->csc.coef_rcb = 0xffffffcc;
> + pic_param->csc.coef_gcb = 0xffffff53;
> + pic_param->csc.coef_bcb = 0x0e1;
> + pic_param->csc.coef_rcr = 0x0e1;
> + pic_param->csc.coef_gcr = 0xffffff38;
> + pic_param->csc.coef_bcr = 0xffffffe7;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = (is_10bit) ?
> 0x200 : 0x80;
> + pic_param->csc.offset_cr = (is_10bit) ?
> 0x200 : 0x80;
> + }
> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_LIM_RANGE) {
> + /*
> + * Y 0.2558(R) 0.5021(G) 0.0975(B)
> + * Cb -0.1476(R) -0.2899(G) 0.4375(B)
> + * Cr 0.4375(R) -0.3664(G) -0.0711(B)
> + */
> + pic_param->csc.coef_ry = 0x083;
> + pic_param->csc.coef_gy = 0x101;
> + pic_param->csc.coef_by = 0x032;
> + pic_param->csc.coef_rcb = 0xffffffb4;
> + pic_param->csc.coef_gcb = 0xffffff6c;
> + pic_param->csc.coef_bcb = 0x0e0;
> + pic_param->csc.coef_rcr = 0x0e0;
> + pic_param->csc.coef_gcr = 0xffffff44;
> + pic_param->csc.coef_bcr = 0xffffffdc;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = 0x0;
> + pic_param->csc.offset_cr = 0x0;
> + }
> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
> + if (inst->quantization ==
> V4L2_QUANTIZATION_LIM_RANGE) {
> + /*
> + * Y 0.1819(R) 0.6118(G) 0.0618(B)
> + * Cb -0.1003(R) -0.3372(G) 0.4375(B)
> + * Cr 0.4375(R) -0.3974(G) -0.0401(B)
> + */
> + pic_param->csc.coef_ry = 0x05d;
> + pic_param->csc.coef_gy = 0x139;
> + pic_param->csc.coef_by = 0x020;
> + pic_param->csc.coef_rcb = 0xffffffcd;
> + pic_param->csc.coef_gcb = 0xffffff53;
> + pic_param->csc.coef_bcb = 0x0e0;
> + pic_param->csc.coef_rcr = 0x0e0;
> + pic_param->csc.coef_gcr = 0xffffff35;
> + pic_param->csc.coef_bcr = 0xffffffeb;
> + pic_param->csc.offset_y = (is_10bit) ? 0x40
> : 0x10;
> + pic_param->csc.offset_cb = 0x0;
> + pic_param->csc.offset_cr = 0x0;
> + }
> + }
> +}
> +
> +static void wave6_update_crop_info(struct vpu_instance *inst,
> + u32 left, u32 top, u32 width, u32
> height)
> +{
> + u32 enc_pic_width, enc_pic_height;
> +
> + inst->crop.left = left;
> + inst->crop.top = top;
> + inst->crop.width = width;
> + inst->crop.height = height;
> +
> + inst->codec_rect.left = round_down(left,
> W6_ENC_CROP_X_POS_STEP);
> + inst->codec_rect.top = round_down(top,
> W6_ENC_CROP_Y_POS_STEP);
> +
> + enc_pic_width = width + left - inst->codec_rect.left;
> + inst->codec_rect.width = round_up(enc_pic_width,
> W6_ENC_PIC_SIZE_STEP);
> +
> + enc_pic_height = height + top - inst->codec_rect.top;
> + inst->codec_rect.height = round_up(enc_pic_height,
> W6_ENC_PIC_SIZE_STEP);
> +}
> +
> +static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
> + enum aux_buffer_type type,
> + int num)
> +{
> + struct aux_buffer buf[WAVE6_MAX_FBS];
> + struct aux_buffer_info buf_info;
> + struct enc_aux_buffer_size_info size_info;
> + unsigned int size;
> + int i, ret;
> +
> + memset(buf, 0, sizeof(buf));
> +
> + size_info.width = inst->codec_rect.width;
> + size_info.height = inst->codec_rect.height;
> + size_info.type = type;
> + size_info.mirror_direction = inst-
> >enc_ctrls.mirror_direction;
> + size_info.rotation_angle = inst->enc_ctrls.rot_angle;
> +
> + ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info,
> &size);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Get size fail (type
> %d)\n", __func__, type);
> + return ret;
> + }
> +
> + for (i = 0; i < num; i++) {
> + inst->aux_vbuf[type][i].size = size;
> + ret = wave6_alloc_dma(inst->dev->dev, &inst-
> >aux_vbuf[type][i]);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Alloc fail
> (type %d)\n", __func__, type);
> + return ret;
> + }
> +
> + buf[i].index = i;
> + buf[i].addr = inst->aux_vbuf[type][i].daddr;
> + buf[i].size = inst->aux_vbuf[type][i].size;
> + }
> +
> + buf_info.type = type;
> + buf_info.num = num;
> + buf_info.buf_array = buf;
> +
> + ret = wave6_vpu_enc_register_aux_buffer(inst, buf_info);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "%s: Register fail (type
> %d)\n", __func__, type);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void wave6_update_frame_buf_addr(struct vpu_instance *inst,
> + struct frame_buffer
> *frame_buf)
> +{
> + const struct v4l2_format_info *fmt_info;
> + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
> + u32 offset;
> +
> + fmt_info = v4l2_format_info(inst->src_fmt.pixelformat);
> + if (!fmt_info)
> + return;
> +
> + offset = inst->codec_rect.top * stride + inst-
> >codec_rect.left * fmt_info->bpp[0];
> + frame_buf->buf_y += offset;
> +
> + stride = DIV_ROUND_UP(stride, fmt_info->bpp[0]) * fmt_info-
> >bpp[1];
> + offset = inst->codec_rect.top * stride / fmt_info->vdiv /
> fmt_info->hdiv
> + + inst->codec_rect.left * fmt_info->bpp[1] /
> fmt_info->hdiv;
> + frame_buf->buf_cb += offset;
> + frame_buf->buf_cr += offset;
> +}
> +
> +static int wave6_update_seq_param(struct vpu_instance *inst)
> +{
> + struct enc_initial_info initial_info;
> + bool changed = false;
> + int ret;
> +
> + ret = wave6_vpu_enc_issue_seq_change(inst, &changed);
> + if (ret) {
> + dev_err(inst->dev->dev, "seq change fail %d\n",
> ret);
> + return ret;
> + }
> +
> + if (!changed)
> + return 0;
> +
> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
> + dev_err(inst->dev->dev, "seq change timeout\n");
> + return ret;
> + }
> +
> + wave6_vpu_enc_complete_seq_init(inst, &initial_info);
> + if (ret) {
> + dev_err(inst->dev->dev, "seq change error\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_start_encode(struct vpu_instance *inst)
> +{
> + int ret = -EINVAL;
> + struct vb2_v4l2_buffer *src_buf = NULL;
> + struct vb2_v4l2_buffer *dst_buf = NULL;
> + struct vpu_buffer *src_vbuf = NULL;
> + struct vpu_buffer *dst_vbuf = NULL;
> + struct frame_buffer frame_buf;
> + struct enc_param pic_param;
> + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
> + u32 luma_size = (stride * inst->src_fmt.height);
> + u32 chroma_size;
> + u32 fail_res;
> +
> + memset(&pic_param, 0, sizeof(struct enc_param));
> + memset(&frame_buf, 0, sizeof(struct frame_buffer));
> +
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M)
> + chroma_size = ((stride / 2) * (inst->src_fmt.height
> / 2));
> + else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M)
> + chroma_size = ((stride) * (inst->src_fmt.height /
> 2));
> + else
> + chroma_size = 0;
> +
> + ret = wave6_update_seq_param(inst);
> + if (ret)
> + goto exit;
> +
> + src_buf = wave6_get_valid_src_buf(inst);
> + dst_buf = wave6_get_valid_dst_buf(inst);
> +
> + if (!dst_buf) {
> + dev_dbg(inst->dev->dev, "no valid dst buf\n");
> + goto exit;
> + }
> +
> + dst_vbuf = wave6_to_vpu_buf(dst_buf);
> + pic_param.pic_stream_buffer_addr =
> wave6_get_dma_addr(dst_buf, 0);
> + pic_param.pic_stream_buffer_size = vb2_plane_size(&dst_buf-
> >vb2_buf, 0);
> + if (!src_buf) {
> + dev_dbg(inst->dev->dev, "no valid src buf\n");
> + if (inst->state == VPU_INST_STATE_STOP)
> + pic_param.src_end = true;
> + else
> + goto exit;
> + } else {
> + src_vbuf = wave6_to_vpu_buf(src_buf);
> + if (inst->src_fmt.num_planes == 1) {
> + frame_buf.buf_y =
> wave6_get_dma_addr(src_buf, 0);
> + frame_buf.buf_cb = frame_buf.buf_y +
> luma_size;
> + frame_buf.buf_cr = frame_buf.buf_cb +
> chroma_size;
> + } else if (inst->src_fmt.num_planes == 2) {
> + frame_buf.buf_y =
> wave6_get_dma_addr(src_buf, 0);
> + frame_buf.buf_cb =
> wave6_get_dma_addr(src_buf, 1);
> + frame_buf.buf_cr = frame_buf.buf_cb +
> chroma_size;
> + } else if (inst->src_fmt.num_planes == 3) {
> + frame_buf.buf_y =
> wave6_get_dma_addr(src_buf, 0);
> + frame_buf.buf_cb =
> wave6_get_dma_addr(src_buf, 1);
> + frame_buf.buf_cr =
> wave6_get_dma_addr(src_buf, 2);
> + }
> + wave6_update_frame_buf_addr(inst, &frame_buf);
> + frame_buf.stride = stride;
> + pic_param.src_idx = src_buf->vb2_buf.index;
> + if (src_vbuf->force_key_frame || inst-
> >error_recovery) {
> + pic_param.force_pic_type_enable = true;
> + pic_param.force_pic_type =
> ENC_FORCE_PIC_TYPE_IDR;
> + inst->error_recovery = false;
> + }
> + if (src_vbuf->force_frame_qp) {
> + pic_param.force_pic_qp_enable = true;
> + pic_param.force_pic_qp_i = src_vbuf-
> >force_i_frame_qp;
> + pic_param.force_pic_qp_p = src_vbuf-
> >force_p_frame_qp;
> + pic_param.force_pic_qp_b = src_vbuf-
> >force_b_frame_qp;
> + }
> + src_vbuf->ts_start = ktime_get_raw();
> + }
> +
> + pic_param.source_frame = &frame_buf;
> + wave6_set_csc(inst, &pic_param);
> +
> + if (src_vbuf)
> + src_vbuf->consumed = true;
> + if (dst_vbuf) {
> + dst_vbuf->consumed = true;
> + dst_vbuf->used = true;
> + }
> +
> + trace_enc_pic(inst, &pic_param);
> +
> + ret = wave6_vpu_enc_start_one_frame(inst, &pic_param,
> &fail_res);
> + if (ret) {
> + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst-
> >id, __func__, ret);
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_STOP);
> +
> + dst_buf = v4l2_m2m_dst_buf_remove(inst-
> >v4l2_fh.m2m_ctx);
> + if (dst_buf) {
> + dst_buf->sequence = inst->sequence;
> + v4l2_m2m_buf_done(dst_buf,
> VB2_BUF_STATE_ERROR);
> + }
> +
> + src_buf = v4l2_m2m_src_buf_remove(inst-
> >v4l2_fh.m2m_ctx);
> + if (src_buf) {
> + v4l2_m2m_buf_done(src_buf,
> VB2_BUF_STATE_ERROR);
> + inst->sequence++;
> + inst->processed_buf_num++;
> + inst->error_buf_num++;
> + }
> + } else {
> + dev_dbg(inst->dev->dev, "%s: success\n", __func__);
> + }
> +
> +exit:
> + return ret;
> +}
> +
> +static void wave6_handle_encoded_frame(struct vpu_instance *inst,
> + struct enc_output_info *info)
> +{
> + struct vb2_v4l2_buffer *src_buf;
> + struct vb2_v4l2_buffer *dst_buf;
> + struct vpu_buffer *vpu_buf;
> + struct vpu_buffer *dst_vpu_buf;
> + enum vb2_buffer_state state;
> +
> + state = info->encoding_success ? VB2_BUF_STATE_DONE :
> VB2_BUF_STATE_ERROR;
> +
> + src_buf = v4l2_m2m_src_buf_remove_by_idx(inst-
> >v4l2_fh.m2m_ctx,
> + info->enc_src_idx);
> + if (!src_buf) {
> + dev_err(inst->dev->dev, "[%d] encoder can't find src
> buffer\n", inst->id);
> + return;
> + }
> +
> + vpu_buf = wave6_to_vpu_buf(src_buf);
> + if (!vpu_buf || !vpu_buf->consumed) {
> + dev_err(inst->dev->dev, "[%d] src buffer is not
> consumed\n", inst->id);
> + return;
> + }
> +
> + dst_buf = wave6_get_dst_buf_by_addr(inst, info-
> >bitstream_buffer);
> + if (!dst_buf) {
> + dev_err(inst->dev->dev, "[%d] encoder can't find dst
> buffer\n", inst->id);
> + return;
> + }
> +
> + dst_vpu_buf = wave6_to_vpu_buf(dst_buf);
> +
> + dst_vpu_buf->average_qp = info->avg_ctu_qp;
> + dst_vpu_buf->ts_input = vpu_buf->ts_input;
> + dst_vpu_buf->ts_start = vpu_buf->ts_start;
> + dst_vpu_buf->ts_finish = ktime_get_raw();
> + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev,
> info->cycle.frame_cycle);
> + dst_vpu_buf->ts_output = ktime_get_raw();
> + wave6_vpu_handle_performance(inst, dst_vpu_buf);
> +
> + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
> + v4l2_m2m_buf_done(src_buf, state);
> +
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, info-
> >bitstream_size);
> + dst_buf->sequence = inst->sequence++;
> + dst_buf->field = V4L2_FIELD_NONE;
> + if (info->pic_type == PIC_TYPE_I)
> + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
> + else if (info->pic_type == PIC_TYPE_P)
> + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
> + else if (info->pic_type == PIC_TYPE_B)
> + dst_buf->flags |= V4L2_BUF_FLAG_BFRAME;
> +
> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
> dst_buf);
> + if (state == VB2_BUF_STATE_ERROR) {
> + dprintk(inst->dev->dev, "[%d] error frame %d\n",
> inst->id, inst->sequence);
> + inst->error_recovery = true;
> + inst->error_buf_num++;
> + }
> + v4l2_m2m_buf_done(dst_buf, state);
> + inst->processed_buf_num++;
> +}
> +
> +static void wave6_handle_last_frame(struct vpu_instance *inst,
> + dma_addr_t addr)
> +{
> + struct vb2_v4l2_buffer *dst_buf;
> +
> + dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
> + if (!dst_buf)
> + return;
> +
> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
> + dst_buf->field = V4L2_FIELD_NONE;
> + dst_buf->flags |= V4L2_BUF_FLAG_LAST;
> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
> dst_buf);
> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
> +
> + dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
> + inst->eos = true;
> +
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
> +}
> +
> +static void wave6_vpu_enc_finish_encode(struct vpu_instance *inst,
> bool error)
> +{
> + int ret;
> + struct enc_output_info info;
> +
> + if (error) {
> + vb2_queue_error(v4l2_m2m_get_src_vq(inst-
> >v4l2_fh.m2m_ctx));
> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst-
> >v4l2_fh.m2m_ctx));
> +
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_STOP);
> + inst->eos = true;
> +
> + goto finish_encode;
> + }
> +
> + ret = wave6_vpu_enc_get_output_info(inst, &info);
> + if (ret) {
> + dev_dbg(inst->dev->dev, "vpu_enc_get_output_info
> fail %d reason: %d | info : %d\n",
> + ret, info.error_reason, info.warn_info);
> + goto finish_encode;
> + }
> +
> + trace_enc_done(inst, &info);
> +
> + if (info.enc_src_idx >= 0 && info.recon_frame_index >= 0)
> + wave6_handle_encoded_frame(inst, &info);
> + else if (info.recon_frame_index == RECON_IDX_FLAG_ENC_END)
> + wave6_handle_last_frame(inst,
> info.bitstream_buffer);
> +
> +finish_encode:
> + wave6_vpu_finish_job(inst);
> +}
> +
> +static int wave6_vpu_enc_querycap(struct file *file, void *fh,
> struct v4l2_capability *cap)
> +{
> + strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver));
> + strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card));
> + strscpy(cap->bus_info, "platform:" VPU_ENC_DRV_NAME,
> sizeof(cap->bus_info));
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_enum_framesizes(struct file *f, void *fh,
> struct v4l2_frmsizeenum *fsize)
> +{
> + const struct vpu_format *vpu_fmt;
> +
> + if (fsize->index)
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt) {
> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt)
> + return -EINVAL;
> + }
> +
> + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
> + fsize->stepwise.min_width = vpu_fmt->min_width;
> + fsize->stepwise.max_width = vpu_fmt->max_width;
> + fsize->stepwise.step_width = W6_ENC_PIC_SIZE_STEP;
> + fsize->stepwise.min_height = vpu_fmt->min_height;
> + fsize->stepwise.max_height = vpu_fmt->max_height;
> + fsize->stepwise.step_height = W6_ENC_PIC_SIZE_STEP;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_enum_fmt_cap(struct file *file, void *fh,
> struct v4l2_fmtdesc *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + const struct vpu_format *vpu_fmt;
> +
> + dev_dbg(inst->dev->dev, "index : %d\n", f->index);
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt)
> + return -EINVAL;
> +
> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + f->flags = 0;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_try_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + const struct vpu_format *vpu_fmt;
> + int width, height;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + if (!V4L2_TYPE_IS_CAPTURE(f->type))
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
> VPU_FMT_TYPE_CODEC);
> + if (!vpu_fmt) {
> + width = inst->dst_fmt.width;
> + height = inst->dst_fmt.height;
> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
> + pix_mp->num_planes = inst->dst_fmt.num_planes;
> + } else {
> + width = pix_mp->width;
> + height = pix_mp->height;
> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + pix_mp->num_planes = vpu_fmt->num_planes;
> + }
> +
> + wave6_update_pix_fmt(pix_mp, width, height);
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_s_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i, ret;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + ret = wave6_vpu_enc_try_fmt_cap(file, fh, f);
> + if (ret)
> + return ret;
> +
> + inst->std = wave6_to_codec_std(inst->type, pix_mp-
> >pixelformat);
> + if (inst->std == STD_UNKNOWN) {
> + dev_err(inst->dev->dev, "unsupported pixelformat:
> %.4s\n",
> + (char *)&pix_mp->pixelformat);
> + return -EINVAL;
> + }
> +
> + inst->dst_fmt.width = pix_mp->width;
> + inst->dst_fmt.height = pix_mp->height;
> + inst->dst_fmt.pixelformat = pix_mp->pixelformat;
> + inst->dst_fmt.field = pix_mp->field;
> + inst->dst_fmt.flags = pix_mp->flags;
> + inst->dst_fmt.num_planes = pix_mp->num_planes;
> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
> + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp-
> >plane_fmt[i].bytesperline;
> + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp-
> >plane_fmt[i].sizeimage;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_g_fmt_cap(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i;
> +
> + pix_mp->width = inst->dst_fmt.width;
> + pix_mp->height = inst->dst_fmt.height;
> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
> + pix_mp->field = inst->dst_fmt.field;
> + pix_mp->flags = inst->dst_fmt.flags;
> + pix_mp->num_planes = inst->dst_fmt.num_planes;
> + for (i = 0; i < pix_mp->num_planes; i++) {
> + pix_mp->plane_fmt[i].bytesperline = inst-
> >dst_fmt.plane_fmt[i].bytesperline;
> + pix_mp->plane_fmt[i].sizeimage = inst-
> >dst_fmt.plane_fmt[i].sizeimage;
> + }
> +
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_enum_fmt_out(struct file *file, void *fh,
> struct v4l2_fmtdesc *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + const struct vpu_format *vpu_fmt;
> +
> + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f-
> >index);
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt)
> + return -EINVAL;
> +
> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + f->flags = 0;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_try_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + const struct vpu_format *vpu_fmt;
> + int width, height;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + if (!V4L2_TYPE_IS_OUTPUT(f->type))
> + return -EINVAL;
> +
> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
> VPU_FMT_TYPE_RAW);
> + if (!vpu_fmt) {
> + width = inst->src_fmt.width;
> + height = inst->src_fmt.height;
> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
> + pix_mp->num_planes = inst->src_fmt.num_planes;
> + } else {
> + width = clamp(pix_mp->width,
> + vpu_fmt->min_width, vpu_fmt-
> >max_width);
> + height = clamp(pix_mp->height,
> + vpu_fmt->min_height, vpu_fmt-
> >max_height);
> +
> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + pix_mp->num_planes = vpu_fmt->num_planes;
> + }
> +
> + wave6_update_pix_fmt(pix_mp, width, height);
> +
> + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
> + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
> + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV601 ||
> + pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
> + if (pix_mp->quantization ==
> V4L2_QUANTIZATION_FULL_RANGE)
> + pix_mp->quantization =
> V4L2_QUANTIZATION_LIM_RANGE;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_s_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i, ret;
> +
> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
> colorspace %d\n",
> + __func__, pix_mp->pixelformat, pix_mp->width,
> pix_mp->height,
> + pix_mp->num_planes, pix_mp->colorspace);
> +
> + ret = wave6_vpu_enc_try_fmt_out(file, fh, f);
> + if (ret)
> + return ret;
> +
> + inst->src_fmt.width = pix_mp->width;
> + inst->src_fmt.height = pix_mp->height;
> + inst->src_fmt.pixelformat = pix_mp->pixelformat;
> + inst->src_fmt.field = pix_mp->field;
> + inst->src_fmt.flags = pix_mp->flags;
> + inst->src_fmt.num_planes = pix_mp->num_planes;
> + for (i = 0; i < inst->src_fmt.num_planes; i++) {
> + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp-
> >plane_fmt[i].bytesperline;
> + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp-
> >plane_fmt[i].sizeimage;
> + }
> +
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) {
> + inst->cbcr_interleave = true;
> + inst->nv21 = false;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M)
> {
> + inst->cbcr_interleave = true;
> + inst->nv21 = true;
> + } else {
> + inst->cbcr_interleave = false;
> + inst->nv21 = false;
> + }
> +
> + inst->colorspace = pix_mp->colorspace;
> + inst->ycbcr_enc = pix_mp->ycbcr_enc;
> + inst->quantization = pix_mp->quantization;
> + inst->xfer_func = pix_mp->xfer_func;
> +
> + wave6_update_pix_fmt(&inst->dst_fmt, pix_mp->width, pix_mp-
> >height);
> + wave6_update_crop_info(inst, 0, 0, pix_mp->width, pix_mp-
> >height);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_g_fmt_out(struct file *file, void *fh,
> struct v4l2_format *f)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + int i;
> +
> + dev_dbg(inst->dev->dev, "\n");
> +
> + pix_mp->width = inst->src_fmt.width;
> + pix_mp->height = inst->src_fmt.height;
> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
> + pix_mp->field = inst->src_fmt.field;
> + pix_mp->flags = inst->src_fmt.flags;
> + pix_mp->num_planes = inst->src_fmt.num_planes;
> + for (i = 0; i < pix_mp->num_planes; i++) {
> + pix_mp->plane_fmt[i].bytesperline = inst-
> >src_fmt.plane_fmt[i].bytesperline;
> + pix_mp->plane_fmt[i].sizeimage = inst-
> >src_fmt.plane_fmt[i].sizeimage;
> + }
> +
> + pix_mp->colorspace = inst->colorspace;
> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
> + pix_mp->quantization = inst->quantization;
> + pix_mp->xfer_func = inst->xfer_func;
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_g_selection(struct file *file, void *fh,
> struct v4l2_selection *s)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> +
> + dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
> + __func__, s->type, s->target);
> +
> + if (!V4L2_TYPE_IS_OUTPUT(s->type))
> + return -EINVAL;
> +
> + switch (s->target) {
> + case V4L2_SEL_TGT_CROP_DEFAULT:
> + case V4L2_SEL_TGT_CROP_BOUNDS:
> + s->r.left = 0;
> + s->r.top = 0;
> + s->r.width = inst->src_fmt.width;
> + s->r.height = inst->src_fmt.height;
> + break;
> + case V4L2_SEL_TGT_CROP:
> + s->r = inst->crop;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_s_selection(struct file *file, void *fh,
> struct v4l2_selection *s)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + u32 max_crop_w, max_crop_h;
> +
> + if (!V4L2_TYPE_IS_OUTPUT(s->type))
> + return -EINVAL;
> +
> + if (s->target != V4L2_SEL_TGT_CROP)
> + return -EINVAL;
> +
> + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
> + s->flags |= V4L2_SEL_FLAG_LE;
> +
> + if (s->flags & V4L2_SEL_FLAG_GE) {
> + s->r.left = round_up(s->r.left, W6_ENC_CROP_STEP);
> + s->r.top = round_up(s->r.top, W6_ENC_CROP_STEP);
> + s->r.width = round_up(s->r.width, W6_ENC_CROP_STEP);
> + s->r.height = round_up(s->r.height,
> W6_ENC_CROP_STEP);
> + }
> + if (s->flags & V4L2_SEL_FLAG_LE) {
> + s->r.left = round_down(s->r.left, W6_ENC_CROP_STEP);
> + s->r.top = round_down(s->r.top, W6_ENC_CROP_STEP);
> + s->r.width = round_down(s->r.width,
> W6_ENC_CROP_STEP);
> + s->r.height = round_down(s->r.height,
> W6_ENC_CROP_STEP);
> + }
> +
> + max_crop_w = inst->src_fmt.width - s->r.left;
> + max_crop_h = inst->src_fmt.height - s->r.top;
> +
> + if (!s->r.width || !s->r.height)
> + return 0;
> + if (max_crop_w < W6_MIN_ENC_PIC_WIDTH)
> + return 0;
> + if (max_crop_h < W6_MIN_ENC_PIC_HEIGHT)
> + return 0;
> +
> + s->r.width = clamp(s->r.width, W6_MIN_ENC_PIC_WIDTH,
> max_crop_w);
> + s->r.height = clamp(s->r.height, W6_MIN_ENC_PIC_HEIGHT,
> max_crop_h);
> +
> + wave6_update_pix_fmt(&inst->dst_fmt, s->r.width, s-
> >r.height);
> + wave6_update_crop_info(inst, s->r.left, s->r.top, s-
> >r.width, s->r.height);
> +
> + dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_CROP %dx%dx%dx%d\n",
> + s->r.left, s->r.top, s->r.width, s->r.height);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_encoder_cmd(struct file *file, void *fh,
> struct v4l2_encoder_cmd *ec)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + int ret;
> +
> + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, ec->cmd);
> +
> + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
> + if (ret)
> + return ret;
> +
> + if (!wave6_vpu_both_queues_are_streaming(inst))
> + return 0;
> +
> + switch (ec->cmd) {
> + case V4L2_ENC_CMD_STOP:
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_STOP);
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
> true);
> + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
> + break;
> + case V4L2_ENC_CMD_START:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_g_parm(struct file *file, void *fh, struct
> v4l2_streamparm *a)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> +
> + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
> +
> + if (!V4L2_TYPE_IS_OUTPUT(a->type))
> + return -EINVAL;
> +
> + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
> + a->parm.output.timeperframe.numerator = 1;
> + a->parm.output.timeperframe.denominator = inst->frame_rate;
> +
> + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator :
> %d\n",
> + __func__,
> + a->parm.output.timeperframe.numerator,
> + a->parm.output.timeperframe.denominator);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_s_parm(struct file *file, void *fh, struct
> v4l2_streamparm *a)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> +
> + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
> +
> + if (!V4L2_TYPE_IS_OUTPUT(a->type))
> + return -EINVAL;
> +
> + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
> + if (a->parm.output.timeperframe.denominator && a-
> >parm.output.timeperframe.numerator) {
> + inst->frame_rate = a-
> >parm.output.timeperframe.denominator /
> + a-
> >parm.output.timeperframe.numerator;
> + } else {
> + a->parm.output.timeperframe.numerator = 1;
> + a->parm.output.timeperframe.denominator = inst-
> >frame_rate;
> + }
> +
> + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator :
> %d\n",
> + __func__,
> + a->parm.output.timeperframe.numerator,
> + a->parm.output.timeperframe.denominator);
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops wave6_vpu_enc_ioctl_ops = {
> + .vidioc_querycap = wave6_vpu_enc_querycap,
> + .vidioc_enum_framesizes = wave6_vpu_enc_enum_framesizes,
> +
> + .vidioc_enum_fmt_vid_cap = wave6_vpu_enc_enum_fmt_cap,
> + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_enc_s_fmt_cap,
> + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_enc_g_fmt_cap,
> + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_enc_try_fmt_cap,
> +
> + .vidioc_enum_fmt_vid_out = wave6_vpu_enc_enum_fmt_out,
> + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_enc_s_fmt_out,
> + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_enc_g_fmt_out,
> + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_enc_try_fmt_out,
> +
> + .vidioc_g_selection = wave6_vpu_enc_g_selection,
> + .vidioc_s_selection = wave6_vpu_enc_s_selection,
> +
> + .vidioc_g_parm = wave6_vpu_enc_g_parm,
> + .vidioc_s_parm = wave6_vpu_enc_s_parm,
> +
> + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
> + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
> + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
> + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
> + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
> + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
> + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
> + .vidioc_streamon = v4l2_m2m_ioctl_streamon,
> + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
> +
> + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
> + .vidioc_encoder_cmd = wave6_vpu_enc_encoder_cmd,
> +
> + .vidioc_subscribe_event = wave6_vpu_subscribe_event,
> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +};
> +
> +static int wave6_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
> + struct enc_controls *p = &inst->enc_ctrls;
> +
> + trace_s_ctrl(inst, ctrl);
> +
> + dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
> + __func__, ctrl->name, ctrl->val);
> +
> + switch (ctrl->id) {
> + case V4L2_CID_HFLIP:
> + p->mirror_direction |= (ctrl->val << 1);
> + break;
> + case V4L2_CID_VFLIP:
> + p->mirror_direction |= ctrl->val;
> + break;
> + case V4L2_CID_ROTATE:
> + p->rot_angle = ctrl->val;
> + break;
> + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
> + break;
> + case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
> + p->gop_size = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
> + p->slice_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
> + p->slice_max_mb = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
> + p->bitrate_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_BITRATE:
> + p->bitrate = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
> + p->frame_rc_enable = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
> + p->mb_rc_enable = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
> + p->force_key_frame = true;
> + break;
> + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
> + p->prepend_spspps_to_idr = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE:
> + break;
> + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
> + p->intra_refresh_period = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
> + p->frame_skip_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
> + p->hevc.profile = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
> + p->hevc.level = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
> + p->hevc.min_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
> + p->hevc.max_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
> + p->hevc.i_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
> + p->hevc.p_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
> + p->hevc.b_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
> + p->hevc.loop_filter_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
> + p->hevc.lf_beta_offset_div2 = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
> + p->hevc.lf_tc_offset_div2 = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
> + p->hevc.refresh_type = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
> + p->hevc.refresh_period = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
> + p->hevc.const_intra_pred = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
> + p->hevc.strong_smoothing = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
> + p->hevc.tmv_prediction = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
> + p->h264.profile = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
> + p->h264.level = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
> + p->h264.min_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
> + p->h264.max_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
> + p->h264.i_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
> + p->h264.p_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
> + p->h264.b_frame_qp = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
> + p->h264.loop_filter_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
> + p->h264.loop_filter_beta = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
> + p->h264.loop_filter_alpha = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
> + p->h264._8x8_transform = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
> + p->h264.constrained_intra_prediction = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:
> + p->h264.chroma_qp_index_offset = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
> + p->h264.entropy_mode = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
> + p->h264.i_period = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
> + p->h264.vui_sar_enable = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
> + p->h264.vui_sar_idc = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
> + p->h264.vui_ext_sar_width = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
> + p->h264.vui_ext_sar_height = ctrl->val;
> + break;
> + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
> + p->h264.cpb_size = ctrl->val;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops wave6_vpu_enc_ctrl_ops = {
> + .s_ctrl = wave6_vpu_enc_s_ctrl,
> +};
> +
> +static u32 to_video_full_range_flag(enum v4l2_quantization
> quantization)
> +{
> + switch (quantization) {
> + case V4L2_QUANTIZATION_FULL_RANGE:
> + return 1;
> + case V4L2_QUANTIZATION_LIM_RANGE:
> + default:
> + return 0;
> + }
> +}
> +
> +static u32 to_colour_primaries(enum v4l2_colorspace colorspace)
> +{
> + switch (colorspace) {
> + case V4L2_COLORSPACE_SMPTE170M:
> + return 6;
> + case V4L2_COLORSPACE_REC709:
> + case V4L2_COLORSPACE_SRGB:
> + case V4L2_COLORSPACE_JPEG:
> + return 1;
> + case V4L2_COLORSPACE_BT2020:
> + return 9;
> + case V4L2_COLORSPACE_DCI_P3:
> + return 11;
> + case V4L2_COLORSPACE_SMPTE240M:
> + return 7;
> + case V4L2_COLORSPACE_470_SYSTEM_M:
> + return 4;
> + case V4L2_COLORSPACE_470_SYSTEM_BG:
> + return 5;
> + case V4L2_COLORSPACE_RAW:
> + default:
> + return 2;
> + }
> +}
> +
> +static u32 to_transfer_characteristics(enum v4l2_colorspace
> colorspace,
> + enum v4l2_xfer_func
> xfer_func)
> +{
> + if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
> + xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
> +
> + switch (xfer_func) {
> + case V4L2_XFER_FUNC_709:
> + if (colorspace == V4L2_COLORSPACE_SMPTE170M)
> + return 6;
> + else if (colorspace == V4L2_COLORSPACE_BT2020)
> + return 14;
> + else
> + return 1;
> + case V4L2_XFER_FUNC_SRGB:
> + return 13;
> + case V4L2_XFER_FUNC_SMPTE240M:
> + return 7;
> + case V4L2_XFER_FUNC_NONE:
> + return 8;
> + case V4L2_XFER_FUNC_SMPTE2084:
> + return 16;
> + case V4L2_XFER_FUNC_DCI_P3:
> + default:
> + return 2;
> + }
> +}
> +
> +static u32 to_matrix_coeffs(enum v4l2_colorspace colorspace,
> + enum v4l2_ycbcr_encoding ycbcr_enc)
> +{
> + if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
> + ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
> +
> + switch (ycbcr_enc) {
> + case V4L2_YCBCR_ENC_601:
> + case V4L2_YCBCR_ENC_XV601:
> + if (colorspace == V4L2_COLORSPACE_SMPTE170M)
> + return 6;
> + else
> + return 5;
> + case V4L2_YCBCR_ENC_709:
> + case V4L2_YCBCR_ENC_XV709:
> + return 1;
> + case V4L2_YCBCR_ENC_BT2020:
> + return 9;
> + case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
> + return 10;
> + case V4L2_YCBCR_ENC_SMPTE240M:
> + return 7;
> + default:
> + return 2;
> + }
> +}
> +
> +static void wave6_set_enc_h264_param(struct enc_codec_param *output,
> + struct h264_enc_controls
> *ctrls)
> +{
> + switch (ctrls->profile) {
> + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
> + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
> + output->profile = H264_PROFILE_BP;
> + output->internal_bit_depth = 8;
> + break;
> + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
> + output->profile = H264_PROFILE_MP;
> + output->internal_bit_depth = 8;
> + break;
> + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
> + output->profile = H264_PROFILE_EXTENDED;
> + output->internal_bit_depth = 8;
> + break;
> + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
> + output->profile = H264_PROFILE_HP;
> + output->internal_bit_depth = 8;
> + break;
> + default:
> + break;
> + }
> + switch (ctrls->level) {
> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
> + output->level = 10;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
> + output->level = 9;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
> + output->level = 11;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
> + output->level = 12;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
> + output->level = 13;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
> + output->level = 20;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
> + output->level = 21;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
> + output->level = 22;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
> + output->level = 30;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
> + output->level = 31;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
> + output->level = 32;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
> + output->level = 40;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
> + output->level = 41;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
> + output->level = 42;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
> + output->level = 50;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
> + output->level = 51;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
> + output->level = 52;
> + break;
> + default:
> + break;
> + }
> + output->qp = ctrls->i_frame_qp;
> + output->min_qp_i = ctrls->min_qp;
> + output->max_qp_i = ctrls->max_qp;
> + output->min_qp_p = ctrls->min_qp;
> + output->max_qp_p = ctrls->max_qp;
> + output->min_qp_b = ctrls->min_qp;
> + output->max_qp_b = ctrls->max_qp;
> + switch (ctrls->loop_filter_mode) {
> + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
> + output->en_dbk = 0;
> + output->en_lf_cross_slice_boundary = 0;
> + break;
> + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
> + output->en_dbk = 1;
> + output->en_lf_cross_slice_boundary = 1;
> + break;
> + case
> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
> + output->en_dbk = 1;
> + output->en_lf_cross_slice_boundary = 0;
> + break;
> + default:
> + break;
> + }
> + output->intra_period = ctrls->i_period;
> + output->beta_offset_div2 = ctrls->loop_filter_beta;
> + output->tc_offset_div2 = ctrls->loop_filter_alpha;
> + if (output->profile >= H264_PROFILE_HP)
> + output->en_transform8x8 = ctrls->_8x8_transform;
> + output->en_constrained_intra_pred = ctrls-
> >constrained_intra_prediction;
> + output->cb_qp_offset = ctrls->chroma_qp_index_offset;
> + output->cr_qp_offset = ctrls->chroma_qp_index_offset;
> + if (output->profile >= H264_PROFILE_MP)
> + output->en_cabac = ctrls->entropy_mode;
> + output->en_auto_level_adjusting =
> DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
> +}
> +
> +static void wave6_set_enc_hevc_param(struct enc_codec_param *output,
> + struct hevc_enc_controls
> *ctrls)
> +{
> + switch (ctrls->profile) {
> + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
> + output->profile = HEVC_PROFILE_MAIN;
> + output->internal_bit_depth = 8;
> + break;
> + default:
> + break;
> + }
> + switch (ctrls->level) {
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
> + output->level = 10 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
> + output->level = 20 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
> + output->level = 21 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
> + output->level = 30 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
> + output->level = 31 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
> + output->level = 40 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
> + output->level = 41 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
> + output->level = 50 * 3;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
> + output->level = 51 * 3;
> + break;
> + default:
> + break;
> + }
> + output->qp = ctrls->i_frame_qp;
> + output->min_qp_i = ctrls->min_qp;
> + output->max_qp_i = ctrls->max_qp;
> + output->min_qp_p = ctrls->min_qp;
> + output->max_qp_p = ctrls->max_qp;
> + output->min_qp_b = ctrls->min_qp;
> + output->max_qp_b = ctrls->max_qp;
> + switch (ctrls->loop_filter_mode) {
> + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
> + output->en_dbk = 0;
> + output->en_sao = 0;
> + output->en_lf_cross_slice_boundary = 0;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
> + output->en_dbk = 1;
> + output->en_sao = 1;
> + output->en_lf_cross_slice_boundary = 1;
> + break;
> + case
> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
> + output->en_dbk = 1;
> + output->en_sao = 1;
> + output->en_lf_cross_slice_boundary = 0;
> + break;
> + default:
> + break;
> + }
> + switch (ctrls->refresh_type) {
> + case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE:
> + output->decoding_refresh_type =
> DEC_REFRESH_TYPE_NON_IRAP;
> + break;
> + case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR:
> + output->decoding_refresh_type =
> DEC_REFRESH_TYPE_IDR;
> + break;
> + default:
> + break;
> + }
> + output->intra_period = ctrls->refresh_period;
> + if (output->idr_period) {
> + output->decoding_refresh_type =
> DEC_REFRESH_TYPE_IDR;
> + output->intra_period = output->idr_period;
> + output->idr_period = 0;
> + }
> + output->beta_offset_div2 = ctrls->lf_beta_offset_div2;
> + output->tc_offset_div2 = ctrls->lf_tc_offset_div2;
> + output->en_constrained_intra_pred = ctrls->const_intra_pred;
> + output->en_strong_intra_smoothing = ctrls->strong_smoothing;
> + output->en_temporal_mvp = ctrls->tmv_prediction;
> + output->num_ticks_poc_diff_one = DEFAULT_NUM_TICKS_POC_DIFF;
> + output->en_auto_level_adjusting =
> DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
> + output->en_intra_trans_skip = DEFAULT_EN_INTRA_TRANS_SKIP;
> + output->en_me_center = DEFAULT_EN_ME_CENTER;
> + output->intra_4x4 = DEFAULT_INTRA_4X4;
> +}
> +
> +static void wave6_set_enc_open_param(struct enc_open_param
> *open_param,
> + struct vpu_instance *inst)
> +{
> + struct enc_controls *ctrls = &inst->enc_ctrls;
> + struct enc_codec_param *output = &open_param->codec_param;
> + u32 ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
> + u32 num_ctu_row = ALIGN(inst->src_fmt.height, ctu_size) /
> ctu_size;
> +
> + open_param->source_endian = VPU_SOURCE_ENDIAN;
> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
> + open_param->src_format = FORMAT_420;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M)
> {
> + open_param->src_format = FORMAT_422;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42) {
> + open_param->src_format = FORMAT_YUV444_24BIT;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24)
> {
> + open_param->src_format = FORMAT_YUV444_24BIT_PACKED;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUYV) {
> + open_param->src_format = FORMAT_YUYV;
> + open_param->packed_format = PACKED_YUYV;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24)
> {
> + open_param->src_format = FORMAT_RGB_24BIT_PACKED;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010) {
> + open_param->src_format = FORMAT_420_P10_16BIT_MSB;
> + open_param->source_endian = VDI_128BIT_LE_BYTE_SWAP;
> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32
> ||
> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32)
> {
> + open_param->src_format = FORMAT_RGB_32BIT_PACKED;
> + } else if (inst->src_fmt.pixelformat ==
> V4L2_PIX_FMT_ARGB2101010) {
> + open_param->src_format =
> FORMAT_RGB_P10_32BIT_PACKED;
> + open_param->source_endian =
> VDI_128BIT_LE_WORD_BYTE_SWAP;
> + }
> + open_param->line_buf_int_en = true;
> + open_param->stream_endian = VPU_STREAM_ENDIAN;
> + open_param->inst_buffer.temp_base = inst->dev-
> >temp_vbuf.daddr;
> + open_param->inst_buffer.temp_size = inst->dev-
> >temp_vbuf.size;
> + open_param->inst_buffer.ar_base = inst->ar_vbuf.daddr;
> + open_param->pic_width = inst->codec_rect.width;
> + open_param->pic_height = inst->codec_rect.height;
> +
> + output->custom_map_endian = VPU_USER_DATA_ENDIAN;
> + output->gop_preset_idx = PRESET_IDX_IPP_SINGLE;
> + output->temp_layer_cnt = DEFAULT_TEMP_LAYER_CNT;
> + output->rc_initial_level = DEFAULT_RC_INITIAL_LEVEL;
> + output->pic_rc_max_dqp = DEFAULT_PIC_RC_MAX_DQP;
> + output->rc_initial_qp = DEFAULT_RC_INITIAL_QP;
> + output->en_adaptive_round = DEFAULT_EN_ADAPTIVE_ROUND;
> + output->q_round_inter = DEFAULT_Q_ROUND_INTER;
> + output->q_round_intra = DEFAULT_Q_ROUND_INTRA;
> +
> + output->frame_rate = inst->frame_rate;
> + output->idr_period = ctrls->gop_size;
> + output->rc_mode = ctrls->bitrate_mode;
> + output->rc_update_speed = (ctrls->bitrate_mode) ?
> DEFAULT_RC_UPDATE_SPEED_CBR :
> +
> DEFAULT_RC_UPDATE_SPEED_VBR;
> + output->en_rate_control = ctrls->frame_rc_enable;
> + output->en_cu_level_rate_control = ctrls->mb_rc_enable;
> + output->max_intra_pic_bit = inst-
> >dst_fmt.plane_fmt[0].sizeimage * 8;
> + output->max_inter_pic_bit = inst-
> >dst_fmt.plane_fmt[0].sizeimage * 8;
> + output->bitrate = ctrls->bitrate;
> + output->cpb_size = wave6_cpb_size_msec(ctrls->h264.cpb_size,
> ctrls->bitrate);
> + output->slice_mode = ctrls->slice_mode;
> + output->slice_arg = ctrls->slice_max_mb;
> + output->forced_idr_header = ctrls->prepend_spspps_to_idr;
> + output->en_vbv_overflow_drop_frame = (ctrls-
> >frame_skip_mode) ? 1 : 0;
> + if (ctrls->intra_refresh_period) {
> + output->intra_refresh_mode = INTRA_REFRESH_ROW;
> + if (ctrls->intra_refresh_period < num_ctu_row) {
> + output->intra_refresh_arg = (num_ctu_row +
> ctrls->intra_refresh_period - 1)
> + / ctrls-
> >intra_refresh_period;
> + } else {
> + output->intra_refresh_arg = 1;
> + }
> + }
> + output->sar.enable = ctrls->h264.vui_sar_enable;
> + output->sar.idc = ctrls->h264.vui_sar_idc;
> + if (output->sar.idc ==
> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED)
> + output->sar.idc = H264_VUI_SAR_IDC_EXTENDED;
> + output->sar.width = ctrls->h264.vui_ext_sar_width;
> + output->sar.height = ctrls->h264.vui_ext_sar_height;
> + output->color.video_signal_type_present =
> DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG;
> + output->color.color_range = to_video_full_range_flag(inst-
> >quantization);
> + output->color.color_description_present =
> DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG;
> + output->color.color_primaries = to_colour_primaries(inst-
> >colorspace);
> + output->color.transfer_characteristics =
> to_transfer_characteristics(inst->colorspace,
> +
> inst->xfer_func);
> + output->color.matrix_coefficients = to_matrix_coeffs(inst-
> >colorspace, inst->ycbcr_enc);
> + output->conf_win.left = inst->crop.left - inst-
> >codec_rect.left;
> + output->conf_win.top = inst->crop.top - inst-
> >codec_rect.top;
> + output->conf_win.right = inst->codec_rect.width
> + - inst->crop.width - output-
> >conf_win.left;
> + output->conf_win.bottom = inst->codec_rect.height
> + - inst->crop.height -
> output->conf_win.top;
> +
> + switch (inst->std) {
> + case W_AVC_ENC:
> + wave6_set_enc_h264_param(output, &ctrls->h264);
> + break;
> + case W_HEVC_ENC:
> + wave6_set_enc_hevc_param(output, &ctrls->hevc);
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static int wave6_vpu_enc_create_instance(struct vpu_instance *inst)
> +{
> + int ret;
> + struct enc_open_param open_param;
> +
> + memset(&open_param, 0, sizeof(struct enc_open_param));
> +
> + wave6_vpu_activate(inst->dev);
> + ret = pm_runtime_resume_and_get(inst->dev->dev);
> + if (ret) {
> + dev_err(inst->dev->dev, "runtime_resume failed
> %d\n", ret);
> + return ret;
> + }
> +
> + wave6_vpu_wait_activated(inst->dev);
> +
> + inst->ar_vbuf.size = ALIGN(WAVE6_ARBUF_SIZE, 4096);
> + ret = wave6_alloc_dma(inst->dev->dev, &inst->ar_vbuf);
> + if (ret) {
> + dev_err(inst->dev->dev, "alloc ar of size %zu
> failed\n",
> + inst->ar_vbuf.size);
> + goto error_pm;
> + }
> +
> + wave6_set_enc_open_param(&open_param, inst);
> +
> + ret = wave6_vpu_enc_open(inst, &open_param);
> + if (ret) {
> + dev_err(inst->dev->dev, "failed create instance :
> %d\n", ret);
> + goto error_open;
> + }
> +
> + dprintk(inst->dev->dev, "[%d] encoder\n", inst->id);
> + wave6_vpu_create_dbgfs_file(inst);
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
> +
> + return 0;
> +
> +error_open:
> + wave6_free_dma(&inst->ar_vbuf);
> +error_pm:
> + pm_runtime_put_sync(inst->dev->dev);
> + return ret;
> +}
> +
> +static int wave6_vpu_enc_initialize_instance(struct vpu_instance
> *inst)
> +{
> + int ret;
> + struct enc_initial_info initial_info;
> + struct v4l2_ctrl *ctrl;
> +
> + if (inst->enc_ctrls.mirror_direction) {
> + wave6_vpu_enc_give_command(inst, ENABLE_MIRRORING,
> NULL);
> + wave6_vpu_enc_give_command(inst,
> SET_MIRROR_DIRECTION,
> + &inst-
> >enc_ctrls.mirror_direction);
> + }
> + if (inst->enc_ctrls.rot_angle) {
> + wave6_vpu_enc_give_command(inst, ENABLE_ROTATION,
> NULL);
> + wave6_vpu_enc_give_command(inst, SET_ROTATION_ANGLE,
> + &inst-
> >enc_ctrls.rot_angle);
> + }
> +
> + ret = wave6_vpu_enc_issue_seq_init(inst);
> + if (ret) {
> + dev_err(inst->dev->dev, "seq init fail %d\n", ret);
> + return ret;
> + }
> +
> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
> + dev_err(inst->dev->dev, "seq init timeout\n");
> + return ret;
> + }
> +
> + ret = wave6_vpu_enc_complete_seq_init(inst, &initial_info);
> + if (ret) {
> + dev_err(inst->dev->dev, "seq init error\n");
> + return ret;
> + }
> +
> + dev_dbg(inst->dev->dev, "min_fb_cnt : %d | min_src_cnt :
> %d\n",
> + initial_info.min_frame_buffer_count,
> + initial_info.min_src_frame_count);
> +
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
> + if (ctrl)
> + v4l2_ctrl_s_ctrl(ctrl,
> initial_info.min_src_frame_count);
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
> +
> + return 0;
> +}
> +
> +static int wave6_vpu_enc_prepare_fb(struct vpu_instance *inst)
> +{
> + int ret;
> + unsigned int i;
> + unsigned int fb_num;
> + unsigned int mv_num;
> + unsigned int fb_stride;
> + unsigned int fb_height;
> + struct enc_info *p_enc_info = &inst->codec_info->enc_info;
> +
> + fb_num = p_enc_info->initial_info.min_frame_buffer_count;
> + mv_num = p_enc_info->initial_info.req_mv_buffer_count;
> +
> + fb_stride = ALIGN(inst->codec_rect.width, 32);
> + fb_height = ALIGN(inst->codec_rect.height, 32);
> +
> + for (i = 0; i < fb_num; i++) {
> + struct frame_buffer *frame = &inst->frame_buf[i];
> + struct vpu_buf *vframe = &inst->frame_vbuf[i];
> + unsigned int l_size = fb_stride * fb_height;
> + unsigned int ch_size = ALIGN(fb_stride / 2, 32) *
> fb_height;
> +
> + vframe->size = l_size + ch_size;
> + ret = wave6_alloc_dma(inst->dev->dev, vframe);
> + if (ret) {
> + dev_err(inst->dev->dev, "alloc FBC buffer
> fail : %zu\n",
> + vframe->size);
> + goto error;
> + }
> +
> + frame->buf_y = vframe->daddr;
> + frame->buf_cb = vframe->daddr + l_size;
> + frame->buf_cr = (dma_addr_t)-1;
> + frame->stride = fb_stride;
> + frame->height = fb_height;
> + frame->map_type = COMPRESSED_FRAME_MAP;
> + }
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL,
> fb_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL,
> fb_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL,
> mv_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_SUB_SAMPLE,
> fb_num);
> + if (ret)
> + goto error;
> +
> + ret = wave6_vpu_enc_register_frame_buffer_ex(inst, fb_num,
> fb_stride,
> + fb_height,
> +
> COMPRESSED_FRAME_MAP);
> + if (ret) {
> + dev_err(inst->dev->dev, "register frame buffer fail
> %d\n", ret);
> + goto error;
> + }
> +
> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
> +
> + return 0;
> +
> +error:
> + wave6_vpu_enc_release_fb(inst);
> + return ret;
> +}
> +
> +static int wave6_vpu_enc_queue_setup(struct vb2_queue *q, unsigned
> int *num_buffers,
> + unsigned int *num_planes,
> unsigned int sizes[],
> + struct device *alloc_devs[])
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct v4l2_pix_format_mplane inst_format =
> + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt :
> inst->dst_fmt;
> + unsigned int i;
> +
> + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d
> type %d\n",
> + __func__, *num_buffers, *num_planes, q->type);
> +
> + if (*num_planes) {
> + if (inst_format.num_planes != *num_planes)
> + return -EINVAL;
> +
> + for (i = 0; i < *num_planes; i++) {
> + if (sizes[i] <
> inst_format.plane_fmt[i].sizeimage)
> + return -EINVAL;
> + }
> + } else {
> + *num_planes = inst_format.num_planes;
> + for (i = 0; i < *num_planes; i++) {
> + sizes[i] =
> inst_format.plane_fmt[i].sizeimage;
> + dev_dbg(inst->dev->dev, "size[%d] : %d\n",
> i, sizes[i]);
> + }
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> + struct v4l2_ctrl *ctrl;
> + unsigned int min_src_frame_count = 0;
> +
> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
> +
> V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
> + if (ctrl)
> + min_src_frame_count =
> v4l2_ctrl_g_ctrl(ctrl);
> +
> + *num_buffers = max(*num_buffers,
> min_src_frame_count);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void wave6_vpu_enc_buf_queue(struct vb2_buffer *vb)
> +{
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
> +
> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
> size[1] : %4ld | size[2] : %4ld\n",
> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
> 0),
> + vb2_plane_size(&vbuf->vb2_buf, 1),
> vb2_plane_size(&vbuf->vb2_buf, 2));
> +
> + if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
> + vbuf->sequence = inst->queued_src_buf_num++;
> +
> + vpu_buf->ts_input = ktime_get_raw();
> + vpu_buf->force_key_frame = inst-
> >enc_ctrls.force_key_frame;
> + inst->enc_ctrls.force_key_frame = false;
> + vpu_buf->force_frame_qp = (!inst-
> >enc_ctrls.frame_rc_enable) ? true : false;
> + if (vpu_buf->force_frame_qp) {
> + if (inst->std == W_AVC_ENC) {
> + vpu_buf->force_i_frame_qp = inst-
> >enc_ctrls.h264.i_frame_qp;
> + vpu_buf->force_p_frame_qp = inst-
> >enc_ctrls.h264.p_frame_qp;
> + vpu_buf->force_b_frame_qp = inst-
> >enc_ctrls.h264.b_frame_qp;
> + } else if (inst->std == W_HEVC_ENC) {
> + vpu_buf->force_i_frame_qp = inst-
> >enc_ctrls.hevc.i_frame_qp;
> + vpu_buf->force_p_frame_qp = inst-
> >enc_ctrls.hevc.p_frame_qp;
> + vpu_buf->force_b_frame_qp = inst-
> >enc_ctrls.hevc.b_frame_qp;
> + }
> + }
> + } else {
> + inst->queued_dst_buf_num++;
> + }
> +
> + vpu_buf->consumed = false;
> + vpu_buf->used = false;
> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
> +}
> +
> +static void wave6_vpu_enc_buf_finish(struct vb2_buffer *vb)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
> + struct v4l2_ctrl *ctrl;
> +
> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
> + return;
> +
> + ctrl = v4l2_ctrl_find(inst->v4l2_fh.ctrl_handler,
> V4L2_CID_MPEG_VIDEO_AVERAGE_QP);
> + if (ctrl)
> + v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp);
> +}
> +
> +static int wave6_vpu_enc_start_streaming(struct vb2_queue *q,
> unsigned int count)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct v4l2_pix_format_mplane *fmt;
> + struct vb2_queue *vq_peer;
> + int ret = 0;
> +
> + trace_start_streaming(inst, q->type);
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> + fmt = &inst->src_fmt;
> + vq_peer = v4l2_m2m_get_dst_vq(inst-
> >v4l2_fh.m2m_ctx);
> + } else {
> + fmt = &inst->dst_fmt;
> + vq_peer = v4l2_m2m_get_src_vq(inst-
> >v4l2_fh.m2m_ctx);
> + }
> +
> + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d
> buffers\n",
> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
> "capture",
> + fmt->pixelformat,
> + fmt->pixelformat >> 8,
> + fmt->pixelformat >> 16,
> + fmt->pixelformat >> 24,
> + fmt->width, fmt->height, vb2_get_num_buffers(q));
> +
> + if (!vb2_is_streaming(vq_peer))
> + return 0;
> +
> + wave6_vpu_pause(inst->dev->dev, 0);
> +
> + if (inst->state == VPU_INST_STATE_NONE) {
> + ret = wave6_vpu_enc_create_instance(inst);
> + if (ret)
> + goto exit;
> + }
> +
> + if (inst->state == VPU_INST_STATE_OPEN) {
> + ret = wave6_vpu_enc_initialize_instance(inst);
> + if (ret) {
> + wave6_vpu_enc_destroy_instance(inst);
> + goto exit;
> + }
> + }
> +
> + if (inst->state == VPU_INST_STATE_INIT_SEQ) {
> + ret = wave6_vpu_enc_prepare_fb(inst);
> + if (ret) {
> + wave6_vpu_enc_destroy_instance(inst);
> + goto exit;
> + }
> + }
> +
> +exit:
> + wave6_vpu_pause(inst->dev->dev, 1);
> + if (ret)
> + wave6_vpu_return_buffers(inst, q->type,
> VB2_BUF_STATE_QUEUED);
> +
> + return ret;
> +}
> +
> +static void wave6_vpu_enc_stop_streaming(struct vb2_queue *q)
> +{
> + struct vpu_instance *inst = vb2_get_drv_priv(q);
> + struct vb2_queue *vq_peer;
> +
> + trace_stop_streaming(inst, q->type);
> +
> + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d\n",
> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
> "capture",
> + inst->queued_src_buf_num, inst->sequence);
> +
> + if (inst->state == VPU_INST_STATE_NONE)
> + goto exit;
> +
> + if (wave6_vpu_both_queues_are_streaming(inst))
> + wave6_vpu_set_instance_state(inst,
> VPU_INST_STATE_STOP);
> +
> + wave6_vpu_pause(inst->dev->dev, 0);
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> + wave6_vpu_reset_performance(inst);
> + inst->queued_src_buf_num = 0;
> + inst->processed_buf_num = 0;
> + inst->error_buf_num = 0;
> + inst->sequence = 0;
> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
> false);
> + } else {
> + inst->eos = false;
> + inst->queued_dst_buf_num = 0;
> + }
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type))
> + vq_peer = v4l2_m2m_get_dst_vq(inst-
> >v4l2_fh.m2m_ctx);
> + else
> + vq_peer = v4l2_m2m_get_src_vq(inst-
> >v4l2_fh.m2m_ctx);
> +
> + if (!vb2_is_streaming(vq_peer) && inst->state !=
> VPU_INST_STATE_NONE)
> + wave6_vpu_enc_destroy_instance(inst);
> +
> + wave6_vpu_pause(inst->dev->dev, 1);
> +
> +exit:
> + wave6_vpu_return_buffers(inst, q->type,
> VB2_BUF_STATE_ERROR);
> +}
> +
> +static const struct vb2_ops wave6_vpu_enc_vb2_ops = {
> + .queue_setup = wave6_vpu_enc_queue_setup,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
> + .buf_queue = wave6_vpu_enc_buf_queue,
> + .buf_finish = wave6_vpu_enc_buf_finish,
> + .start_streaming = wave6_vpu_enc_start_streaming,
> + .stop_streaming = wave6_vpu_enc_stop_streaming,
> +};
> +
> +static void wave6_set_default_format(struct v4l2_pix_format_mplane
> *src_fmt,
> + struct v4l2_pix_format_mplane
> *dst_fmt)
> +{
> + const struct vpu_format *vpu_fmt;
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
> + if (vpu_fmt) {
> + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + src_fmt->num_planes = vpu_fmt->num_planes;
> + wave6_update_pix_fmt(src_fmt,
> + W6_DEF_ENC_PIC_WIDTH,
> W6_DEF_ENC_PIC_HEIGHT);
> + }
> +
> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
> + if (vpu_fmt) {
> + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
> + dst_fmt->num_planes = vpu_fmt->num_planes;
> + wave6_update_pix_fmt(dst_fmt,
> + W6_DEF_ENC_PIC_WIDTH,
> W6_DEF_ENC_PIC_HEIGHT);
> + }
> +}
> +
> +static int wave6_vpu_enc_queue_init(void *priv, struct vb2_queue
> *src_vq, struct vb2_queue *dst_vq)
> +{
> + struct vpu_instance *inst = priv;
> + int ret;
> +
> + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> + src_vq->mem_ops = &vb2_dma_contig_memops;
> + src_vq->ops = &wave6_vpu_enc_vb2_ops;
> + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> + src_vq->buf_struct_size = sizeof(struct vpu_buffer);
> + src_vq->drv_priv = inst;
> + src_vq->lock = &inst->dev->dev_lock;
> + src_vq->dev = inst->dev->v4l2_dev.dev;
> + ret = vb2_queue_init(src_vq);
> + if (ret)
> + return ret;
> +
> + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> + dst_vq->mem_ops = &vb2_dma_contig_memops;
> + dst_vq->ops = &wave6_vpu_enc_vb2_ops;
> + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> + dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
> + dst_vq->drv_priv = inst;
> + dst_vq->lock = &inst->dev->dev_lock;
> + dst_vq->dev = inst->dev->v4l2_dev.dev;
> + ret = vb2_queue_init(dst_vq);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static const struct vpu_instance_ops wave6_vpu_enc_inst_ops = {
> + .start_process = wave6_vpu_enc_start_encode,
> + .finish_process = wave6_vpu_enc_finish_encode,
> +};
> +
> +static int wave6_vpu_open_enc(struct file *filp)
> +{
> + struct video_device *vdev = video_devdata(filp);
> + struct vpu_device *dev = video_drvdata(filp);
> + struct vpu_instance *inst = NULL;
> + struct v4l2_ctrl_handler *v4l2_ctrl_hdl;
> + int ret;
> +
> + inst = kzalloc(sizeof(*inst), GFP_KERNEL);
> + if (!inst)
> + return -ENOMEM;
> + v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl;
> +
> + inst->dev = dev;
> + inst->type = VPU_INST_TYPE_ENC;
> + inst->ops = &wave6_vpu_enc_inst_ops;
> +
> + v4l2_fh_init(&inst->v4l2_fh, vdev);
> + filp->private_data = &inst->v4l2_fh;
> + v4l2_fh_add(&inst->v4l2_fh);
> +
> + inst->v4l2_fh.m2m_ctx =
> + v4l2_m2m_ctx_init(dev->m2m_dev, inst,
> wave6_vpu_enc_queue_init);
> + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
> + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
> + goto free_inst;
> + }
> +
> + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
> + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0,
> + V4L2_MPEG_VIDEO_HEVC_LEVEL_5);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
> + 0, 51, 1, 8);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
> + 0, 51, 1, 51);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
> +
> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
> +
> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
> + -6, 6, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
> + -6, 6, 1, 0);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
> + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR,
> +
> BIT(V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA),
> + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
> + 0, 2047, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_LEVEL,
> + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, 0,
> + V4L2_MPEG_VIDEO_H264_LEVEL_5_0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
> + 0, 51, 1, 8);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
> + 0, 51, 1, 51);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
> + 0, 51, 1, 30);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
> +
> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
> +
> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
> + -6, 6, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
> + -6, 6, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
> + -12, 12, 1, 0);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
> +
> V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0,
> +
> V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
> + 0, 2047, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
> 0, 1, 1, 0);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
> +
> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, 0,
> +
> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
> + 0, 0xFFFF, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
> + 0, 0xFFFF, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_HFLIP,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_VFLIP,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_ROTATE,
> + 0, 270, 90, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
> + 0, 18750000, 1, 0);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
> + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
> + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_BITRATE,
> + 1, 1500000000, 1, 2097152);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_GOP_SIZE,
> + 0, 2047, 1, 30);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
> +
> V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0,
> +
> V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
> + 0, 0x3FFFF, 1, 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
> + 0, 1, 1, 0);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
> + 0, 1, 1, 1);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> +
> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
> +
> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
> +
> BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM),
> +
> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
> + 0, 2160, 1, 0);
> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
> &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
> +
> V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
> +
> BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT),
> +
> V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
> + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1,
> 1);
> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, NULL,
> + V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1,
> 0);
> +
> + if (v4l2_ctrl_hdl->error) {
> + ret = -ENODEV;
> + goto err_m2m_release;
> + }
> +
> + inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl;
> + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
> +
> + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
> + wave6_update_crop_info(inst, 0, 0, inst->dst_fmt.width,
> inst->dst_fmt.height);
> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> + inst->frame_rate = 30;
> +
> + return 0;
> +
> +err_m2m_release:
> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
> +free_inst:
> + kfree(inst);
> + return ret;
> +}
> +
> +static int wave6_vpu_enc_release(struct file *filp)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(filp-
> >private_data);
> +
> + dprintk(inst->dev->dev, "[%d] release\n", inst->id);
> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
> +
> + mutex_lock(&inst->dev->dev_lock);
> + if (inst->state != VPU_INST_STATE_NONE) {
> + wave6_vpu_pause(inst->dev->dev, 0);
> + wave6_vpu_enc_destroy_instance(inst);
> + wave6_vpu_pause(inst->dev->dev, 1);
> + }
> + mutex_unlock(&inst->dev->dev_lock);
> +
> + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
> + v4l2_fh_del(&inst->v4l2_fh);
> + v4l2_fh_exit(&inst->v4l2_fh);
> + kfree(inst);
> +
> + return 0;
> +}
> +
> +static const struct v4l2_file_operations wave6_vpu_enc_fops = {
> + .owner = THIS_MODULE,
> + .open = wave6_vpu_open_enc,
> + .release = wave6_vpu_enc_release,
> + .unlocked_ioctl = video_ioctl2,
> + .poll = v4l2_m2m_fop_poll,
> + .mmap = v4l2_m2m_fop_mmap,
> +};
> +
> +int wave6_vpu_enc_register_device(struct vpu_device *dev)
> +{
> + struct video_device *vdev_enc;
> + int ret;
> +
> + vdev_enc = devm_kzalloc(dev->v4l2_dev.dev,
> sizeof(*vdev_enc), GFP_KERNEL);
> + if (!vdev_enc)
> + return -ENOMEM;
> +
> + dev->video_dev_enc = vdev_enc;
> +
> + strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc-
> >name));
> + vdev_enc->fops = &wave6_vpu_enc_fops;
> + vdev_enc->ioctl_ops = &wave6_vpu_enc_ioctl_ops;
> + vdev_enc->release = video_device_release_empty;
> + vdev_enc->v4l2_dev = &dev->v4l2_dev;
> + vdev_enc->vfl_dir = VFL_DIR_M2M;
> + vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
> V4L2_CAP_STREAMING;
> + vdev_enc->lock = &dev->dev_lock;
> + video_set_drvdata(vdev_enc, dev);
> +
> + ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +void wave6_vpu_enc_unregister_device(struct vpu_device *dev)
> +{
> + video_unregister_device(dev->video_dev_enc);
> +}
> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-
> v4l2.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
> new file mode 100644
> index 000000000000..e614eda01a5a
> --- /dev/null
> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
> @@ -0,0 +1,381 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +/*
> + * Wave6 series multi-standard codec IP - v4l2 driver helper
> interface
> + *
> + * Copyright (C) 2025 CHIPS&MEDIA INC
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/math64.h>
> +#include "wave6-vpu.h"
> +#include "wave6-vpu-dbg.h"
> +#include "wave6-trace.h"
> +
> +void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
> + unsigned int width,
> + unsigned int height)
> +{
> + const struct v4l2_format_info *fmt_info;
> + unsigned int stride_y;
> + int i;
> +
> + pix_mp->width = width;
> + pix_mp->height = height;
> + pix_mp->flags = 0;
> + pix_mp->field = V4L2_FIELD_NONE;
> + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
> +
> + fmt_info = v4l2_format_info(pix_mp->pixelformat);
> + if (!fmt_info) {
> + pix_mp->plane_fmt[0].bytesperline = 0;
> + if (!pix_mp->plane_fmt[0].sizeimage)
> + pix_mp->plane_fmt[0].sizeimage = width *
> height;
> +
> + return;
> + }
> +
> + stride_y = width * fmt_info->bpp[0];
> + if (pix_mp->plane_fmt[0].bytesperline <= W6_MAX_PIC_STRIDE)
> + stride_y = max(stride_y, pix_mp-
> >plane_fmt[0].bytesperline);
> + stride_y = round_up(stride_y, 32);
> + pix_mp->plane_fmt[0].bytesperline = stride_y;
> + pix_mp->plane_fmt[0].sizeimage = stride_y * height;
> +
> + stride_y = DIV_ROUND_UP(stride_y, fmt_info->bpp[0]);
> +
> + for (i = 1; i < fmt_info->comp_planes; i++) {
> + unsigned int stride_c, sizeimage_c;
> +
> + stride_c = DIV_ROUND_UP(stride_y, fmt_info->hdiv) *
> + fmt_info->bpp[i];
> + sizeimage_c = stride_c * DIV_ROUND_UP(height,
> fmt_info->vdiv);
> +
> + if (fmt_info->mem_planes == 1) {
> + pix_mp->plane_fmt[0].sizeimage +=
> sizeimage_c;
> + } else {
> + pix_mp->plane_fmt[i].bytesperline =
> stride_c;
> + pix_mp->plane_fmt[i].sizeimage =
> sizeimage_c;
> + }
> + }
> +}
> +
> +dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf, unsigned
> int plane_no)
> +{
> + return vb2_dma_contig_plane_dma_addr(&buf->vb2_buf,
> plane_no) +
> + buf->planes[plane_no].data_offset;
> +}
> +
> +struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct
> vpu_instance *inst,
> + dma_addr_t addr)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vb2_v4l2_buffer *dst_buf = NULL;
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + if (addr == wave6_get_dma_addr(vb2_v4l2_buf, 0)) {
> + dst_buf = vb2_v4l2_buf;
> + break;
> + }
> + }
> +
> + return dst_buf;
> +}
> +
> +enum codec_std wave6_to_codec_std(enum vpu_instance_type type,
> unsigned int v4l2_pix_fmt)
> +{
> + enum codec_std std = STD_UNKNOWN;
> +
> + if (v4l2_pix_fmt == V4L2_PIX_FMT_H264)
> + std = (type == VPU_INST_TYPE_DEC) ? W_AVC_DEC :
> W_AVC_ENC;
> + else if (v4l2_pix_fmt == V4L2_PIX_FMT_HEVC)
> + std = (type == VPU_INST_TYPE_DEC) ? W_HEVC_DEC :
> W_HEVC_ENC;
> +
> + return std;
> +}
> +
> +const char *wave6_vpu_instance_state_name(u32 state)
> +{
> + switch (state) {
> + case VPU_INST_STATE_NONE: return "none";
> + case VPU_INST_STATE_OPEN: return "open";
> + case VPU_INST_STATE_INIT_SEQ: return "init_seq";
> + case VPU_INST_STATE_PIC_RUN: return "pic_run";
> + case VPU_INST_STATE_SEEK: return "seek";
> + case VPU_INST_STATE_STOP: return "stop";
> + }
> + return "unknown";
> +}
> +
> +void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32
> state)
> +{
> + trace_set_state(inst, state);
> +
> + dprintk(inst->dev->dev, "[%d] %s -> %s\n",
> + inst->id,
> + wave6_vpu_instance_state_name(inst->state),
> + wave6_vpu_instance_state_name(state));
> +
> + inst->state = state;
> + if (state == VPU_INST_STATE_PIC_RUN && !inst-
> >performance.ts_first)
> + inst->performance.ts_first = ktime_get_raw();
> +}
> +
> +u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle)
> +{
> + if (!vpu_dev || !vpu_dev->clk_vpu || !clk_get_rate(vpu_dev-
> >clk_vpu))
> + return 0;
> +
> + return (cycle * NSEC_PER_SEC) / clk_get_rate(vpu_dev-
> >clk_vpu);
> +}
> +
> +int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int
> timeout)
> +{
> + int ret;
> +
> + ret = wait_for_completion_timeout(&inst->dev->irq_done,
> +
> msecs_to_jiffies(timeout));
> + if (!ret)
> + return -ETIMEDOUT;
> +
> + reinit_completion(&inst->dev->irq_done);
> +
> + return 0;
> +}
> +
> +int wave6_vpu_subscribe_event(struct v4l2_fh *fh,
> + const struct v4l2_event_subscription
> *sub)
> +{
> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
> + bool is_decoder = (inst->type == VPU_INST_TYPE_DEC) ? true :
> false;
> +
> + dev_dbg(inst->dev->dev, "%s: [%s] type: %d id: %d | flags:
> %d\n",
> + __func__, is_decoder ? "decoder" : "encoder", sub-
> >type,
> + sub->id, sub->flags);
> +
> + switch (sub->type) {
> + case V4L2_EVENT_SOURCE_CHANGE:
> + if (is_decoder)
> + return v4l2_src_change_event_subscribe(fh,
> sub);
> + return -EINVAL;
> + case V4L2_EVENT_CTRL:
> + return v4l2_ctrl_subscribe_event(fh, sub);
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +void wave6_vpu_return_buffers(struct vpu_instance *inst,
> + unsigned int type, enum
> vb2_buffer_state state)
> +{
> + struct vb2_v4l2_buffer *buf;
> + int i;
> +
> + if (V4L2_TYPE_IS_OUTPUT(type)) {
> + while ((buf = v4l2_m2m_src_buf_remove(inst-
> >v4l2_fh.m2m_ctx)))
> + v4l2_m2m_buf_done(buf, state);
> + } else {
> + while ((buf = v4l2_m2m_dst_buf_remove(inst-
> >v4l2_fh.m2m_ctx))) {
> + for (i = 0; i < inst->dst_fmt.num_planes;
> i++)
> + vb2_set_plane_payload(&buf->vb2_buf,
> i, 0);
> + v4l2_m2m_buf_done(buf, state);
> + }
> + }
> +}
> +
> +u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf;
> + u32 num = 0;
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
> + if (vpu_buf->consumed)
> + num++;
> + }
> +
> + return num;
> +}
> +
> +u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf;
> + u32 num = 0;
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
> + if (vpu_buf->used)
> + num++;
> + }
> +
> + return num;
> +}
> +
> +static bool wave6_vpu_check_fb_available(struct vpu_instance *inst)
> +{
> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
> + struct vpu_buffer *vpu_buf;
> +
> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
> v4l2_m2m_buf) {
> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
> +
> + if (!vpu_buf->used)
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static int wave6_vpu_job_ready(void *priv)
> +{
> + struct vpu_instance *inst = priv;
> +
> + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
> + inst->id, __func__, inst->state);
> +
> + if (inst->type == VPU_INST_TYPE_DEC && inst->state ==
> VPU_INST_STATE_OPEN)
> + return 1;
> + if (inst->state < VPU_INST_STATE_PIC_RUN)
> + return 0;
> + if (inst->state == VPU_INST_STATE_STOP && inst->eos)
> + return 0;
> + if (!wave6_vpu_check_fb_available(inst))
> + return 0;
> +
> + return 1;
> +}
> +
> +static void wave6_vpu_device_run_timeout(struct work_struct *work)
> +{
> + struct delayed_work *dwork = to_delayed_work(work);
> + struct vpu_device *dev = container_of(dwork, struct
> vpu_device, task_timer);
> + struct vpu_instance *inst = v4l2_m2m_get_curr_priv(dev-
> >m2m_dev);
> + struct vb2_v4l2_buffer *src_buf = NULL;
> + struct vb2_v4l2_buffer *dst_buf = NULL;
> +
> + if (!inst)
> + return;
> +
> + dev_err(inst->dev->dev, "[%d] sequence %d timeout\n", inst-
> >id, inst->sequence);
> + src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
> + if (src_buf) {
> + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
> + if (inst->type == VPU_INST_TYPE_DEC)
> + inst->processed_buf_num++;
> + inst->error_buf_num++;
> + }
> +
> + dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
> + if (dst_buf)
> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
> +
> + vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx));
> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx));
> +
> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
> >v4l2_fh.m2m_ctx);
> +}
> +
> +static void wave6_vpu_device_run(void *priv)
> +{
> + struct vpu_instance *inst = priv;
> + int ret;
> +
> + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
> + inst->id, __func__, inst->state);
> +
> + ret = inst->ops->start_process(inst);
> + if (!ret)
> + schedule_delayed_work(&inst->dev->task_timer,
> msecs_to_jiffies(W6_VPU_TIMEOUT));
> + else
> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
> >v4l2_fh.m2m_ctx);
> +}
> +
> +void wave6_vpu_finish_job(struct vpu_instance *inst)
> +{
> + cancel_delayed_work(&inst->dev->task_timer);
> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
> >v4l2_fh.m2m_ctx);
> +}
> +
> +void wave6_vpu_handle_performance(struct vpu_instance *inst, struct
> vpu_buffer *vpu_buf)
> +{
> + s64 latency, time_spent;
> +
> + if (!inst || !vpu_buf)
> + return;
> +
> + inst->performance.ts_last = vpu_buf->ts_output;
> +
> + latency = vpu_buf->ts_output - vpu_buf->ts_input;
> + time_spent = vpu_buf->ts_finish - vpu_buf->ts_start;
> +
> + if (!inst->performance.latency_first)
> + inst->performance.latency_first = latency;
> + inst->performance.latency_max = max_t(s64, latency, inst-
> >performance.latency_max);
> +
> + if (!inst->performance.min_process_time)
> + inst->performance.min_process_time = time_spent;
> + else if (inst->performance.min_process_time > time_spent)
> + inst->performance.min_process_time = time_spent;
> +
> + if (inst->performance.max_process_time < time_spent)
> + inst->performance.max_process_time = time_spent;
> +
> + inst->performance.total_sw_time += time_spent;
> + inst->performance.total_hw_time += vpu_buf->hw_time;
> +}
> +
> +void wave6_vpu_reset_performance(struct vpu_instance *inst)
> +{
> + if (!inst)
> + return;
> +
> + if (inst->processed_buf_num) {
> + s64 tmp;
> + s64 fps_act, fps_sw, fps_hw;
> + struct vpu_performance_info *perf = &inst-
> >performance;
> +
> + tmp = MSEC_PER_SEC * inst->processed_buf_num;
> + fps_act = DIV_ROUND_CLOSEST(tmp, (perf->ts_last -
> perf->ts_first) / NSEC_PER_MSEC);
> + fps_sw = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time
> / NSEC_PER_MSEC);
> + fps_hw = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time
> / NSEC_PER_MSEC);
> + dprintk(inst->dev->dev,
> + "[%d] fps actual: %lld, sw: %lld, hw: %lld,
> latency(ms) %llu.%06llu\n",
> + inst->id, fps_act, fps_sw, fps_hw,
> + perf->latency_first / NSEC_PER_MSEC,
> + perf->latency_first % NSEC_PER_MSEC);
> + }
> +
> + memset(&inst->performance, 0, sizeof(inst->performance));
> +}
> +
> +static const struct v4l2_m2m_ops wave6_vpu_m2m_ops = {
> + .device_run = wave6_vpu_device_run,
> + .job_ready = wave6_vpu_job_ready,
> +};
> +
> +int wave6_vpu_init_m2m_dev(struct vpu_device *dev)
> +{
> + dev->m2m_dev = v4l2_m2m_init(&wave6_vpu_m2m_ops);
> + if (IS_ERR(dev->m2m_dev)) {
> + dev_err(dev->dev, "v4l2_m2m_init fail: %ld\n",
> PTR_ERR(dev->m2m_dev));
> + return PTR_ERR(dev->m2m_dev);
> + }
> +
> + INIT_DELAYED_WORK(&dev->task_timer,
> wave6_vpu_device_run_timeout);
> +
> + return 0;
> +}
> +
> +void wave6_vpu_release_m2m_dev(struct vpu_device *dev)
> +{
> + v4l2_m2m_release(dev->m2m_dev);
> +}
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver
2025-02-17 18:33 ` Nicolas Dufresne
@ 2025-02-19 4:36 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-19 4:36 UTC (permalink / raw)
To: Nicolas Dufresne, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Nicolas.
>-----Original Message-----
>From: Nicolas Dufresne <nicolas@ndufresne.ca>
>Sent: Tuesday, February 18, 2025 3:33 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; sebastian.fricke@collabora.com; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver
>
>Hi Nas.
>
>Le lundi 10 février 2025 à 18:07 +0900, Nas Chung a écrit :
>> Add v4l2 m2m drivers which support stateful decoder and encoder.
>
>Before sending updates, note that this is quite short of a commit
>message for a newly introduce driver. Your readers would certainly like
>to know what feature have been included, what is not, etc. My
>understanding from the discussion is that the Wave6 design can be
>configured with a lot more features then what this driver covers.
>
>I know you have placed some of that in the cover letter, but no one
>will find it when later doing git blame.
Thanks for you feedback.
Got it! I will ensure that each commit message includes enough details.
Thanks.
Nas.
>
>regards,
>Nicolas
>
>>
>> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>> ---
>> .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++++
>> .../chips-media/wave6/wave6-vpu-enc.c | 2698
>> +++++++++++++++++
>> .../chips-media/wave6/wave6-vpu-v4l2.c | 381 +++
>> 3 files changed, 4962 insertions(+)
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>> vpu-dec.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>> vpu-enc.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>> vpu-v4l2.c
>>
>> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
>> b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
>> new file mode 100644
>> index 000000000000..f6ed078a2824
>> --- /dev/null
>> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
>> @@ -0,0 +1,1883 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>> +/*
>> + * Wave6 series multi-standard codec IP - v4l2 stateful decoder
>> interface
>> + *
>> + * Copyright (C) 2025 CHIPS&MEDIA INC
>> + */
>> +
>> +#include <linux/pm_runtime.h>
>> +#include <linux/delay.h>
>> +#include "wave6-vpu.h"
>> +#include "wave6-vpu-dbg.h"
>> +#include "wave6-trace.h"
>> +
>> +#define VPU_DEC_DEV_NAME "C&M Wave6 VPU decoder"
>> +#define VPU_DEC_DRV_NAME "wave6-dec"
>> +#define V4L2_CID_VPU_THUMBNAIL_MODE (V4L2_CID_USER_BASE + 0x1001)
>> +
>> +static const struct vpu_format wave6_vpu_dec_fmt_list[2][6] = {
>> + [VPU_FMT_TYPE_CODEC] = {
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + },
>> + [VPU_FMT_TYPE_RAW] = {
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 3,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
>> + .max_width = W6_MAX_DEC_PIC_WIDTH,
>> + .min_width = W6_MIN_DEC_PIC_WIDTH,
>> + .max_height = W6_MAX_DEC_PIC_HEIGHT,
>> + .min_height = W6_MIN_DEC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + }
>> +};
>> +
>> +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst);
>> +
>> +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int
>> v4l2_pix_fmt,
>> + enum vpu_fmt_type
>> type)
>> +{
>> + unsigned int index;
>> +
>> + for (index = 0; index <
>> ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]); index++) {
>> + if (wave6_vpu_dec_fmt_list[type][index].v4l2_pix_fmt
>> == v4l2_pix_fmt)
>> + return &wave6_vpu_dec_fmt_list[type][index];
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned
>> int idx,
>> + enum
>> vpu_fmt_type type)
>> +{
>> + if (idx >= ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]))
>> + return NULL;
>> +
>> + if (!wave6_vpu_dec_fmt_list[type][idx].v4l2_pix_fmt)
>> + return NULL;
>> +
>> + return &wave6_vpu_dec_fmt_list[type][idx];
>> +}
>> +
>> +static void wave6_vpu_dec_release_fb(struct vpu_instance *inst)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < WAVE6_MAX_FBS; i++) {
>> + wave6_free_dma(&inst->frame_vbuf[i]);
>> + memset(&inst->frame_buf[i], 0, sizeof(struct
>> frame_buffer));
>> + wave6_free_dma(&inst-
>> >aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
>> + wave6_free_dma(&inst-
>> >aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
>> + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
>> + }
>> +}
>> +
>> +static void wave6_vpu_dec_destroy_instance(struct vpu_instance
>> *inst)
>> +{
>> + u32 fail_res;
>> + int ret;
>> +
>> + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst-
>> >id);
>> + wave6_vpu_remove_dbgfs_file(inst);
>> +
>> + ret = wave6_vpu_dec_close(inst, &fail_res);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "failed destroy instance: %d
>> (%d)\n",
>> + ret, fail_res);
>> + }
>> +
>> + wave6_vpu_dec_release_fb(inst);
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
>> +
>> + if (!pm_runtime_suspended(inst->dev->dev))
>> + pm_runtime_put_sync(inst->dev->dev);
>> +}
>> +
>> +static void wave6_handle_bitstream_buffer(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *src_buf;
>> + u32 src_size = 0;
>> + int ret;
>> +
>> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
>> + if (src_buf) {
>> + struct vpu_buffer *vpu_buf =
>> wave6_to_vpu_buf(src_buf);
>> + dma_addr_t rd_ptr = wave6_get_dma_addr(src_buf, 0);
>> +
>> + if (vpu_buf->consumed) {
>> + dev_dbg(inst->dev->dev, "%s: Already
>> consumed buffer\n",
>> + __func__);
>> + return;
>> + }
>> +
>> + vpu_buf->ts_start = ktime_get_raw();
>> + vpu_buf->consumed = true;
>> + wave6_vpu_dec_set_rd_ptr(inst, rd_ptr, true);
>> +
>> + src_size = vb2_get_plane_payload(&src_buf->vb2_buf,
>> 0);
>> + }
>> +
>> + if (!src_size) {
>> + dma_addr_t rd = 0, wr = 0;
>> +
>> + wave6_vpu_dec_get_bitstream_buffer(inst, &rd, &wr);
>> + wave6_vpu_dec_set_rd_ptr(inst, wr, true);
>> + }
>> +
>> + trace_dec_pic(inst, src_buf ? src_buf->vb2_buf.index : -1,
>> src_size);
>> +
>> + ret = wave6_vpu_dec_update_bitstream_buffer(inst, src_size);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Update bitstream buffer
>> fail %d\n",
>> + __func__, ret);
>> + return;
>> + }
>> +}
>> +
>> +static void wave6_update_pix_fmt_cap(struct v4l2_pix_format_mplane
>> *pix_mp,
>> + unsigned int width,
>> + unsigned int height,
>> + bool new_resolution)
>> +{
>> + unsigned int aligned_width;
>> +
>> + if (new_resolution)
>> + pix_mp->plane_fmt[0].bytesperline = 0;
>> +
>> + aligned_width = round_up(width, 32);
>> + wave6_update_pix_fmt(pix_mp, aligned_width, height);
>> +}
>> +
>> +static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
>> + enum aux_buffer_type type,
>> + int num)
>> +{
>> + struct aux_buffer buf[WAVE6_MAX_FBS];
>> + struct aux_buffer_info buf_info;
>> + struct dec_aux_buffer_size_info size_info;
>> + unsigned int size;
>> + int i, ret;
>> +
>> + memset(buf, 0, sizeof(buf));
>> +
>> + size_info.width = inst->src_fmt.width;
>> + size_info.height = inst->src_fmt.height;
>> + size_info.type = type;
>> +
>> + ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info,
>> &size);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Get size fail (type
>> %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + num = min_t(u32, num, WAVE6_MAX_FBS);
>> + for (i = 0; i < num; i++) {
>> + inst->aux_vbuf[type][i].size = size;
>> + ret = wave6_alloc_dma(inst->dev->dev, &inst-
>> >aux_vbuf[type][i]);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Alloc fail
>> (type %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + buf[i].index = i;
>> + buf[i].addr = inst->aux_vbuf[type][i].daddr;
>> + buf[i].size = inst->aux_vbuf[type][i].size;
>> + }
>> +
>> + buf_info.type = type;
>> + buf_info.num = num;
>> + buf_info.buf_array = buf;
>> +
>> + ret = wave6_vpu_dec_register_aux_buffer(inst, buf_info);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Register fail (type
>> %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void wave6_vpu_dec_handle_dst_buffer(struct vpu_instance
>> *inst)
>> +{
>> + struct vb2_v4l2_buffer *dst_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf;
>> + dma_addr_t buf_addr_y, buf_addr_cb, buf_addr_cr;
>> + u32 buf_size;
>> + u32 fb_stride = inst->dst_fmt.plane_fmt[0].bytesperline;
>> + u32 luma_size = fb_stride * inst->dst_fmt.height;
>> + u32 chroma_size = (fb_stride / 2) * (inst->dst_fmt.height /
>> 2);
>> + struct frame_buffer disp_buffer = {0};
>> + struct dec_initial_info initial_info = {0};
>> + int consumed_num = wave6_vpu_get_consumed_fb_num(inst);
>> + int ret;
>> +
>> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
>> &initial_info);
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + dst_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(dst_buf);
>> +
>> + if (vpu_buf->consumed)
>> + continue;
>> +
>> + if (consumed_num >= WAVE6_MAX_FBS)
>> + break;
>> +
>> + if (inst->dst_fmt.num_planes == 1) {
>> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
>> 0);
>> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
>> + buf_addr_cb = buf_addr_y + luma_size;
>> + buf_addr_cr = buf_addr_cb + chroma_size;
>> + } else if (inst->dst_fmt.num_planes == 2) {
>> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
>> 0) +
>> + vb2_plane_size(&dst_buf->vb2_buf,
>> 1);
>> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
>> + buf_addr_cb = wave6_get_dma_addr(dst_buf,
>> 1);
>> + buf_addr_cr = buf_addr_cb + chroma_size;
>> + } else if (inst->dst_fmt.num_planes == 3) {
>> + buf_size = vb2_plane_size(&dst_buf->vb2_buf,
>> 0) +
>> + vb2_plane_size(&dst_buf->vb2_buf,
>> 1) +
>> + vb2_plane_size(&dst_buf->vb2_buf,
>> 2);
>> + buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
>> + buf_addr_cb = wave6_get_dma_addr(dst_buf,
>> 1);
>> + buf_addr_cr = wave6_get_dma_addr(dst_buf,
>> 2);
>> + }
>> + disp_buffer.buf_y = buf_addr_y;
>> + disp_buffer.buf_cb = buf_addr_cb;
>> + disp_buffer.buf_cr = buf_addr_cr;
>> + disp_buffer.width = inst->src_fmt.width;
>> + disp_buffer.height = inst->src_fmt.height;
>> + disp_buffer.stride = fb_stride;
>> + disp_buffer.map_type = LINEAR_FRAME_MAP;
>> + disp_buffer.luma_bitdepth =
>> initial_info.luma_bitdepth;
>> + disp_buffer.chroma_bitdepth =
>> initial_info.chroma_bitdepth;
>> + disp_buffer.chroma_format_idc =
>> initial_info.chroma_format_idc;
>> +
>> + ret = wave6_vpu_dec_register_display_buffer_ex(inst,
>> disp_buffer);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "fail register
>> display buffer %d", ret);
>> + break;
>> + }
>> +
>> + vpu_buf->consumed = true;
>> + consumed_num++;
>> + }
>> +}
>> +
>> +static enum v4l2_quantization to_v4l2_quantization(u32
>> video_full_range_flag)
>> +{
>> + switch (video_full_range_flag) {
>> + case 0:
>> + return V4L2_QUANTIZATION_LIM_RANGE;
>> + case 1:
>> + return V4L2_QUANTIZATION_FULL_RANGE;
>> + default:
>> + return V4L2_QUANTIZATION_DEFAULT;
>> + }
>> +}
>> +
>> +static enum v4l2_colorspace to_v4l2_colorspace(u32 colour_primaries)
>> +{
>> + switch (colour_primaries) {
>> + case 1:
>> + return V4L2_COLORSPACE_REC709;
>> + case 4:
>> + return V4L2_COLORSPACE_470_SYSTEM_M;
>> + case 5:
>> + return V4L2_COLORSPACE_470_SYSTEM_BG;
>> + case 6:
>> + return V4L2_COLORSPACE_SMPTE170M;
>> + case 7:
>> + return V4L2_COLORSPACE_SMPTE240M;
>> + case 9:
>> + return V4L2_COLORSPACE_BT2020;
>> + case 11:
>> + return V4L2_COLORSPACE_DCI_P3;
>> + default:
>> + return V4L2_COLORSPACE_DEFAULT;
>> + }
>> +}
>> +
>> +static enum v4l2_xfer_func to_v4l2_xfer_func(u32
>> transfer_characteristics)
>> +{
>> + switch (transfer_characteristics) {
>> + case 1:
>> + return V4L2_XFER_FUNC_709;
>> + case 6:
>> + return V4L2_XFER_FUNC_709;
>> + case 7:
>> + return V4L2_XFER_FUNC_SMPTE240M;
>> + case 8:
>> + return V4L2_XFER_FUNC_NONE;
>> + case 13:
>> + return V4L2_XFER_FUNC_SRGB;
>> + case 14:
>> + return V4L2_XFER_FUNC_709;
>> + case 16:
>> + return V4L2_XFER_FUNC_SMPTE2084;
>> + default:
>> + return V4L2_XFER_FUNC_DEFAULT;
>> + }
>> +}
>> +
>> +static enum v4l2_ycbcr_encoding to_v4l2_ycbcr_encoding(u32
>> matrix_coeffs)
>> +{
>> + switch (matrix_coeffs) {
>> + case 1:
>> + return V4L2_YCBCR_ENC_709;
>> + case 5:
>> + return V4L2_YCBCR_ENC_601;
>> + case 6:
>> + return V4L2_YCBCR_ENC_601;
>> + case 7:
>> + return V4L2_YCBCR_ENC_SMPTE240M;
>> + case 9:
>> + return V4L2_YCBCR_ENC_BT2020;
>> + case 10:
>> + return V4L2_YCBCR_ENC_BT2020_CONST_LUM;
>> + default:
>> + return V4L2_YCBCR_ENC_DEFAULT;
>> + }
>> +}
>> +
>> +static void wave6_update_color_info(struct vpu_instance *inst,
>> + struct dec_initial_info
>> *initial_info)
>> +{
>> + struct color_param *color = &initial_info->color;
>> +
>> + if (!color->video_signal_type_present)
>> + goto set_default_all;
>> +
>> + inst->quantization = to_v4l2_quantization(color-
>> >color_range);
>> +
>> + if (!color->color_description_present)
>> + goto set_default_color;
>> +
>> + inst->colorspace = to_v4l2_colorspace(color-
>> >color_primaries);
>> + inst->xfer_func = to_v4l2_xfer_func(color-
>> >transfer_characteristics);
>> + inst->ycbcr_enc = to_v4l2_ycbcr_encoding(color-
>> >matrix_coefficients);
>> +
>> + return;
>> +
>> +set_default_all:
>> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
>> +set_default_color:
>> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
>> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
>> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
>> +}
>> +
>> +static enum v4l2_mpeg_video_hevc_profile to_v4l2_hevc_profile(u32
>> profile)
>> +{
>> + switch (profile) {
>> + case HEVC_PROFILE_MAIN:
>> + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
>> + default:
>> + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
>> + }
>> +}
>> +
>> +static enum v4l2_mpeg_video_h264_profile to_v4l2_h264_profile(u32
>> profile)
>> +{
>> + switch (profile) {
>> + case H264_PROFILE_BP:
>> + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
>> + case H264_PROFILE_MP:
>> + return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
>> + case H264_PROFILE_EXTENDED:
>> + return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
>> + case H264_PROFILE_HP:
>> + return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
>> + default:
>> + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
>> + }
>> +}
>> +
>> +static void wave6_update_v4l2_ctrls(struct vpu_instance *inst,
>> + struct dec_initial_info *info)
>> +{
>> + struct v4l2_ctrl *ctrl;
>> + u32 min_disp_cnt;
>> +
>> + min_disp_cnt = info->frame_buf_delay + 1;
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
>> + if (ctrl)
>> + v4l2_ctrl_s_ctrl(ctrl, min_disp_cnt);
>> +
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_HEVC) {
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> +
>> V4L2_CID_MPEG_VIDEO_HEVC_PROFILE);
>> + if (ctrl)
>> + v4l2_ctrl_s_ctrl(ctrl,
>> to_v4l2_hevc_profile(info->profile));
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_H264) {
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_PROFILE);
>> + if (ctrl)
>> + v4l2_ctrl_s_ctrl(ctrl,
>> to_v4l2_h264_profile(info->profile));
>> + }
>> +}
>> +
>> +static int wave6_vpu_dec_start_decode(struct vpu_instance *inst)
>> +{
>> + struct dec_param pic_param;
>> + int ret;
>> + u32 fail_res = 0;
>> +
>> + memset(&pic_param, 0, sizeof(struct dec_param));
>> +
>> + wave6_handle_bitstream_buffer(inst);
>> + if (inst->state == VPU_INST_STATE_OPEN) {
>> + ret = wave6_vpu_dec_seek_header(inst);
>> + if (ret) {
>> + vb2_queue_error(v4l2_m2m_get_src_vq(inst-
>> >v4l2_fh.m2m_ctx));
>> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst-
>> >v4l2_fh.m2m_ctx));
>> + }
>> + return -EAGAIN;
>> + }
>> +
>> + wave6_vpu_dec_handle_dst_buffer(inst);
>> +
>> + ret = wave6_vpu_dec_start_one_frame(inst, &pic_param,
>> &fail_res);
>> + if (ret) {
>> + struct vb2_v4l2_buffer *src_buf = NULL;
>> +
>> + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst-
>> >id, __func__, ret);
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_STOP);
>> +
>> + src_buf = v4l2_m2m_src_buf_remove(inst-
>> >v4l2_fh.m2m_ctx);
>> + if (src_buf) {
>> + v4l2_m2m_buf_done(src_buf,
>> VB2_BUF_STATE_ERROR);
>> + inst->sequence++;
>> + inst->processed_buf_num++;
>> + inst->error_buf_num++;
>> + }
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static void wave6_handle_decoded_frame(struct vpu_instance *inst,
>> + struct dec_output_info *info)
>> +{
>> + struct vb2_v4l2_buffer *src_buf;
>> + struct vb2_v4l2_buffer *dst_buf;
>> + struct vpu_buffer *vpu_buf;
>> + enum vb2_buffer_state state;
>> +
>> + state = info->decoding_success ? VB2_BUF_STATE_DONE :
>> VB2_BUF_STATE_ERROR;
>> +
>> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
>> + if (!src_buf) {
>> + dev_err(inst->dev->dev, "[%d] decoder can't find src
>> buffer\n", inst->id);
>> + return;
>> + }
>> +
>> + vpu_buf = wave6_to_vpu_buf(src_buf);
>> + if (!vpu_buf || !vpu_buf->consumed) {
>> + dev_err(inst->dev->dev, "[%d] src buffer is not
>> consumed\n", inst->id);
>> + return;
>> + }
>> +
>> + dst_buf = wave6_get_dst_buf_by_addr(inst, info-
>> >frame_decoded_addr);
>> + if (dst_buf) {
>> + struct vpu_buffer *dst_vpu_buf =
>> wave6_to_vpu_buf(dst_buf);
>> +
>> + if (wave6_to_vpu_buf(dst_buf)->used) {
>> + dev_warn(inst->dev->dev, "[%d] duplication
>> frame buffer\n", inst->id);
>> + inst->sequence++;
>> + }
>> + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
>> + dst_vpu_buf->used = true;
>> + if (state == VB2_BUF_STATE_ERROR)
>> + dst_vpu_buf->error = true;
>> + dst_vpu_buf->ts_input = vpu_buf->ts_input;
>> + dst_vpu_buf->ts_start = vpu_buf->ts_start;
>> + dst_vpu_buf->ts_finish = ktime_get_raw();
>> + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst-
>> >dev, info->cycle.frame_cycle);
>> + }
>> +
>> + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
>> src_buf);
>> + if (state == VB2_BUF_STATE_ERROR) {
>> + dprintk(inst->dev->dev, "[%d] error frame %d\n",
>> inst->id, inst->sequence);
>> + inst->error_buf_num++;
>> + }
>> + v4l2_m2m_buf_done(src_buf, state);
>> + inst->processed_buf_num++;
>> +}
>> +
>> +static void wave6_handle_skipped_frame(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *src_buf;
>> + struct vpu_buffer *vpu_buf;
>> +
>> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
>> + if (!src_buf)
>> + return;
>> +
>> + vpu_buf = wave6_to_vpu_buf(src_buf);
>> + if (!vpu_buf || !vpu_buf->consumed)
>> + return;
>> +
>> + dprintk(inst->dev->dev, "[%d] skip frame %d\n", inst->id,
>> inst->sequence);
>> +
>> + inst->sequence++;
>> + inst->processed_buf_num++;
>> + inst->error_buf_num++;
>> + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
>> src_buf);
>> + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
>> +}
>> +
>> +static void wave6_handle_display_frame(struct vpu_instance *inst,
>> + dma_addr_t addr, enum
>> vb2_buffer_state state)
>> +{
>> + struct vb2_v4l2_buffer *dst_buf;
>> + struct vpu_buffer *vpu_buf;
>> +
>> + dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
>> + if (!dst_buf)
>> + return;
>> +
>> + vpu_buf = wave6_to_vpu_buf(dst_buf);
>> + if (!vpu_buf->used) {
>> + dprintk(inst->dev->dev, "[%d] recycle display
>> buffer\n", inst->id);
>> + vpu_buf->consumed = false;
>> + return;
>> + }
>> +
>> + if (inst->dst_fmt.num_planes == 1) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
>> + inst-
>> >dst_fmt.plane_fmt[0].sizeimage);
>> + } else if (inst->dst_fmt.num_planes == 2) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
>> + inst-
>> >dst_fmt.plane_fmt[0].sizeimage);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
>> + inst-
>> >dst_fmt.plane_fmt[1].sizeimage);
>> + } else if (inst->dst_fmt.num_planes == 3) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
>> + inst-
>> >dst_fmt.plane_fmt[0].sizeimage);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1,
>> + inst-
>> >dst_fmt.plane_fmt[1].sizeimage);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 2,
>> + inst-
>> >dst_fmt.plane_fmt[2].sizeimage);
>> + }
>> +
>> + vpu_buf->ts_output = ktime_get_raw();
>> + wave6_vpu_handle_performance(inst, vpu_buf);
>> +
>> + if (vpu_buf->error)
>> + state = VB2_BUF_STATE_ERROR;
>> + dst_buf->sequence = inst->sequence++;
>> + dst_buf->field = V4L2_FIELD_NONE;
>> + if (state == VB2_BUF_STATE_ERROR)
>> + dprintk(inst->dev->dev, "[%d] discard frame %d\n",
>> inst->id, dst_buf->sequence);
>> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
>> dst_buf);
>> + v4l2_m2m_buf_done(dst_buf, state);
>> +}
>> +
>> +static void wave6_handle_display_frames(struct vpu_instance *inst,
>> + struct dec_output_info
>> *info)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < info->disp_frame_num; i++)
>> + wave6_handle_display_frame(inst,
>> + info->disp_frame_addr[i],
>> + VB2_BUF_STATE_DONE);
>> +}
>> +
>> +static void wave6_handle_discard_frames(struct vpu_instance *inst,
>> + struct dec_output_info
>> *info)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < info->release_disp_frame_num; i++)
>> + wave6_handle_display_frame(inst,
>> + info-
>> >release_disp_frame_addr[i],
>> + VB2_BUF_STATE_ERROR);
>> +}
>> +
>> +static void wave6_handle_last_frame(struct vpu_instance *inst,
>> + struct vb2_v4l2_buffer *dst_buf)
>> +{
>> + if (!dst_buf) {
>> + dst_buf = v4l2_m2m_dst_buf_remove(inst-
>> >v4l2_fh.m2m_ctx);
>> + if (!dst_buf) {
>> + inst->next_buf_last = true;
>> + return;
>> + }
>> + }
>> +
>> + if (inst->dst_fmt.num_planes == 1) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
>> + } else if (inst->dst_fmt.num_planes == 2) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
>> + } else if (inst->dst_fmt.num_planes == 3) {
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 2, 0);
>> + }
>> +
>> + dst_buf->flags |= V4L2_BUF_FLAG_LAST;
>> + dst_buf->field = V4L2_FIELD_NONE;
>> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
>> +
>> + if (inst->state != VPU_INST_STATE_INIT_SEQ) {
>> + dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
>> + inst->eos = true;
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
>> false);
>> + }
>> +}
>> +
>> +static void wave6_vpu_dec_retry_one_frame(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *src_buf;
>> + struct vpu_buffer *vpu_buf;
>> +
>> + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
>> + if (!src_buf)
>> + return;
>> +
>> + vpu_buf = wave6_to_vpu_buf(src_buf);
>> + vpu_buf->consumed = false;
>> +}
>> +
>> +static void wave6_vpu_dec_handle_source_change(struct vpu_instance
>> *inst,
>> + struct
>> dec_initial_info *info)
>> +{
>> + static const struct v4l2_event vpu_event_src_ch = {
>> + .type = V4L2_EVENT_SOURCE_CHANGE,
>> + .u.src_change.changes =
>> V4L2_EVENT_SRC_CH_RESOLUTION,
>> + };
>> +
>> + dprintk(inst->dev->dev, "pic size %dx%d profile %d,
>> min_fb_cnt : %d | min_disp_cnt : %d\n",
>> + info->pic_width, info->pic_height,
>> + info->profile, info->min_frame_buffer_count, info-
>> >frame_buf_delay);
>> +
>> + wave6_vpu_dec_retry_one_frame(inst);
>> + wave6_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO,
>> NULL);
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
>> +
>> + inst->crop.left = info->pic_crop_rect.left;
>> + inst->crop.top = info->pic_crop_rect.top;
>> + inst->crop.width = info->pic_crop_rect.right - inst-
>> >crop.left;
>> + inst->crop.height = info->pic_crop_rect.bottom - inst-
>> >crop.top;
>> +
>> + wave6_update_v4l2_ctrls(inst, info);
>> + wave6_update_color_info(inst, info);
>> + wave6_update_pix_fmt(&inst->src_fmt, info->pic_width, info-
>> >pic_height);
>> + wave6_update_pix_fmt_cap(&inst->dst_fmt,
>> + info->pic_width, info->pic_height,
>> + true);
>> +
>> + trace_source_change(inst, info);
>> +
>> + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_src_ch);
>> +}
>> +
>> +static void wave6_vpu_dec_handle_decoding_warn_error(struct
>> vpu_instance *inst,
>> + struct
>> dec_output_info *info)
>> +{
>> + if (info->warn_info)
>> + dev_dbg(inst->dev->dev, "[%d] decoding %d warning
>> 0x%x\n",
>> + inst->id, inst->processed_buf_num, info-
>> >warn_info);
>> +
>> + if (info->error_reason)
>> + dev_err(inst->dev->dev, "[%d] decoding %d error
>> 0x%x\n",
>> + inst->id, inst->processed_buf_num, info-
>> >error_reason);
>> +}
>> +
>> +static void wave6_vpu_dec_finish_decode(struct vpu_instance *inst,
>> bool error)
>> +{
>> + struct dec_output_info info;
>> + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
>> + int ret;
>> +
>> + ret = wave6_vpu_dec_get_output_info(inst, &info);
>> + if (ret)
>> + goto finish_decode;
>> +
>> + trace_dec_done(inst, &info);
>> +
>> + dev_dbg(inst->dev->dev, "dec %d dis %d noti_flag %d
>> stream_end %d\n",
>> + info.frame_decoded, info.frame_display,
>> + info.notification_flags, info.stream_end);
>> +
>> + if (info.notification_flags & DEC_NOTI_FLAG_NO_FB) {
>> + wave6_vpu_dec_retry_one_frame(inst);
>> + goto finish_decode;
>> + }
>> +
>> + if (info.notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) {
>> + struct dec_initial_info initial_info = {0};
>> +
>> + v4l2_m2m_mark_stopped(m2m_ctx);
>> +
>> + if (info.frame_display)
>> + wave6_handle_display_frames(inst, &info);
>> +
>> + if (info.release_disp_frame_num)
>> + wave6_handle_discard_frames(inst, &info);
>> +
>> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
>> &initial_info);
>> + wave6_vpu_dec_handle_source_change(inst,
>> &initial_info);
>> +
>> + wave6_handle_last_frame(inst, NULL);
>> +
>> + goto finish_decode;
>> + }
>> +
>> + wave6_vpu_dec_handle_decoding_warn_error(inst, &info);
>> +
>> + if (info.frame_decoded)
>> + wave6_handle_decoded_frame(inst, &info);
>> + else
>> + wave6_handle_skipped_frame(inst);
>> +
>> + if (info.frame_display)
>> + wave6_handle_display_frames(inst, &info);
>> +
>> + if (info.release_disp_frame_num)
>> + wave6_handle_discard_frames(inst, &info);
>> +
>> + if (info.stream_end && !inst->eos)
>> + wave6_handle_last_frame(inst, NULL);
>> +
>> +finish_decode:
>> + wave6_vpu_finish_job(inst);
>> +}
>> +
>> +static int wave6_vpu_dec_querycap(struct file *file, void *fh,
>> struct v4l2_capability *cap)
>> +{
>> + strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver));
>> + strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card));
>> + strscpy(cap->bus_info, "platform:" VPU_DEC_DRV_NAME,
>> sizeof(cap->bus_info));
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_enum_framesizes(struct file *f, void *fh,
>> struct v4l2_frmsizeenum *fsize)
>> +{
>> + const struct vpu_format *vpu_fmt;
>> +
>> + if (fsize->index)
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt) {
>> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> + }
>> +
>> + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
>> + fsize->stepwise.min_width = vpu_fmt->min_width;
>> + fsize->stepwise.max_width = vpu_fmt->max_width;
>> + fsize->stepwise.step_width = W6_DEC_PIC_SIZE_STEP;
>> + fsize->stepwise.min_height = vpu_fmt->min_height;
>> + fsize->stepwise.max_height = vpu_fmt->max_height;
>> + fsize->stepwise.step_height = W6_DEC_PIC_SIZE_STEP;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_enum_fmt_cap(struct file *file, void *fh,
>> struct v4l2_fmtdesc *f)
>> +{
>> + const struct vpu_format *vpu_fmt;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> +
>> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + f->flags = 0;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_try_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + const struct vpu_format *vpu_fmt;
>> + int width, height;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + if (!V4L2_TYPE_IS_CAPTURE(f->type))
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt) {
>> + width = inst->dst_fmt.width;
>> + height = inst->dst_fmt.height;
>> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
>> + pix_mp->num_planes = inst->dst_fmt.num_planes;
>> + } else {
>> + width = clamp(pix_mp->width,
>> + vpu_fmt->min_width, round_up(inst-
>> >src_fmt.width, 32));
>> + height = clamp(pix_mp->height,
>> + vpu_fmt->min_height, inst-
>> >src_fmt.height);
>> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + pix_mp->num_planes = vpu_fmt->num_planes;
>> + }
>> +
>> + if (inst->state >= VPU_INST_STATE_INIT_SEQ) {
>> + width = inst->dst_fmt.width;
>> + height = inst->dst_fmt.height;
>> + }
>> +
>> + wave6_update_pix_fmt_cap(pix_mp, width, height, false);
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_s_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i, ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + ret = wave6_vpu_dec_try_fmt_cap(file, fh, f);
>> + if (ret)
>> + return ret;
>> +
>> + inst->dst_fmt.width = pix_mp->width;
>> + inst->dst_fmt.height = pix_mp->height;
>> + inst->dst_fmt.pixelformat = pix_mp->pixelformat;
>> + inst->dst_fmt.field = pix_mp->field;
>> + inst->dst_fmt.flags = pix_mp->flags;
>> + inst->dst_fmt.num_planes = pix_mp->num_planes;
>> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
>> + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp-
>> >plane_fmt[i].bytesperline;
>> + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp-
>> >plane_fmt[i].sizeimage;
>> + }
>> +
>> + if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
>> + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
>> + inst->cbcr_interleave = true;
>> + inst->nv21 = false;
>> + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
>> + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M)
>> {
>> + inst->cbcr_interleave = true;
>> + inst->nv21 = true;
>> + } else {
>> + inst->cbcr_interleave = false;
>> + inst->nv21 = false;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_g_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i;
>> +
>> + pix_mp->width = inst->dst_fmt.width;
>> + pix_mp->height = inst->dst_fmt.height;
>> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
>> + pix_mp->field = inst->dst_fmt.field;
>> + pix_mp->flags = inst->dst_fmt.flags;
>> + pix_mp->num_planes = inst->dst_fmt.num_planes;
>> + for (i = 0; i < pix_mp->num_planes; i++) {
>> + pix_mp->plane_fmt[i].bytesperline = inst-
>> >dst_fmt.plane_fmt[i].bytesperline;
>> + pix_mp->plane_fmt[i].sizeimage = inst-
>> >dst_fmt.plane_fmt[i].sizeimage;
>> + }
>> +
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_enum_fmt_out(struct file *file, void *fh,
>> struct v4l2_fmtdesc *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + const struct vpu_format *vpu_fmt;
>> +
>> + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f-
>> >index);
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> +
>> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + f->flags = 0;
>> + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
>> V4L2_FMT_FLAG_COMPRESSED;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_try_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + const struct vpu_format *vpu_fmt;
>> + int width, height;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(f->type))
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt) {
>> + width = inst->src_fmt.width;
>> + height = inst->src_fmt.height;
>> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
>> + pix_mp->num_planes = inst->src_fmt.num_planes;
>> + } else {
>> + width = pix_mp->width;
>> + height = pix_mp->height;
>> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + pix_mp->num_planes = vpu_fmt->num_planes;
>> + }
>> +
>> + wave6_update_pix_fmt(pix_mp, width, height);
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_s_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane in_pix_mp = f->fmt.pix_mp;
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i, ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + ret = wave6_vpu_dec_try_fmt_out(file, fh, f);
>> + if (ret)
>> + return ret;
>> +
>> + pix_mp->colorspace = in_pix_mp.colorspace;
>> + pix_mp->ycbcr_enc = in_pix_mp.ycbcr_enc;
>> + pix_mp->quantization = in_pix_mp.quantization;
>> + pix_mp->xfer_func = in_pix_mp.xfer_func;
>> +
>> + inst->src_fmt.width = pix_mp->width;
>> + inst->src_fmt.height = pix_mp->height;
>> + inst->src_fmt.pixelformat = pix_mp->pixelformat;
>> + inst->src_fmt.field = pix_mp->field;
>> + inst->src_fmt.flags = pix_mp->flags;
>> + inst->src_fmt.num_planes = pix_mp->num_planes;
>> + for (i = 0; i < inst->src_fmt.num_planes; i++) {
>> + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp-
>> >plane_fmt[i].bytesperline;
>> + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp-
>> >plane_fmt[i].sizeimage;
>> + }
>> +
>> + inst->colorspace = pix_mp->colorspace;
>> + inst->ycbcr_enc = pix_mp->ycbcr_enc;
>> + inst->quantization = pix_mp->quantization;
>> + inst->xfer_func = pix_mp->xfer_func;
>> +
>> + wave6_update_pix_fmt_cap(&inst->dst_fmt,
>> + pix_mp->width, pix_mp->height,
>> + true);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_g_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i;
>> +
>> + pix_mp->width = inst->src_fmt.width;
>> + pix_mp->height = inst->src_fmt.height;
>> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
>> + pix_mp->field = inst->src_fmt.field;
>> + pix_mp->flags = inst->src_fmt.flags;
>> + pix_mp->num_planes = inst->src_fmt.num_planes;
>> + for (i = 0; i < pix_mp->num_planes; i++) {
>> + pix_mp->plane_fmt[i].bytesperline = inst-
>> >src_fmt.plane_fmt[i].bytesperline;
>> + pix_mp->plane_fmt[i].sizeimage = inst-
>> >src_fmt.plane_fmt[i].sizeimage;
>> + }
>> +
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_g_selection(struct file *file, void *fh,
>> struct v4l2_selection *s)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> +
>> + dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
>> + __func__, s->type, s->target);
>> +
>> + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
>> + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
>> + return -EINVAL;
>> +
>> + switch (s->target) {
>> + case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>> + s->r.left = 0;
>> + s->r.top = 0;
>> + s->r.width = inst->dst_fmt.width;
>> + s->r.height = inst->dst_fmt.height;
>> + break;
>> + case V4L2_SEL_TGT_COMPOSE_PADDED:
>> + case V4L2_SEL_TGT_COMPOSE:
>> + s->r.left = 0;
>> + s->r.top = 0;
>> + if (inst->scaler_info.enable) {
>> + s->r.width = inst->scaler_info.width;
>> + s->r.height = inst->scaler_info.height;
>> + } else if (inst->crop.width && inst->crop.height) {
>> + s->r = inst->crop;
>> + } else {
>> + s->r.width = inst->src_fmt.width;
>> + s->r.height = inst->src_fmt.height;
>> + }
>> + break;
>> + case V4L2_SEL_TGT_CROP:
>> + case V4L2_SEL_TGT_CROP_DEFAULT:
>> + case V4L2_SEL_TGT_CROP_BOUNDS:
>> + case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>> + s->r.left = 0;
>> + s->r.top = 0;
>> + s->r.width = inst->src_fmt.width;
>> + s->r.height = inst->src_fmt.height;
>> + if (inst->crop.width && inst->crop.height)
>> + s->r = inst->crop;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_s_selection(struct file *file, void *fh,
>> struct v4l2_selection *s)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + int step = 4;
>> + int scale_width, scale_height;
>> + int min_scale_width, min_scale_height;
>> +
>> + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
>> + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
>> + return -EINVAL;
>> +
>> + if (s->target != V4L2_SEL_TGT_COMPOSE)
>> + return -EINVAL;
>> +
>> + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
>> + s->flags |= V4L2_SEL_FLAG_LE;
>> +
>> + scale_width = clamp(s->r.width, W6_MIN_DEC_PIC_WIDTH,
>> + round_up(inst->src_fmt.width, 32));
>> + scale_height = clamp(s->r.height, W6_MIN_DEC_PIC_HEIGHT,
>> + inst->src_fmt.height);
>> + if (s->flags & V4L2_SEL_FLAG_GE) {
>> + scale_width = round_up(scale_width, step);
>> + scale_height = round_up(scale_height, step);
>> + }
>> + if (s->flags & V4L2_SEL_FLAG_LE) {
>> + scale_width = round_down(scale_width, step);
>> + scale_height = round_down(scale_height, step);
>> + }
>> +
>> + if (scale_width < inst->src_fmt.width ||
>> + scale_height < inst->src_fmt.height)
>> + inst->scaler_info.enable = true;
>> +
>> + if (inst->scaler_info.enable) {
>> + min_scale_width = ALIGN((inst->src_fmt.width / 8),
>> step);
>> + min_scale_height = ALIGN((inst->src_fmt.height / 8),
>> step);
>> +
>> + if (scale_width < W6_MIN_DEC_PIC_WIDTH)
>> + scale_width = W6_MIN_DEC_PIC_WIDTH;
>> + if (scale_width < min_scale_width)
>> + scale_width = min_scale_width;
>> + if (scale_height < W6_MIN_DEC_PIC_HEIGHT)
>> + scale_height = W6_MIN_DEC_PIC_HEIGHT;
>> + if (scale_height < min_scale_height)
>> + scale_height = min_scale_height;
>> +
>> + inst->scaler_info.width = scale_width;
>> + inst->scaler_info.height = scale_height;
>> + }
>> +
>> + s->r.left = 0;
>> + s->r.top = 0;
>> + s->r.width = scale_width;
>> + s->r.height = scale_height;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_decoder_cmd(struct file *file, void *fh,
>> struct v4l2_decoder_cmd *dc)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + int ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, dc->cmd);
>> +
>> + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
>> + if (ret)
>> + return ret;
>> +
>> + switch (dc->cmd) {
>> + case V4L2_DEC_CMD_STOP:
>> + dprintk(inst->dev->dev, "[%d] drain\n", inst->id);
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
>> true);
>> + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
>> + break;
>> + case V4L2_DEC_CMD_START:
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_ioctl_ops wave6_vpu_dec_ioctl_ops = {
>> + .vidioc_querycap = wave6_vpu_dec_querycap,
>> + .vidioc_enum_framesizes = wave6_vpu_dec_enum_framesizes,
>> +
>> + .vidioc_enum_fmt_vid_cap = wave6_vpu_dec_enum_fmt_cap,
>> + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_dec_s_fmt_cap,
>> + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_dec_g_fmt_cap,
>> + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_dec_try_fmt_cap,
>> +
>> + .vidioc_enum_fmt_vid_out = wave6_vpu_dec_enum_fmt_out,
>> + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_dec_s_fmt_out,
>> + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_dec_g_fmt_out,
>> + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_dec_try_fmt_out,
>> +
>> + .vidioc_g_selection = wave6_vpu_dec_g_selection,
>> + .vidioc_s_selection = wave6_vpu_dec_s_selection,
>> +
>> + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
>> + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
>> + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
>> + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
>> + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
>> + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
>> + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
>> + .vidioc_streamon = v4l2_m2m_ioctl_streamon,
>> + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
>> +
>> + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
>> + .vidioc_decoder_cmd = wave6_vpu_dec_decoder_cmd,
>> +
>> + .vidioc_subscribe_event = wave6_vpu_subscribe_event,
>> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>> +};
>> +
>> +static int wave6_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
>> +
>> + trace_s_ctrl(inst, ctrl);
>> +
>> + dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
>> + __func__, ctrl->name, ctrl->val);
>> +
>> + switch (ctrl->id) {
>> + case V4L2_CID_VPU_THUMBNAIL_MODE:
>> + inst->thumbnail_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
>> + inst->disp_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
>> + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
>> + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
>> + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops wave6_vpu_dec_ctrl_ops = {
>> + .s_ctrl = wave6_vpu_dec_s_ctrl,
>> +};
>> +
>> +static const struct v4l2_ctrl_config wave6_vpu_thumbnail_mode = {
>> + .ops = &wave6_vpu_dec_ctrl_ops,
>> + .id = V4L2_CID_VPU_THUMBNAIL_MODE,
>> + .name = "thumbnail mode",
>> + .type = V4L2_CTRL_TYPE_BOOLEAN,
>> + .def = 0,
>> + .min = 0,
>> + .max = 1,
>> + .step = 1,
>> + .flags = V4L2_CTRL_FLAG_WRITE_ONLY,
>> +};
>> +
>> +static void wave6_set_dec_openparam(struct dec_open_param
>> *open_param,
>> + struct vpu_instance *inst)
>> +{
>> + open_param->inst_buffer.temp_base = inst->dev-
>> >temp_vbuf.daddr;
>> + open_param->inst_buffer.temp_size = inst->dev-
>> >temp_vbuf.size;
>> + open_param->bs_mode = BS_MODE_PIC_END;
>> + open_param->stream_endian = VPU_STREAM_ENDIAN;
>> + open_param->frame_endian = VPU_FRAME_ENDIAN;
>> + open_param->disp_mode = inst->disp_mode;
>> +}
>> +
>> +static int wave6_vpu_dec_create_instance(struct vpu_instance *inst)
>> +{
>> + int ret;
>> + struct dec_open_param open_param;
>> +
>> + memset(&open_param, 0, sizeof(struct dec_open_param));
>> +
>> + wave6_vpu_activate(inst->dev);
>> + ret = pm_runtime_resume_and_get(inst->dev->dev);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "runtime_resume failed
>> %d\n", ret);
>> + return ret;
>> + }
>> +
>> + wave6_vpu_wait_activated(inst->dev);
>> +
>> + inst->std = wave6_to_codec_std(inst->type, inst-
>> >src_fmt.pixelformat);
>> + if (inst->std == STD_UNKNOWN) {
>> + dev_err(inst->dev->dev, "unsupported pixelformat:
>> %.4s\n",
>> + (char *)&inst->src_fmt.pixelformat);
>> + ret = -EINVAL;
>> + goto error_pm;
>> + }
>> +
>> + wave6_set_dec_openparam(&open_param, inst);
>> +
>> + ret = wave6_vpu_dec_open(inst, &open_param);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "failed create instance :
>> %d\n", ret);
>> + goto error_pm;
>> + }
>> +
>> + dprintk(inst->dev->dev, "[%d] decoder\n", inst->id);
>> +
>> + if (inst->thumbnail_mode)
>> + wave6_vpu_dec_give_command(inst,
>> ENABLE_DEC_THUMBNAIL_MODE, NULL);
>> +
>> + wave6_vpu_create_dbgfs_file(inst);
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
>> + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = true;
>> + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, true);
>> +
>> + return 0;
>> +
>> +error_pm:
>> + pm_runtime_put_sync(inst->dev->dev);
>> +
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_dec_prepare_fb(struct vpu_instance *inst)
>> +{
>> + int ret;
>> + unsigned int i;
>> + unsigned int fb_num;
>> + unsigned int mv_num;
>> + unsigned int fb_stride;
>> + unsigned int fb_height;
>> + struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>> +
>> + fb_num = p_dec_info->initial_info.min_frame_buffer_count;
>> + mv_num = p_dec_info->initial_info.req_mv_buffer_count;
>> +
>> + fb_stride = ALIGN(inst->src_fmt.width, 32);
>> + fb_height = ALIGN(inst->src_fmt.height, 32);
>> +
>> + for (i = 0; i < fb_num; i++) {
>> + struct frame_buffer *frame = &inst->frame_buf[i];
>> + struct vpu_buf *vframe = &inst->frame_vbuf[i];
>> + unsigned int l_size = fb_stride * fb_height;
>> + unsigned int ch_size = ALIGN(fb_stride / 2, 32) *
>> fb_height;
>> +
>> + vframe->size = l_size + ch_size;
>> + ret = wave6_alloc_dma(inst->dev->dev, vframe);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "alloc FBC buffer
>> fail : %zu\n",
>> + vframe->size);
>> + goto error;
>> + }
>> +
>> + frame->buf_y = vframe->daddr;
>> + frame->buf_cb = vframe->daddr + l_size;
>> + frame->buf_cr = (dma_addr_t)-1;
>> + frame->width = inst->src_fmt.width;
>> + frame->stride = fb_stride;
>> + frame->height = fb_height;
>> + frame->map_type = COMPRESSED_FRAME_MAP;
>> + }
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL,
>> fb_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL,
>> fb_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL,
>> mv_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_vpu_dec_register_frame_buffer_ex(inst, fb_num,
>> fb_stride,
>> + fb_height,
>> +
>> COMPRESSED_FRAME_MAP);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "register frame buffer fail
>> %d\n", ret);
>> + goto error;
>> + }
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
>> +
>> + return 0;
>> +
>> +error:
>> + wave6_vpu_dec_release_fb(inst);
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_dec_queue_setup(struct vb2_queue *q, unsigned
>> int *num_buffers,
>> + unsigned int *num_planes,
>> unsigned int sizes[],
>> + struct device *alloc_devs[])
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct v4l2_pix_format_mplane inst_format =
>> + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt :
>> inst->dst_fmt;
>> + unsigned int i;
>> +
>> + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d
>> type %d\n",
>> + __func__, *num_buffers, *num_planes, q->type);
>> +
>> + if (*num_planes) {
>> + if (inst_format.num_planes != *num_planes)
>> + return -EINVAL;
>> +
>> + for (i = 0; i < *num_planes; i++) {
>> + if (sizes[i] <
>> inst_format.plane_fmt[i].sizeimage)
>> + return -EINVAL;
>> + }
>> + } else {
>> + *num_planes = inst_format.num_planes;
>> + for (i = 0; i < *num_planes; i++) {
>> + sizes[i] =
>> inst_format.plane_fmt[i].sizeimage;
>> + dev_dbg(inst->dev->dev, "size[%d] : %d\n",
>> i, sizes[i]);
>> + }
>> +
>> + if (V4L2_TYPE_IS_CAPTURE(q->type)) {
>> + struct v4l2_ctrl *ctrl;
>> + unsigned int min_disp_cnt = 0;
>> +
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> +
>> V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
>> + if (ctrl)
>> + min_disp_cnt =
>> v4l2_ctrl_g_ctrl(ctrl);
>> +
>> + *num_buffers = max(*num_buffers,
>> min_disp_cnt);
>> +
>> + if (*num_buffers > WAVE6_MAX_FBS)
>> + *num_buffers = min_disp_cnt;
>> + }
>> + }
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type) &&
>> + inst->state == VPU_INST_STATE_SEEK) {
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> + wave6_vpu_dec_destroy_instance(inst);
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst)
>> +{
>> + struct dec_initial_info initial_info;
>> + int ret;
>> +
>> + memset(&initial_info, 0, sizeof(struct dec_initial_info));
>> +
>> + ret = wave6_vpu_dec_issue_seq_init(inst);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "failed
>> wave6_vpu_dec_issue_seq_init %d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0)
>> + dev_err(inst->dev->dev, "failed to call
>> vpu_wait_interrupt()\n");
>> +
>> + ret = wave6_vpu_dec_complete_seq_init(inst, &initial_info);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "vpu_dec_complete_seq_init:
>> %d, reason : 0x%x\n",
>> + ret, initial_info.err_reason);
>> + if ((initial_info.err_reason &
>> WAVE6_SYSERR_NOT_SUPPORT) ||
>> + (initial_info.err_reason &
>> WAVE6_SYSERR_NOT_SUPPORT_PROFILE)) {
>> + ret = -EINVAL;
>> + } else if ((initial_info.err_reason &
>> HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND) ||
>> + (initial_info.err_reason &
>> AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND)) {
>> + wave6_handle_skipped_frame(inst);
>> + ret = 0;
>> + }
>> + } else {
>> + wave6_vpu_dec_handle_source_change(inst,
>> &initial_info);
>> + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = false;
>> + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx,
>> false);
>> + if (vb2_is_streaming(v4l2_m2m_get_dst_vq(inst-
>> >v4l2_fh.m2m_ctx)))
>> + wave6_handle_last_frame(inst, NULL);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static void wave6_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
>> +{
>> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
>> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
>> +
>> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
>> size[1] : %4ld | size[2] : %4ld\n",
>> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
>> 0),
>> + vb2_plane_size(&vbuf->vb2_buf, 1),
>> vb2_plane_size(&vbuf->vb2_buf, 2));
>> +
>> + vbuf->sequence = inst->queued_src_buf_num++;
>> + vpu_buf->ts_input = ktime_get_raw();
>> +
>> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
>> +}
>> +
>> +static void wave6_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
>> +{
>> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
>> +
>> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
>> size[1] : %4ld | size[2] : %4ld\n",
>> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
>> 0),
>> + vb2_plane_size(&vbuf->vb2_buf, 1),
>> vb2_plane_size(&vbuf->vb2_buf, 2));
>> +
>> + inst->queued_dst_buf_num++;
>> + if (inst->next_buf_last) {
>> + wave6_handle_last_frame(inst, vbuf);
>> + inst->next_buf_last = false;
>> + } else {
>> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
>> + }
>> +}
>> +
>> +static void wave6_vpu_dec_buf_queue(struct vb2_buffer *vb)
>> +{
>> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
>> +
>> + vpu_buf->consumed = false;
>> + vpu_buf->used = false;
>> + vpu_buf->error = false;
>> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
>> + wave6_vpu_dec_buf_queue_src(vb);
>> + else
>> + wave6_vpu_dec_buf_queue_dst(vb);
>> +}
>> +
>> +static int wave6_vpu_dec_start_streaming(struct vb2_queue *q,
>> unsigned int count)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct v4l2_pix_format_mplane *fmt;
>> + int ret = 0;
>> +
>> + trace_start_streaming(inst, q->type);
>> +
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
>> + fmt = &inst->src_fmt;
>> + if (inst->state == VPU_INST_STATE_NONE) {
>> + ret = wave6_vpu_dec_create_instance(inst);
>> + if (ret)
>> + goto exit;
>> + }
>> +
>> + if (inst->state == VPU_INST_STATE_SEEK)
>> + wave6_vpu_set_instance_state(inst, inst-
>> >state_in_seek);
>> + } else {
>> + fmt = &inst->dst_fmt;
>> + if (inst->state == VPU_INST_STATE_INIT_SEQ) {
>> + ret = wave6_vpu_dec_prepare_fb(inst);
>> + if (ret)
>> + goto exit;
>> + }
>> + }
>> +
>> +exit:
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> + if (ret)
>> + wave6_vpu_return_buffers(inst, q->type,
>> VB2_BUF_STATE_QUEUED);
>> +
>> + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers,
>> ret = %d\n",
>> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
>> "capture",
>> + fmt->pixelformat,
>> + fmt->pixelformat >> 8,
>> + fmt->pixelformat >> 16,
>> + fmt->pixelformat >> 24,
>> + fmt->width, fmt->height, vb2_get_num_buffers(q),
>> ret);
>> +
>> + return ret;
>> +}
>> +
>> +static void wave6_vpu_dec_stop_streaming(struct vb2_queue *q)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
>> +
>> + trace_stop_streaming(inst, q->type);
>> +
>> + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d error
>> %d\n",
>> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
>> "capture",
>> + inst->queued_src_buf_num, inst->processed_buf_num,
>> inst->error_buf_num);
>> +
>> + if (inst->state == VPU_INST_STATE_NONE)
>> + goto exit;
>> +
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
>> + wave6_vpu_reset_performance(inst);
>> + inst->queued_src_buf_num = 0;
>> + inst->processed_buf_num = 0;
>> + inst->error_buf_num = 0;
>> + inst->state_in_seek = inst->state;
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
>> false);
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_SEEK);
>> + inst->sequence = 0;
>> + } else {
>> + if (v4l2_m2m_has_stopped(m2m_ctx))
>> + v4l2_m2m_clear_state(m2m_ctx);
>> +
>> + inst->eos = false;
>> + inst->queued_dst_buf_num = 0;
>> + inst->sequence = 0;
>> + wave6_vpu_dec_flush_instance(inst);
>> + }
>> +
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> +
>> +exit:
>> + wave6_vpu_return_buffers(inst, q->type,
>> VB2_BUF_STATE_ERROR);
>> +}
>> +
>> +static int wave6_vpu_dec_buf_init(struct vb2_buffer *vb)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
>> + struct dec_initial_info initial_info = {0};
>> + int i;
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
>> + return 0;
>> +
>> + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO,
>> &initial_info);
>> + if (initial_info.chroma_format_idc != YUV400)
>> + return 0;
>> +
>> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
>> + void *vaddr = vb2_plane_vaddr(vb, i);
>> +
>> + if (vaddr)
>> + memset(vaddr, 0x80, vb2_plane_size(vb, i));
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct vb2_ops wave6_vpu_dec_vb2_ops = {
>> + .queue_setup = wave6_vpu_dec_queue_setup,
>> + .wait_prepare = vb2_ops_wait_prepare,
>> + .wait_finish = vb2_ops_wait_finish,
>> + .buf_queue = wave6_vpu_dec_buf_queue,
>> + .start_streaming = wave6_vpu_dec_start_streaming,
>> + .stop_streaming = wave6_vpu_dec_stop_streaming,
>> + .buf_init = wave6_vpu_dec_buf_init,
>> +};
>> +
>> +static void wave6_set_default_format(struct v4l2_pix_format_mplane
>> *src_fmt,
>> + struct v4l2_pix_format_mplane
>> *dst_fmt)
>> +{
>> + const struct vpu_format *vpu_fmt;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
>> + if (vpu_fmt) {
>> + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + src_fmt->num_planes = vpu_fmt->num_planes;
>> + wave6_update_pix_fmt(src_fmt,
>> + W6_DEF_DEC_PIC_WIDTH,
>> W6_DEF_DEC_PIC_HEIGHT);
>> + }
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
>> + if (vpu_fmt) {
>> + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + dst_fmt->num_planes = vpu_fmt->num_planes;
>> + wave6_update_pix_fmt_cap(dst_fmt,
>> + W6_DEF_DEC_PIC_WIDTH,
>> W6_DEF_DEC_PIC_HEIGHT,
>> + true);
>> + }
>> +}
>> +
>> +static int wave6_vpu_dec_queue_init(void *priv, struct vb2_queue
>> *src_vq, struct vb2_queue *dst_vq)
>> +{
>> + struct vpu_instance *inst = priv;
>> + int ret;
>> +
>> + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
>> + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> + src_vq->mem_ops = &vb2_dma_contig_memops;
>> + src_vq->ops = &wave6_vpu_dec_vb2_ops;
>> + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> + src_vq->buf_struct_size = sizeof(struct vpu_buffer);
>> + src_vq->min_queued_buffers = 1;
>> + src_vq->drv_priv = inst;
>> + src_vq->lock = &inst->dev->dev_lock;
>> + src_vq->dev = inst->dev->v4l2_dev.dev;
>> + ret = vb2_queue_init(src_vq);
>> + if (ret)
>> + return ret;
>> +
>> + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
>> + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> + dst_vq->mem_ops = &vb2_dma_contig_memops;
>> + dst_vq->ops = &wave6_vpu_dec_vb2_ops;
>> + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> + dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
>> + dst_vq->min_queued_buffers = 1;
>> + dst_vq->drv_priv = inst;
>> + dst_vq->lock = &inst->dev->dev_lock;
>> + dst_vq->dev = inst->dev->v4l2_dev.dev;
>> + ret = vb2_queue_init(dst_vq);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +
>> +static const struct vpu_instance_ops wave6_vpu_dec_inst_ops = {
>> + .start_process = wave6_vpu_dec_start_decode,
>> + .finish_process = wave6_vpu_dec_finish_decode,
>> +};
>> +
>> +static int wave6_vpu_open_dec(struct file *filp)
>> +{
>> + struct video_device *vdev = video_devdata(filp);
>> + struct vpu_device *dev = video_drvdata(filp);
>> + struct vpu_instance *inst = NULL;
>> + int ret;
>> +
>> + inst = kzalloc(sizeof(*inst), GFP_KERNEL);
>> + if (!inst)
>> + return -ENOMEM;
>> +
>> + inst->dev = dev;
>> + inst->type = VPU_INST_TYPE_DEC;
>> + inst->ops = &wave6_vpu_dec_inst_ops;
>> +
>> + v4l2_fh_init(&inst->v4l2_fh, vdev);
>> + filp->private_data = &inst->v4l2_fh;
>> + v4l2_fh_add(&inst->v4l2_fh);
>> +
>> + inst->v4l2_fh.m2m_ctx =
>> + v4l2_m2m_ctx_init(dev->m2m_dev, inst,
>> wave6_vpu_dec_queue_init);
>> + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
>> + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
>> + goto free_inst;
>> + }
>> +
>> + v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10);
>> + v4l2_ctrl_new_custom(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_thumbnail_mode, NULL);
>> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_dec_ctrl_ops,
>> + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32,
>> 1, 1);
>> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_dec_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
>> + 0, 0, 1, 0);
>> + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_dec_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_dec_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
>> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
>> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
>> + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl,
>> &wave6_vpu_dec_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
>> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
>> +
>> V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
>> +
>> + if (inst->v4l2_ctrl_hdl.error) {
>> + ret = -ENODEV;
>> + goto err_m2m_release;
>> + }
>> +
>> + inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl;
>> + v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl);
>> +
>> + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
>> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
>> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
>> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
>> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
>> +
>> + return 0;
>> +
>> +err_m2m_release:
>> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
>> +free_inst:
>> + kfree(inst);
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_dec_release(struct file *filp)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(filp-
>> >private_data);
>> +
>> + dprintk(inst->dev->dev, "[%d] release\n", inst->id);
>> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
>> +
>> + mutex_lock(&inst->dev->dev_lock);
>> + if (inst->state != VPU_INST_STATE_NONE) {
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> + wave6_vpu_dec_destroy_instance(inst);
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> + }
>> + mutex_unlock(&inst->dev->dev_lock);
>> +
>> + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
>> + v4l2_fh_del(&inst->v4l2_fh);
>> + v4l2_fh_exit(&inst->v4l2_fh);
>> + kfree(inst);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_file_operations wave6_vpu_dec_fops = {
>> + .owner = THIS_MODULE,
>> + .open = wave6_vpu_open_dec,
>> + .release = wave6_vpu_dec_release,
>> + .unlocked_ioctl = video_ioctl2,
>> + .poll = v4l2_m2m_fop_poll,
>> + .mmap = v4l2_m2m_fop_mmap,
>> +};
>> +
>> +int wave6_vpu_dec_register_device(struct vpu_device *dev)
>> +{
>> + struct video_device *vdev_dec;
>> + int ret;
>> +
>> + vdev_dec = devm_kzalloc(dev->v4l2_dev.dev,
>> sizeof(*vdev_dec), GFP_KERNEL);
>> + if (!vdev_dec)
>> + return -ENOMEM;
>> +
>> + dev->video_dev_dec = vdev_dec;
>> +
>> + strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec-
>> >name));
>> + vdev_dec->fops = &wave6_vpu_dec_fops;
>> + vdev_dec->ioctl_ops = &wave6_vpu_dec_ioctl_ops;
>> + vdev_dec->release = video_device_release_empty;
>> + vdev_dec->v4l2_dev = &dev->v4l2_dev;
>> + vdev_dec->vfl_dir = VFL_DIR_M2M;
>> + vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
>> V4L2_CAP_STREAMING;
>> + vdev_dec->lock = &dev->dev_lock;
>> + video_set_drvdata(vdev_dec, dev);
>> +
>> + ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +
>> +void wave6_vpu_dec_unregister_device(struct vpu_device *dev)
>> +{
>> + video_unregister_device(dev->video_dev_dec);
>> +}
>> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
>> b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
>> new file mode 100644
>> index 000000000000..36417a7fef99
>> --- /dev/null
>> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
>> @@ -0,0 +1,2698 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>> +/*
>> + * Wave6 series multi-standard codec IP - v4l2 stateful encoder
>> interface
>> + *
>> + * Copyright (C) 2025 CHIPS&MEDIA INC
>> + */
>> +
>> +#include <linux/pm_runtime.h>
>> +#include "wave6-vpu.h"
>> +#include "wave6-vpu-dbg.h"
>> +#include "wave6-trace.h"
>> +
>> +#define VPU_ENC_DEV_NAME "C&M Wave6 VPU encoder"
>> +#define VPU_ENC_DRV_NAME "wave6-enc"
>> +
>> +static const struct vpu_format wave6_vpu_enc_fmt_list[2][23] = {
>> + [VPU_FMT_TYPE_CODEC] = {
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + },
>> + [VPU_FMT_TYPE_RAW] = {
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUYV,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV24,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV24,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV42,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 3,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 3,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 2,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGB24,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_P010,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB32,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_XRGB32,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBA32,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBX32,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + {
>> + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB2101010,
>> + .max_width = W6_MAX_ENC_PIC_WIDTH,
>> + .min_width = W6_MIN_ENC_PIC_WIDTH,
>> + .max_height = W6_MAX_ENC_PIC_HEIGHT,
>> + .min_height = W6_MIN_ENC_PIC_HEIGHT,
>> + .num_planes = 1,
>> + },
>> + }
>> +};
>> +
>> +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int
>> v4l2_pix_fmt,
>> + enum vpu_fmt_type
>> type)
>> +{
>> + unsigned int index;
>> +
>> + for (index = 0; index <
>> ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]); index++) {
>> + if (wave6_vpu_enc_fmt_list[type][index].v4l2_pix_fmt
>> == v4l2_pix_fmt)
>> + return &wave6_vpu_enc_fmt_list[type][index];
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned
>> int idx,
>> + enum
>> vpu_fmt_type type)
>> +{
>> + if (idx >= ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]))
>> + return NULL;
>> +
>> + if (!wave6_vpu_enc_fmt_list[type][idx].v4l2_pix_fmt)
>> + return NULL;
>> +
>> + return &wave6_vpu_enc_fmt_list[type][idx];
>> +}
>> +
>> +static u32 wave6_cpb_size_msec(u32 cpb_size_kb, u32 bitrate)
>> +{
>> + u64 cpb_size_bit;
>> + u64 cpb_size_msec;
>> +
>> + cpb_size_bit = (u64)cpb_size_kb * 1000 * BITS_PER_BYTE;
>> + cpb_size_msec = (cpb_size_bit * 1000) / bitrate;
>> +
>> + if (cpb_size_msec < 10 || cpb_size_msec > 100000)
>> + cpb_size_msec = 10000;
>> +
>> + return cpb_size_msec;
>> +}
>> +
>> +static void wave6_vpu_enc_release_fb(struct vpu_instance *inst)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < WAVE6_MAX_FBS; i++) {
>> + wave6_free_dma(&inst->frame_vbuf[i]);
>> + memset(&inst->frame_buf[i], 0, sizeof(struct
>> frame_buffer));
>> + wave6_free_dma(&inst-
>> >aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
>> + wave6_free_dma(&inst-
>> >aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
>> + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
>> + wave6_free_dma(&inst-
>> >aux_vbuf[AUX_BUF_SUB_SAMPLE][i]);
>> + }
>> +}
>> +
>> +static void wave6_vpu_enc_destroy_instance(struct vpu_instance
>> *inst)
>> +{
>> + u32 fail_res;
>> + int ret;
>> +
>> + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst-
>> >id);
>> + wave6_vpu_remove_dbgfs_file(inst);
>> +
>> + ret = wave6_vpu_enc_close(inst, &fail_res);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "failed destroy instance: %d
>> (%d)\n",
>> + ret, fail_res);
>> + }
>> +
>> + wave6_vpu_enc_release_fb(inst);
>> + wave6_free_dma(&inst->ar_vbuf);
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE);
>> +
>> + if (!pm_runtime_suspended(inst->dev->dev))
>> + pm_runtime_put_sync(inst->dev->dev);
>> +}
>> +
>> +static struct vb2_v4l2_buffer *wave6_get_valid_src_buf(struct
>> vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf = NULL;
>> +
>> + v4l2_m2m_for_each_src_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
>> +
>> + if (!vpu_buf->consumed) {
>> + dev_dbg(inst->dev->dev, "no consumed src idx
>> : %d\n",
>> + vb2_v4l2_buf->vb2_buf.index);
>> + return vb2_v4l2_buf;
>> + }
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static struct vb2_v4l2_buffer *wave6_get_valid_dst_buf(struct
>> vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf;
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
>> +
>> + if (!vpu_buf->consumed) {
>> + dev_dbg(inst->dev->dev, "no consumed dst idx
>> : %d\n",
>> + vb2_v4l2_buf->vb2_buf.index);
>> + return vb2_v4l2_buf;
>> + }
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static void wave6_set_csc(struct vpu_instance *inst, struct
>> enc_param *pic_param)
>> +{
>> + bool is_10bit = false;
>> +
>> + if (!(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) &&
>> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32) &&
>> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32) &&
>> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32) &&
>> + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) &&
>> + !(inst->src_fmt.pixelformat ==
>> V4L2_PIX_FMT_ARGB2101010))
>> + return;
>> +
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010)
>> + is_10bit = true;
>> +
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32)
>> + pic_param->csc.format_order = 8;
>> +
>> + if (inst->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT ||
>> + inst->ycbcr_enc == V4L2_YCBCR_ENC_601) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_FULL_RANGE) {
>> + /*
>> + * Y 0.299(R) 0.587(G) 0.114(B)
>> + * Cb -0.16874(R) -0.33126(G) 0.5(B)
>> + * Cr 0.5(R) -0.41869(G) -0.08131(B)
>> + */
>> + pic_param->csc.coef_ry = 0x099;
>> + pic_param->csc.coef_gy = 0x12d;
>> + pic_param->csc.coef_by = 0x03a;
>> + pic_param->csc.coef_rcb = 0xffffffaa;
>> + pic_param->csc.coef_gcb = 0xffffff56;
>> + pic_param->csc.coef_bcb = 0x100;
>> + pic_param->csc.coef_rcr = 0x100;
>> + pic_param->csc.coef_gcr = 0xffffff2a;
>> + pic_param->csc.coef_bcr = 0xffffffd6;
>> + pic_param->csc.offset_y = 0x0;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + } else {
>> + /*
>> + * Y 0.258(R) 0.504(G) 0.098(B)
>> + * Cb -0.1484(R) -0.2891(G) 0.4375(B)
>> + * Cr 0.4375(R) -0.3672(G) -0.0703(B)
>> + */
>> + pic_param->csc.coef_ry = 0x084;
>> + pic_param->csc.coef_gy = 0x102;
>> + pic_param->csc.coef_by = 0x032;
>> + pic_param->csc.coef_rcb = 0xffffffb4;
>> + pic_param->csc.coef_gcb = 0xffffff6c;
>> + pic_param->csc.coef_bcb = 0x0e0;
>> + pic_param->csc.coef_rcr = 0x0e0;
>> + pic_param->csc.coef_gcr = 0xffffff44;
>> + pic_param->csc.coef_bcr = 0xffffffdc;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + }
>> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_709) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_FULL_RANGE) {
>> + /*
>> + * Y 0.2126(R) 0.7152(G) 0.0722(B)
>> + * Cb -0.11457(R) -0.38543(G) 0.5(B)
>> + * Cr 0.5(R) -0.45415(G) -0.04585(B)
>> + */
>> + pic_param->csc.coef_ry = 0x06d;
>> + pic_param->csc.coef_gy = 0x16e;
>> + pic_param->csc.coef_by = 0x025;
>> + pic_param->csc.coef_rcb = 0xffffffc5;
>> + pic_param->csc.coef_gcb = 0xffffff3b;
>> + pic_param->csc.coef_bcb = 0x100;
>> + pic_param->csc.coef_rcr = 0x100;
>> + pic_param->csc.coef_gcr = 0xffffff17;
>> + pic_param->csc.coef_bcr = 0xffffffe9;
>> + pic_param->csc.offset_y = 0x0;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + } else {
>> + pic_param->csc.coef_ry = 0x05e;
>> + pic_param->csc.coef_gy = 0x13b;
>> + pic_param->csc.coef_by = 0x020;
>> + pic_param->csc.coef_rcb = 0xffffffcc;
>> + pic_param->csc.coef_gcb = 0xffffff53;
>> + pic_param->csc.coef_bcb = 0x0e1;
>> + pic_param->csc.coef_rcr = 0x0e1;
>> + pic_param->csc.coef_gcr = 0xffffff34;
>> + pic_param->csc.coef_bcr = 0xffffffeb;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + }
>> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_FULL_RANGE) {
>> + /*
>> + * Y 0.2627(R) 0.678(G) 0.0593(B)
>> + * Cb -0.13963(R) -0.36037(G) 0.5(B)
>> + * Cr 0.5(R) -0.45979(G) -0.04021(B)
>> + */
>> + pic_param->csc.coef_ry = 0x087;
>> + pic_param->csc.coef_gy = 0x15b;
>> + pic_param->csc.coef_by = 0x01e;
>> + pic_param->csc.coef_rcb = 0xffffffb9;
>> + pic_param->csc.coef_gcb = 0xffffff47;
>> + pic_param->csc.coef_bcb = 0x100;
>> + pic_param->csc.coef_rcr = 0x100;
>> + pic_param->csc.coef_gcr = 0xffffff15;
>> + pic_param->csc.coef_bcr = 0xffffffeb;
>> + pic_param->csc.offset_y = 0x0;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + } else {
>> + pic_param->csc.coef_ry = 0x074;
>> + pic_param->csc.coef_gy = 0x12a;
>> + pic_param->csc.coef_by = 0x01a;
>> + pic_param->csc.coef_rcb = 0xffffffc1;
>> + pic_param->csc.coef_gcb = 0xffffff5e;
>> + pic_param->csc.coef_bcb = 0x0e1;
>> + pic_param->csc.coef_rcr = 0x0e1;
>> + pic_param->csc.coef_gcr = 0xffffff31;
>> + pic_param->csc.coef_bcr = 0xffffffee;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + }
>> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_SMPTE240M) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_FULL_RANGE) {
>> + /*
>> + * Y 0.2122(R) 0.7013(G) 0.0865(B)
>> + * Cb -0.1161(R) -0.3839(G) 0.5(B)
>> + * Cr 0.5(R) -0.4451(G) -0.0549(B)
>> + */
>> + pic_param->csc.coef_ry = 0x06d;
>> + pic_param->csc.coef_gy = 0x167;
>> + pic_param->csc.coef_by = 0x02c;
>> + pic_param->csc.coef_rcb = 0xffffffc5;
>> + pic_param->csc.coef_gcb = 0xffffff3b;
>> + pic_param->csc.coef_bcb = 0x100;
>> + pic_param->csc.coef_rcr = 0x100;
>> + pic_param->csc.coef_gcr = 0xffffff1c;
>> + pic_param->csc.coef_bcr = 0xffffffe4;
>> + pic_param->csc.offset_y = 0x0;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + } else {
>> + pic_param->csc.coef_ry = 0x05d;
>> + pic_param->csc.coef_gy = 0x134;
>> + pic_param->csc.coef_by = 0x026;
>> + pic_param->csc.coef_rcb = 0xffffffcc;
>> + pic_param->csc.coef_gcb = 0xffffff53;
>> + pic_param->csc.coef_bcb = 0x0e1;
>> + pic_param->csc.coef_rcr = 0x0e1;
>> + pic_param->csc.coef_gcr = 0xffffff38;
>> + pic_param->csc.coef_bcr = 0xffffffe7;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = (is_10bit) ?
>> 0x200 : 0x80;
>> + pic_param->csc.offset_cr = (is_10bit) ?
>> 0x200 : 0x80;
>> + }
>> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_LIM_RANGE) {
>> + /*
>> + * Y 0.2558(R) 0.5021(G) 0.0975(B)
>> + * Cb -0.1476(R) -0.2899(G) 0.4375(B)
>> + * Cr 0.4375(R) -0.3664(G) -0.0711(B)
>> + */
>> + pic_param->csc.coef_ry = 0x083;
>> + pic_param->csc.coef_gy = 0x101;
>> + pic_param->csc.coef_by = 0x032;
>> + pic_param->csc.coef_rcb = 0xffffffb4;
>> + pic_param->csc.coef_gcb = 0xffffff6c;
>> + pic_param->csc.coef_bcb = 0x0e0;
>> + pic_param->csc.coef_rcr = 0x0e0;
>> + pic_param->csc.coef_gcr = 0xffffff44;
>> + pic_param->csc.coef_bcr = 0xffffffdc;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = 0x0;
>> + pic_param->csc.offset_cr = 0x0;
>> + }
>> + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
>> + if (inst->quantization ==
>> V4L2_QUANTIZATION_LIM_RANGE) {
>> + /*
>> + * Y 0.1819(R) 0.6118(G) 0.0618(B)
>> + * Cb -0.1003(R) -0.3372(G) 0.4375(B)
>> + * Cr 0.4375(R) -0.3974(G) -0.0401(B)
>> + */
>> + pic_param->csc.coef_ry = 0x05d;
>> + pic_param->csc.coef_gy = 0x139;
>> + pic_param->csc.coef_by = 0x020;
>> + pic_param->csc.coef_rcb = 0xffffffcd;
>> + pic_param->csc.coef_gcb = 0xffffff53;
>> + pic_param->csc.coef_bcb = 0x0e0;
>> + pic_param->csc.coef_rcr = 0x0e0;
>> + pic_param->csc.coef_gcr = 0xffffff35;
>> + pic_param->csc.coef_bcr = 0xffffffeb;
>> + pic_param->csc.offset_y = (is_10bit) ? 0x40
>> : 0x10;
>> + pic_param->csc.offset_cb = 0x0;
>> + pic_param->csc.offset_cr = 0x0;
>> + }
>> + }
>> +}
>> +
>> +static void wave6_update_crop_info(struct vpu_instance *inst,
>> + u32 left, u32 top, u32 width, u32
>> height)
>> +{
>> + u32 enc_pic_width, enc_pic_height;
>> +
>> + inst->crop.left = left;
>> + inst->crop.top = top;
>> + inst->crop.width = width;
>> + inst->crop.height = height;
>> +
>> + inst->codec_rect.left = round_down(left,
>> W6_ENC_CROP_X_POS_STEP);
>> + inst->codec_rect.top = round_down(top,
>> W6_ENC_CROP_Y_POS_STEP);
>> +
>> + enc_pic_width = width + left - inst->codec_rect.left;
>> + inst->codec_rect.width = round_up(enc_pic_width,
>> W6_ENC_PIC_SIZE_STEP);
>> +
>> + enc_pic_height = height + top - inst->codec_rect.top;
>> + inst->codec_rect.height = round_up(enc_pic_height,
>> W6_ENC_PIC_SIZE_STEP);
>> +}
>> +
>> +static int wave6_allocate_aux_buffer(struct vpu_instance *inst,
>> + enum aux_buffer_type type,
>> + int num)
>> +{
>> + struct aux_buffer buf[WAVE6_MAX_FBS];
>> + struct aux_buffer_info buf_info;
>> + struct enc_aux_buffer_size_info size_info;
>> + unsigned int size;
>> + int i, ret;
>> +
>> + memset(buf, 0, sizeof(buf));
>> +
>> + size_info.width = inst->codec_rect.width;
>> + size_info.height = inst->codec_rect.height;
>> + size_info.type = type;
>> + size_info.mirror_direction = inst-
>> >enc_ctrls.mirror_direction;
>> + size_info.rotation_angle = inst->enc_ctrls.rot_angle;
>> +
>> + ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info,
>> &size);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Get size fail (type
>> %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + for (i = 0; i < num; i++) {
>> + inst->aux_vbuf[type][i].size = size;
>> + ret = wave6_alloc_dma(inst->dev->dev, &inst-
>> >aux_vbuf[type][i]);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Alloc fail
>> (type %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + buf[i].index = i;
>> + buf[i].addr = inst->aux_vbuf[type][i].daddr;
>> + buf[i].size = inst->aux_vbuf[type][i].size;
>> + }
>> +
>> + buf_info.type = type;
>> + buf_info.num = num;
>> + buf_info.buf_array = buf;
>> +
>> + ret = wave6_vpu_enc_register_aux_buffer(inst, buf_info);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "%s: Register fail (type
>> %d)\n", __func__, type);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void wave6_update_frame_buf_addr(struct vpu_instance *inst,
>> + struct frame_buffer
>> *frame_buf)
>> +{
>> + const struct v4l2_format_info *fmt_info;
>> + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
>> + u32 offset;
>> +
>> + fmt_info = v4l2_format_info(inst->src_fmt.pixelformat);
>> + if (!fmt_info)
>> + return;
>> +
>> + offset = inst->codec_rect.top * stride + inst-
>> >codec_rect.left * fmt_info->bpp[0];
>> + frame_buf->buf_y += offset;
>> +
>> + stride = DIV_ROUND_UP(stride, fmt_info->bpp[0]) * fmt_info-
>> >bpp[1];
>> + offset = inst->codec_rect.top * stride / fmt_info->vdiv /
>> fmt_info->hdiv
>> + + inst->codec_rect.left * fmt_info->bpp[1] /
>> fmt_info->hdiv;
>> + frame_buf->buf_cb += offset;
>> + frame_buf->buf_cr += offset;
>> +}
>> +
>> +static int wave6_update_seq_param(struct vpu_instance *inst)
>> +{
>> + struct enc_initial_info initial_info;
>> + bool changed = false;
>> + int ret;
>> +
>> + ret = wave6_vpu_enc_issue_seq_change(inst, &changed);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "seq change fail %d\n",
>> ret);
>> + return ret;
>> + }
>> +
>> + if (!changed)
>> + return 0;
>> +
>> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
>> + dev_err(inst->dev->dev, "seq change timeout\n");
>> + return ret;
>> + }
>> +
>> + wave6_vpu_enc_complete_seq_init(inst, &initial_info);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "seq change error\n");
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_start_encode(struct vpu_instance *inst)
>> +{
>> + int ret = -EINVAL;
>> + struct vb2_v4l2_buffer *src_buf = NULL;
>> + struct vb2_v4l2_buffer *dst_buf = NULL;
>> + struct vpu_buffer *src_vbuf = NULL;
>> + struct vpu_buffer *dst_vbuf = NULL;
>> + struct frame_buffer frame_buf;
>> + struct enc_param pic_param;
>> + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
>> + u32 luma_size = (stride * inst->src_fmt.height);
>> + u32 chroma_size;
>> + u32 fail_res;
>> +
>> + memset(&pic_param, 0, sizeof(struct enc_param));
>> + memset(&frame_buf, 0, sizeof(struct frame_buffer));
>> +
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M)
>> + chroma_size = ((stride / 2) * (inst->src_fmt.height
>> / 2));
>> + else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M)
>> + chroma_size = ((stride) * (inst->src_fmt.height /
>> 2));
>> + else
>> + chroma_size = 0;
>> +
>> + ret = wave6_update_seq_param(inst);
>> + if (ret)
>> + goto exit;
>> +
>> + src_buf = wave6_get_valid_src_buf(inst);
>> + dst_buf = wave6_get_valid_dst_buf(inst);
>> +
>> + if (!dst_buf) {
>> + dev_dbg(inst->dev->dev, "no valid dst buf\n");
>> + goto exit;
>> + }
>> +
>> + dst_vbuf = wave6_to_vpu_buf(dst_buf);
>> + pic_param.pic_stream_buffer_addr =
>> wave6_get_dma_addr(dst_buf, 0);
>> + pic_param.pic_stream_buffer_size = vb2_plane_size(&dst_buf-
>> >vb2_buf, 0);
>> + if (!src_buf) {
>> + dev_dbg(inst->dev->dev, "no valid src buf\n");
>> + if (inst->state == VPU_INST_STATE_STOP)
>> + pic_param.src_end = true;
>> + else
>> + goto exit;
>> + } else {
>> + src_vbuf = wave6_to_vpu_buf(src_buf);
>> + if (inst->src_fmt.num_planes == 1) {
>> + frame_buf.buf_y =
>> wave6_get_dma_addr(src_buf, 0);
>> + frame_buf.buf_cb = frame_buf.buf_y +
>> luma_size;
>> + frame_buf.buf_cr = frame_buf.buf_cb +
>> chroma_size;
>> + } else if (inst->src_fmt.num_planes == 2) {
>> + frame_buf.buf_y =
>> wave6_get_dma_addr(src_buf, 0);
>> + frame_buf.buf_cb =
>> wave6_get_dma_addr(src_buf, 1);
>> + frame_buf.buf_cr = frame_buf.buf_cb +
>> chroma_size;
>> + } else if (inst->src_fmt.num_planes == 3) {
>> + frame_buf.buf_y =
>> wave6_get_dma_addr(src_buf, 0);
>> + frame_buf.buf_cb =
>> wave6_get_dma_addr(src_buf, 1);
>> + frame_buf.buf_cr =
>> wave6_get_dma_addr(src_buf, 2);
>> + }
>> + wave6_update_frame_buf_addr(inst, &frame_buf);
>> + frame_buf.stride = stride;
>> + pic_param.src_idx = src_buf->vb2_buf.index;
>> + if (src_vbuf->force_key_frame || inst-
>> >error_recovery) {
>> + pic_param.force_pic_type_enable = true;
>> + pic_param.force_pic_type =
>> ENC_FORCE_PIC_TYPE_IDR;
>> + inst->error_recovery = false;
>> + }
>> + if (src_vbuf->force_frame_qp) {
>> + pic_param.force_pic_qp_enable = true;
>> + pic_param.force_pic_qp_i = src_vbuf-
>> >force_i_frame_qp;
>> + pic_param.force_pic_qp_p = src_vbuf-
>> >force_p_frame_qp;
>> + pic_param.force_pic_qp_b = src_vbuf-
>> >force_b_frame_qp;
>> + }
>> + src_vbuf->ts_start = ktime_get_raw();
>> + }
>> +
>> + pic_param.source_frame = &frame_buf;
>> + wave6_set_csc(inst, &pic_param);
>> +
>> + if (src_vbuf)
>> + src_vbuf->consumed = true;
>> + if (dst_vbuf) {
>> + dst_vbuf->consumed = true;
>> + dst_vbuf->used = true;
>> + }
>> +
>> + trace_enc_pic(inst, &pic_param);
>> +
>> + ret = wave6_vpu_enc_start_one_frame(inst, &pic_param,
>> &fail_res);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst-
>> >id, __func__, ret);
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_STOP);
>> +
>> + dst_buf = v4l2_m2m_dst_buf_remove(inst-
>> >v4l2_fh.m2m_ctx);
>> + if (dst_buf) {
>> + dst_buf->sequence = inst->sequence;
>> + v4l2_m2m_buf_done(dst_buf,
>> VB2_BUF_STATE_ERROR);
>> + }
>> +
>> + src_buf = v4l2_m2m_src_buf_remove(inst-
>> >v4l2_fh.m2m_ctx);
>> + if (src_buf) {
>> + v4l2_m2m_buf_done(src_buf,
>> VB2_BUF_STATE_ERROR);
>> + inst->sequence++;
>> + inst->processed_buf_num++;
>> + inst->error_buf_num++;
>> + }
>> + } else {
>> + dev_dbg(inst->dev->dev, "%s: success\n", __func__);
>> + }
>> +
>> +exit:
>> + return ret;
>> +}
>> +
>> +static void wave6_handle_encoded_frame(struct vpu_instance *inst,
>> + struct enc_output_info *info)
>> +{
>> + struct vb2_v4l2_buffer *src_buf;
>> + struct vb2_v4l2_buffer *dst_buf;
>> + struct vpu_buffer *vpu_buf;
>> + struct vpu_buffer *dst_vpu_buf;
>> + enum vb2_buffer_state state;
>> +
>> + state = info->encoding_success ? VB2_BUF_STATE_DONE :
>> VB2_BUF_STATE_ERROR;
>> +
>> + src_buf = v4l2_m2m_src_buf_remove_by_idx(inst-
>> >v4l2_fh.m2m_ctx,
>> + info->enc_src_idx);
>> + if (!src_buf) {
>> + dev_err(inst->dev->dev, "[%d] encoder can't find src
>> buffer\n", inst->id);
>> + return;
>> + }
>> +
>> + vpu_buf = wave6_to_vpu_buf(src_buf);
>> + if (!vpu_buf || !vpu_buf->consumed) {
>> + dev_err(inst->dev->dev, "[%d] src buffer is not
>> consumed\n", inst->id);
>> + return;
>> + }
>> +
>> + dst_buf = wave6_get_dst_buf_by_addr(inst, info-
>> >bitstream_buffer);
>> + if (!dst_buf) {
>> + dev_err(inst->dev->dev, "[%d] encoder can't find dst
>> buffer\n", inst->id);
>> + return;
>> + }
>> +
>> + dst_vpu_buf = wave6_to_vpu_buf(dst_buf);
>> +
>> + dst_vpu_buf->average_qp = info->avg_ctu_qp;
>> + dst_vpu_buf->ts_input = vpu_buf->ts_input;
>> + dst_vpu_buf->ts_start = vpu_buf->ts_start;
>> + dst_vpu_buf->ts_finish = ktime_get_raw();
>> + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev,
>> info->cycle.frame_cycle);
>> + dst_vpu_buf->ts_output = ktime_get_raw();
>> + wave6_vpu_handle_performance(inst, dst_vpu_buf);
>> +
>> + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true);
>> + v4l2_m2m_buf_done(src_buf, state);
>> +
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, info-
>> >bitstream_size);
>> + dst_buf->sequence = inst->sequence++;
>> + dst_buf->field = V4L2_FIELD_NONE;
>> + if (info->pic_type == PIC_TYPE_I)
>> + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
>> + else if (info->pic_type == PIC_TYPE_P)
>> + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
>> + else if (info->pic_type == PIC_TYPE_B)
>> + dst_buf->flags |= V4L2_BUF_FLAG_BFRAME;
>> +
>> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
>> dst_buf);
>> + if (state == VB2_BUF_STATE_ERROR) {
>> + dprintk(inst->dev->dev, "[%d] error frame %d\n",
>> inst->id, inst->sequence);
>> + inst->error_recovery = true;
>> + inst->error_buf_num++;
>> + }
>> + v4l2_m2m_buf_done(dst_buf, state);
>> + inst->processed_buf_num++;
>> +}
>> +
>> +static void wave6_handle_last_frame(struct vpu_instance *inst,
>> + dma_addr_t addr)
>> +{
>> + struct vb2_v4l2_buffer *dst_buf;
>> +
>> + dst_buf = wave6_get_dst_buf_by_addr(inst, addr);
>> + if (!dst_buf)
>> + return;
>> +
>> + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
>> + dst_buf->field = V4L2_FIELD_NONE;
>> + dst_buf->flags |= V4L2_BUF_FLAG_LAST;
>> + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx,
>> dst_buf);
>> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
>> +
>> + dprintk(inst->dev->dev, "[%d] eos\n", inst->id);
>> + inst->eos = true;
>> +
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false);
>> +}
>> +
>> +static void wave6_vpu_enc_finish_encode(struct vpu_instance *inst,
>> bool error)
>> +{
>> + int ret;
>> + struct enc_output_info info;
>> +
>> + if (error) {
>> + vb2_queue_error(v4l2_m2m_get_src_vq(inst-
>> >v4l2_fh.m2m_ctx));
>> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst-
>> >v4l2_fh.m2m_ctx));
>> +
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_STOP);
>> + inst->eos = true;
>> +
>> + goto finish_encode;
>> + }
>> +
>> + ret = wave6_vpu_enc_get_output_info(inst, &info);
>> + if (ret) {
>> + dev_dbg(inst->dev->dev, "vpu_enc_get_output_info
>> fail %d reason: %d | info : %d\n",
>> + ret, info.error_reason, info.warn_info);
>> + goto finish_encode;
>> + }
>> +
>> + trace_enc_done(inst, &info);
>> +
>> + if (info.enc_src_idx >= 0 && info.recon_frame_index >= 0)
>> + wave6_handle_encoded_frame(inst, &info);
>> + else if (info.recon_frame_index == RECON_IDX_FLAG_ENC_END)
>> + wave6_handle_last_frame(inst,
>> info.bitstream_buffer);
>> +
>> +finish_encode:
>> + wave6_vpu_finish_job(inst);
>> +}
>> +
>> +static int wave6_vpu_enc_querycap(struct file *file, void *fh,
>> struct v4l2_capability *cap)
>> +{
>> + strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver));
>> + strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card));
>> + strscpy(cap->bus_info, "platform:" VPU_ENC_DRV_NAME,
>> sizeof(cap->bus_info));
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_enum_framesizes(struct file *f, void *fh,
>> struct v4l2_frmsizeenum *fsize)
>> +{
>> + const struct vpu_format *vpu_fmt;
>> +
>> + if (fsize->index)
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt) {
>> + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> + }
>> +
>> + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
>> + fsize->stepwise.min_width = vpu_fmt->min_width;
>> + fsize->stepwise.max_width = vpu_fmt->max_width;
>> + fsize->stepwise.step_width = W6_ENC_PIC_SIZE_STEP;
>> + fsize->stepwise.min_height = vpu_fmt->min_height;
>> + fsize->stepwise.max_height = vpu_fmt->max_height;
>> + fsize->stepwise.step_height = W6_ENC_PIC_SIZE_STEP;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_enum_fmt_cap(struct file *file, void *fh,
>> struct v4l2_fmtdesc *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + const struct vpu_format *vpu_fmt;
>> +
>> + dev_dbg(inst->dev->dev, "index : %d\n", f->index);
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> +
>> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + f->flags = 0;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_try_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + const struct vpu_format *vpu_fmt;
>> + int width, height;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + if (!V4L2_TYPE_IS_CAPTURE(f->type))
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
>> VPU_FMT_TYPE_CODEC);
>> + if (!vpu_fmt) {
>> + width = inst->dst_fmt.width;
>> + height = inst->dst_fmt.height;
>> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
>> + pix_mp->num_planes = inst->dst_fmt.num_planes;
>> + } else {
>> + width = pix_mp->width;
>> + height = pix_mp->height;
>> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + pix_mp->num_planes = vpu_fmt->num_planes;
>> + }
>> +
>> + wave6_update_pix_fmt(pix_mp, width, height);
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_s_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i, ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + ret = wave6_vpu_enc_try_fmt_cap(file, fh, f);
>> + if (ret)
>> + return ret;
>> +
>> + inst->std = wave6_to_codec_std(inst->type, pix_mp-
>> >pixelformat);
>> + if (inst->std == STD_UNKNOWN) {
>> + dev_err(inst->dev->dev, "unsupported pixelformat:
>> %.4s\n",
>> + (char *)&pix_mp->pixelformat);
>> + return -EINVAL;
>> + }
>> +
>> + inst->dst_fmt.width = pix_mp->width;
>> + inst->dst_fmt.height = pix_mp->height;
>> + inst->dst_fmt.pixelformat = pix_mp->pixelformat;
>> + inst->dst_fmt.field = pix_mp->field;
>> + inst->dst_fmt.flags = pix_mp->flags;
>> + inst->dst_fmt.num_planes = pix_mp->num_planes;
>> + for (i = 0; i < inst->dst_fmt.num_planes; i++) {
>> + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp-
>> >plane_fmt[i].bytesperline;
>> + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp-
>> >plane_fmt[i].sizeimage;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_g_fmt_cap(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i;
>> +
>> + pix_mp->width = inst->dst_fmt.width;
>> + pix_mp->height = inst->dst_fmt.height;
>> + pix_mp->pixelformat = inst->dst_fmt.pixelformat;
>> + pix_mp->field = inst->dst_fmt.field;
>> + pix_mp->flags = inst->dst_fmt.flags;
>> + pix_mp->num_planes = inst->dst_fmt.num_planes;
>> + for (i = 0; i < pix_mp->num_planes; i++) {
>> + pix_mp->plane_fmt[i].bytesperline = inst-
>> >dst_fmt.plane_fmt[i].bytesperline;
>> + pix_mp->plane_fmt[i].sizeimage = inst-
>> >dst_fmt.plane_fmt[i].sizeimage;
>> + }
>> +
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_enum_fmt_out(struct file *file, void *fh,
>> struct v4l2_fmtdesc *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + const struct vpu_format *vpu_fmt;
>> +
>> + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f-
>> >index);
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt)
>> + return -EINVAL;
>> +
>> + f->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + f->flags = 0;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_try_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + const struct vpu_format *vpu_fmt;
>> + int width, height;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(f->type))
>> + return -EINVAL;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat,
>> VPU_FMT_TYPE_RAW);
>> + if (!vpu_fmt) {
>> + width = inst->src_fmt.width;
>> + height = inst->src_fmt.height;
>> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
>> + pix_mp->num_planes = inst->src_fmt.num_planes;
>> + } else {
>> + width = clamp(pix_mp->width,
>> + vpu_fmt->min_width, vpu_fmt-
>> >max_width);
>> + height = clamp(pix_mp->height,
>> + vpu_fmt->min_height, vpu_fmt-
>> >max_height);
>> +
>> + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + pix_mp->num_planes = vpu_fmt->num_planes;
>> + }
>> +
>> + wave6_update_pix_fmt(pix_mp, width, height);
>> +
>> + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
>> + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
>> + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV601 ||
>> + pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
>> + if (pix_mp->quantization ==
>> V4L2_QUANTIZATION_FULL_RANGE)
>> + pix_mp->quantization =
>> V4L2_QUANTIZATION_LIM_RANGE;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_s_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i, ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d
>> colorspace %d\n",
>> + __func__, pix_mp->pixelformat, pix_mp->width,
>> pix_mp->height,
>> + pix_mp->num_planes, pix_mp->colorspace);
>> +
>> + ret = wave6_vpu_enc_try_fmt_out(file, fh, f);
>> + if (ret)
>> + return ret;
>> +
>> + inst->src_fmt.width = pix_mp->width;
>> + inst->src_fmt.height = pix_mp->height;
>> + inst->src_fmt.pixelformat = pix_mp->pixelformat;
>> + inst->src_fmt.field = pix_mp->field;
>> + inst->src_fmt.flags = pix_mp->flags;
>> + inst->src_fmt.num_planes = pix_mp->num_planes;
>> + for (i = 0; i < inst->src_fmt.num_planes; i++) {
>> + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp-
>> >plane_fmt[i].bytesperline;
>> + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp-
>> >plane_fmt[i].sizeimage;
>> + }
>> +
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) {
>> + inst->cbcr_interleave = true;
>> + inst->nv21 = false;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M)
>> {
>> + inst->cbcr_interleave = true;
>> + inst->nv21 = true;
>> + } else {
>> + inst->cbcr_interleave = false;
>> + inst->nv21 = false;
>> + }
>> +
>> + inst->colorspace = pix_mp->colorspace;
>> + inst->ycbcr_enc = pix_mp->ycbcr_enc;
>> + inst->quantization = pix_mp->quantization;
>> + inst->xfer_func = pix_mp->xfer_func;
>> +
>> + wave6_update_pix_fmt(&inst->dst_fmt, pix_mp->width, pix_mp-
>> >height);
>> + wave6_update_crop_info(inst, 0, 0, pix_mp->width, pix_mp-
>> >height);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_g_fmt_out(struct file *file, void *fh,
>> struct v4l2_format *f)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> + int i;
>> +
>> + dev_dbg(inst->dev->dev, "\n");
>> +
>> + pix_mp->width = inst->src_fmt.width;
>> + pix_mp->height = inst->src_fmt.height;
>> + pix_mp->pixelformat = inst->src_fmt.pixelformat;
>> + pix_mp->field = inst->src_fmt.field;
>> + pix_mp->flags = inst->src_fmt.flags;
>> + pix_mp->num_planes = inst->src_fmt.num_planes;
>> + for (i = 0; i < pix_mp->num_planes; i++) {
>> + pix_mp->plane_fmt[i].bytesperline = inst-
>> >src_fmt.plane_fmt[i].bytesperline;
>> + pix_mp->plane_fmt[i].sizeimage = inst-
>> >src_fmt.plane_fmt[i].sizeimage;
>> + }
>> +
>> + pix_mp->colorspace = inst->colorspace;
>> + pix_mp->ycbcr_enc = inst->ycbcr_enc;
>> + pix_mp->quantization = inst->quantization;
>> + pix_mp->xfer_func = inst->xfer_func;
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_g_selection(struct file *file, void *fh,
>> struct v4l2_selection *s)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> +
>> + dev_dbg(inst->dev->dev, "%s: type %d target %d\n",
>> + __func__, s->type, s->target);
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(s->type))
>> + return -EINVAL;
>> +
>> + switch (s->target) {
>> + case V4L2_SEL_TGT_CROP_DEFAULT:
>> + case V4L2_SEL_TGT_CROP_BOUNDS:
>> + s->r.left = 0;
>> + s->r.top = 0;
>> + s->r.width = inst->src_fmt.width;
>> + s->r.height = inst->src_fmt.height;
>> + break;
>> + case V4L2_SEL_TGT_CROP:
>> + s->r = inst->crop;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_s_selection(struct file *file, void *fh,
>> struct v4l2_selection *s)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + u32 max_crop_w, max_crop_h;
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(s->type))
>> + return -EINVAL;
>> +
>> + if (s->target != V4L2_SEL_TGT_CROP)
>> + return -EINVAL;
>> +
>> + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)))
>> + s->flags |= V4L2_SEL_FLAG_LE;
>> +
>> + if (s->flags & V4L2_SEL_FLAG_GE) {
>> + s->r.left = round_up(s->r.left, W6_ENC_CROP_STEP);
>> + s->r.top = round_up(s->r.top, W6_ENC_CROP_STEP);
>> + s->r.width = round_up(s->r.width, W6_ENC_CROP_STEP);
>> + s->r.height = round_up(s->r.height,
>> W6_ENC_CROP_STEP);
>> + }
>> + if (s->flags & V4L2_SEL_FLAG_LE) {
>> + s->r.left = round_down(s->r.left, W6_ENC_CROP_STEP);
>> + s->r.top = round_down(s->r.top, W6_ENC_CROP_STEP);
>> + s->r.width = round_down(s->r.width,
>> W6_ENC_CROP_STEP);
>> + s->r.height = round_down(s->r.height,
>> W6_ENC_CROP_STEP);
>> + }
>> +
>> + max_crop_w = inst->src_fmt.width - s->r.left;
>> + max_crop_h = inst->src_fmt.height - s->r.top;
>> +
>> + if (!s->r.width || !s->r.height)
>> + return 0;
>> + if (max_crop_w < W6_MIN_ENC_PIC_WIDTH)
>> + return 0;
>> + if (max_crop_h < W6_MIN_ENC_PIC_HEIGHT)
>> + return 0;
>> +
>> + s->r.width = clamp(s->r.width, W6_MIN_ENC_PIC_WIDTH,
>> max_crop_w);
>> + s->r.height = clamp(s->r.height, W6_MIN_ENC_PIC_HEIGHT,
>> max_crop_h);
>> +
>> + wave6_update_pix_fmt(&inst->dst_fmt, s->r.width, s-
>> >r.height);
>> + wave6_update_crop_info(inst, s->r.left, s->r.top, s-
>> >r.width, s->r.height);
>> +
>> + dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_CROP %dx%dx%dx%d\n",
>> + s->r.left, s->r.top, s->r.width, s->r.height);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_encoder_cmd(struct file *file, void *fh,
>> struct v4l2_encoder_cmd *ec)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + int ret;
>> +
>> + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, ec->cmd);
>> +
>> + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
>> + if (ret)
>> + return ret;
>> +
>> + if (!wave6_vpu_both_queues_are_streaming(inst))
>> + return 0;
>> +
>> + switch (ec->cmd) {
>> + case V4L2_ENC_CMD_STOP:
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_STOP);
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
>> true);
>> + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx);
>> + break;
>> + case V4L2_ENC_CMD_START:
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_g_parm(struct file *file, void *fh, struct
>> v4l2_streamparm *a)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> +
>> + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(a->type))
>> + return -EINVAL;
>> +
>> + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
>> + a->parm.output.timeperframe.numerator = 1;
>> + a->parm.output.timeperframe.denominator = inst->frame_rate;
>> +
>> + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator :
>> %d\n",
>> + __func__,
>> + a->parm.output.timeperframe.numerator,
>> + a->parm.output.timeperframe.denominator);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_s_parm(struct file *file, void *fh, struct
>> v4l2_streamparm *a)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> +
>> + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type);
>> +
>> + if (!V4L2_TYPE_IS_OUTPUT(a->type))
>> + return -EINVAL;
>> +
>> + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
>> + if (a->parm.output.timeperframe.denominator && a-
>> >parm.output.timeperframe.numerator) {
>> + inst->frame_rate = a-
>> >parm.output.timeperframe.denominator /
>> + a-
>> >parm.output.timeperframe.numerator;
>> + } else {
>> + a->parm.output.timeperframe.numerator = 1;
>> + a->parm.output.timeperframe.denominator = inst-
>> >frame_rate;
>> + }
>> +
>> + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator :
>> %d\n",
>> + __func__,
>> + a->parm.output.timeperframe.numerator,
>> + a->parm.output.timeperframe.denominator);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_ioctl_ops wave6_vpu_enc_ioctl_ops = {
>> + .vidioc_querycap = wave6_vpu_enc_querycap,
>> + .vidioc_enum_framesizes = wave6_vpu_enc_enum_framesizes,
>> +
>> + .vidioc_enum_fmt_vid_cap = wave6_vpu_enc_enum_fmt_cap,
>> + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_enc_s_fmt_cap,
>> + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_enc_g_fmt_cap,
>> + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_enc_try_fmt_cap,
>> +
>> + .vidioc_enum_fmt_vid_out = wave6_vpu_enc_enum_fmt_out,
>> + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_enc_s_fmt_out,
>> + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_enc_g_fmt_out,
>> + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_enc_try_fmt_out,
>> +
>> + .vidioc_g_selection = wave6_vpu_enc_g_selection,
>> + .vidioc_s_selection = wave6_vpu_enc_s_selection,
>> +
>> + .vidioc_g_parm = wave6_vpu_enc_g_parm,
>> + .vidioc_s_parm = wave6_vpu_enc_s_parm,
>> +
>> + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
>> + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
>> + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
>> + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
>> + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
>> + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
>> + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
>> + .vidioc_streamon = v4l2_m2m_ioctl_streamon,
>> + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
>> +
>> + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
>> + .vidioc_encoder_cmd = wave6_vpu_enc_encoder_cmd,
>> +
>> + .vidioc_subscribe_event = wave6_vpu_subscribe_event,
>> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>> +};
>> +
>> +static int wave6_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl);
>> + struct enc_controls *p = &inst->enc_ctrls;
>> +
>> + trace_s_ctrl(inst, ctrl);
>> +
>> + dev_dbg(inst->dev->dev, "%s: name %s value %d\n",
>> + __func__, ctrl->name, ctrl->val);
>> +
>> + switch (ctrl->id) {
>> + case V4L2_CID_HFLIP:
>> + p->mirror_direction |= (ctrl->val << 1);
>> + break;
>> + case V4L2_CID_VFLIP:
>> + p->mirror_direction |= ctrl->val;
>> + break;
>> + case V4L2_CID_ROTATE:
>> + p->rot_angle = ctrl->val;
>> + break;
>> + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
>> + p->gop_size = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
>> + p->slice_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
>> + p->slice_max_mb = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
>> + p->bitrate_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_BITRATE:
>> + p->bitrate = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
>> + p->frame_rc_enable = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
>> + p->mb_rc_enable = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
>> + p->force_key_frame = true;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
>> + p->prepend_spspps_to_idr = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE:
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
>> + p->intra_refresh_period = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
>> + p->frame_skip_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
>> + p->hevc.profile = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
>> + p->hevc.level = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
>> + p->hevc.min_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
>> + p->hevc.max_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
>> + p->hevc.i_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
>> + p->hevc.p_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
>> + p->hevc.b_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
>> + p->hevc.loop_filter_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
>> + p->hevc.lf_beta_offset_div2 = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
>> + p->hevc.lf_tc_offset_div2 = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
>> + p->hevc.refresh_type = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
>> + p->hevc.refresh_period = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
>> + p->hevc.const_intra_pred = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
>> + p->hevc.strong_smoothing = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
>> + p->hevc.tmv_prediction = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
>> + p->h264.profile = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
>> + p->h264.level = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
>> + p->h264.min_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
>> + p->h264.max_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
>> + p->h264.i_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
>> + p->h264.p_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
>> + p->h264.b_frame_qp = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
>> + p->h264.loop_filter_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
>> + p->h264.loop_filter_beta = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
>> + p->h264.loop_filter_alpha = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
>> + p->h264._8x8_transform = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
>> + p->h264.constrained_intra_prediction = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:
>> + p->h264.chroma_qp_index_offset = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
>> + p->h264.entropy_mode = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
>> + p->h264.i_period = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
>> + p->h264.vui_sar_enable = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
>> + p->h264.vui_sar_idc = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
>> + p->h264.vui_ext_sar_width = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
>> + p->h264.vui_ext_sar_height = ctrl->val;
>> + break;
>> + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
>> + p->h264.cpb_size = ctrl->val;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops wave6_vpu_enc_ctrl_ops = {
>> + .s_ctrl = wave6_vpu_enc_s_ctrl,
>> +};
>> +
>> +static u32 to_video_full_range_flag(enum v4l2_quantization
>> quantization)
>> +{
>> + switch (quantization) {
>> + case V4L2_QUANTIZATION_FULL_RANGE:
>> + return 1;
>> + case V4L2_QUANTIZATION_LIM_RANGE:
>> + default:
>> + return 0;
>> + }
>> +}
>> +
>> +static u32 to_colour_primaries(enum v4l2_colorspace colorspace)
>> +{
>> + switch (colorspace) {
>> + case V4L2_COLORSPACE_SMPTE170M:
>> + return 6;
>> + case V4L2_COLORSPACE_REC709:
>> + case V4L2_COLORSPACE_SRGB:
>> + case V4L2_COLORSPACE_JPEG:
>> + return 1;
>> + case V4L2_COLORSPACE_BT2020:
>> + return 9;
>> + case V4L2_COLORSPACE_DCI_P3:
>> + return 11;
>> + case V4L2_COLORSPACE_SMPTE240M:
>> + return 7;
>> + case V4L2_COLORSPACE_470_SYSTEM_M:
>> + return 4;
>> + case V4L2_COLORSPACE_470_SYSTEM_BG:
>> + return 5;
>> + case V4L2_COLORSPACE_RAW:
>> + default:
>> + return 2;
>> + }
>> +}
>> +
>> +static u32 to_transfer_characteristics(enum v4l2_colorspace
>> colorspace,
>> + enum v4l2_xfer_func
>> xfer_func)
>> +{
>> + if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
>> + xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
>> +
>> + switch (xfer_func) {
>> + case V4L2_XFER_FUNC_709:
>> + if (colorspace == V4L2_COLORSPACE_SMPTE170M)
>> + return 6;
>> + else if (colorspace == V4L2_COLORSPACE_BT2020)
>> + return 14;
>> + else
>> + return 1;
>> + case V4L2_XFER_FUNC_SRGB:
>> + return 13;
>> + case V4L2_XFER_FUNC_SMPTE240M:
>> + return 7;
>> + case V4L2_XFER_FUNC_NONE:
>> + return 8;
>> + case V4L2_XFER_FUNC_SMPTE2084:
>> + return 16;
>> + case V4L2_XFER_FUNC_DCI_P3:
>> + default:
>> + return 2;
>> + }
>> +}
>> +
>> +static u32 to_matrix_coeffs(enum v4l2_colorspace colorspace,
>> + enum v4l2_ycbcr_encoding ycbcr_enc)
>> +{
>> + if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
>> + ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
>> +
>> + switch (ycbcr_enc) {
>> + case V4L2_YCBCR_ENC_601:
>> + case V4L2_YCBCR_ENC_XV601:
>> + if (colorspace == V4L2_COLORSPACE_SMPTE170M)
>> + return 6;
>> + else
>> + return 5;
>> + case V4L2_YCBCR_ENC_709:
>> + case V4L2_YCBCR_ENC_XV709:
>> + return 1;
>> + case V4L2_YCBCR_ENC_BT2020:
>> + return 9;
>> + case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
>> + return 10;
>> + case V4L2_YCBCR_ENC_SMPTE240M:
>> + return 7;
>> + default:
>> + return 2;
>> + }
>> +}
>> +
>> +static void wave6_set_enc_h264_param(struct enc_codec_param *output,
>> + struct h264_enc_controls
>> *ctrls)
>> +{
>> + switch (ctrls->profile) {
>> + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
>> + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
>> + output->profile = H264_PROFILE_BP;
>> + output->internal_bit_depth = 8;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
>> + output->profile = H264_PROFILE_MP;
>> + output->internal_bit_depth = 8;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
>> + output->profile = H264_PROFILE_EXTENDED;
>> + output->internal_bit_depth = 8;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
>> + output->profile = H264_PROFILE_HP;
>> + output->internal_bit_depth = 8;
>> + break;
>> + default:
>> + break;
>> + }
>> + switch (ctrls->level) {
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
>> + output->level = 10;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
>> + output->level = 9;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
>> + output->level = 11;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
>> + output->level = 12;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
>> + output->level = 13;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
>> + output->level = 20;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
>> + output->level = 21;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
>> + output->level = 22;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
>> + output->level = 30;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
>> + output->level = 31;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
>> + output->level = 32;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
>> + output->level = 40;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
>> + output->level = 41;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
>> + output->level = 42;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
>> + output->level = 50;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
>> + output->level = 51;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
>> + output->level = 52;
>> + break;
>> + default:
>> + break;
>> + }
>> + output->qp = ctrls->i_frame_qp;
>> + output->min_qp_i = ctrls->min_qp;
>> + output->max_qp_i = ctrls->max_qp;
>> + output->min_qp_p = ctrls->min_qp;
>> + output->max_qp_p = ctrls->max_qp;
>> + output->min_qp_b = ctrls->min_qp;
>> + output->max_qp_b = ctrls->max_qp;
>> + switch (ctrls->loop_filter_mode) {
>> + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
>> + output->en_dbk = 0;
>> + output->en_lf_cross_slice_boundary = 0;
>> + break;
>> + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
>> + output->en_dbk = 1;
>> + output->en_lf_cross_slice_boundary = 1;
>> + break;
>> + case
>> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
>> + output->en_dbk = 1;
>> + output->en_lf_cross_slice_boundary = 0;
>> + break;
>> + default:
>> + break;
>> + }
>> + output->intra_period = ctrls->i_period;
>> + output->beta_offset_div2 = ctrls->loop_filter_beta;
>> + output->tc_offset_div2 = ctrls->loop_filter_alpha;
>> + if (output->profile >= H264_PROFILE_HP)
>> + output->en_transform8x8 = ctrls->_8x8_transform;
>> + output->en_constrained_intra_pred = ctrls-
>> >constrained_intra_prediction;
>> + output->cb_qp_offset = ctrls->chroma_qp_index_offset;
>> + output->cr_qp_offset = ctrls->chroma_qp_index_offset;
>> + if (output->profile >= H264_PROFILE_MP)
>> + output->en_cabac = ctrls->entropy_mode;
>> + output->en_auto_level_adjusting =
>> DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
>> +}
>> +
>> +static void wave6_set_enc_hevc_param(struct enc_codec_param *output,
>> + struct hevc_enc_controls
>> *ctrls)
>> +{
>> + switch (ctrls->profile) {
>> + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
>> + output->profile = HEVC_PROFILE_MAIN;
>> + output->internal_bit_depth = 8;
>> + break;
>> + default:
>> + break;
>> + }
>> + switch (ctrls->level) {
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
>> + output->level = 10 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
>> + output->level = 20 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
>> + output->level = 21 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
>> + output->level = 30 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
>> + output->level = 31 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
>> + output->level = 40 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
>> + output->level = 41 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
>> + output->level = 50 * 3;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
>> + output->level = 51 * 3;
>> + break;
>> + default:
>> + break;
>> + }
>> + output->qp = ctrls->i_frame_qp;
>> + output->min_qp_i = ctrls->min_qp;
>> + output->max_qp_i = ctrls->max_qp;
>> + output->min_qp_p = ctrls->min_qp;
>> + output->max_qp_p = ctrls->max_qp;
>> + output->min_qp_b = ctrls->min_qp;
>> + output->max_qp_b = ctrls->max_qp;
>> + switch (ctrls->loop_filter_mode) {
>> + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
>> + output->en_dbk = 0;
>> + output->en_sao = 0;
>> + output->en_lf_cross_slice_boundary = 0;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
>> + output->en_dbk = 1;
>> + output->en_sao = 1;
>> + output->en_lf_cross_slice_boundary = 1;
>> + break;
>> + case
>> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
>> + output->en_dbk = 1;
>> + output->en_sao = 1;
>> + output->en_lf_cross_slice_boundary = 0;
>> + break;
>> + default:
>> + break;
>> + }
>> + switch (ctrls->refresh_type) {
>> + case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE:
>> + output->decoding_refresh_type =
>> DEC_REFRESH_TYPE_NON_IRAP;
>> + break;
>> + case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR:
>> + output->decoding_refresh_type =
>> DEC_REFRESH_TYPE_IDR;
>> + break;
>> + default:
>> + break;
>> + }
>> + output->intra_period = ctrls->refresh_period;
>> + if (output->idr_period) {
>> + output->decoding_refresh_type =
>> DEC_REFRESH_TYPE_IDR;
>> + output->intra_period = output->idr_period;
>> + output->idr_period = 0;
>> + }
>> + output->beta_offset_div2 = ctrls->lf_beta_offset_div2;
>> + output->tc_offset_div2 = ctrls->lf_tc_offset_div2;
>> + output->en_constrained_intra_pred = ctrls->const_intra_pred;
>> + output->en_strong_intra_smoothing = ctrls->strong_smoothing;
>> + output->en_temporal_mvp = ctrls->tmv_prediction;
>> + output->num_ticks_poc_diff_one = DEFAULT_NUM_TICKS_POC_DIFF;
>> + output->en_auto_level_adjusting =
>> DEFAULT_EN_AUTO_LEVEL_ADJUSTING;
>> + output->en_intra_trans_skip = DEFAULT_EN_INTRA_TRANS_SKIP;
>> + output->en_me_center = DEFAULT_EN_ME_CENTER;
>> + output->intra_4x4 = DEFAULT_INTRA_4X4;
>> +}
>> +
>> +static void wave6_set_enc_open_param(struct enc_open_param
>> *open_param,
>> + struct vpu_instance *inst)
>> +{
>> + struct enc_controls *ctrls = &inst->enc_ctrls;
>> + struct enc_codec_param *output = &open_param->codec_param;
>> + u32 ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
>> + u32 num_ctu_row = ALIGN(inst->src_fmt.height, ctu_size) /
>> ctu_size;
>> +
>> + open_param->source_endian = VPU_SOURCE_ENDIAN;
>> + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
>> + open_param->src_format = FORMAT_420;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M)
>> {
>> + open_param->src_format = FORMAT_422;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42) {
>> + open_param->src_format = FORMAT_YUV444_24BIT;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24)
>> {
>> + open_param->src_format = FORMAT_YUV444_24BIT_PACKED;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUYV) {
>> + open_param->src_format = FORMAT_YUYV;
>> + open_param->packed_format = PACKED_YUYV;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24)
>> {
>> + open_param->src_format = FORMAT_RGB_24BIT_PACKED;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010) {
>> + open_param->src_format = FORMAT_420_P10_16BIT_MSB;
>> + open_param->source_endian = VDI_128BIT_LE_BYTE_SWAP;
>> + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32
>> ||
>> + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32)
>> {
>> + open_param->src_format = FORMAT_RGB_32BIT_PACKED;
>> + } else if (inst->src_fmt.pixelformat ==
>> V4L2_PIX_FMT_ARGB2101010) {
>> + open_param->src_format =
>> FORMAT_RGB_P10_32BIT_PACKED;
>> + open_param->source_endian =
>> VDI_128BIT_LE_WORD_BYTE_SWAP;
>> + }
>> + open_param->line_buf_int_en = true;
>> + open_param->stream_endian = VPU_STREAM_ENDIAN;
>> + open_param->inst_buffer.temp_base = inst->dev-
>> >temp_vbuf.daddr;
>> + open_param->inst_buffer.temp_size = inst->dev-
>> >temp_vbuf.size;
>> + open_param->inst_buffer.ar_base = inst->ar_vbuf.daddr;
>> + open_param->pic_width = inst->codec_rect.width;
>> + open_param->pic_height = inst->codec_rect.height;
>> +
>> + output->custom_map_endian = VPU_USER_DATA_ENDIAN;
>> + output->gop_preset_idx = PRESET_IDX_IPP_SINGLE;
>> + output->temp_layer_cnt = DEFAULT_TEMP_LAYER_CNT;
>> + output->rc_initial_level = DEFAULT_RC_INITIAL_LEVEL;
>> + output->pic_rc_max_dqp = DEFAULT_PIC_RC_MAX_DQP;
>> + output->rc_initial_qp = DEFAULT_RC_INITIAL_QP;
>> + output->en_adaptive_round = DEFAULT_EN_ADAPTIVE_ROUND;
>> + output->q_round_inter = DEFAULT_Q_ROUND_INTER;
>> + output->q_round_intra = DEFAULT_Q_ROUND_INTRA;
>> +
>> + output->frame_rate = inst->frame_rate;
>> + output->idr_period = ctrls->gop_size;
>> + output->rc_mode = ctrls->bitrate_mode;
>> + output->rc_update_speed = (ctrls->bitrate_mode) ?
>> DEFAULT_RC_UPDATE_SPEED_CBR :
>> +
>> DEFAULT_RC_UPDATE_SPEED_VBR;
>> + output->en_rate_control = ctrls->frame_rc_enable;
>> + output->en_cu_level_rate_control = ctrls->mb_rc_enable;
>> + output->max_intra_pic_bit = inst-
>> >dst_fmt.plane_fmt[0].sizeimage * 8;
>> + output->max_inter_pic_bit = inst-
>> >dst_fmt.plane_fmt[0].sizeimage * 8;
>> + output->bitrate = ctrls->bitrate;
>> + output->cpb_size = wave6_cpb_size_msec(ctrls->h264.cpb_size,
>> ctrls->bitrate);
>> + output->slice_mode = ctrls->slice_mode;
>> + output->slice_arg = ctrls->slice_max_mb;
>> + output->forced_idr_header = ctrls->prepend_spspps_to_idr;
>> + output->en_vbv_overflow_drop_frame = (ctrls-
>> >frame_skip_mode) ? 1 : 0;
>> + if (ctrls->intra_refresh_period) {
>> + output->intra_refresh_mode = INTRA_REFRESH_ROW;
>> + if (ctrls->intra_refresh_period < num_ctu_row) {
>> + output->intra_refresh_arg = (num_ctu_row +
>> ctrls->intra_refresh_period - 1)
>> + / ctrls-
>> >intra_refresh_period;
>> + } else {
>> + output->intra_refresh_arg = 1;
>> + }
>> + }
>> + output->sar.enable = ctrls->h264.vui_sar_enable;
>> + output->sar.idc = ctrls->h264.vui_sar_idc;
>> + if (output->sar.idc ==
>> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED)
>> + output->sar.idc = H264_VUI_SAR_IDC_EXTENDED;
>> + output->sar.width = ctrls->h264.vui_ext_sar_width;
>> + output->sar.height = ctrls->h264.vui_ext_sar_height;
>> + output->color.video_signal_type_present =
>> DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG;
>> + output->color.color_range = to_video_full_range_flag(inst-
>> >quantization);
>> + output->color.color_description_present =
>> DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG;
>> + output->color.color_primaries = to_colour_primaries(inst-
>> >colorspace);
>> + output->color.transfer_characteristics =
>> to_transfer_characteristics(inst->colorspace,
>> +
>> inst->xfer_func);
>> + output->color.matrix_coefficients = to_matrix_coeffs(inst-
>> >colorspace, inst->ycbcr_enc);
>> + output->conf_win.left = inst->crop.left - inst-
>> >codec_rect.left;
>> + output->conf_win.top = inst->crop.top - inst-
>> >codec_rect.top;
>> + output->conf_win.right = inst->codec_rect.width
>> + - inst->crop.width - output-
>> >conf_win.left;
>> + output->conf_win.bottom = inst->codec_rect.height
>> + - inst->crop.height -
>> output->conf_win.top;
>> +
>> + switch (inst->std) {
>> + case W_AVC_ENC:
>> + wave6_set_enc_h264_param(output, &ctrls->h264);
>> + break;
>> + case W_HEVC_ENC:
>> + wave6_set_enc_hevc_param(output, &ctrls->hevc);
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static int wave6_vpu_enc_create_instance(struct vpu_instance *inst)
>> +{
>> + int ret;
>> + struct enc_open_param open_param;
>> +
>> + memset(&open_param, 0, sizeof(struct enc_open_param));
>> +
>> + wave6_vpu_activate(inst->dev);
>> + ret = pm_runtime_resume_and_get(inst->dev->dev);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "runtime_resume failed
>> %d\n", ret);
>> + return ret;
>> + }
>> +
>> + wave6_vpu_wait_activated(inst->dev);
>> +
>> + inst->ar_vbuf.size = ALIGN(WAVE6_ARBUF_SIZE, 4096);
>> + ret = wave6_alloc_dma(inst->dev->dev, &inst->ar_vbuf);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "alloc ar of size %zu
>> failed\n",
>> + inst->ar_vbuf.size);
>> + goto error_pm;
>> + }
>> +
>> + wave6_set_enc_open_param(&open_param, inst);
>> +
>> + ret = wave6_vpu_enc_open(inst, &open_param);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "failed create instance :
>> %d\n", ret);
>> + goto error_open;
>> + }
>> +
>> + dprintk(inst->dev->dev, "[%d] encoder\n", inst->id);
>> + wave6_vpu_create_dbgfs_file(inst);
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN);
>> +
>> + return 0;
>> +
>> +error_open:
>> + wave6_free_dma(&inst->ar_vbuf);
>> +error_pm:
>> + pm_runtime_put_sync(inst->dev->dev);
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_enc_initialize_instance(struct vpu_instance
>> *inst)
>> +{
>> + int ret;
>> + struct enc_initial_info initial_info;
>> + struct v4l2_ctrl *ctrl;
>> +
>> + if (inst->enc_ctrls.mirror_direction) {
>> + wave6_vpu_enc_give_command(inst, ENABLE_MIRRORING,
>> NULL);
>> + wave6_vpu_enc_give_command(inst,
>> SET_MIRROR_DIRECTION,
>> + &inst-
>> >enc_ctrls.mirror_direction);
>> + }
>> + if (inst->enc_ctrls.rot_angle) {
>> + wave6_vpu_enc_give_command(inst, ENABLE_ROTATION,
>> NULL);
>> + wave6_vpu_enc_give_command(inst, SET_ROTATION_ANGLE,
>> + &inst-
>> >enc_ctrls.rot_angle);
>> + }
>> +
>> + ret = wave6_vpu_enc_issue_seq_init(inst);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "seq init fail %d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) {
>> + dev_err(inst->dev->dev, "seq init timeout\n");
>> + return ret;
>> + }
>> +
>> + ret = wave6_vpu_enc_complete_seq_init(inst, &initial_info);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "seq init error\n");
>> + return ret;
>> + }
>> +
>> + dev_dbg(inst->dev->dev, "min_fb_cnt : %d | min_src_cnt :
>> %d\n",
>> + initial_info.min_frame_buffer_count,
>> + initial_info.min_src_frame_count);
>> +
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
>> + if (ctrl)
>> + v4l2_ctrl_s_ctrl(ctrl,
>> initial_info.min_src_frame_count);
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
>> +
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_enc_prepare_fb(struct vpu_instance *inst)
>> +{
>> + int ret;
>> + unsigned int i;
>> + unsigned int fb_num;
>> + unsigned int mv_num;
>> + unsigned int fb_stride;
>> + unsigned int fb_height;
>> + struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>> +
>> + fb_num = p_enc_info->initial_info.min_frame_buffer_count;
>> + mv_num = p_enc_info->initial_info.req_mv_buffer_count;
>> +
>> + fb_stride = ALIGN(inst->codec_rect.width, 32);
>> + fb_height = ALIGN(inst->codec_rect.height, 32);
>> +
>> + for (i = 0; i < fb_num; i++) {
>> + struct frame_buffer *frame = &inst->frame_buf[i];
>> + struct vpu_buf *vframe = &inst->frame_vbuf[i];
>> + unsigned int l_size = fb_stride * fb_height;
>> + unsigned int ch_size = ALIGN(fb_stride / 2, 32) *
>> fb_height;
>> +
>> + vframe->size = l_size + ch_size;
>> + ret = wave6_alloc_dma(inst->dev->dev, vframe);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "alloc FBC buffer
>> fail : %zu\n",
>> + vframe->size);
>> + goto error;
>> + }
>> +
>> + frame->buf_y = vframe->daddr;
>> + frame->buf_cb = vframe->daddr + l_size;
>> + frame->buf_cr = (dma_addr_t)-1;
>> + frame->stride = fb_stride;
>> + frame->height = fb_height;
>> + frame->map_type = COMPRESSED_FRAME_MAP;
>> + }
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL,
>> fb_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL,
>> fb_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL,
>> mv_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_SUB_SAMPLE,
>> fb_num);
>> + if (ret)
>> + goto error;
>> +
>> + ret = wave6_vpu_enc_register_frame_buffer_ex(inst, fb_num,
>> fb_stride,
>> + fb_height,
>> +
>> COMPRESSED_FRAME_MAP);
>> + if (ret) {
>> + dev_err(inst->dev->dev, "register frame buffer fail
>> %d\n", ret);
>> + goto error;
>> + }
>> +
>> + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
>> +
>> + return 0;
>> +
>> +error:
>> + wave6_vpu_enc_release_fb(inst);
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_enc_queue_setup(struct vb2_queue *q, unsigned
>> int *num_buffers,
>> + unsigned int *num_planes,
>> unsigned int sizes[],
>> + struct device *alloc_devs[])
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct v4l2_pix_format_mplane inst_format =
>> + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt :
>> inst->dst_fmt;
>> + unsigned int i;
>> +
>> + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d
>> type %d\n",
>> + __func__, *num_buffers, *num_planes, q->type);
>> +
>> + if (*num_planes) {
>> + if (inst_format.num_planes != *num_planes)
>> + return -EINVAL;
>> +
>> + for (i = 0; i < *num_planes; i++) {
>> + if (sizes[i] <
>> inst_format.plane_fmt[i].sizeimage)
>> + return -EINVAL;
>> + }
>> + } else {
>> + *num_planes = inst_format.num_planes;
>> + for (i = 0; i < *num_planes; i++) {
>> + sizes[i] =
>> inst_format.plane_fmt[i].sizeimage;
>> + dev_dbg(inst->dev->dev, "size[%d] : %d\n",
>> i, sizes[i]);
>> + }
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
>> + struct v4l2_ctrl *ctrl;
>> + unsigned int min_src_frame_count = 0;
>> +
>> + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
>> +
>> V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
>> + if (ctrl)
>> + min_src_frame_count =
>> v4l2_ctrl_g_ctrl(ctrl);
>> +
>> + *num_buffers = max(*num_buffers,
>> min_src_frame_count);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void wave6_vpu_enc_buf_queue(struct vb2_buffer *vb)
>> +{
>> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
>> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
>> +
>> + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld
>> size[1] : %4ld | size[2] : %4ld\n",
>> + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf,
>> 0),
>> + vb2_plane_size(&vbuf->vb2_buf, 1),
>> vb2_plane_size(&vbuf->vb2_buf, 2));
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
>> + vbuf->sequence = inst->queued_src_buf_num++;
>> +
>> + vpu_buf->ts_input = ktime_get_raw();
>> + vpu_buf->force_key_frame = inst-
>> >enc_ctrls.force_key_frame;
>> + inst->enc_ctrls.force_key_frame = false;
>> + vpu_buf->force_frame_qp = (!inst-
>> >enc_ctrls.frame_rc_enable) ? true : false;
>> + if (vpu_buf->force_frame_qp) {
>> + if (inst->std == W_AVC_ENC) {
>> + vpu_buf->force_i_frame_qp = inst-
>> >enc_ctrls.h264.i_frame_qp;
>> + vpu_buf->force_p_frame_qp = inst-
>> >enc_ctrls.h264.p_frame_qp;
>> + vpu_buf->force_b_frame_qp = inst-
>> >enc_ctrls.h264.b_frame_qp;
>> + } else if (inst->std == W_HEVC_ENC) {
>> + vpu_buf->force_i_frame_qp = inst-
>> >enc_ctrls.hevc.i_frame_qp;
>> + vpu_buf->force_p_frame_qp = inst-
>> >enc_ctrls.hevc.p_frame_qp;
>> + vpu_buf->force_b_frame_qp = inst-
>> >enc_ctrls.hevc.b_frame_qp;
>> + }
>> + }
>> + } else {
>> + inst->queued_dst_buf_num++;
>> + }
>> +
>> + vpu_buf->consumed = false;
>> + vpu_buf->used = false;
>> + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf);
>> +}
>> +
>> +static void wave6_vpu_enc_buf_finish(struct vb2_buffer *vb)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
>> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf);
>> + struct v4l2_ctrl *ctrl;
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(vb->type))
>> + return;
>> +
>> + ctrl = v4l2_ctrl_find(inst->v4l2_fh.ctrl_handler,
>> V4L2_CID_MPEG_VIDEO_AVERAGE_QP);
>> + if (ctrl)
>> + v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp);
>> +}
>> +
>> +static int wave6_vpu_enc_start_streaming(struct vb2_queue *q,
>> unsigned int count)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct v4l2_pix_format_mplane *fmt;
>> + struct vb2_queue *vq_peer;
>> + int ret = 0;
>> +
>> + trace_start_streaming(inst, q->type);
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
>> + fmt = &inst->src_fmt;
>> + vq_peer = v4l2_m2m_get_dst_vq(inst-
>> >v4l2_fh.m2m_ctx);
>> + } else {
>> + fmt = &inst->dst_fmt;
>> + vq_peer = v4l2_m2m_get_src_vq(inst-
>> >v4l2_fh.m2m_ctx);
>> + }
>> +
>> + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d
>> buffers\n",
>> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
>> "capture",
>> + fmt->pixelformat,
>> + fmt->pixelformat >> 8,
>> + fmt->pixelformat >> 16,
>> + fmt->pixelformat >> 24,
>> + fmt->width, fmt->height, vb2_get_num_buffers(q));
>> +
>> + if (!vb2_is_streaming(vq_peer))
>> + return 0;
>> +
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> +
>> + if (inst->state == VPU_INST_STATE_NONE) {
>> + ret = wave6_vpu_enc_create_instance(inst);
>> + if (ret)
>> + goto exit;
>> + }
>> +
>> + if (inst->state == VPU_INST_STATE_OPEN) {
>> + ret = wave6_vpu_enc_initialize_instance(inst);
>> + if (ret) {
>> + wave6_vpu_enc_destroy_instance(inst);
>> + goto exit;
>> + }
>> + }
>> +
>> + if (inst->state == VPU_INST_STATE_INIT_SEQ) {
>> + ret = wave6_vpu_enc_prepare_fb(inst);
>> + if (ret) {
>> + wave6_vpu_enc_destroy_instance(inst);
>> + goto exit;
>> + }
>> + }
>> +
>> +exit:
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> + if (ret)
>> + wave6_vpu_return_buffers(inst, q->type,
>> VB2_BUF_STATE_QUEUED);
>> +
>> + return ret;
>> +}
>> +
>> +static void wave6_vpu_enc_stop_streaming(struct vb2_queue *q)
>> +{
>> + struct vpu_instance *inst = vb2_get_drv_priv(q);
>> + struct vb2_queue *vq_peer;
>> +
>> + trace_stop_streaming(inst, q->type);
>> +
>> + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d\n",
>> + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" :
>> "capture",
>> + inst->queued_src_buf_num, inst->sequence);
>> +
>> + if (inst->state == VPU_INST_STATE_NONE)
>> + goto exit;
>> +
>> + if (wave6_vpu_both_queues_are_streaming(inst))
>> + wave6_vpu_set_instance_state(inst,
>> VPU_INST_STATE_STOP);
>> +
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type)) {
>> + wave6_vpu_reset_performance(inst);
>> + inst->queued_src_buf_num = 0;
>> + inst->processed_buf_num = 0;
>> + inst->error_buf_num = 0;
>> + inst->sequence = 0;
>> + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx,
>> false);
>> + } else {
>> + inst->eos = false;
>> + inst->queued_dst_buf_num = 0;
>> + }
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(q->type))
>> + vq_peer = v4l2_m2m_get_dst_vq(inst-
>> >v4l2_fh.m2m_ctx);
>> + else
>> + vq_peer = v4l2_m2m_get_src_vq(inst-
>> >v4l2_fh.m2m_ctx);
>> +
>> + if (!vb2_is_streaming(vq_peer) && inst->state !=
>> VPU_INST_STATE_NONE)
>> + wave6_vpu_enc_destroy_instance(inst);
>> +
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> +
>> +exit:
>> + wave6_vpu_return_buffers(inst, q->type,
>> VB2_BUF_STATE_ERROR);
>> +}
>> +
>> +static const struct vb2_ops wave6_vpu_enc_vb2_ops = {
>> + .queue_setup = wave6_vpu_enc_queue_setup,
>> + .wait_prepare = vb2_ops_wait_prepare,
>> + .wait_finish = vb2_ops_wait_finish,
>> + .buf_queue = wave6_vpu_enc_buf_queue,
>> + .buf_finish = wave6_vpu_enc_buf_finish,
>> + .start_streaming = wave6_vpu_enc_start_streaming,
>> + .stop_streaming = wave6_vpu_enc_stop_streaming,
>> +};
>> +
>> +static void wave6_set_default_format(struct v4l2_pix_format_mplane
>> *src_fmt,
>> + struct v4l2_pix_format_mplane
>> *dst_fmt)
>> +{
>> + const struct vpu_format *vpu_fmt;
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW);
>> + if (vpu_fmt) {
>> + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + src_fmt->num_planes = vpu_fmt->num_planes;
>> + wave6_update_pix_fmt(src_fmt,
>> + W6_DEF_ENC_PIC_WIDTH,
>> W6_DEF_ENC_PIC_HEIGHT);
>> + }
>> +
>> + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC);
>> + if (vpu_fmt) {
>> + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt;
>> + dst_fmt->num_planes = vpu_fmt->num_planes;
>> + wave6_update_pix_fmt(dst_fmt,
>> + W6_DEF_ENC_PIC_WIDTH,
>> W6_DEF_ENC_PIC_HEIGHT);
>> + }
>> +}
>> +
>> +static int wave6_vpu_enc_queue_init(void *priv, struct vb2_queue
>> *src_vq, struct vb2_queue *dst_vq)
>> +{
>> + struct vpu_instance *inst = priv;
>> + int ret;
>> +
>> + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
>> + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> + src_vq->mem_ops = &vb2_dma_contig_memops;
>> + src_vq->ops = &wave6_vpu_enc_vb2_ops;
>> + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> + src_vq->buf_struct_size = sizeof(struct vpu_buffer);
>> + src_vq->drv_priv = inst;
>> + src_vq->lock = &inst->dev->dev_lock;
>> + src_vq->dev = inst->dev->v4l2_dev.dev;
>> + ret = vb2_queue_init(src_vq);
>> + if (ret)
>> + return ret;
>> +
>> + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
>> + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> + dst_vq->mem_ops = &vb2_dma_contig_memops;
>> + dst_vq->ops = &wave6_vpu_enc_vb2_ops;
>> + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> + dst_vq->buf_struct_size = sizeof(struct vpu_buffer);
>> + dst_vq->drv_priv = inst;
>> + dst_vq->lock = &inst->dev->dev_lock;
>> + dst_vq->dev = inst->dev->v4l2_dev.dev;
>> + ret = vb2_queue_init(dst_vq);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +
>> +static const struct vpu_instance_ops wave6_vpu_enc_inst_ops = {
>> + .start_process = wave6_vpu_enc_start_encode,
>> + .finish_process = wave6_vpu_enc_finish_encode,
>> +};
>> +
>> +static int wave6_vpu_open_enc(struct file *filp)
>> +{
>> + struct video_device *vdev = video_devdata(filp);
>> + struct vpu_device *dev = video_drvdata(filp);
>> + struct vpu_instance *inst = NULL;
>> + struct v4l2_ctrl_handler *v4l2_ctrl_hdl;
>> + int ret;
>> +
>> + inst = kzalloc(sizeof(*inst), GFP_KERNEL);
>> + if (!inst)
>> + return -ENOMEM;
>> + v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl;
>> +
>> + inst->dev = dev;
>> + inst->type = VPU_INST_TYPE_ENC;
>> + inst->ops = &wave6_vpu_enc_inst_ops;
>> +
>> + v4l2_fh_init(&inst->v4l2_fh, vdev);
>> + filp->private_data = &inst->v4l2_fh;
>> + v4l2_fh_add(&inst->v4l2_fh);
>> +
>> + inst->v4l2_fh.m2m_ctx =
>> + v4l2_m2m_ctx_init(dev->m2m_dev, inst,
>> wave6_vpu_enc_queue_init);
>> + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
>> + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
>> + goto free_inst;
>> + }
>> +
>> + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
>> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0,
>> + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
>> + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0,
>> + V4L2_MPEG_VIDEO_HEVC_LEVEL_5);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
>> + 0, 51, 1, 8);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
>> + 0, 51, 1, 51);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
>> +
>> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
>> +
>> V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
>> + -6, 6, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
>> + -6, 6, 1, 0);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
>> + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR,
>> +
>> BIT(V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA),
>> + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
>> + 0, 2047, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_PROFILE,
>> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0,
>> + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_LEVEL,
>> + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, 0,
>> + V4L2_MPEG_VIDEO_H264_LEVEL_5_0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
>> + 0, 51, 1, 8);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
>> + 0, 51, 1, 51);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
>> + 0, 51, 1, 30);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
>> +
>> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
>> +
>> V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
>> + -6, 6, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
>> + -6, 6, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
>> + -12, 12, 1, 0);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
>> +
>> V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0,
>> +
>> V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
>> + 0, 2047, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
>> 0, 1, 1, 0);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
>> +
>> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, 0,
>> +
>> V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
>> + 0, 0xFFFF, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
>> + 0, 0xFFFF, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_HFLIP,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_VFLIP,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_ROTATE,
>> + 0, 270, 90, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
>> + 0, 18750000, 1, 0);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
>> + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
>> + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_BITRATE,
>> + 1, 1500000000, 1, 2097152);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_GOP_SIZE,
>> + 0, 2047, 1, 30);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
>> +
>> V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0,
>> +
>> V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
>> + 0, 0x3FFFF, 1, 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
>> + 0, 1, 1, 0);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
>> + 0, 1, 1, 1);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> +
>> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
>> +
>> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
>> +
>> BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM),
>> +
>> V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD,
>> + 0, 2160, 1, 0);
>> + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl,
>> &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
>> +
>> V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
>> +
>> BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT),
>> +
>> V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops,
>> + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1,
>> 1);
>> + v4l2_ctrl_new_std(v4l2_ctrl_hdl, NULL,
>> + V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1,
>> 0);
>> +
>> + if (v4l2_ctrl_hdl->error) {
>> + ret = -ENODEV;
>> + goto err_m2m_release;
>> + }
>> +
>> + inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl;
>> + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
>> +
>> + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt);
>> + wave6_update_crop_info(inst, 0, 0, inst->dst_fmt.width,
>> inst->dst_fmt.height);
>> + inst->colorspace = V4L2_COLORSPACE_DEFAULT;
>> + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
>> + inst->quantization = V4L2_QUANTIZATION_DEFAULT;
>> + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
>> + inst->frame_rate = 30;
>> +
>> + return 0;
>> +
>> +err_m2m_release:
>> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
>> +free_inst:
>> + kfree(inst);
>> + return ret;
>> +}
>> +
>> +static int wave6_vpu_enc_release(struct file *filp)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(filp-
>> >private_data);
>> +
>> + dprintk(inst->dev->dev, "[%d] release\n", inst->id);
>> + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
>> +
>> + mutex_lock(&inst->dev->dev_lock);
>> + if (inst->state != VPU_INST_STATE_NONE) {
>> + wave6_vpu_pause(inst->dev->dev, 0);
>> + wave6_vpu_enc_destroy_instance(inst);
>> + wave6_vpu_pause(inst->dev->dev, 1);
>> + }
>> + mutex_unlock(&inst->dev->dev_lock);
>> +
>> + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
>> + v4l2_fh_del(&inst->v4l2_fh);
>> + v4l2_fh_exit(&inst->v4l2_fh);
>> + kfree(inst);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct v4l2_file_operations wave6_vpu_enc_fops = {
>> + .owner = THIS_MODULE,
>> + .open = wave6_vpu_open_enc,
>> + .release = wave6_vpu_enc_release,
>> + .unlocked_ioctl = video_ioctl2,
>> + .poll = v4l2_m2m_fop_poll,
>> + .mmap = v4l2_m2m_fop_mmap,
>> +};
>> +
>> +int wave6_vpu_enc_register_device(struct vpu_device *dev)
>> +{
>> + struct video_device *vdev_enc;
>> + int ret;
>> +
>> + vdev_enc = devm_kzalloc(dev->v4l2_dev.dev,
>> sizeof(*vdev_enc), GFP_KERNEL);
>> + if (!vdev_enc)
>> + return -ENOMEM;
>> +
>> + dev->video_dev_enc = vdev_enc;
>> +
>> + strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc-
>> >name));
>> + vdev_enc->fops = &wave6_vpu_enc_fops;
>> + vdev_enc->ioctl_ops = &wave6_vpu_enc_ioctl_ops;
>> + vdev_enc->release = video_device_release_empty;
>> + vdev_enc->v4l2_dev = &dev->v4l2_dev;
>> + vdev_enc->vfl_dir = VFL_DIR_M2M;
>> + vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
>> V4L2_CAP_STREAMING;
>> + vdev_enc->lock = &dev->dev_lock;
>> + video_set_drvdata(vdev_enc, dev);
>> +
>> + ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +
>> +void wave6_vpu_enc_unregister_device(struct vpu_device *dev)
>> +{
>> + video_unregister_device(dev->video_dev_enc);
>> +}
>> diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-
>> v4l2.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
>> new file mode 100644
>> index 000000000000..e614eda01a5a
>> --- /dev/null
>> +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
>> @@ -0,0 +1,381 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>> +/*
>> + * Wave6 series multi-standard codec IP - v4l2 driver helper
>> interface
>> + *
>> + * Copyright (C) 2025 CHIPS&MEDIA INC
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/math64.h>
>> +#include "wave6-vpu.h"
>> +#include "wave6-vpu-dbg.h"
>> +#include "wave6-trace.h"
>> +
>> +void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
>> + unsigned int width,
>> + unsigned int height)
>> +{
>> + const struct v4l2_format_info *fmt_info;
>> + unsigned int stride_y;
>> + int i;
>> +
>> + pix_mp->width = width;
>> + pix_mp->height = height;
>> + pix_mp->flags = 0;
>> + pix_mp->field = V4L2_FIELD_NONE;
>> + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
>> +
>> + fmt_info = v4l2_format_info(pix_mp->pixelformat);
>> + if (!fmt_info) {
>> + pix_mp->plane_fmt[0].bytesperline = 0;
>> + if (!pix_mp->plane_fmt[0].sizeimage)
>> + pix_mp->plane_fmt[0].sizeimage = width *
>> height;
>> +
>> + return;
>> + }
>> +
>> + stride_y = width * fmt_info->bpp[0];
>> + if (pix_mp->plane_fmt[0].bytesperline <= W6_MAX_PIC_STRIDE)
>> + stride_y = max(stride_y, pix_mp-
>> >plane_fmt[0].bytesperline);
>> + stride_y = round_up(stride_y, 32);
>> + pix_mp->plane_fmt[0].bytesperline = stride_y;
>> + pix_mp->plane_fmt[0].sizeimage = stride_y * height;
>> +
>> + stride_y = DIV_ROUND_UP(stride_y, fmt_info->bpp[0]);
>> +
>> + for (i = 1; i < fmt_info->comp_planes; i++) {
>> + unsigned int stride_c, sizeimage_c;
>> +
>> + stride_c = DIV_ROUND_UP(stride_y, fmt_info->hdiv) *
>> + fmt_info->bpp[i];
>> + sizeimage_c = stride_c * DIV_ROUND_UP(height,
>> fmt_info->vdiv);
>> +
>> + if (fmt_info->mem_planes == 1) {
>> + pix_mp->plane_fmt[0].sizeimage +=
>> sizeimage_c;
>> + } else {
>> + pix_mp->plane_fmt[i].bytesperline =
>> stride_c;
>> + pix_mp->plane_fmt[i].sizeimage =
>> sizeimage_c;
>> + }
>> + }
>> +}
>> +
>> +dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf, unsigned
>> int plane_no)
>> +{
>> + return vb2_dma_contig_plane_dma_addr(&buf->vb2_buf,
>> plane_no) +
>> + buf->planes[plane_no].data_offset;
>> +}
>> +
>> +struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct
>> vpu_instance *inst,
>> + dma_addr_t addr)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vb2_v4l2_buffer *dst_buf = NULL;
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + if (addr == wave6_get_dma_addr(vb2_v4l2_buf, 0)) {
>> + dst_buf = vb2_v4l2_buf;
>> + break;
>> + }
>> + }
>> +
>> + return dst_buf;
>> +}
>> +
>> +enum codec_std wave6_to_codec_std(enum vpu_instance_type type,
>> unsigned int v4l2_pix_fmt)
>> +{
>> + enum codec_std std = STD_UNKNOWN;
>> +
>> + if (v4l2_pix_fmt == V4L2_PIX_FMT_H264)
>> + std = (type == VPU_INST_TYPE_DEC) ? W_AVC_DEC :
>> W_AVC_ENC;
>> + else if (v4l2_pix_fmt == V4L2_PIX_FMT_HEVC)
>> + std = (type == VPU_INST_TYPE_DEC) ? W_HEVC_DEC :
>> W_HEVC_ENC;
>> +
>> + return std;
>> +}
>> +
>> +const char *wave6_vpu_instance_state_name(u32 state)
>> +{
>> + switch (state) {
>> + case VPU_INST_STATE_NONE: return "none";
>> + case VPU_INST_STATE_OPEN: return "open";
>> + case VPU_INST_STATE_INIT_SEQ: return "init_seq";
>> + case VPU_INST_STATE_PIC_RUN: return "pic_run";
>> + case VPU_INST_STATE_SEEK: return "seek";
>> + case VPU_INST_STATE_STOP: return "stop";
>> + }
>> + return "unknown";
>> +}
>> +
>> +void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32
>> state)
>> +{
>> + trace_set_state(inst, state);
>> +
>> + dprintk(inst->dev->dev, "[%d] %s -> %s\n",
>> + inst->id,
>> + wave6_vpu_instance_state_name(inst->state),
>> + wave6_vpu_instance_state_name(state));
>> +
>> + inst->state = state;
>> + if (state == VPU_INST_STATE_PIC_RUN && !inst-
>> >performance.ts_first)
>> + inst->performance.ts_first = ktime_get_raw();
>> +}
>> +
>> +u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle)
>> +{
>> + if (!vpu_dev || !vpu_dev->clk_vpu || !clk_get_rate(vpu_dev-
>> >clk_vpu))
>> + return 0;
>> +
>> + return (cycle * NSEC_PER_SEC) / clk_get_rate(vpu_dev-
>> >clk_vpu);
>> +}
>> +
>> +int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int
>> timeout)
>> +{
>> + int ret;
>> +
>> + ret = wait_for_completion_timeout(&inst->dev->irq_done,
>> +
>> msecs_to_jiffies(timeout));
>> + if (!ret)
>> + return -ETIMEDOUT;
>> +
>> + reinit_completion(&inst->dev->irq_done);
>> +
>> + return 0;
>> +}
>> +
>> +int wave6_vpu_subscribe_event(struct v4l2_fh *fh,
>> + const struct v4l2_event_subscription
>> *sub)
>> +{
>> + struct vpu_instance *inst = wave6_to_vpu_inst(fh);
>> + bool is_decoder = (inst->type == VPU_INST_TYPE_DEC) ? true :
>> false;
>> +
>> + dev_dbg(inst->dev->dev, "%s: [%s] type: %d id: %d | flags:
>> %d\n",
>> + __func__, is_decoder ? "decoder" : "encoder", sub-
>> >type,
>> + sub->id, sub->flags);
>> +
>> + switch (sub->type) {
>> + case V4L2_EVENT_SOURCE_CHANGE:
>> + if (is_decoder)
>> + return v4l2_src_change_event_subscribe(fh,
>> sub);
>> + return -EINVAL;
>> + case V4L2_EVENT_CTRL:
>> + return v4l2_ctrl_subscribe_event(fh, sub);
>> + default:
>> + return -EINVAL;
>> + }
>> +}
>> +
>> +void wave6_vpu_return_buffers(struct vpu_instance *inst,
>> + unsigned int type, enum
>> vb2_buffer_state state)
>> +{
>> + struct vb2_v4l2_buffer *buf;
>> + int i;
>> +
>> + if (V4L2_TYPE_IS_OUTPUT(type)) {
>> + while ((buf = v4l2_m2m_src_buf_remove(inst-
>> >v4l2_fh.m2m_ctx)))
>> + v4l2_m2m_buf_done(buf, state);
>> + } else {
>> + while ((buf = v4l2_m2m_dst_buf_remove(inst-
>> >v4l2_fh.m2m_ctx))) {
>> + for (i = 0; i < inst->dst_fmt.num_planes;
>> i++)
>> + vb2_set_plane_payload(&buf->vb2_buf,
>> i, 0);
>> + v4l2_m2m_buf_done(buf, state);
>> + }
>> + }
>> +}
>> +
>> +u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf;
>> + u32 num = 0;
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
>> + if (vpu_buf->consumed)
>> + num++;
>> + }
>> +
>> + return num;
>> +}
>> +
>> +u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf;
>> + u32 num = 0;
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
>> + if (vpu_buf->used)
>> + num++;
>> + }
>> +
>> + return num;
>> +}
>> +
>> +static bool wave6_vpu_check_fb_available(struct vpu_instance *inst)
>> +{
>> + struct vb2_v4l2_buffer *vb2_v4l2_buf;
>> + struct v4l2_m2m_buffer *v4l2_m2m_buf;
>> + struct vpu_buffer *vpu_buf;
>> +
>> + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx,
>> v4l2_m2m_buf) {
>> + vb2_v4l2_buf = &v4l2_m2m_buf->vb;
>> + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf);
>> +
>> + if (!vpu_buf->used)
>> + return true;
>> + }
>> +
>> + return false;
>> +}
>> +
>> +static int wave6_vpu_job_ready(void *priv)
>> +{
>> + struct vpu_instance *inst = priv;
>> +
>> + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
>> + inst->id, __func__, inst->state);
>> +
>> + if (inst->type == VPU_INST_TYPE_DEC && inst->state ==
>> VPU_INST_STATE_OPEN)
>> + return 1;
>> + if (inst->state < VPU_INST_STATE_PIC_RUN)
>> + return 0;
>> + if (inst->state == VPU_INST_STATE_STOP && inst->eos)
>> + return 0;
>> + if (!wave6_vpu_check_fb_available(inst))
>> + return 0;
>> +
>> + return 1;
>> +}
>> +
>> +static void wave6_vpu_device_run_timeout(struct work_struct *work)
>> +{
>> + struct delayed_work *dwork = to_delayed_work(work);
>> + struct vpu_device *dev = container_of(dwork, struct
>> vpu_device, task_timer);
>> + struct vpu_instance *inst = v4l2_m2m_get_curr_priv(dev-
>> >m2m_dev);
>> + struct vb2_v4l2_buffer *src_buf = NULL;
>> + struct vb2_v4l2_buffer *dst_buf = NULL;
>> +
>> + if (!inst)
>> + return;
>> +
>> + dev_err(inst->dev->dev, "[%d] sequence %d timeout\n", inst-
>> >id, inst->sequence);
>> + src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
>> + if (src_buf) {
>> + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
>> + if (inst->type == VPU_INST_TYPE_DEC)
>> + inst->processed_buf_num++;
>> + inst->error_buf_num++;
>> + }
>> +
>> + dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx);
>> + if (dst_buf)
>> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
>> +
>> + vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx));
>> + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx));
>> +
>> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
>> >v4l2_fh.m2m_ctx);
>> +}
>> +
>> +static void wave6_vpu_device_run(void *priv)
>> +{
>> + struct vpu_instance *inst = priv;
>> + int ret;
>> +
>> + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n",
>> + inst->id, __func__, inst->state);
>> +
>> + ret = inst->ops->start_process(inst);
>> + if (!ret)
>> + schedule_delayed_work(&inst->dev->task_timer,
>> msecs_to_jiffies(W6_VPU_TIMEOUT));
>> + else
>> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
>> >v4l2_fh.m2m_ctx);
>> +}
>> +
>> +void wave6_vpu_finish_job(struct vpu_instance *inst)
>> +{
>> + cancel_delayed_work(&inst->dev->task_timer);
>> + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst-
>> >v4l2_fh.m2m_ctx);
>> +}
>> +
>> +void wave6_vpu_handle_performance(struct vpu_instance *inst, struct
>> vpu_buffer *vpu_buf)
>> +{
>> + s64 latency, time_spent;
>> +
>> + if (!inst || !vpu_buf)
>> + return;
>> +
>> + inst->performance.ts_last = vpu_buf->ts_output;
>> +
>> + latency = vpu_buf->ts_output - vpu_buf->ts_input;
>> + time_spent = vpu_buf->ts_finish - vpu_buf->ts_start;
>> +
>> + if (!inst->performance.latency_first)
>> + inst->performance.latency_first = latency;
>> + inst->performance.latency_max = max_t(s64, latency, inst-
>> >performance.latency_max);
>> +
>> + if (!inst->performance.min_process_time)
>> + inst->performance.min_process_time = time_spent;
>> + else if (inst->performance.min_process_time > time_spent)
>> + inst->performance.min_process_time = time_spent;
>> +
>> + if (inst->performance.max_process_time < time_spent)
>> + inst->performance.max_process_time = time_spent;
>> +
>> + inst->performance.total_sw_time += time_spent;
>> + inst->performance.total_hw_time += vpu_buf->hw_time;
>> +}
>> +
>> +void wave6_vpu_reset_performance(struct vpu_instance *inst)
>> +{
>> + if (!inst)
>> + return;
>> +
>> + if (inst->processed_buf_num) {
>> + s64 tmp;
>> + s64 fps_act, fps_sw, fps_hw;
>> + struct vpu_performance_info *perf = &inst-
>> >performance;
>> +
>> + tmp = MSEC_PER_SEC * inst->processed_buf_num;
>> + fps_act = DIV_ROUND_CLOSEST(tmp, (perf->ts_last -
>> perf->ts_first) / NSEC_PER_MSEC);
>> + fps_sw = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time
>> / NSEC_PER_MSEC);
>> + fps_hw = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time
>> / NSEC_PER_MSEC);
>> + dprintk(inst->dev->dev,
>> + "[%d] fps actual: %lld, sw: %lld, hw: %lld,
>> latency(ms) %llu.%06llu\n",
>> + inst->id, fps_act, fps_sw, fps_hw,
>> + perf->latency_first / NSEC_PER_MSEC,
>> + perf->latency_first % NSEC_PER_MSEC);
>> + }
>> +
>> + memset(&inst->performance, 0, sizeof(inst->performance));
>> +}
>> +
>> +static const struct v4l2_m2m_ops wave6_vpu_m2m_ops = {
>> + .device_run = wave6_vpu_device_run,
>> + .job_ready = wave6_vpu_job_ready,
>> +};
>> +
>> +int wave6_vpu_init_m2m_dev(struct vpu_device *dev)
>> +{
>> + dev->m2m_dev = v4l2_m2m_init(&wave6_vpu_m2m_ops);
>> + if (IS_ERR(dev->m2m_dev)) {
>> + dev_err(dev->dev, "v4l2_m2m_init fail: %ld\n",
>> PTR_ERR(dev->m2m_dev));
>> + return PTR_ERR(dev->m2m_dev);
>> + }
>> +
>> + INIT_DELAYED_WORK(&dev->task_timer,
>> wave6_vpu_device_run_timeout);
>> +
>> + return 0;
>> +}
>> +
>> +void wave6_vpu_release_m2m_dev(struct vpu_device *dev)
>> +{
>> + v4l2_m2m_release(dev->m2m_dev);
>> +}
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (4 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-28 8:33 ` [EXT] " Ming Qian
2025-02-10 9:07 ` [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Nas Chung
` (3 subsequent siblings)
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Add control layer to configure hardware registers and
manage communication with the Wave6 vpu.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../platform/chips-media/wave6/wave6-hw.c | 3113 +++++++++++++++++
.../platform/chips-media/wave6/wave6-hw.h | 69 +
.../chips-media/wave6/wave6-regdefine.h | 675 ++++
.../platform/chips-media/wave6/wave6-vdi.c | 52 +
.../platform/chips-media/wave6/wave6-vdi.h | 59 +
.../platform/chips-media/wave6/wave6-vpuapi.c | 1001 ++++++
.../platform/chips-media/wave6/wave6-vpuapi.h | 993 ++++++
.../chips-media/wave6/wave6-vpuconfig.h | 80 +
.../chips-media/wave6/wave6-vpuerror.h | 262 ++
9 files changed, 6304 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-regdefine.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
diff --git a/drivers/media/platform/chips-media/wave6/wave6-hw.c b/drivers/media/platform/chips-media/wave6/wave6-hw.c
new file mode 100644
index 000000000000..dba08d3451c9
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-hw.c
@@ -0,0 +1,3113 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 backend interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/iopoll.h>
+#include "wave6-vpu.h"
+#include "wave6-hw.h"
+#include "wave6-regdefine.h"
+#include "wave6-trace.h"
+
+static void wave6_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason)
+{
+ char *caller = __builtin_return_address(0);
+ struct device *dev = vpu_dev->dev;
+
+ switch (reg_fail_reason) {
+ case WAVE6_SYSERR_QUEUEING_FAIL:
+ dev_dbg(dev, "%s: queueing failure 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_RESULT_NOT_READY:
+ dev_err(dev, "%s: result not ready 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_ACCESS_VIOLATION_HW:
+ dev_err(dev, "%s: access violation 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_WATCHDOG_TIMEOUT:
+ dev_err(dev, "%s: watchdog timeout 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_BUS_ERROR:
+ dev_err(dev, "%s: bus error 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_DOUBLE_FAULT:
+ dev_err(dev, "%s: double fault 0x%x\n", caller, reg_fail_reason);
+ break;
+ case WAVE6_SYSERR_VPU_STILL_RUNNING:
+ dev_err(dev, "%s: still running 0x%x\n", caller, reg_fail_reason);
+ break;
+ default:
+ dev_err(dev, "%s: failure: 0x%x\n", caller, reg_fail_reason);
+ break;
+ }
+}
+
+static void wave6_dec_set_display_buffer(struct vpu_instance *inst, struct frame_buffer fb)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int index;
+
+ for (index = 0; index < WAVE6_MAX_FBS; index++) {
+ if (!p_dec_info->disp_buf[index].buf_y) {
+ p_dec_info->disp_buf[index] = fb;
+ p_dec_info->disp_buf[index].index = index;
+ break;
+ }
+ }
+}
+
+static struct frame_buffer wave6_dec_get_display_buffer(struct vpu_instance *inst,
+ dma_addr_t addr,
+ bool remove)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int i;
+ struct frame_buffer fb;
+
+ memset(&fb, 0, sizeof(struct frame_buffer));
+
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ if (p_dec_info->disp_buf[i].buf_y == addr) {
+ fb = p_dec_info->disp_buf[i];
+ if (remove)
+ memset(&p_dec_info->disp_buf[i], 0, sizeof(struct frame_buffer));
+ break;
+ }
+ }
+
+ return fb;
+}
+
+static int wave6_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int addr)
+{
+ u32 data;
+
+ return read_poll_timeout(wave6_vdi_readl, data, !data,
+ 0, W6_VPU_POLL_TIMEOUT, false, vpu_dev, addr);
+}
+
+void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev)
+{
+ u32 data;
+
+ data = BIT(W6_INT_BIT_ENC_SET_PARAM);
+ data |= BIT(W6_INT_BIT_ENC_PIC);
+ data |= BIT(W6_INT_BIT_INIT_SEQ);
+ data |= BIT(W6_INT_BIT_DEC_PIC);
+ data |= BIT(W6_INT_BIT_BSBUF_ERROR);
+ data |= BIT(W6_INT_BIT_REQ_WORK_BUF);
+
+ vpu_write_reg(vpu_dev, W6_VPU_VINT_ENABLE, data);
+}
+
+void wave6_vpu_check_state(struct vpu_device *vpu_dev)
+{
+ if (vpu_dev->ctrl) {
+ int state = wave6_vpu_ctrl_get_state(vpu_dev->ctrl);
+
+ if (state == WAVE6_VPU_STATE_PREPARE)
+ wave6_vpu_ctrl_wait_done(vpu_dev->ctrl);
+ } else {
+ u32 val;
+ int ret;
+
+ ret = read_poll_timeout(vpu_read_reg, val, val != 0, 0,
+ W6_VPU_POLL_TIMEOUT, false,
+ vpu_dev, W6_VPU_VCPU_CUR_PC);
+ if (!ret)
+ vpu_dev->entity.on_boot(vpu_dev->dev);
+ }
+}
+
+bool wave6_vpu_is_init(struct vpu_device *vpu_dev)
+{
+ return vpu_read_reg(vpu_dev, W6_VPU_VCPU_CUR_PC) != 0;
+}
+
+static int32_t wave6_vpu_get_product_id(struct vpu_device *vpu_dev)
+{
+ u32 product_id = PRODUCT_ID_NONE;
+ u32 val;
+
+ val = vpu_read_reg(vpu_dev, W6_VPU_RET_PRODUCT_VERSION);
+
+ switch (val) {
+ case WAVE617_CODE:
+ product_id = PRODUCT_ID_617; break;
+ case WAVE627_CODE:
+ product_id = PRODUCT_ID_627; break;
+ case WAVE633_CODE:
+ case WAVE637_CODE:
+ case WAVE663_CODE:
+ case WAVE677_CODE:
+ product_id = PRODUCT_ID_637; break;
+ default:
+ dev_err(vpu_dev->dev, "Invalid product (%x)\n", val);
+ break;
+ }
+
+ return product_id;
+}
+
+static void wave6_send_command(struct vpu_device *vpu_dev, u32 id, u32 std, u32 cmd)
+{
+ if (cmd == W6_CMD_CREATE_INSTANCE) {
+ vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16));
+
+ vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W6_COMMAND, cmd);
+
+ vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1);
+ } else {
+ vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16) | (id & 0xffff));
+
+ vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W6_COMMAND, cmd);
+
+ vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1);
+ }
+
+ trace_send_command(vpu_dev, id, std, cmd);
+}
+
+static int wave6_send_query(struct vpu_device *vpu_dev, u32 id, u32 std,
+ enum wave6_query_option query_opt)
+{
+ int ret;
+ u32 reg_val;
+
+ vpu_write_reg(vpu_dev, W6_QUERY_OPTION, query_opt);
+ wave6_send_command(vpu_dev, id, std, W6_CMD_QUERY);
+
+ ret = wave6_wait_vpu_busy(vpu_dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(vpu_dev->dev, "query timed out opt=0x%x\n", query_opt);
+ return ret;
+ }
+
+ if (!vpu_read_reg(vpu_dev, W6_RET_SUCCESS)) {
+ reg_val = vpu_read_reg(vpu_dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(vpu_dev, reg_val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_get_version(struct vpu_device *vpu_dev, uint32_t *version_info,
+ uint32_t *revision)
+{
+ struct vpu_attr *attr = &vpu_dev->attr;
+ u32 reg_val;
+ u8 *str;
+ int ret;
+ u32 hw_config_def1, hw_config_feature;
+
+ ret = wave6_send_query(vpu_dev, 0, 0, W6_QUERY_OPT_GET_VPU_INFO);
+ if (ret)
+ return ret;
+
+ reg_val = vpu_read_reg(vpu_dev, W6_RET_PRODUCT_NAME);
+ str = (u8 *)®_val;
+ attr->product_name[0] = str[3];
+ attr->product_name[1] = str[2];
+ attr->product_name[2] = str[1];
+ attr->product_name[3] = str[0];
+ attr->product_name[4] = 0;
+
+ attr->product_id = wave6_vpu_get_product_id(vpu_dev);
+ attr->product_version = vpu_read_reg(vpu_dev, W6_RET_PRODUCT_VERSION);
+ attr->fw_version = vpu_read_reg(vpu_dev, W6_RET_FW_API_VERSION);
+ attr->fw_revision = vpu_read_reg(vpu_dev, W6_RET_FW_VERSION);
+ hw_config_def1 = vpu_read_reg(vpu_dev, W6_RET_STD_DEF1);
+ hw_config_feature = vpu_read_reg(vpu_dev, W6_RET_CONF_FEATURE);
+
+ attr->support_hevc10bit_enc = (hw_config_feature >> 3) & 1;
+ attr->support_avc10bit_enc = (hw_config_feature >> 11) & 1;
+
+ attr->support_decoders = 0;
+ attr->support_encoders = 0;
+ if (attr->product_id == PRODUCT_ID_617) {
+ attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) << STD_HEVC);
+ attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVC);
+ } else if (attr->product_id == PRODUCT_ID_627) {
+ attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) << STD_HEVC);
+ attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) << STD_AVC);
+ } else if (attr->product_id == PRODUCT_ID_637) {
+ attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) << STD_HEVC);
+ attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVC);
+ attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) << STD_HEVC);
+ attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) << STD_AVC);
+ }
+
+ attr->support_dual_core = (hw_config_def1 >> 26) & 0x01;
+ attr->support_bitstream_mode = BS_MODE_PIC_END;
+
+ if (version_info)
+ *version_info = attr->fw_version;
+ if (revision)
+ *revision = attr->fw_revision;
+
+ return 0;
+}
+
+int wave6_vpu_build_up_dec_param(struct vpu_instance *inst,
+ struct dec_open_param *param)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 reg_val;
+ int ret;
+
+ p_dec_info->cycle_per_tick = 256;
+ p_dec_info->sec_axi_info.use_dec_ip = true;
+ p_dec_info->sec_axi_info.use_dec_lf_row = true;
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC;
+ break;
+ case W_AVC_DEC:
+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_BASE, param->inst_buffer.temp_base);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_SIZE, param->inst_buffer.temp_size);
+
+ reg_val = wave6_vdi_convert_endian(param->stream_endian);
+ reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_BS_PARAM, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_ADDR_EXT, param->ext_addr_vcpu);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_DISP_MODE, param->disp_mode);
+
+ reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_CORE_INFO, reg_val);
+
+ reg_val = (param->is_secure_inst << 8) | (param->inst_priority);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_PRIORITY, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT,
+ W6_VPU_TIMEOUT_CYCLE_COUNT);
+
+ wave6_send_command(inst->dev, 0, inst->std, W6_CMD_CREATE_INSTANCE);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+
+ wave6_print_reg_err(inst->dev, reason_code);
+ return -EIO;
+ }
+
+ inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID);
+
+ return 0;
+}
+
+int wave6_vpu_dec_init_seq(struct vpu_instance *inst)
+{
+ struct dec_info *p_dec_info;
+ u32 cmd_option = W6_INIT_SEQ_OPT_NORMAL, bs_option;
+ int ret;
+
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+ if (p_dec_info->thumbnail_mode)
+ cmd_option = W6_INIT_SEQ_OPT_W_THUMBNAIL;
+
+ bs_option = 0;
+ switch (p_dec_info->open_param.bs_mode) {
+ case BS_MODE_INTERRUPT:
+ bs_option = 0;
+ break;
+ case BS_MODE_PIC_END:
+ bs_option = BSOPTION_ENABLE_EXPLICIT_END;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_RD_PTR, p_dec_info->stream_rd_ptr);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_WR_PTR, p_dec_info->stream_wr_ptr);
+
+ if (p_dec_info->stream_end)
+ bs_option = 3;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_OPTION, bs_option);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_OPTION, cmd_option);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_INIT_SEQ);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+
+ wave6_print_reg_err(inst->dev, reason_code);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void wave6_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ u32 reg_val;
+ u32 profile_compatibility;
+ u32 left, right, top, bottom;
+
+ info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE);
+ info->pic_width = ((reg_val >> 16) & 0xffff);
+ info->pic_height = (reg_val & 0xffff);
+ info->min_frame_buffer_count = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REQUIRED_FBC_FB);
+ info->frame_buf_delay = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REORDER_DELAY);
+ info->req_mv_buffer_count = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REQUIRED_COL_BUF);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_LEFT_RIGHT);
+ left = (reg_val >> 16) & 0xffff;
+ right = reg_val & 0xffff;
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_TOP_BOTTOM);
+ top = (reg_val >> 16) & 0xffff;
+ bottom = reg_val & 0xffff;
+
+ info->pic_crop_rect.left = left;
+ info->pic_crop_rect.right = info->pic_width - right;
+ info->pic_crop_rect.top = top;
+ info->pic_crop_rect.bottom = info->pic_height - bottom;
+
+ info->f_rate_numerator = vpu_read_reg(inst->dev, W6_RET_DEC_FRAME_RATE_NR);
+ info->f_rate_denominator = vpu_read_reg(inst->dev, W6_RET_DEC_FRAME_RATE_DR);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_SAMPLE_INFO);
+ info->luma_bitdepth = (reg_val >> 0) & 0x0f;
+ info->chroma_bitdepth = (reg_val >> 4) & 0x0f;
+ info->chroma_format_idc = (reg_val >> 8) & 0x0f;
+ info->aspect_rate_info = (reg_val >> 16) & 0xff;
+ info->is_ext_sar = (info->aspect_rate_info == H264_VUI_SAR_IDC_EXTENDED ? true : false);
+ if (info->is_ext_sar)
+ info->aspect_rate_info = vpu_read_reg(inst->dev, W6_RET_DEC_ASPECT_RATIO);
+ info->bitrate = vpu_read_reg(inst->dev, W6_RET_DEC_BIT_RATE);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_SEQ_PARAM);
+ info->level = reg_val & 0xff;
+ profile_compatibility = (reg_val >> 12) & 0xff;
+ info->profile = (reg_val >> 24) & 0x1f;
+ info->tier = (reg_val >> 29) & 0x01;
+
+ if (inst->std == W_HEVC_DEC) {
+ if (!info->profile) {
+ if ((profile_compatibility & 0x06) == 0x06)
+ info->profile = HEVC_PROFILE_MAIN;
+ else if ((profile_compatibility & 0x04) == 0x04)
+ info->profile = HEVC_PROFILE_MAIN10;
+ else if ((profile_compatibility & 0x08) == 0x08)
+ info->profile = HEVC_PROFILE_STILLPICTURE;
+ else
+ info->profile = HEVC_PROFILE_MAIN;
+ }
+ } else if (inst->std == W_AVC_DEC) {
+ info->profile = (reg_val >> 24) & 0x7f;
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_CONFIG);
+ if (reg_val) {
+ info->color.video_signal_type_present = true;
+ info->color.color_description_present = reg_val & 0x1;
+ info->color.color_primaries = (reg_val >> 1) & 0xFF;
+ info->color.transfer_characteristics = (reg_val >> 9) & 0xFF;
+ info->color.matrix_coefficients = (reg_val >> 17) & 0xFF;
+ info->color.color_range = (reg_val >> 25) & 0x1;
+ info->color.chroma_sample_position = (reg_val >> 26) & 0x3;
+ } else {
+ info->color.video_signal_type_present = false;
+ }
+}
+
+int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ int ret;
+
+ ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT);
+ if (ret)
+ return ret;
+
+ if (vpu_read_reg(inst->dev, W6_RET_DEC_DECODING_SUCCESS) != 1) {
+ info->err_reason = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_INFO);
+ ret = -EIO;
+ } else {
+ info->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO);
+ }
+
+ wave6_get_dec_seq_result(inst, info);
+
+ return ret;
+}
+
+int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst,
+ struct frame_buffer *fb_arr,
+ enum tiled_map_type map_type, u32 count)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ size_t fbc_remain, mv_remain, fbc_idx = 0, mv_idx = 0;
+ size_t i, k, group_num, mv_count;
+ dma_addr_t fbc_cr_tbl_addr;
+ u32 reg_val;
+ u32 endian;
+ int ret;
+
+ mv_count = p_dec_info->initial_info.req_mv_buffer_count;
+
+ for (i = 0; i < count; i++) {
+ if (!p_dec_info->vb_fbc_y_tbl[i].daddr)
+ return -EINVAL;
+ if (!p_dec_info->vb_fbc_c_tbl[i].daddr)
+ return -EINVAL;
+ }
+ for (i = 0; i < mv_count; i++) {
+ if (!p_dec_info->vb_mv[i].daddr)
+ return -EINVAL;
+ }
+
+ endian = wave6_vdi_convert_endian(p_dec_info->open_param.frame_endian);
+
+ reg_val = (p_dec_info->initial_info.pic_width << 16) |
+ (p_dec_info->initial_info.pic_height);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_PIC_SIZE, reg_val);
+ reg_val = (p_dec_info->initial_info.chroma_format_idc << 25) |
+ (p_dec_info->initial_info.luma_bitdepth << 21) |
+ (p_dec_info->initial_info.chroma_bitdepth << 17);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_COMMON_PIC_INFO, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_DEFAULT_CDF, 0);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_SEGMAP, 0);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT, 0);
+
+ fbc_remain = count;
+ mv_remain = mv_count;
+ group_num = (count > mv_count) ? ((ALIGN(count, 16) / 16) - 1) :
+ ((ALIGN(mv_count, 16) / 16) - 1);
+ for (i = 0; i <= group_num; i++) {
+ bool first_group = (i == 0) ? true : false;
+ bool last_group = (i == group_num) ? true : false;
+ u32 set_fbc_num = (fbc_remain >= 16) ? 16 : fbc_remain;
+ u32 set_mv_num = (mv_remain >= 16) ? 16 : mv_remain;
+ u32 fbc_start_no = i * 16;
+ u32 fbc_end_no = fbc_start_no + set_fbc_num - 1;
+ u32 mv_start_no = i * 16;
+ u32 mv_end_no = mv_start_no + set_mv_num - 1;
+
+ reg_val = (p_dec_info->open_param.enable_non_ref_fbc_write << 26) |
+ (endian << 16) |
+ (last_group << 4) |
+ (first_group << 3);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_OPTION, reg_val);
+
+ reg_val = (fbc_start_no << 24) | (fbc_end_no << 16) |
+ (mv_start_no << 5) | mv_end_no;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_NUM, reg_val);
+
+ for (k = 0; k < set_fbc_num; k++) {
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_Y0 + (k * 24),
+ fb_arr[fbc_idx].buf_y);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_C0 + (k * 24),
+ fb_arr[fbc_idx].buf_cb);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_CR0 + (k * 8),
+ fb_arr[fbc_idx].buf_cr);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 + (k * 24),
+ p_dec_info->vb_fbc_y_tbl[fbc_idx].daddr);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 + (k * 24),
+ p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr);
+ fbc_cr_tbl_addr = p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr +
+ (p_dec_info->vb_fbc_c_tbl[fbc_idx].size >> 1);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 + (k * 8),
+ fbc_cr_tbl_addr);
+ fbc_idx++;
+ }
+ fbc_remain -= k;
+
+ for (k = 0; k < set_mv_num; k++) {
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL0 + (k * 24),
+ p_dec_info->vb_mv[mv_idx].daddr);
+ mv_idx++;
+ }
+ mv_remain -= k;
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_SET_FB);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS))
+ return -EIO;
+
+ return 0;
+}
+
+int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct frame_buffer fb)
+{
+ int ret;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 reg_val, cbcr_interleave, nv21;
+ u32 endian;
+ u32 addr_y, addr_cb, addr_cr;
+ u32 color_format;
+ u32 justified = WTL_RIGHT_JUSTIFIED;
+ u32 format_no = WTL_PIXEL_8BIT;
+
+ cbcr_interleave = inst->cbcr_interleave;
+ nv21 = inst->nv21;
+
+ endian = wave6_vdi_convert_endian(p_dec_info->open_param.frame_endian);
+
+ switch (p_dec_info->wtl_format) {
+ case FORMAT_420:
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_420_P10_16BIT_LSB:
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_420_P10_32BIT_LSB:
+ color_format = 1;
+ break;
+ case FORMAT_422:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ color_format = 2;
+ break;
+ case FORMAT_444:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ color_format = 3;
+ break;
+ case FORMAT_400:
+ case FORMAT_400_P10_16BIT_MSB:
+ case FORMAT_400_P10_16BIT_LSB:
+ case FORMAT_400_P10_32BIT_MSB:
+ case FORMAT_400_P10_32BIT_LSB:
+ color_format = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg_val = (color_format << 3) |
+ (inst->scaler_info.scale_mode << 1) |
+ (inst->scaler_info.enable);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PARAM, reg_val);
+ reg_val = (inst->scaler_info.width << 16) |
+ (inst->scaler_info.height);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE, reg_val);
+ reg_val = (p_dec_info->initial_info.pic_width << 16) |
+ (p_dec_info->initial_info.pic_height);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_SIZE, reg_val);
+
+ switch (p_dec_info->wtl_format) {
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_400_P10_16BIT_MSB:
+ justified = WTL_RIGHT_JUSTIFIED;
+ format_no = WTL_PIXEL_16BIT;
+ break;
+ case FORMAT_420_P10_16BIT_LSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ case FORMAT_400_P10_16BIT_LSB:
+ justified = WTL_LEFT_JUSTIFIED;
+ format_no = WTL_PIXEL_16BIT;
+ break;
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_400_P10_32BIT_MSB:
+ justified = WTL_RIGHT_JUSTIFIED;
+ format_no = WTL_PIXEL_32BIT;
+ break;
+ case FORMAT_420_P10_32BIT_LSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ case FORMAT_400_P10_32BIT_LSB:
+ justified = WTL_LEFT_JUSTIFIED;
+ format_no = WTL_PIXEL_32BIT;
+ break;
+ default:
+ break;
+ }
+
+ reg_val = (REGISTER_DISPLAY_BUFFER << 28) | (color_format << 24) |
+ (DEFAULT_PIXEL_ORDER << 23) | (justified << 22) | (format_no << 20) |
+ (nv21 << 17) | (cbcr_interleave << 16) | (fb.stride);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_OPTION, (endian << 16));
+ reg_val = (fb.luma_bitdepth << 22) |
+ (fb.chroma_bitdepth << 18) |
+ (fb.chroma_format_idc << 16);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_INFO, reg_val);
+
+ if (p_dec_info->open_param.cbcr_order == CBCR_ORDER_REVERSED) {
+ addr_y = fb.buf_y;
+ addr_cb = fb.buf_cr;
+ addr_cr = fb.buf_cb;
+ } else {
+ addr_y = fb.buf_y;
+ addr_cb = fb.buf_cb;
+ addr_cr = fb.buf_cr;
+ }
+
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_Y_BASE, addr_y);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CB_BASE, addr_cb);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CR_BASE, addr_cr);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DEC_SET_DISP);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS))
+ return -EIO;
+
+ wave6_dec_set_display_buffer(inst, fb);
+
+ return 0;
+}
+
+int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option, u32 *fail_res)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ struct dec_open_param *p_open_param = &p_dec_info->open_param;
+ u32 mode_option = W6_DEC_PIC_OPT_NORMAL, bs_option, reg_val;
+ int ret;
+
+ if (p_dec_info->thumbnail_mode) {
+ mode_option = W6_DEC_PIC_OPT_W_THUMBNAIL;
+ } else if (option->skipframe_mode) {
+ switch (option->skipframe_mode) {
+ case WAVE_SKIPMODE_NON_IRAP:
+ mode_option = W6_DEC_PIC_OPT_SKIP_NON_IRAP;
+ break;
+ case WAVE_SKIPMODE_NON_REF:
+ mode_option = W6_DEC_PIC_OPT_SKIP_NON_REF_PIC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ bs_option = 0;
+ switch (p_open_param->bs_mode) {
+ case BS_MODE_INTERRUPT:
+ bs_option = 0;
+ break;
+ case BS_MODE_PIC_END:
+ bs_option = BSOPTION_ENABLE_EXPLICIT_END;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_RD_PTR, p_dec_info->stream_rd_ptr);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_WR_PTR, p_dec_info->stream_wr_ptr);
+ if (p_dec_info->stream_end)
+ bs_option = 3;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_OPTION, bs_option);
+
+ reg_val = (p_dec_info->sec_axi_info.use_dec_ip << 1) |
+ p_dec_info->sec_axi_info.use_dec_lf_row;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_USE_SEC_AXI, reg_val);
+
+ reg_val = (option->disable_film_grain << 6) |
+ (option->decode_cra_as_bla << 5) |
+ mode_option;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_OPTION, reg_val);
+ reg_val = (DECODE_ALL_SPATIAL_LAYERS << 9) |
+ (TEMPORAL_ID_MODE_ABSOLUTE << 8) |
+ DECODE_ALL_TEMPORAL_LAYERS;
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG,
+ p_dec_info->seq_change_mask);
+ reg_val = ((option->timestamp.hour & 0x1F) << 26) |
+ ((option->timestamp.min & 0x3F) << 20) |
+ ((option->timestamp.sec & 0x3F) << 14) |
+ (option->timestamp.ms & 0x3FFF);
+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TIMESTAMP, reg_val);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DEC_PIC);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(inst->dev, *fail_res);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 reg_val, nal_unit_type, i;
+ int decoded_index = -1, display_index = -1;
+ int ret;
+
+ ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT);
+ if (ret)
+ return ret;
+
+ result->decoding_success = vpu_read_reg(inst->dev, W6_RET_DEC_DECODING_SUCCESS);
+ if (!result->decoding_success)
+ result->error_reason = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_INFO);
+ else
+ result->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_TYPE);
+ nal_unit_type = (reg_val & 0x3f0) >> 4;
+ result->nal_type = nal_unit_type;
+
+ if (inst->std == W_HEVC_DEC) {
+ if (reg_val & 0x04)
+ result->pic_type = PIC_TYPE_B;
+ else if (reg_val & 0x02)
+ result->pic_type = PIC_TYPE_P;
+ else if (reg_val & 0x01)
+ result->pic_type = PIC_TYPE_I;
+ else
+ result->pic_type = PIC_TYPE_MAX;
+ if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type == PIC_TYPE_I)
+ result->pic_type = PIC_TYPE_IDR;
+ } else if (inst->std == W_AVC_DEC) {
+ if (reg_val & 0x04)
+ result->pic_type = PIC_TYPE_B;
+ else if (reg_val & 0x02)
+ result->pic_type = PIC_TYPE_P;
+ else if (reg_val & 0x01)
+ result->pic_type = PIC_TYPE_I;
+ else
+ result->pic_type = PIC_TYPE_MAX;
+ if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I)
+ result->pic_type = PIC_TYPE_IDR;
+ }
+ result->ctu_size = 16 << ((reg_val >> 10) & 0x3);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DECODED_FLAG);
+ if (reg_val) {
+ struct frame_buffer fb;
+ dma_addr_t addr = vpu_read_reg(inst->dev, W6_RET_DEC_DECODED_ADDR);
+
+ fb = wave6_dec_get_display_buffer(inst, addr, false);
+ result->frame_decoded_addr = addr;
+ result->frame_decoded = true;
+ decoded_index = fb.index;
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISPLAY_FLAG);
+ if (reg_val) {
+ struct frame_buffer fb;
+ dma_addr_t addr = vpu_read_reg(inst->dev, W6_RET_DEC_DISPLAY_ADDR);
+
+ fb = wave6_dec_get_display_buffer(inst, addr, false);
+ result->frame_display_addr = addr;
+ result->frame_display = true;
+ display_index = fb.index;
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISP_IDC);
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ if (reg_val & (1 << i)) {
+ dma_addr_t addr = vpu_read_reg(inst->dev,
+ W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4);
+
+ result->disp_frame_addr[result->disp_frame_num] = addr;
+ result->disp_frame_num++;
+ }
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RELEASE_IDC);
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ if (reg_val & (1 << i)) {
+ struct frame_buffer fb;
+ dma_addr_t addr = vpu_read_reg(inst->dev,
+ W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4);
+
+ fb = wave6_dec_get_display_buffer(inst, addr, true);
+ result->release_disp_frame_addr[result->release_disp_frame_num] = fb.buf_y;
+ result->release_disp_frame_num++;
+ }
+ }
+
+ result->stream_end = vpu_read_reg(inst->dev, W6_RET_DEC_STREAM_END);
+ result->notification_flags = vpu_read_reg(inst->dev, W6_RET_DEC_NOTIFICATION);
+
+ if (inst->std == W_HEVC_DEC) {
+ result->decoded_poc = -1;
+ result->display_poc = -1;
+ if (decoded_index >= 0)
+ result->decoded_poc = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_POC);
+ } else if (inst->std == W_AVC_DEC) {
+ result->decoded_poc = -1;
+ result->display_poc = -1;
+ if (decoded_index >= 0)
+ result->decoded_poc = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_POC);
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE);
+ result->dec_pic_width = reg_val >> 16;
+ result->dec_pic_height = reg_val & 0xffff;
+
+ result->num_of_err_m_bs = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_CTB_NUM) >> 16;
+ result->num_of_tot_m_bs = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_CTB_NUM) & 0xffff;
+ result->byte_pos_frame_start = vpu_read_reg(inst->dev, W6_RET_DEC_AU_START_POS);
+ result->byte_pos_frame_end = vpu_read_reg(inst->dev, W6_RET_DEC_AU_END_POS);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RECOVERY_POINT);
+ result->h265_rp_sei.recovery_poc_cnt = reg_val & 0xFFFF;
+ result->h265_rp_sei.exact_match = (reg_val >> 16) & 0x01;
+ result->h265_rp_sei.broken_link = (reg_val >> 17) & 0x01;
+ result->h265_rp_sei.exist = (reg_val >> 18) & 0x01;
+ if (!result->h265_rp_sei.exist) {
+ result->h265_rp_sei.recovery_poc_cnt = 0;
+ result->h265_rp_sei.exact_match = false;
+ result->h265_rp_sei.broken_link = false;
+ }
+
+ result->last_frame_in_au = vpu_read_reg(inst->dev, W6_RET_DEC_LAST_FRAME_FLAG);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_TIMESTAMP);
+ result->timestamp.hour = (reg_val >> 26) & 0x1F;
+ result->timestamp.min = (reg_val >> 20) & 0x3F;
+ result->timestamp.sec = (reg_val >> 14) & 0x3F;
+ result->timestamp.ms = reg_val & 0x3FFF;
+
+ result->cycle.host_cmd_s = vpu_read_reg(inst->dev, W6_RET_CQ_IN_TICK);
+ result->cycle.host_cmd_e = vpu_read_reg(inst->dev, W6_RET_RQ_OUT_TICK);
+ result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK);
+ result->cycle.proc_e = vpu_read_reg(inst->dev, W6_RET_HW_DONE_TICK);
+ result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK);
+ result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK);
+ result->cycle.frame_cycle = (result->cycle.vpu_e - result->cycle.host_cmd_s) *
+ p_dec_info->cycle_per_tick;
+ result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) *
+ p_dec_info->cycle_per_tick;
+ result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) -
+ (result->cycle.proc_e - result->cycle.proc_s)) *
+ p_dec_info->cycle_per_tick;
+
+ if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS) {
+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC)
+ p_dec_info->dec_out_info[decoded_index].decoded_poc = result->decoded_poc;
+ }
+
+ if (display_index >= 0 && display_index < WAVE6_MAX_FBS) {
+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC)
+ result->display_poc = p_dec_info->dec_out_info[display_index].decoded_poc;
+
+ result->disp_pic_width = p_dec_info->dec_out_info[display_index].dec_pic_width;
+ result->disp_pic_height = p_dec_info->dec_out_info[display_index].dec_pic_height;
+ }
+
+ result->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
+ result->wr_ptr = p_dec_info->stream_wr_ptr;
+
+ result->sequence_no = p_dec_info->initial_info.sequence_no;
+ if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS)
+ p_dec_info->dec_out_info[decoded_index] = *result;
+
+ if (display_index >= 0 && display_index < WAVE6_MAX_FBS) {
+ result->num_of_tot_m_bs_in_disp =
+ p_dec_info->dec_out_info[display_index].num_of_tot_m_bs;
+ result->num_of_err_m_bs_in_disp =
+ p_dec_info->dec_out_info[display_index].num_of_err_m_bs;
+ } else {
+ result->num_of_tot_m_bs_in_disp = 0;
+ result->num_of_err_m_bs_in_disp = 0;
+ }
+
+ if (result->notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) {
+ wave6_get_dec_seq_result(inst, &p_dec_info->initial_info);
+ p_dec_info->initial_info.sequence_no++;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res)
+{
+ int ret;
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DESTROY_INSTANCE);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret)
+ return -ETIMEDOUT;
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(inst->dev, *fail_res);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ p_dec_info->stream_end = eos ? true : false;
+}
+
+dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst)
+{
+ return vpu_read_reg(inst->dev, W6_RET_DEC_BS_RD_PTR);
+}
+
+int wave6_vpu_dec_flush(struct vpu_instance *inst)
+{
+ int ret, index;
+ u32 unused_idc;
+ u32 used_idc;
+ u32 using_idc;
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_FLUSH_INSTANCE);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret)
+ return -ETIMEDOUT;
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reg_val;
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(inst->dev, reg_val);
+ return -EIO;
+ }
+
+ ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_FLUSH_CMD_INFO);
+ if (ret)
+ return ret;
+
+ unused_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC);
+ if (unused_idc)
+ dev_dbg(inst->dev->dev, "%s: unused_idc %d\n", __func__, unused_idc);
+
+ used_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC);
+ if (used_idc)
+ dev_dbg(inst->dev->dev, "%s: used_idc %d\n", __func__, used_idc);
+
+ using_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC);
+ if (using_idc)
+ dev_err(inst->dev->dev, "%s: using_idc %d\n", __func__, using_idc);
+
+ for (index = 0; index < WAVE6_MAX_FBS; index++) {
+ struct frame_buffer fb;
+ bool remove = false;
+ dma_addr_t addr = vpu_read_reg(inst->dev,
+ W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 + index * 4);
+
+ if ((unused_idc >> index) & 0x1)
+ remove = true;
+ if ((used_idc >> index) & 0x1)
+ remove = true;
+
+ fb = wave6_dec_get_display_buffer(inst, addr, remove);
+ }
+
+ return 0;
+}
+
+struct enc_cmd_set_param_reg {
+ u32 enable;
+ u32 src_size;
+ u32 custom_map_endian;
+ u32 sps_param;
+ u32 pps_param;
+ u32 gop_param;
+ u32 intra_param;
+ u32 conf_win_top_bot;
+ u32 conf_win_left_right;
+ u32 rdo_param;
+ u32 slice_param;
+ u32 intra_refresh;
+ u32 intra_min_max_qp;
+ u32 rc_frame_rate;
+ u32 rc_target_rate;
+ u32 rc_param;
+ u32 hvs_param;
+ u32 rc_max_bitrate;
+ u32 rc_vbv_buffer_size;
+ u32 inter_min_max_qp;
+ u32 rot_param;
+ u32 num_units_in_tick;
+ u32 time_scale;
+ u32 num_ticks_poc_diff_one;
+ u32 max_intra_pic_bit;
+ u32 max_inter_pic_bit;
+ u32 bg_param;
+ u32 non_vcl_param;
+ u32 vui_rbsp_addr;
+ u32 hrd_rbsp_addr;
+ u32 qround_offset;
+ u32 quant_param_1;
+ u32 quant_param_2;
+ u32 custom_gop_param;
+ u32 custom_gop_pic_param[MAX_GOP_NUM];
+ u32 tile_param;
+ u32 custom_lambda[MAX_CUSTOM_LAMBDA_NUM];
+ u32 temporal_layer_qp[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER];
+ u32 scl_src_size;
+ u32 scl_param;
+ u32 color_param;
+ u32 sar_param;
+ u32 sar_extended;
+};
+
+struct enc_cmd_change_param_reg {
+ u32 enable;
+ u32 rc_target_rate;
+};
+
+int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
+ struct enc_open_param *param)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 reg_val;
+ int ret;
+
+ p_enc_info->cycle_per_tick = 256;
+ p_enc_info->line_buf_int_en = param->line_buf_int_en;
+ p_enc_info->stride = 0;
+ p_enc_info->initial_info_obtained = false;
+ p_enc_info->sec_axi_info.use_enc_rdo = true;
+ p_enc_info->sec_axi_info.use_enc_lf = true;
+
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_BASE, param->inst_buffer.temp_base);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_SIZE, param->inst_buffer.temp_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE, param->inst_buffer.ar_base);
+
+ reg_val = wave6_vdi_convert_endian(param->stream_endian);
+ reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_BS_PARAM, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_SRC_OPT, 0);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_ADDR_EXT, param->ext_addr_vcpu);
+
+ reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1;
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_CORE_INFO, reg_val);
+
+ reg_val = (param->is_secure_inst << 8) | (param->inst_priority);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_PRIORITY, reg_val);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT,
+ W6_VPU_TIMEOUT_CYCLE_COUNT);
+
+ wave6_send_command(inst->dev, 0, inst->std, W6_CMD_CREATE_INSTANCE);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+
+ wave6_print_reg_err(inst->dev, reason_code);
+ return -EIO;
+ }
+
+ inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID);
+
+ return 0;
+}
+
+static int wave6_set_enc_crop_info(u32 codec, struct enc_codec_param *param, int rot_mode,
+ int width, int height)
+{
+ int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(width, 32) : ALIGN(width, 16);
+ int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(height, 32) : ALIGN(height, 16);
+ int pad_right, pad_bot;
+ int crop_right, crop_left, crop_top, crop_bot;
+ int prp_mode = rot_mode >> 1;
+
+ if (codec == W_HEVC_ENC &&
+ (!rot_mode || prp_mode == 14))
+ return 0;
+
+ pad_right = aligned_width - width;
+ pad_bot = aligned_height - height;
+
+ if (param->conf_win.right > 0)
+ crop_right = param->conf_win.right + pad_right;
+ else
+ crop_right = pad_right;
+
+ if (param->conf_win.bottom > 0)
+ crop_bot = param->conf_win.bottom + pad_bot;
+ else
+ crop_bot = pad_bot;
+
+ crop_top = param->conf_win.top;
+ crop_left = param->conf_win.left;
+
+ param->conf_win.top = crop_top;
+ param->conf_win.left = crop_left;
+ param->conf_win.bottom = crop_bot;
+ param->conf_win.right = crop_right;
+
+ if (prp_mode == 1 || prp_mode == 15) {
+ param->conf_win.top = crop_right;
+ param->conf_win.left = crop_top;
+ param->conf_win.bottom = crop_left;
+ param->conf_win.right = crop_bot;
+ } else if (prp_mode == 2 || prp_mode == 12) {
+ param->conf_win.top = crop_bot;
+ param->conf_win.left = crop_right;
+ param->conf_win.bottom = crop_top;
+ param->conf_win.right = crop_left;
+ } else if (prp_mode == 3 || prp_mode == 13) {
+ param->conf_win.top = crop_left;
+ param->conf_win.left = crop_bot;
+ param->conf_win.bottom = crop_right;
+ param->conf_win.right = crop_top;
+ } else if (prp_mode == 4 || prp_mode == 10) {
+ param->conf_win.top = crop_bot;
+ param->conf_win.bottom = crop_top;
+ } else if (prp_mode == 8 || prp_mode == 6) {
+ param->conf_win.left = crop_right;
+ param->conf_win.right = crop_left;
+ } else if (prp_mode == 5 || prp_mode == 11) {
+ param->conf_win.top = crop_left;
+ param->conf_win.left = crop_top;
+ param->conf_win.bottom = crop_right;
+ param->conf_win.right = crop_bot;
+ } else if (prp_mode == 7 || prp_mode == 9) {
+ param->conf_win.top = crop_right;
+ param->conf_win.left = crop_bot;
+ param->conf_win.bottom = crop_left;
+ param->conf_win.right = crop_top;
+ }
+
+ return 0;
+}
+
+static bool wave6_update_enc_info(struct enc_info *p_enc_info)
+{
+ struct enc_open_param open_param = p_enc_info->open_param;
+
+ p_enc_info->width = open_param.pic_width;
+ p_enc_info->height = open_param.pic_height;
+
+ switch (open_param.output_format) {
+ case FORMAT_420:
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_420_P10_16BIT_LSB:
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_420_P10_32BIT_LSB:
+ p_enc_info->color_format = 1;
+ break;
+ case FORMAT_422:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ p_enc_info->color_format = 2;
+ break;
+ case FORMAT_444:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ p_enc_info->color_format = 3;
+ break;
+ case FORMAT_400:
+ case FORMAT_400_P10_16BIT_MSB:
+ case FORMAT_400_P10_16BIT_LSB:
+ case FORMAT_400_P10_32BIT_MSB:
+ case FORMAT_400_P10_32BIT_LSB:
+ p_enc_info->color_format = 0;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void wave6_gen_set_param_reg_common(struct enc_info *p_enc_info, enum codec_std std,
+ struct enc_cmd_set_param_reg *reg)
+{
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ struct enc_codec_param *p_param = &p_open_param->codec_param;
+ unsigned int i, endian;
+ u32 rot_mir_mode = 0;
+
+ endian = wave6_vdi_convert_endian(p_param->custom_map_endian);
+ endian = (~endian & VDI_128BIT_ENDIAN_MASK);
+
+ if (p_enc_info->rotation_enable) {
+ switch (p_enc_info->rotation_angle) {
+ case 0:
+ rot_mir_mode |= 0x0; break;
+ case 90:
+ rot_mir_mode |= 0x3; break;
+ case 180:
+ rot_mir_mode |= 0x5; break;
+ case 270:
+ rot_mir_mode |= 0x7; break;
+ }
+ }
+
+ if (p_enc_info->mirror_enable) {
+ switch (p_enc_info->mirror_direction) {
+ case MIRDIR_NONE:
+ rot_mir_mode |= 0x0; break;
+ case MIRDIR_VER:
+ rot_mir_mode |= 0x9; break;
+ case MIRDIR_HOR:
+ rot_mir_mode |= 0x11; break;
+ case MIRDIR_HOR_VER:
+ rot_mir_mode |= 0x19; break;
+ }
+ }
+
+ wave6_set_enc_crop_info(std, p_param, rot_mir_mode, p_enc_info->width, p_enc_info->height);
+
+ reg->src_size = (p_enc_info->height << 16) | p_enc_info->width;
+ reg->custom_map_endian = endian;
+ reg->gop_param = (p_param->temp_layer_cnt << 16) |
+ (p_param->temp_layer[3].change_qp << 11) |
+ (p_param->temp_layer[2].change_qp << 10) |
+ (p_param->temp_layer[1].change_qp << 9) |
+ (p_param->temp_layer[0].change_qp << 8) |
+ p_param->gop_preset_idx;
+ reg->intra_refresh = (p_param->intra_refresh_arg << 16) | p_param->intra_refresh_mode;
+ reg->intra_min_max_qp = (p_param->max_qp_i << 6) | p_param->min_qp_i;
+ reg->rc_frame_rate = p_param->frame_rate;
+ reg->rc_target_rate = p_param->bitrate;
+ reg->rc_param = (p_param->rc_update_speed << 24) |
+ (p_param->rc_initial_level << 20) |
+ ((p_param->rc_initial_qp & 0x3f) << 14) |
+ (p_param->rc_mode << 13) |
+ (p_param->pic_rc_max_dqp << 7) |
+ (p_param->en_vbv_overflow_drop_frame << 3) |
+ (p_param->en_cu_level_rate_control << 1) |
+ p_param->en_rate_control;
+ reg->hvs_param = (p_param->max_delta_qp << 12) | p_param->hvs_qp_scale_div2;
+ reg->rc_max_bitrate = p_param->max_bitrate;
+ reg->rc_vbv_buffer_size = p_param->cpb_size;
+ reg->inter_min_max_qp = (p_param->max_qp_b << 18) |
+ (p_param->min_qp_b << 12) |
+ (p_param->max_qp_p << 6) |
+ p_param->min_qp_p;
+ reg->rot_param = rot_mir_mode;
+ reg->conf_win_top_bot = (p_param->conf_win.bottom << 16) | p_param->conf_win.top;
+ reg->conf_win_left_right = (p_param->conf_win.right << 16) | p_param->conf_win.left;
+ reg->num_units_in_tick = p_param->num_units_in_tick;
+ reg->time_scale = p_param->time_scale;
+ reg->num_ticks_poc_diff_one = p_param->num_ticks_poc_diff_one;
+ reg->max_intra_pic_bit = p_param->max_intra_pic_bit;
+ reg->max_inter_pic_bit = p_param->max_inter_pic_bit;
+ reg->bg_param = ((p_param->bg_delta_qp & 0x3F) << 24) |
+ (p_param->bg_th_mean_diff << 10) |
+ (p_param->bg_th_diff << 1) |
+ p_param->en_bg_detect;
+ reg->qround_offset = (p_param->q_round_inter << 13) |
+ (p_param->q_round_intra << 2);
+ reg->custom_gop_param = p_param->gop_param.custom_gop_size;
+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
+ struct custom_gop_pic_param pic_param = p_param->gop_param.pic_param[i];
+
+ reg->custom_gop_pic_param[i] = (pic_param.temporal_id << 26) |
+ ((pic_param.ref_poc_l1 & 0x3F) << 20) |
+ ((pic_param.ref_poc_l0 & 0x3F) << 14) |
+ (pic_param.use_multi_ref_p << 13) |
+ (pic_param.pic_qp << 7) |
+ (pic_param.poc_offset << 2) |
+ pic_param.pic_type;
+ }
+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) {
+ reg->custom_lambda[i] = (p_param->custom_lambda_ssd[i] << 7) |
+ p_param->custom_lambda_sad[i];
+ }
+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) {
+ reg->temporal_layer_qp[i] = (p_param->temp_layer[i].qp_b << 12) |
+ (p_param->temp_layer[i].qp_p << 6) |
+ p_param->temp_layer[i].qp_i;
+ }
+ reg->scl_src_size = (p_open_param->pic_height << 16) | p_open_param->pic_width;
+ reg->scl_param = (p_enc_info->scaler_info.coef_mode << 1) | p_enc_info->scaler_info.enable;
+ reg->color_param = ((p_param->color.chroma_sample_position & 0x3) << 26) |
+ (p_param->color.color_range << 25) |
+ ((p_param->color.matrix_coefficients & 0xFF) << 17) |
+ ((p_param->color.transfer_characteristics & 0xFF) << 9) |
+ ((p_param->color.color_primaries & 0xFF) << 1) |
+ p_param->color.color_description_present;
+ reg->sar_param = ((p_param->sar.idc & 0xFF) << 1) |
+ (p_param->sar.enable & 0x1);
+ reg->sar_extended = ((p_param->sar.height & 0xFFFF) << 16) |
+ (p_param->sar.width & 0xFFFF);
+}
+
+static void wave6_gen_set_param_reg_hevc(struct enc_info *p_enc_info,
+ struct enc_cmd_set_param_reg *reg)
+{
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ struct enc_codec_param *p_param = &p_open_param->codec_param;
+
+ reg->sps_param = (p_param->en_scaling_list << 31) |
+ (p_param->en_still_picture << 30) |
+ (p_param->en_auto_level_adjusting << 28) |
+ (p_param->en_strong_intra_smoothing << 27) |
+ (p_param->en_intra_trans_skip << 25) |
+ (p_param->en_sao << 24) |
+ (p_param->en_temporal_mvp << 23) |
+ (p_param->en_long_term << 21) |
+ (p_enc_info->color_format << 19) |
+ (p_param->internal_bit_depth << 14) |
+ (p_param->tier << 12) |
+ (p_param->level << 3) |
+ p_param->profile;
+ reg->pps_param = ((p_param->cr_qp_offset & 0x1F) << 19) |
+ ((p_param->cb_qp_offset & 0x1F) << 14) |
+ ((p_param->tc_offset_div2 & 0xF) << 10) |
+ ((p_param->beta_offset_div2 & 0xF) << 6) |
+ ((!p_param->en_dbk) << 5) |
+ (p_param->en_lf_cross_slice_boundary << 2) |
+ (p_param->en_constrained_intra_pred << 1);
+ reg->intra_param = (p_param->intra_period << 16) |
+ (p_param->forced_idr_header << 9) |
+ (p_param->qp << 3) |
+ p_param->decoding_refresh_type;
+ reg->rdo_param = (p_param->en_custom_lambda << 22) |
+ (p_param->en_me_center << 21) |
+ (p_param->en_qp_map << 20) |
+ (p_param->en_mode_map << 19) |
+ (p_param->en_q_round_offset << 17) |
+ (p_param->dis_coef_clear << 4) |
+ (p_param->en_adaptive_round << 3) |
+ (p_param->en_hvs_qp << 2);
+ reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode;
+ reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) |
+ ((p_param->lambda_dqp_intra & 0x3F) << 8);
+ reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) |
+ (p_open_param->enc_hrd_rbsp_in_vps << 2) |
+ (NON_VCL_PARAM_ENCODE_VUI) |
+ p_open_param->enc_aud;
+ reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr;
+}
+
+static void wave6_gen_set_param_reg_avc(struct enc_info *p_enc_info,
+ struct enc_cmd_set_param_reg *reg)
+{
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ struct enc_codec_param *p_param = &p_open_param->codec_param;
+
+ reg->sps_param = (p_param->en_scaling_list << 31) |
+ (p_param->en_auto_level_adjusting << 28) |
+ (p_param->en_long_term << 21) |
+ (p_enc_info->color_format << 19) |
+ (p_param->internal_bit_depth << 14) |
+ (p_param->level << 3) |
+ p_param->profile;
+ reg->pps_param = (p_param->en_cabac << 30) |
+ (p_param->en_transform8x8 << 29) |
+ ((p_param->cr_qp_offset & 0x1F) << 19) |
+ ((p_param->cb_qp_offset & 0x1F) << 14) |
+ ((p_param->tc_offset_div2 & 0xF) << 10) |
+ ((p_param->beta_offset_div2 & 0xF) << 6) |
+ ((!p_param->en_dbk) << 5) |
+ (p_param->en_lf_cross_slice_boundary << 2) |
+ (p_param->en_constrained_intra_pred << 1);
+ reg->intra_param = (p_param->forced_idr_header << 28) |
+ (p_param->idr_period << 17) |
+ (p_param->intra_period << 6) |
+ p_param->qp;
+ reg->rdo_param = (p_param->en_custom_lambda << 22) |
+ (p_param->en_me_center << 21) |
+ (p_param->en_qp_map << 20) |
+ (p_param->en_mode_map << 19) |
+ (p_param->en_q_round_offset << 17) |
+ (p_param->dis_coef_clear << 4) |
+ (p_param->en_adaptive_round << 3) |
+ (p_param->en_hvs_qp << 2);
+ reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode;
+ reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) |
+ ((p_param->lambda_dqp_intra & 0x3F) << 8);
+ reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) |
+ (p_open_param->enc_hrd_rbsp_in_vps << 2) |
+ (NON_VCL_PARAM_ENCODE_VUI) |
+ p_open_param->enc_aud;
+ reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr;
+}
+
+static void wave6_gen_change_param_reg_common(struct vpu_instance *inst,
+ struct enc_info *p_enc_info,
+ struct enc_cmd_change_param_reg *reg)
+{
+ if (p_enc_info->open_param.codec_param.bitrate != inst->enc_ctrls.bitrate) {
+ reg->enable |= BIT(W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE);
+ reg->rc_target_rate = inst->enc_ctrls.bitrate;
+ p_enc_info->open_param.codec_param.bitrate = inst->enc_ctrls.bitrate;
+ }
+}
+
+int wave6_vpu_enc_init_seq(struct vpu_instance *inst)
+{
+ struct enc_cmd_set_param_reg reg;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 i;
+ int ret;
+
+ memset(®, 0, sizeof(struct enc_cmd_set_param_reg));
+
+ if (!wave6_update_enc_info(p_enc_info))
+ return -EINVAL;
+
+ wave6_gen_set_param_reg_common(p_enc_info, inst->std, ®);
+ if (inst->std == W_HEVC_ENC)
+ wave6_gen_set_param_reg_hevc(p_enc_info, ®);
+ else if (inst->std == W_AVC_ENC)
+ wave6_gen_set_param_reg_avc(p_enc_info, ®);
+
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION, W6_SET_PARAM_OPT_COMMON);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE, reg.enable);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SRC_SIZE, reg.src_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN, reg.custom_map_endian);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SPS_PARAM, reg.sps_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_PPS_PARAM, reg.pps_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_GOP_PARAM, reg.gop_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_PARAM, reg.intra_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT, reg.conf_win_top_bot);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT, reg.conf_win_left_right);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RDO_PARAM, reg.rdo_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SLICE_PARAM, reg.slice_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_REFRESH, reg.intra_refresh);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP, reg.intra_min_max_qp);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE, reg.rc_frame_rate);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE, reg.rc_target_rate);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_PARAM, reg.rc_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HVS_PARAM, reg.hvs_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE, reg.rc_max_bitrate);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE, reg.rc_vbv_buffer_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP, reg.inter_min_max_qp);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ROT_PARAM, reg.rot_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK, reg.num_units_in_tick);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TIME_SCALE, reg.time_scale);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE,
+ reg.num_ticks_poc_diff_one);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT, reg.max_intra_pic_bit);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT, reg.max_inter_pic_bit);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_BG_PARAM, reg.bg_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM, reg.non_vcl_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR, reg.vui_rbsp_addr);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR, reg.hrd_rbsp_addr);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QROUND_OFFSET, reg.qround_offset);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1, reg.quant_param_1);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2, reg.quant_param_2);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM, reg.custom_gop_param);
+ for (i = 0; i < MAX_GOP_NUM; i++)
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0 + (i * 4),
+ reg.custom_gop_pic_param[i]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TILE_PARAM, reg.tile_param);
+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++)
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0 + (i * 4),
+ reg.custom_lambda[i]);
+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++)
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP + (i * 4),
+ reg.temporal_layer_qp[i]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE, reg.scl_src_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_PARAM, reg.scl_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_COLOR_PARAM, reg.color_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_PARAM, reg.sar_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_EXTENDED, reg.sar_extended);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_SET_PARAM);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+
+ wave6_print_reg_err(inst->dev, reason_code);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info)
+{
+ int ret;
+
+ ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT);
+ if (ret)
+ return ret;
+
+ if (vpu_read_reg(inst->dev, W6_RET_ENC_ENCODING_SUCCESS) != 1) {
+ info->err_reason = vpu_read_reg(inst->dev, W6_RET_ENC_ERR_INFO);
+ ret = -EIO;
+ } else {
+ info->warn_info = vpu_read_reg(inst->dev, W6_RET_ENC_WARN_INFO);
+ }
+
+ info->min_frame_buffer_count = vpu_read_reg(inst->dev, W6_RET_ENC_NUM_REQUIRED_FBC_FB);
+ info->min_src_frame_count = vpu_read_reg(inst->dev, W6_RET_ENC_MIN_SRC_BUF_NUM);
+ info->max_latency_pictures = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_MAX_LATENCY_PICTURES);
+ info->req_mv_buffer_count = vpu_read_reg(inst->dev, W6_RET_ENC_NUM_REQUIRED_COL_BUF);
+
+ return ret;
+}
+
+int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed)
+{
+ struct enc_cmd_change_param_reg reg;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+
+ memset(®, 0, sizeof(struct enc_cmd_change_param_reg));
+
+ wave6_gen_change_param_reg_common(inst, p_enc_info, ®);
+
+ if (!reg.enable)
+ return 0;
+
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION, W6_SET_PARAM_OPT_CHANGE_PARAM);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE, reg.enable);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE, reg.rc_target_rate);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_SET_PARAM);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_warn(inst->dev->dev, "enc set param timed out\n");
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+
+ wave6_print_reg_err(inst->dev, reason_code);
+ return -EIO;
+ }
+
+ *changed = true;
+
+ return 0;
+}
+
+struct enc_cmd_set_fb_reg {
+ u32 option;
+ u32 pic_info;
+ u32 pic_size;
+ u32 num_fb;
+ u32 fbc_stride;
+ u32 fbc_y[WAVE6_MAX_FBS];
+ u32 fbc_c[WAVE6_MAX_FBS];
+ u32 fbc_cr[WAVE6_MAX_FBS];
+ u32 fbc_y_offset[WAVE6_MAX_FBS];
+ u32 fbc_c_offset[WAVE6_MAX_FBS];
+ u32 fbc_cr_offset[WAVE6_MAX_FBS];
+ u32 mv_col[WAVE6_MAX_FBS];
+ u32 sub_sampled[WAVE6_MAX_FBS];
+ u32 default_cdf;
+};
+
+static void wave6_gen_set_fb_reg(struct enc_info *p_enc_info, enum codec_std std,
+ struct frame_buffer *fb_arr, struct enc_cmd_set_fb_reg *reg)
+{
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count;
+ u32 buf_width, buf_height;
+ u32 stride_l, stride_c, i;
+
+ if (std == W_AVC_ENC) {
+ buf_width = ALIGN(p_enc_info->width, 16);
+ buf_height = ALIGN(p_enc_info->height, 16);
+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) {
+ buf_width = ALIGN(p_enc_info->height, 16);
+ buf_height = ALIGN(p_enc_info->width, 16);
+ }
+ } else {
+ buf_width = ALIGN(p_enc_info->width, 8);
+ buf_height = ALIGN(p_enc_info->height, 8);
+ if ((p_enc_info->rotation_angle != 0 || p_enc_info->mirror_direction != 0) &&
+ !(p_enc_info->rotation_angle == 180 &&
+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
+ buf_width = ALIGN(p_enc_info->width, 32);
+ buf_height = ALIGN(p_enc_info->height, 32);
+ }
+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) {
+ buf_width = ALIGN(p_enc_info->height, 32);
+ buf_height = ALIGN(p_enc_info->width, 32);
+ }
+ }
+
+ if ((p_enc_info->rotation_angle != 0 || p_enc_info->mirror_direction != 0) &&
+ !(p_enc_info->rotation_angle == 180 &&
+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
+ stride_l = ALIGN((buf_width + 63), 64);
+ stride_c = ALIGN((buf_width + 31), 32) / 2;
+ } else {
+ stride_l = ALIGN((p_enc_info->width) + 63, 64);
+ stride_c = ALIGN((p_enc_info->width) + 31, 32) / 2;
+ }
+
+ reg->option = (p_open_param->enable_non_ref_fbc_write << 26) | (1 << 4) | (1 << 3);
+ reg->pic_info = p_enc_info->stride;
+ reg->pic_size = (buf_width << 16) | buf_height;
+ reg->num_fb = ((p_enc_info->num_frame_buffers - 1) << 16) | (mv_count - 1);
+ reg->fbc_stride = (stride_l << 16) | stride_c;
+ reg->default_cdf = 0;
+
+ for (i = 0; i < p_enc_info->num_frame_buffers; i++) {
+ reg->fbc_y[i] = fb_arr[i].buf_y;
+ reg->fbc_c[i] = fb_arr[i].buf_cb;
+ reg->fbc_cr[i] = fb_arr[i].buf_cr;
+ reg->fbc_y_offset[i] = p_enc_info->vb_fbc_y_tbl[i].daddr;
+ reg->fbc_c_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr;
+ reg->fbc_cr_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr +
+ (p_enc_info->vb_fbc_c_tbl[i].size >> 1);
+ reg->sub_sampled[i] = p_enc_info->vb_sub_sam_buf[i].daddr;
+ }
+ for (i = 0; i < mv_count; i++)
+ reg->mv_col[i] = p_enc_info->vb_mv[i].daddr;
+}
+
+int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst, struct frame_buffer *fb_arr)
+{
+ struct enc_cmd_set_fb_reg *reg;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count;
+ int ret;
+ u32 idx;
+
+ for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) {
+ if (!p_enc_info->vb_fbc_y_tbl[idx].daddr)
+ return -EINVAL;
+ if (!p_enc_info->vb_fbc_c_tbl[idx].daddr)
+ return -EINVAL;
+ if (!p_enc_info->vb_sub_sam_buf[idx].daddr)
+ return -EINVAL;
+ }
+ for (idx = 0; idx < mv_count; idx++) {
+ if (!p_enc_info->vb_mv[idx].daddr)
+ return -EINVAL;
+ }
+
+ reg = kzalloc(sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ wave6_gen_set_fb_reg(p_enc_info, inst->std, fb_arr, reg);
+
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_OPTION, reg->option);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_INFO, reg->pic_info);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_SIZE, reg->pic_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_NUM, reg->num_fb);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_STRIDE, reg->fbc_stride);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_DEFAULT_CDF, reg->default_cdf);
+ for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) {
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y0 + (idx * 24), reg->fbc_y[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C0 + (idx * 24), reg->fbc_c[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR0 + (idx * 8), reg->fbc_cr[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 + (idx * 24),
+ reg->fbc_y_offset[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 + (idx * 24),
+ reg->fbc_c_offset[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 + (idx * 8),
+ reg->fbc_cr_offset[idx]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_SUB_SAMPLED0 + (idx * 24),
+ reg->sub_sampled[idx]);
+ }
+ for (idx = 0; idx < mv_count; idx++)
+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_MV_COL0 + (idx * 24), reg->mv_col[idx]);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_SET_FB);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ kfree(reg);
+ return ret;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ kfree(reg);
+ return -EIO;
+ }
+
+ kfree(reg);
+ return 0;
+}
+
+struct enc_cmd_enc_pic_reg {
+ u32 bs_start;
+ u32 bs_size;
+ u32 bs_option;
+ u32 use_sec_axi;
+ u32 report_param;
+ u32 mv_histo_class0;
+ u32 mv_histo_class1;
+ u32 custom_map_param;
+ u32 custom_map_addr;
+ u32 src_pic_idx;
+ u32 src_addr_y;
+ u32 src_addr_u;
+ u32 src_addr_v;
+ u32 src_stride;
+ u32 src_format;
+ u32 src_axi_sel;
+ u32 code_option;
+ u32 pic_param;
+ u32 longterm_pic;
+ u32 prefix_sei_nal_addr;
+ u32 prefix_sei_info;
+ u32 suffix_sei_nal_addr;
+ u32 suffix_sei_info;
+ u32 timestamp;
+ u32 csc_coeff[MAX_CSC_COEFF_NUM];
+};
+
+static bool is_format_conv(enum frame_buffer_format in_fmt,
+ enum frame_buffer_format out_fmt)
+{
+ if (in_fmt == FORMAT_420 ||
+ in_fmt == FORMAT_420_P10_16BIT_MSB ||
+ in_fmt == FORMAT_420_P10_16BIT_LSB ||
+ in_fmt == FORMAT_420_P10_32BIT_MSB ||
+ in_fmt == FORMAT_420_P10_32BIT_LSB) {
+ if (out_fmt != FORMAT_420 &&
+ out_fmt != FORMAT_420_P10_16BIT_MSB &&
+ out_fmt != FORMAT_420_P10_16BIT_LSB &&
+ out_fmt != FORMAT_420_P10_32BIT_MSB &&
+ out_fmt != FORMAT_420_P10_32BIT_LSB)
+ return true;
+ } else if (in_fmt == FORMAT_422 ||
+ in_fmt == FORMAT_422_P10_16BIT_MSB ||
+ in_fmt == FORMAT_422_P10_16BIT_LSB ||
+ in_fmt == FORMAT_422_P10_32BIT_MSB ||
+ in_fmt == FORMAT_422_P10_32BIT_LSB) {
+ if (out_fmt != FORMAT_422 &&
+ out_fmt != FORMAT_422_P10_16BIT_MSB &&
+ out_fmt != FORMAT_422_P10_16BIT_LSB &&
+ out_fmt != FORMAT_422_P10_32BIT_MSB &&
+ out_fmt != FORMAT_422_P10_32BIT_LSB)
+ return true;
+ } else if (in_fmt == FORMAT_444 ||
+ in_fmt == FORMAT_444_P10_16BIT_MSB ||
+ in_fmt == FORMAT_444_P10_16BIT_LSB ||
+ in_fmt == FORMAT_444_P10_32BIT_MSB ||
+ in_fmt == FORMAT_444_P10_32BIT_LSB) {
+ if (out_fmt != FORMAT_444 &&
+ out_fmt != FORMAT_444_P10_16BIT_MSB &&
+ out_fmt != FORMAT_444_P10_16BIT_LSB &&
+ out_fmt != FORMAT_444_P10_32BIT_MSB &&
+ out_fmt != FORMAT_444_P10_32BIT_LSB)
+ return true;
+ }
+
+ return false;
+}
+
+static void wave6_gen_enc_pic_reg(struct enc_info *p_enc_info, bool cbcr_interleave, bool nv21,
+ struct enc_param *opt, struct enc_cmd_enc_pic_reg *reg)
+{
+ struct enc_open_param open = p_enc_info->open_param;
+ struct enc_codec_param param = open.codec_param;
+ bool is_lsb = false;
+ bool is_10bit = false;
+ bool is_3p4b = false;
+ u32 stride_c;
+ u32 src_frame_format;
+ u32 endian;
+ u32 color_format;
+ bool is_ayuv = false;
+ bool is_csc_format = false;
+ bool is_24bit = false;
+ bool format_conv;
+
+ endian = wave6_vdi_convert_endian(open.source_endian);
+ endian = (~endian & VDI_128BIT_ENDIAN_MASK);
+ format_conv = is_format_conv(open.src_format, open.output_format);
+
+ switch (open.src_format) {
+ case FORMAT_420:
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_420_P10_16BIT_LSB:
+ color_format = 1;
+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
+ (opt->source_frame->stride / 2);
+ break;
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_420_P10_32BIT_LSB:
+ color_format = 1;
+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
+ ALIGN((opt->source_frame->stride / 2), 16);
+ break;
+ case FORMAT_422:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ color_format = 2;
+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
+ (opt->source_frame->stride / 2);
+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
+ break;
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ color_format = 2;
+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
+ ALIGN((opt->source_frame->stride / 2), 16);
+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
+ break;
+ case FORMAT_444:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ color_format = 3;
+ stride_c = (cbcr_interleave) ? (opt->source_frame->stride * 2) :
+ opt->source_frame->stride;
+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
+ break;
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ color_format = 3;
+ stride_c = (cbcr_interleave) ? ALIGN((opt->source_frame->stride * 2), 16) :
+ opt->source_frame->stride;
+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
+ break;
+ case FORMAT_YUV444_24BIT:
+ color_format = 0;
+ stride_c = ALIGN((opt->source_frame->stride * 2), 16);
+ break;
+ case FORMAT_RGB_24BIT_PACKED:
+ case FORMAT_YUV444_24BIT_PACKED:
+ case FORMAT_RGB_32BIT_PACKED:
+ case FORMAT_RGB_P10_32BIT_PACKED:
+ case FORMAT_YUV444_32BIT_PACKED:
+ case FORMAT_YUV444_P10_32BIT_PACKED:
+ color_format = 4;
+ stride_c = 0;
+ break;
+ case FORMAT_YUYV:
+ case FORMAT_YVYU:
+ case FORMAT_UYVY:
+ case FORMAT_VYUY:
+ case FORMAT_YUYV_P10_16BIT_MSB:
+ case FORMAT_YVYU_P10_16BIT_MSB:
+ case FORMAT_UYVY_P10_16BIT_MSB:
+ case FORMAT_VYUY_P10_16BIT_MSB:
+ case FORMAT_YUYV_P10_16BIT_LSB:
+ case FORMAT_YVYU_P10_16BIT_LSB:
+ case FORMAT_UYVY_P10_16BIT_LSB:
+ case FORMAT_VYUY_P10_16BIT_LSB:
+ case FORMAT_YUYV_P10_32BIT_MSB:
+ case FORMAT_YVYU_P10_32BIT_MSB:
+ case FORMAT_UYVY_P10_32BIT_MSB:
+ case FORMAT_VYUY_P10_32BIT_MSB:
+ case FORMAT_YUYV_P10_32BIT_LSB:
+ case FORMAT_YVYU_P10_32BIT_LSB:
+ case FORMAT_UYVY_P10_32BIT_LSB:
+ case FORMAT_VYUY_P10_32BIT_LSB:
+ color_format = 2;
+ stride_c = 0;
+ break;
+ default:
+ color_format = 0;
+ stride_c = 0;
+ break;
+ }
+
+ switch (open.src_format) {
+ case FORMAT_420:
+ case FORMAT_422:
+ case FORMAT_444:
+ case FORMAT_400:
+ case FORMAT_YUYV:
+ case FORMAT_YVYU:
+ case FORMAT_UYVY:
+ case FORMAT_VYUY:
+ is_lsb = false;
+ is_3p4b = false;
+ break;
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_400_P10_16BIT_MSB:
+ case FORMAT_YUYV_P10_16BIT_MSB:
+ case FORMAT_YVYU_P10_16BIT_MSB:
+ case FORMAT_UYVY_P10_16BIT_MSB:
+ case FORMAT_VYUY_P10_16BIT_MSB:
+ is_lsb = false;
+ is_10bit = true;
+ is_3p4b = false;
+ break;
+ case FORMAT_420_P10_16BIT_LSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ case FORMAT_400_P10_16BIT_LSB:
+ case FORMAT_YUYV_P10_16BIT_LSB:
+ case FORMAT_YVYU_P10_16BIT_LSB:
+ case FORMAT_UYVY_P10_16BIT_LSB:
+ case FORMAT_VYUY_P10_16BIT_LSB:
+ is_lsb = true;
+ is_10bit = true;
+ is_3p4b = false;
+ break;
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_400_P10_32BIT_MSB:
+ case FORMAT_YUYV_P10_32BIT_MSB:
+ case FORMAT_YVYU_P10_32BIT_MSB:
+ case FORMAT_UYVY_P10_32BIT_MSB:
+ case FORMAT_VYUY_P10_32BIT_MSB:
+ is_lsb = false;
+ is_10bit = true;
+ is_3p4b = true;
+ break;
+ case FORMAT_420_P10_32BIT_LSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ case FORMAT_400_P10_32BIT_LSB:
+ case FORMAT_YUYV_P10_32BIT_LSB:
+ case FORMAT_YVYU_P10_32BIT_LSB:
+ case FORMAT_UYVY_P10_32BIT_LSB:
+ case FORMAT_VYUY_P10_32BIT_LSB:
+ is_lsb = true;
+ is_10bit = true;
+ is_3p4b = true;
+ break;
+ case FORMAT_RGB_32BIT_PACKED:
+ is_ayuv = false;
+ is_csc_format = true;
+ break;
+ case FORMAT_RGB_P10_32BIT_PACKED:
+ is_ayuv = false;
+ is_csc_format = true;
+ is_10bit = true;
+ break;
+ case FORMAT_YUV444_32BIT_PACKED:
+ is_ayuv = true;
+ is_csc_format = true;
+ break;
+ case FORMAT_YUV444_P10_32BIT_PACKED:
+ is_ayuv = true;
+ is_csc_format = true;
+ is_10bit = true;
+ break;
+ case FORMAT_RGB_24BIT_PACKED:
+ is_ayuv = false;
+ is_csc_format = true;
+ is_24bit = true;
+ break;
+ case FORMAT_YUV444_24BIT_PACKED:
+ is_ayuv = true;
+ is_csc_format = true;
+ is_24bit = true;
+ break;
+ case FORMAT_YUV444_24BIT:
+ is_ayuv = true;
+ break;
+ default:
+ break;
+ }
+
+ src_frame_format = (nv21 << 2) | (cbcr_interleave << 1);
+ switch (open.packed_format) {
+ case PACKED_YUYV:
+ src_frame_format = 1; break;
+ case PACKED_YVYU:
+ src_frame_format = 5; break;
+ case PACKED_UYVY:
+ src_frame_format = 9; break;
+ case PACKED_VYUY:
+ src_frame_format = 13; break;
+ default:
+ break;
+ }
+
+ reg->bs_start = opt->pic_stream_buffer_addr;
+ reg->bs_size = opt->pic_stream_buffer_size;
+ reg->bs_option = (p_enc_info->line_buf_int_en << 6);
+ reg->use_sec_axi = (p_enc_info->sec_axi_info.use_enc_rdo << 1) |
+ p_enc_info->sec_axi_info.use_enc_lf;
+ reg->report_param = (param.en_report_mv_histo << 1);
+ reg->mv_histo_class0 = (param.report_mv_histo_threshold0 << 16) |
+ param.report_mv_histo_threshold1;
+ reg->mv_histo_class1 = (param.report_mv_histo_threshold2 << 16) |
+ param.report_mv_histo_threshold3;
+
+ reg->src_pic_idx = opt->src_idx;
+ if (opt->src_end)
+ reg->src_pic_idx = 0xFFFFFFFF;
+
+ reg->src_addr_y = opt->source_frame->buf_y;
+ if (open.cbcr_order == CBCR_ORDER_NORMAL) {
+ reg->src_addr_u = opt->source_frame->buf_cb;
+ reg->src_addr_v = opt->source_frame->buf_cr;
+ } else {
+ reg->src_addr_u = opt->source_frame->buf_cr;
+ reg->src_addr_v = opt->source_frame->buf_cb;
+ }
+ reg->src_stride = (opt->source_frame->stride << 16) | stride_c;
+ reg->src_format = (color_format << 28) |
+ (is_24bit << 25) |
+ (is_ayuv << 24) |
+ (is_csc_format << 20) |
+ (opt->csc.format_order << 16) |
+ (endian << 12) |
+ (is_lsb << 6) |
+ (is_3p4b << 5) |
+ (is_10bit << 4) |
+ src_frame_format;
+ reg->src_axi_sel = DEFAULT_SRC_AXI;
+ reg->code_option = (opt->src_end << 10) |
+ (W6_ENC_PIC_OPT_VCL) |
+ (W6_ENC_PIC_OPT_HEADER_IMPLICIT);
+ reg->pic_param = (param.intra_4x4 << 28) |
+ (opt->force_pic_type << 21) |
+ (opt->force_pic_type_enable << 20) |
+ (opt->force_pic_qp_b << 14) |
+ (opt->force_pic_qp_p << 8) |
+ (opt->force_pic_qp_i << 2) |
+ (opt->force_pic_qp_enable << 1) |
+ opt->skip_picture;
+ reg->timestamp = ((opt->timestamp.hour & 0x1F) << 26) |
+ ((opt->timestamp.min & 0x3F) << 20) |
+ ((opt->timestamp.sec & 0x3F) << 14) |
+ ((opt->timestamp.ms & 0x3FFF));
+ reg->csc_coeff[0] = ((opt->csc.coef_ry & 0x3FF) << 20) |
+ ((opt->csc.coef_gy & 0x3FF) << 10) |
+ (opt->csc.coef_by & 0x3FF);
+ reg->csc_coeff[1] = ((opt->csc.coef_rcb & 0x3FF) << 20) |
+ ((opt->csc.coef_gcb & 0x3FF) << 10) |
+ (opt->csc.coef_bcb & 0x3FF);
+ reg->csc_coeff[2] = ((opt->csc.coef_rcr & 0x3FF) << 20) |
+ ((opt->csc.coef_gcr & 0x3FF) << 10) |
+ (opt->csc.coef_bcr & 0x3FF);
+ reg->csc_coeff[3] = ((opt->csc.offset_y & 0x3FF) << 20) |
+ ((opt->csc.offset_cb & 0x3FF) << 10) |
+ (opt->csc.offset_cr & 0x3FF);
+}
+
+int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res)
+{
+ struct enc_cmd_enc_pic_reg reg;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+
+ memset(®, 0, sizeof(struct enc_cmd_enc_pic_reg));
+
+ wave6_gen_enc_pic_reg(p_enc_info, inst->cbcr_interleave,
+ inst->nv21, option, ®);
+
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_START, reg.bs_start);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_SIZE, reg.bs_size);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_OPTION, reg.bs_option);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_USE_SEC_AXI, reg.use_sec_axi);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_REPORT_PARAM, reg.report_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS0, reg.mv_histo_class0);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS1, reg.mv_histo_class1);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM, reg.custom_map_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, reg.custom_map_addr);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_PIC_IDX, reg.src_pic_idx);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_Y, reg.src_addr_y);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_U, reg.src_addr_u);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_V, reg.src_addr_v);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_STRIDE, reg.src_stride);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_FORMAT, reg.src_format);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_AXI_SEL, reg.src_axi_sel);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CODE_OPTION, reg.code_option);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PIC_PARAM, reg.pic_param);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_LONGTERM_PIC, reg.longterm_pic);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR, reg.prefix_sei_nal_addr);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_INFO, reg.prefix_sei_info);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR, reg.suffix_sei_nal_addr);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_INFO, reg.suffix_sei_info);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_TIMESTAMP, reg.timestamp);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_0, reg.csc_coeff[0]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_1, reg.csc_coeff[1]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_2, reg.csc_coeff[2]);
+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_3, reg.csc_coeff[3]);
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_PIC);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(inst->dev, *fail_res);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 reg_val;
+ int ret;
+
+ ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT);
+ if (ret)
+ return ret;
+
+ result->encoding_success = vpu_read_reg(inst->dev, W6_RET_ENC_ENCODING_SUCCESS);
+ if (!result->encoding_success)
+ result->error_reason = vpu_read_reg(inst->dev, W6_RET_ENC_ERR_INFO);
+ else
+ result->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO);
+
+ result->enc_pic_cnt = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM);
+ reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_TYPE);
+ result->pic_type = reg_val & 0xFFFF;
+
+ result->enc_vcl_nut = vpu_read_reg(inst->dev, W6_RET_ENC_VCL_NUT);
+ result->recon_frame_index = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_IDX);
+ if (result->recon_frame_index >= 0)
+ result->recon_frame = inst->frame_buf[result->recon_frame_index];
+
+ result->non_ref_pic = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NON_REF_PIC_FLAG);
+ result->num_of_slices = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_SLICE_NUM);
+ result->pic_skipped = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_SKIP);
+ result->num_of_intra = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_INTRA);
+ result->num_of_merge = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_MERGE);
+ result->num_of_skip_block = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_SKIP);
+ result->bitstream_wrap_around = 0;
+
+ result->avg_ctu_qp = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_AVG_CTU_QP);
+ result->enc_pic_byte = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_BYTE);
+
+ result->enc_gop_pic_idx = vpu_read_reg(inst->dev, W6_RET_ENC_GOP_PIC_IDX);
+ result->enc_pic_poc = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_POC);
+ result->enc_src_idx = vpu_read_reg(inst->dev, W6_RET_ENC_USED_SRC_IDX);
+ result->wr_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_WR_PTR);
+ result->rd_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_RD_PTR);
+
+ result->pic_distortion_low = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_DIST_LOW);
+ result->pic_distortion_high = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_DIST_HIGH);
+
+ result->mv_histo.cnt0 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_0);
+ result->mv_histo.cnt1 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_1);
+ result->mv_histo.cnt2 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_2);
+ result->mv_histo.cnt3 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_3);
+ result->mv_histo.cnt4 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_4);
+
+ result->fme_sum.lower_x0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_X_DIR_LOWER);
+ result->fme_sum.higher_x0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_X_DIR_HIGHER);
+ result->fme_sum.lower_y0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_Y_DIR_LOWER);
+ result->fme_sum.higher_y0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER);
+ result->fme_sum.lower_x1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_X_DIR_LOWER);
+ result->fme_sum.higher_x1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_X_DIR_HIGHER);
+ result->fme_sum.lower_y1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_Y_DIR_LOWER);
+ result->fme_sum.higher_y1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER);
+
+ result->src_y_addr = vpu_read_reg(inst->dev, W6_RET_ENC_SRC_Y_ADDR);
+ result->custom_map_addr = vpu_read_reg(inst->dev, W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR);
+ result->prefix_sei_nal_addr = vpu_read_reg(inst->dev, W6_RET_ENC_PREFIX_SEI_NAL_ADDR);
+ result->suffix_sei_nal_addr = vpu_read_reg(inst->dev, W6_RET_ENC_SUFFIX_SEI_NAL_ADDR);
+
+ reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_TIMESTAMP);
+ result->timestamp.hour = (reg_val >> 26) & 0x1F;
+ result->timestamp.min = (reg_val >> 20) & 0x3F;
+ result->timestamp.sec = (reg_val >> 14) & 0x3F;
+ result->timestamp.ms = reg_val & 0x3FFF;
+
+ result->bitstream_buffer = vpu_read_reg(inst->dev, W6_RET_ENC_RD_PTR);
+
+ if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY)
+ result->bitstream_size = result->enc_pic_byte;
+ else if (result->recon_frame_index < 0)
+ result->bitstream_size = 0;
+ else
+ result->bitstream_size = result->enc_pic_byte;
+
+ result->cycle.host_cmd_s = vpu_read_reg(inst->dev, W6_RET_CQ_IN_TICK);
+ result->cycle.host_cmd_e = vpu_read_reg(inst->dev, W6_RET_RQ_OUT_TICK);
+ result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK);
+ result->cycle.proc_e = vpu_read_reg(inst->dev, W6_RET_HW_DONE_TICK);
+ result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK);
+ result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK);
+ result->cycle.frame_cycle = (result->cycle.vpu_e - result->cycle.host_cmd_s) *
+ p_enc_info->cycle_per_tick;
+ result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) *
+ p_enc_info->cycle_per_tick;
+ result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) -
+ (result->cycle.proc_e - result->cycle.proc_s)) *
+ p_enc_info->cycle_per_tick;
+
+ return 0;
+}
+
+int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res)
+{
+ int ret;
+
+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DESTROY_INSTANCE);
+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
+ if (ret)
+ return -ETIMEDOUT;
+
+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
+ wave6_print_reg_err(inst->dev, *fail_res);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_gop_param(struct vpu_instance *inst, struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ int i;
+ bool low_delay = true;
+
+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) {
+ if (p_param->gop_param.custom_gop_size > 1) {
+ int min_val = p_param->gop_param.pic_param[0].poc_offset;
+
+ for (i = 1; i < p_param->gop_param.custom_gop_size; i++) {
+ if (min_val > p_param->gop_param.pic_param[i].poc_offset) {
+ low_delay = false;
+ break;
+ }
+ min_val = p_param->gop_param.pic_param[i].poc_offset;
+ }
+ }
+ } else if (p_param->gop_preset_idx == PRESET_IDX_ALL_I ||
+ p_param->gop_preset_idx == PRESET_IDX_IPP ||
+ p_param->gop_preset_idx == PRESET_IDX_IBBB ||
+ p_param->gop_preset_idx == PRESET_IDX_IPPPP ||
+ p_param->gop_preset_idx == PRESET_IDX_IBBBB ||
+ p_param->gop_preset_idx == PRESET_IDX_IPP_SINGLE) {
+ }
+
+ if (p_param->gop_preset_idx >= PRESET_IDX_MAX) {
+ dev_err(dev, "gop_preset_idx: %d\n", p_param->gop_preset_idx);
+ return -EINVAL;
+ }
+
+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) {
+ if (p_param->gop_param.custom_gop_size < 1 ||
+ p_param->gop_param.custom_gop_size > MAX_GOP_NUM) {
+ dev_err(dev, "custom_gop_size: %d\n", p_param->gop_param.custom_gop_size);
+ return -EINVAL;
+ }
+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
+ struct custom_gop_pic_param pic_param = p_param->gop_param.pic_param[i];
+
+ if (pic_param.pic_type != PIC_TYPE_I &&
+ pic_param.pic_type != PIC_TYPE_P &&
+ pic_param.pic_type != PIC_TYPE_B) {
+ dev_err(dev, "pic_param[%d].pic_type: %d\n", i, pic_param.pic_type);
+ return -EINVAL;
+ }
+ if (pic_param.poc_offset < 1 ||
+ pic_param.poc_offset > p_param->gop_param.custom_gop_size) {
+ dev_err(dev, "pic_param[%d].poc_offset: %d\n",
+ i, pic_param.poc_offset);
+ return -EINVAL;
+ }
+ if (pic_param.use_multi_ref_p < 0 || pic_param.use_multi_ref_p > 1) {
+ dev_err(dev, "pic_param[%d].use_multi_ref_p: %d\n",
+ i, pic_param.use_multi_ref_p);
+ return -EINVAL;
+ }
+ if (pic_param.temporal_id < 0 || pic_param.temporal_id > 3) {
+ dev_err(dev, "pic_param[%d].temporal_id: %d\n",
+ i, pic_param.temporal_id);
+ return -EINVAL;
+ }
+ }
+ if (inst->std == W_AVC_ENC && !low_delay) {
+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
+ if (p_param->gop_param.pic_param[i].temporal_id > 0) {
+ dev_err(dev, "std: %d, pic_param[%d].temporal_id: %d\n",
+ inst->std, i,
+ p_param->gop_param.pic_param[i].temporal_id);
+ return -EINVAL;
+ }
+ }
+ }
+ }
+
+ if (inst->std == W_HEVC_ENC) {
+ if (p_param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) {
+ dev_err(dev, "decoding_refresh_type: %d\n", p_param->decoding_refresh_type);
+ return -EINVAL;
+ }
+ } else {
+ if (p_param->decoding_refresh_type != DEC_REFRESH_TYPE_NON_IRAP) {
+ dev_err(dev, "decoding_refresh_type: %d\n", p_param->decoding_refresh_type);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_tile_slice_param(struct vpu_instance *inst,
+ int width, int height,
+ struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+
+ if (p_param->slice_mode > 2) {
+ dev_err(dev, "slice_mode: %d\n", p_param->slice_mode);
+ return -EINVAL;
+ }
+ if (p_param->slice_mode == 1) {
+ unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
+ unsigned int mb_num = ((width + ctu_size - 1) / ctu_size) *
+ ((height + ctu_size - 1) / ctu_size);
+
+ if (p_param->slice_arg < 1 || p_param->slice_arg > 0x3FFFF) {
+ dev_err(dev, "slice_arg: %d\n", p_param->slice_arg);
+ return -EINVAL;
+ }
+ if (p_param->slice_arg > mb_num) {
+ dev_info(dev, "slice_arg: %d, mb_num: %d\n",
+ p_param->slice_arg, mb_num);
+ p_param->slice_arg = mb_num;
+ }
+ if (inst->std == W_AVC_ENC && p_param->slice_arg < 4) {
+ dev_info(dev, "std: %d, slice_arg: %d\n",
+ inst->std, p_param->slice_arg);
+ p_param->slice_arg = 4;
+ }
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_rc_param(struct vpu_instance *inst, struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+
+ if (p_param->frame_rate < 1 || p_param->frame_rate > 960) {
+ dev_err(dev, "frame_rate: %d\n", p_param->frame_rate);
+ return -EINVAL;
+ }
+ if (p_param->bitrate > 1500000000) {
+ dev_err(dev, "bitrate: %d\n", p_param->bitrate);
+ return -EINVAL;
+ }
+ if (p_param->qp > 51) {
+ dev_err(dev, "qp: %d\n", p_param->qp);
+ return -EINVAL;
+ }
+ if (p_param->min_qp_i > 51 || p_param->min_qp_p > 51 || p_param->min_qp_b > 51) {
+ dev_err(dev, "min_qp_i: %d, min_qp_p: %d, min_qp_b: %d\n",
+ p_param->min_qp_i, p_param->min_qp_p, p_param->min_qp_b);
+ return -EINVAL;
+ }
+ if (p_param->max_qp_i > 51 || p_param->max_qp_p > 51 || p_param->max_qp_b > 51) {
+ dev_err(dev, "max_qp_i: %d, max_qp_p: %d, max_qp_b: %d\n",
+ p_param->max_qp_i, p_param->max_qp_p, p_param->max_qp_b);
+ return -EINVAL;
+ }
+ if (p_param->min_qp_i > p_param->max_qp_i) {
+ dev_err(dev, "min_qp_i: %d, max_qp_i: %d\n", p_param->min_qp_i, p_param->max_qp_i);
+ return -EINVAL;
+ }
+ if (p_param->min_qp_p > p_param->max_qp_p) {
+ dev_err(dev, "min_qp_p: %d, max_qp_p: %d\n", p_param->min_qp_p, p_param->max_qp_p);
+ return -EINVAL;
+ }
+ if (p_param->min_qp_b > p_param->max_qp_b) {
+ dev_err(dev, "min_qp_b: %d, max_qp_b: %d\n", p_param->min_qp_b, p_param->max_qp_b);
+ return -EINVAL;
+ }
+ if (p_param->rc_initial_qp < -1 || p_param->rc_initial_qp > 51) {
+ dev_err(dev, "rc_initial_qp: %d\n", p_param->rc_initial_qp);
+ return -EINVAL;
+ }
+ if (p_param->en_rate_control != 1 && p_param->en_rate_control != 0) {
+ dev_err(dev, "en_rate_control: %d\n", p_param->en_rate_control);
+ return -EINVAL;
+ }
+ if (p_param->rc_mode > 1) {
+ dev_err(dev, "rc_mode: %d\n", p_param->rc_mode);
+ return -EINVAL;
+ }
+ if (p_param->en_rate_control) {
+ if (p_param->bitrate <= p_param->frame_rate) {
+ dev_err(dev, "bitrate: %d, frame_rate: %d\n",
+ p_param->bitrate, p_param->frame_rate);
+ return -EINVAL;
+ }
+ if (p_param->rc_initial_qp != -1) {
+ if (p_param->rc_initial_qp < p_param->min_qp_i) {
+ dev_err(dev, "rc_initial_qp: %d, min_qp_i: %d\n",
+ p_param->rc_initial_qp, p_param->min_qp_i);
+ return -EINVAL;
+ }
+ if (p_param->rc_initial_qp > p_param->max_qp_i) {
+ dev_err(dev, "rc_initial_qp: %d, max_qp_i: %d\n",
+ p_param->rc_initial_qp, p_param->max_qp_i);
+ return -EINVAL;
+ }
+ }
+ } else {
+ if (p_param->qp < p_param->min_qp_i) {
+ dev_err(dev, "qp: %d, min_qp_i: %d\n", p_param->qp, p_param->min_qp_i);
+ return -EINVAL;
+ }
+ if (p_param->qp < p_param->min_qp_p) {
+ dev_err(dev, "qp: %d, min_qp_p: %d\n", p_param->qp, p_param->min_qp_p);
+ return -EINVAL;
+ }
+ if (p_param->qp < p_param->min_qp_b) {
+ dev_err(dev, "qp: %d, min_qp_b: %d\n", p_param->qp, p_param->min_qp_b);
+ return -EINVAL;
+ }
+ if (p_param->qp > p_param->max_qp_i) {
+ dev_err(dev, "qp: %d, max_qp_i: %d\n", p_param->qp, p_param->max_qp_i);
+ return -EINVAL;
+ }
+ if (p_param->qp > p_param->max_qp_p) {
+ dev_err(dev, "qp: %d, max_qp_p: %d\n", p_param->qp, p_param->max_qp_p);
+ return -EINVAL;
+ }
+ if (p_param->qp > p_param->max_qp_b) {
+ dev_err(dev, "qp: %d, max_qp_b: %d\n", p_param->qp, p_param->max_qp_b);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_intra_param(struct vpu_instance *inst,
+ int width, int height,
+ struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
+ unsigned int num_ctu_col = (width + ctu_size - 1) / ctu_size;
+ unsigned int num_ctu_row = (height + ctu_size - 1) / ctu_size;
+
+ if (p_param->intra_refresh_mode > INTRA_REFRESH_COLUMN) {
+ dev_err(dev, "intra_refresh_mode: %d\n", p_param->intra_refresh_mode);
+ return -EINVAL;
+ }
+ if (p_param->intra_refresh_mode != INTRA_REFRESH_NONE) {
+ if (p_param->intra_refresh_arg < 1 || p_param->intra_refresh_arg > 511) {
+ dev_err(dev, "intra_refresh_arg: %d\n", p_param->intra_refresh_arg);
+ return -EINVAL;
+ }
+ }
+ if (p_param->intra_refresh_mode == INTRA_REFRESH_ROW &&
+ p_param->intra_refresh_arg > num_ctu_row) {
+ dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n",
+ p_param->intra_refresh_mode, p_param->intra_refresh_arg);
+ return -EINVAL;
+ }
+ if (p_param->intra_refresh_mode == INTRA_REFRESH_COLUMN &&
+ p_param->intra_refresh_arg > num_ctu_col) {
+ dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n",
+ p_param->intra_refresh_mode, p_param->intra_refresh_arg);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_custom_param(struct vpu_instance *inst,
+ struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ int i;
+
+ if (p_param->en_qp_map != 1 && p_param->en_qp_map != 0) {
+ dev_err(dev, "en_qp_map: %d\n", p_param->en_qp_map);
+ return -EINVAL;
+ }
+ if (p_param->en_mode_map != 1 && p_param->en_mode_map != 0) {
+ dev_err(dev, "en_mode_map: %d\n", p_param->en_mode_map);
+ return -EINVAL;
+ }
+ if (p_param->en_custom_lambda != 1 && p_param->en_custom_lambda != 0) {
+ dev_err(dev, "en_custom_lambda: %d\n", p_param->en_custom_lambda);
+ return -EINVAL;
+ }
+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) {
+ if (p_param->custom_lambda_ssd[i] > 16383) {
+ dev_err(dev, "custom_lambda_ssd[%d]: %d\n",
+ i, p_param->custom_lambda_ssd[i]);
+ return -EINVAL;
+ }
+ if (p_param->custom_lambda_sad[i] > 127) {
+ dev_err(dev, "custom_lambda_sad[%d]: %d\n",
+ i, p_param->custom_lambda_sad[i]);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_conf_win_size_param(struct vpu_instance *inst,
+ int width, int height,
+ struct vpu_rect conf_win)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+
+ if (conf_win.left % 2 || conf_win.top % 2 || conf_win.right % 2 || conf_win.bottom % 2) {
+ dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n",
+ conf_win.left, conf_win.top, conf_win.right, conf_win.bottom);
+ return -EINVAL;
+ }
+ if (conf_win.left > 8192 || conf_win.top > 8192 ||
+ conf_win.right > 8192 || conf_win.bottom > 8192) {
+ dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n",
+ conf_win.left, conf_win.top, conf_win.right, conf_win.bottom);
+ return -EINVAL;
+ }
+ if ((conf_win.right + conf_win.left) > width) {
+ dev_err(dev, "conf_win.left: %d, conf_win.right: %d, width: %d\n",
+ conf_win.left, conf_win.right, width);
+ return -EINVAL;
+ }
+ if ((conf_win.bottom + conf_win.top) > height) {
+ dev_err(dev, "conf_win.top: %d, conf_win.bottom: %d, height: %d\n",
+ conf_win.top, conf_win.bottom, height);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_enc_check_temporal_layer_param(struct vpu_instance *inst,
+ struct enc_codec_param *p_param)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ int i;
+
+ if (p_param->temp_layer_cnt < 1 || p_param->temp_layer_cnt > 4) {
+ dev_err(dev, "temp_layer_cnt: %d\n", p_param->temp_layer_cnt);
+ return -EINVAL;
+ }
+ if (p_param->temp_layer_cnt > 1) {
+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP ||
+ p_param->gop_preset_idx == PRESET_IDX_ALL_I) {
+ dev_err(dev, "temp_layer_cnt: %d, gop_preset_idx: %d\n",
+ p_param->temp_layer_cnt, p_param->gop_preset_idx);
+ return -EINVAL;
+ }
+ }
+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) {
+ if (p_param->temp_layer[i].change_qp != 1 &&
+ p_param->temp_layer[i].change_qp != 0) {
+ dev_err(dev, "temp_layer[%d].change_qp: %d\n",
+ i, p_param->temp_layer[i].change_qp);
+ return -EINVAL;
+ }
+ if (p_param->temp_layer[i].qp_b > 51) {
+ dev_err(dev, "temp_layer[%d].qp_b: %d\n", i, p_param->temp_layer[i].qp_b);
+ return -EINVAL;
+ }
+ if (p_param->temp_layer[i].qp_p > 51) {
+ dev_err(dev, "temp_layer[%d].qp_p: %d\n", i, p_param->temp_layer[i].qp_p);
+ return -EINVAL;
+ }
+ if (p_param->temp_layer[i].qp_i > 51) {
+ dev_err(dev, "temp_layer[%d].qp_i: %d\n", i, p_param->temp_layer[i].qp_i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *pop)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ struct vpu_attr *attr = &inst->dev->attr;
+ struct enc_codec_param *p_param = &pop->codec_param;
+
+ if (inst->std != W_HEVC_ENC && inst->std != W_AVC_ENC) {
+ dev_err(dev, "std %d\n", inst->std);
+ return -EOPNOTSUPP;
+ }
+
+ if (pop->pic_width % W6_ENC_PIC_SIZE_STEP || pop->pic_height % W6_ENC_PIC_SIZE_STEP) {
+ dev_err(dev, "pic_width: %d | pic_height: %d\n", pop->pic_width, pop->pic_height);
+ return -EINVAL;
+ }
+ if (pop->pic_width < W6_MIN_ENC_PIC_WIDTH || pop->pic_width > W6_MAX_ENC_PIC_WIDTH) {
+ dev_err(dev, "pic_width: %d\n", pop->pic_width);
+ return -EINVAL;
+ }
+ if (pop->pic_height < W6_MIN_ENC_PIC_HEIGHT || pop->pic_height > W6_MAX_ENC_PIC_HEIGHT) {
+ dev_err(dev, "pic_height: %d\n", pop->pic_height);
+ return -EINVAL;
+ }
+
+ if (pop->packed_format && inst->cbcr_interleave == 1) {
+ dev_err(dev, "packed_format: %d, cbcr_interleave: %d\n",
+ pop->packed_format, inst->cbcr_interleave);
+ return -EINVAL;
+ }
+ if (pop->packed_format && inst->nv21 == 1) {
+ dev_err(dev, "packed_format: %d, nv21: %d\n", pop->packed_format, inst->nv21);
+ return -EINVAL;
+ }
+ if (pop->src_format == FORMAT_RGB_32BIT_PACKED ||
+ pop->src_format == FORMAT_YUV444_32BIT_PACKED ||
+ pop->src_format == FORMAT_RGB_P10_32BIT_PACKED ||
+ pop->src_format == FORMAT_YUV444_P10_32BIT_PACKED) {
+ if (!inst->cbcr_interleave) {
+ dev_err(dev, "src_format: %d, cbcr_interleave: %d\n",
+ pop->src_format, inst->cbcr_interleave);
+ return -EINVAL;
+ }
+ if (inst->nv21 == 1) {
+ dev_err(dev, "src_format: %d, nv21: %d\n", pop->src_format, inst->nv21);
+ return -EINVAL;
+ }
+ }
+ if (pop->src_format == FORMAT_RGB_24BIT_PACKED ||
+ pop->src_format == FORMAT_YUV444_24BIT_PACKED) {
+ if (!inst->cbcr_interleave || inst->nv21 == 1) {
+ dev_err(dev, "src_format: %d, cbcr_interleave: %d, nv21: %d\n",
+ pop->src_format, inst->cbcr_interleave, inst->nv21);
+ return -EINVAL;
+ }
+ }
+ if (pop->src_format == FORMAT_YUV444_24BIT) {
+ if (!inst->cbcr_interleave) {
+ dev_err(dev, "src_format: %d, cbcr_interleave: %d\n",
+ pop->src_format, inst->cbcr_interleave);
+ return -EINVAL;
+ }
+ }
+
+ if (wave6_vpu_enc_check_gop_param(inst, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_gop_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_tile_slice_param(inst, pop->pic_width, pop->pic_height, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_tile_slice_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_rc_param(inst, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_rc_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_intra_param(inst, pop->pic_width, pop->pic_height, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_intra_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_custom_param(inst, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_custom_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_conf_win_size_param(inst, pop->pic_width, pop->pic_height,
+ p_param->conf_win)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_conf_win_size_param()\n");
+ return -EINVAL;
+ }
+ if (wave6_vpu_enc_check_temporal_layer_param(inst, p_param)) {
+ dev_err(dev, "failed wave6_vpu_enc_check_temporal_layer_param()\n");
+ return -EINVAL;
+ }
+
+ if (p_param->internal_bit_depth != 8 && p_param->internal_bit_depth != 10) {
+ dev_err(dev, "internal_bit_depth: %d\n", p_param->internal_bit_depth);
+ return -EINVAL;
+ }
+ if (p_param->intra_period > 2047) {
+ dev_err(dev, "intra_period: %d\n", p_param->intra_period);
+ return -EINVAL;
+ }
+ if (p_param->intra_period == 1 && p_param->gop_preset_idx == PRESET_IDX_ALL_I) {
+ dev_err(dev, "intra_period: %d, gop_preset_idx: %d\n",
+ p_param->intra_period, p_param->gop_preset_idx);
+ return -EINVAL;
+ }
+ if (p_param->en_long_term != 1 && p_param->en_long_term != 0) {
+ dev_err(dev, "en_long_term: %d\n", p_param->en_long_term);
+ return -EINVAL;
+ }
+ if (p_param->cpb_size < 10 || p_param->cpb_size > 100000) {
+ dev_err(dev, "cpb_size: %d\n", p_param->cpb_size);
+ return -EINVAL;
+ }
+ if (p_param->en_cu_level_rate_control != 1 && p_param->en_cu_level_rate_control != 0) {
+ dev_err(dev, "en_cu_level_rate_control: %d\n", p_param->en_cu_level_rate_control);
+ return -EINVAL;
+ }
+ if (p_param->en_vbv_overflow_drop_frame != 1 && p_param->en_vbv_overflow_drop_frame != 0) {
+ dev_err(dev, "en_vbv_overflow_drop_frame: %d\n",
+ p_param->en_vbv_overflow_drop_frame);
+ return -EINVAL;
+ }
+ if (p_param->en_hvs_qp != 1 && p_param->en_hvs_qp != 0) {
+ dev_err(dev, "en_hvs_qp: %d\n", p_param->en_hvs_qp);
+ return -EINVAL;
+ }
+ if (p_param->en_hvs_qp) {
+ if (p_param->hvs_qp_scale_div2 < 1 || p_param->hvs_qp_scale_div2 > 4) {
+ dev_err(dev, "hvs_qp_scale_div2: %d\n", p_param->hvs_qp_scale_div2);
+ return -EINVAL;
+ }
+ }
+ if (p_param->max_delta_qp > 12) {
+ dev_err(dev, "max_delta_qp: %d\n", p_param->max_delta_qp);
+ return -EINVAL;
+ }
+ if (p_param->rc_update_speed > 255) {
+ dev_err(dev, "rc_update_speed: %d\n", p_param->rc_update_speed);
+ return -EINVAL;
+ }
+ if (p_param->max_bitrate > 1500000000) {
+ dev_err(dev, "max_bitrate: %d\n", p_param->max_bitrate);
+ return -EINVAL;
+ }
+ if (p_param->rc_initial_level > 15) {
+ dev_err(dev, "rc_initial_level: %d\n", p_param->rc_initial_level);
+ return -EINVAL;
+ }
+ if (p_param->pic_rc_max_dqp > 51) {
+ dev_err(dev, "pic_rc_max_dqp: %d\n", p_param->pic_rc_max_dqp);
+ return -EINVAL;
+ }
+ if (p_param->en_bg_detect != 1 && p_param->en_bg_detect != 0) {
+ dev_err(dev, "en_bg_detect: %d\n", p_param->en_bg_detect);
+ return -EINVAL;
+ }
+ if (p_param->bg_th_diff > 255) {
+ dev_err(dev, "bg_th_diff: %d\n", p_param->bg_th_diff);
+ return -EINVAL;
+ }
+ if (p_param->bg_th_mean_diff > 255) {
+ dev_err(dev, "bg_th_mean_diff: %d\n", p_param->bg_th_mean_diff);
+ return -EINVAL;
+ }
+ if (p_param->bg_delta_qp < -16 || p_param->bg_delta_qp > 15) {
+ dev_err(dev, "bg_delta_qp: %d\n", p_param->bg_delta_qp);
+ return -EINVAL;
+ }
+ if (p_param->en_me_center != 1 && p_param->en_me_center != 0) {
+ dev_err(dev, "en_me_center: %d\n", p_param->en_me_center);
+ return -EINVAL;
+ }
+ if (p_param->en_dbk != 1 && p_param->en_dbk != 0) {
+ dev_err(dev, "en_dbk: %d\n", p_param->en_dbk);
+ return -EINVAL;
+ }
+ if (p_param->en_scaling_list != 1 && p_param->en_scaling_list != 0) {
+ dev_err(dev, "en_scaling_list: %d\n", p_param->en_scaling_list);
+ return -EINVAL;
+ }
+ if (p_param->en_adaptive_round != 1 && p_param->en_adaptive_round != 0) {
+ dev_err(dev, "en_adaptive_round: %d\n", p_param->en_adaptive_round);
+ return -EINVAL;
+ }
+ if (p_param->q_round_intra > 255) {
+ dev_err(dev, "q_round_intra: %d\n", p_param->q_round_intra);
+ return -EINVAL;
+ }
+ if (p_param->q_round_inter > 255) {
+ dev_err(dev, "q_round_inter: %d\n", p_param->q_round_inter);
+ return -EINVAL;
+ }
+ if (p_param->dis_coef_clear != 1 && p_param->dis_coef_clear != 0) {
+ dev_err(dev, "dis_coef_clear: %d\n", p_param->dis_coef_clear);
+ return -EINVAL;
+ }
+ if (p_param->lambda_dqp_intra < -32 || p_param->lambda_dqp_intra > 31) {
+ dev_err(dev, "lambda_dqp_intra: %d\n", p_param->lambda_dqp_intra);
+ return -EINVAL;
+ }
+ if (p_param->lambda_dqp_inter < -32 || p_param->lambda_dqp_inter > 31) {
+ dev_err(dev, "lambda_dqp_inter: %d\n", p_param->lambda_dqp_inter);
+ return -EINVAL;
+ }
+ if (p_param->en_q_round_offset != 1 && p_param->en_q_round_offset != 0) {
+ dev_err(dev, "en_q_round_offset: %d\n", p_param->en_q_round_offset);
+ return -EINVAL;
+ }
+ if (p_param->forced_idr_header > 2) {
+ dev_err(dev, "forced_idr_header: %d\n", p_param->forced_idr_header);
+ return -EINVAL;
+ }
+ if (p_param->num_units_in_tick > INT_MAX) {
+ dev_err(dev, "num_units_in_tick: %d\n", p_param->num_units_in_tick);
+ return -EINVAL;
+ }
+ if (p_param->time_scale > INT_MAX) {
+ dev_err(dev, "time_scale: %d\n", p_param->time_scale);
+ return -EINVAL;
+ }
+ if (p_param->max_intra_pic_bit > 1500000000) {
+ dev_err(dev, "max_intra_pic_bit: %d\n", p_param->max_intra_pic_bit);
+ return -EINVAL;
+ }
+ if (p_param->max_inter_pic_bit > 1500000000) {
+ dev_err(dev, "max_inter_pic_bit: %d\n", p_param->max_inter_pic_bit);
+ return -EINVAL;
+ }
+
+ if (p_param->color.color_range > 1) {
+ dev_err(dev, "color_range: %d\n", p_param->color.color_range);
+ return -EINVAL;
+ }
+ if (p_param->color.matrix_coefficients > 255) {
+ dev_err(dev, "matrix_coefficients: %d\n", p_param->color.matrix_coefficients);
+ return -EINVAL;
+ }
+ if (p_param->color.transfer_characteristics > 255) {
+ dev_err(dev, "transfer_characteristics: %d\n",
+ p_param->color.transfer_characteristics);
+ return -EINVAL;
+ }
+ if (p_param->color.color_primaries > 255) {
+ dev_err(dev, "color_primaries: %d\n", p_param->color.color_primaries);
+ return -EINVAL;
+ }
+ if (inst->std == W_HEVC_ENC) {
+ if (p_param->internal_bit_depth == 10 && !attr->support_hevc10bit_enc) {
+ dev_err(dev, "internal_bit_depth: %d, support_hevc10bit_enc: %d\n",
+ p_param->internal_bit_depth, attr->support_hevc10bit_enc);
+ return -EOPNOTSUPP;
+ }
+ if (p_param->idr_period != 0) {
+ dev_err(dev, "idr_period: %d\n", p_param->idr_period);
+ return -EINVAL;
+ }
+ if (p_param->en_strong_intra_smoothing != 1 &&
+ p_param->en_strong_intra_smoothing != 0) {
+ dev_err(dev, "en_strong_intra_smoothing: %d\n",
+ p_param->en_strong_intra_smoothing);
+ return -EINVAL;
+ }
+ if (p_param->en_constrained_intra_pred != 1 &&
+ p_param->en_constrained_intra_pred != 0) {
+ dev_err(dev, "en_constrained_intra_pred: %d\n",
+ p_param->en_constrained_intra_pred);
+ return -EINVAL;
+ }
+ if (p_param->en_intra_trans_skip != 1 && p_param->en_intra_trans_skip != 0) {
+ dev_err(dev, "en_intra_trans_skip: %d\n", p_param->en_intra_trans_skip);
+ return -EINVAL;
+ }
+ if (p_param->en_temporal_mvp != 1 && p_param->en_temporal_mvp != 0) {
+ dev_err(dev, "en_temporal_mvp: %d\n", p_param->en_temporal_mvp);
+ return -EINVAL;
+ }
+ if (p_param->en_cabac != 0) {
+ dev_err(dev, "en_cabac: %d\n", p_param->en_cabac);
+ return -EINVAL;
+ }
+ if (p_param->en_transform8x8 != 0) {
+ dev_err(dev, "en_transform8x8: %d\n", p_param->en_transform8x8);
+ return -EINVAL;
+ }
+ if (p_param->en_lf_cross_slice_boundary != 1 &&
+ p_param->en_lf_cross_slice_boundary != 0) {
+ dev_err(dev, "en_lf_cross_slice_boundary: %d\n",
+ p_param->en_lf_cross_slice_boundary);
+ return -EINVAL;
+ }
+ if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 > 6) {
+ dev_err(dev, "beta_offset_div2: %d\n", p_param->beta_offset_div2);
+ return -EINVAL;
+ }
+ if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) {
+ dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2);
+ return -EINVAL;
+ }
+ if (p_param->en_sao != 1 && p_param->en_sao != 0) {
+ dev_err(dev, "en_sao: %d\n", p_param->en_sao);
+ return -EINVAL;
+ }
+ if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) {
+ dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset);
+ return -EINVAL;
+ }
+ if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) {
+ dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset);
+ return -EINVAL;
+ }
+ if (p_param->en_still_picture != 1 && p_param->en_still_picture != 0) {
+ dev_err(dev, "en_still_picture: %d\n", p_param->en_still_picture);
+ return -EINVAL;
+ }
+ if (p_param->en_auto_level_adjusting != 1 &&
+ p_param->en_auto_level_adjusting != 0) {
+ dev_err(dev, "en_auto_level_adjusting: %d\n",
+ p_param->en_auto_level_adjusting);
+ return -EINVAL;
+ }
+ if (p_param->tier > 1) {
+ dev_err(dev, "tier: %d\n", p_param->tier);
+ return -EINVAL;
+ }
+ if (p_param->profile > HEVC_PROFILE_STILLPICTURE) {
+ dev_err(dev, "profile: %d\n", p_param->profile);
+ return -EINVAL;
+ }
+ if (p_param->internal_bit_depth == 10 && p_param->profile == HEVC_PROFILE_MAIN) {
+ dev_err(dev, "internal_bit_depth: %d, profile: %d\n",
+ p_param->internal_bit_depth, p_param->profile);
+ return -EINVAL;
+ }
+ if (p_param->num_ticks_poc_diff_one < 1 ||
+ p_param->num_ticks_poc_diff_one > 65535) {
+ dev_err(dev, "num_ticks_poc_diff_one: %d\n",
+ p_param->num_ticks_poc_diff_one);
+ return -EINVAL;
+ }
+ if (p_param->color.chroma_sample_position != 0) {
+ dev_err(dev, "chroma_sample_position: %d\n",
+ p_param->color.chroma_sample_position);
+ return -EINVAL;
+ }
+ if (p_param->intra_4x4 > 3 || p_param->intra_4x4 == 1) {
+ dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4);
+ return -EINVAL;
+ }
+ } else if (inst->std == W_AVC_ENC) {
+ if (p_param->internal_bit_depth == 10 && !attr->support_avc10bit_enc) {
+ dev_err(dev, "internal_bit_depth: %d, support_avc10bit_enc: %d\n",
+ p_param->internal_bit_depth, attr->support_avc10bit_enc);
+ return -EOPNOTSUPP;
+ }
+ if (p_param->idr_period > 2047) {
+ dev_err(dev, "idr_period: %d\n", p_param->idr_period);
+ return -EINVAL;
+ }
+ if (p_param->idr_period == 1 && p_param->gop_preset_idx == PRESET_IDX_ALL_I) {
+ dev_err(dev, "idr_period: %d, gop_preset_idx: %d\n",
+ p_param->idr_period, p_param->gop_preset_idx);
+ return -EINVAL;
+ }
+ if (p_param->en_strong_intra_smoothing != 0) {
+ dev_err(dev, "en_strong_intra_smoothing: %d\n",
+ p_param->en_strong_intra_smoothing);
+ return -EINVAL;
+ }
+ if (p_param->en_constrained_intra_pred != 1 &&
+ p_param->en_constrained_intra_pred != 0) {
+ dev_err(dev, "en_constrained_intra_pred: %d\n",
+ p_param->en_constrained_intra_pred);
+ return -EINVAL;
+ }
+ if (p_param->en_intra_trans_skip != 0) {
+ dev_err(dev, "en_intra_trans_skip: %d\n", p_param->en_intra_trans_skip);
+ return -EINVAL;
+ }
+ if (p_param->en_temporal_mvp != 0) {
+ dev_err(dev, "en_temporal_mvp: %d\n", p_param->en_temporal_mvp);
+ return -EINVAL;
+ }
+ if (p_param->en_cabac != 1 && p_param->en_cabac != 0) {
+ dev_err(dev, "en_cabac: %d\n", p_param->en_cabac);
+ return -EINVAL;
+ }
+ if (p_param->en_transform8x8 != 1 && p_param->en_transform8x8 != 0) {
+ dev_err(dev, "en_transform8x8: %d\n", p_param->en_transform8x8);
+ return -EINVAL;
+ }
+ if (p_param->en_lf_cross_slice_boundary != 1 &&
+ p_param->en_lf_cross_slice_boundary != 0) {
+ dev_err(dev, "en_lf_cross_slice_boundary: %d\n",
+ p_param->en_lf_cross_slice_boundary);
+ return -EINVAL;
+ }
+ if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 > 6) {
+ dev_err(dev, "beta_offset_div2: %d\n", p_param->beta_offset_div2);
+ return -EINVAL;
+ }
+ if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) {
+ dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2);
+ return -EINVAL;
+ }
+ if (p_param->en_sao != 0) {
+ dev_err(dev, "en_sao: %d\n", p_param->en_sao);
+ return -EINVAL;
+ }
+ if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) {
+ dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset);
+ return -EINVAL;
+ }
+ if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) {
+ dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset);
+ return -EINVAL;
+ }
+ if (p_param->en_still_picture != 0) {
+ dev_err(dev, "en_still_picture: %d\n", p_param->en_still_picture);
+ return -EINVAL;
+ }
+ if (p_param->en_auto_level_adjusting != 1 &&
+ p_param->en_auto_level_adjusting != 0) {
+ dev_err(dev, "en_auto_level_adjusting: %d\n",
+ p_param->en_auto_level_adjusting);
+ return -EINVAL;
+ }
+ if (p_param->tier != 0) {
+ dev_err(dev, "tier: %d\n", p_param->tier);
+ return -EINVAL;
+ }
+ if (p_param->profile > H264_PROFILE_HIGH10) {
+ dev_err(dev, "profile: %d\n", p_param->profile);
+ return -EINVAL;
+ }
+ if (p_param->profile) {
+ if (p_param->internal_bit_depth == 10 &&
+ p_param->profile != H264_PROFILE_HIGH10) {
+ dev_err(dev, "internal_bit_depth: %d, profile: %d\n",
+ p_param->internal_bit_depth, p_param->profile);
+ return -EINVAL;
+ }
+ }
+ if (p_param->num_ticks_poc_diff_one != 0) {
+ dev_err(dev, "num_ticks_poc_diff_one: %d\n",
+ p_param->num_ticks_poc_diff_one);
+ return -EINVAL;
+ }
+ if (p_param->color.chroma_sample_position != 0) {
+ dev_err(dev, "chroma_sample_position: %d\n",
+ p_param->color.chroma_sample_position);
+ return -EINVAL;
+ }
+ if (p_param->intra_4x4 != 0) {
+ dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-hw.h b/drivers/media/platform/chips-media/wave6/wave6-hw.h
new file mode 100644
index 000000000000..a40477dc023e
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-hw.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 backend interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_HW_H__
+#define __WAVE6_HW_H__
+
+#define STD_AVC 0
+#define STD_HEVC 12
+
+enum product_id {
+ PRODUCT_ID_617,
+ PRODUCT_ID_627,
+ PRODUCT_ID_637,
+ PRODUCT_ID_NONE,
+};
+
+#define BSOPTION_ENABLE_EXPLICIT_END BIT(0)
+#define NON_VCL_PARAM_ENCODE_VUI BIT(1)
+
+#define DECODE_ALL_TEMPORAL_LAYERS 0
+#define DECODE_ALL_SPATIAL_LAYERS 0
+
+#define REGISTER_DISPLAY_BUFFER 1
+#define DEFAULT_PIXEL_ORDER 1
+
+#define WTL_RIGHT_JUSTIFIED 0
+#define WTL_LEFT_JUSTIFIED 1
+#define WTL_PIXEL_8BIT 0
+#define WTL_PIXEL_16BIT 1
+#define WTL_PIXEL_32BIT 2
+
+#define MAX_CSC_COEFF_NUM 4
+
+bool wave6_vpu_is_init(struct vpu_device *vpu_dev);
+void wave6_vpu_check_state(struct vpu_device *vpu_dev);
+int wave6_vpu_get_version(struct vpu_device *vpu_dev, u32 *version_info, uint32_t *revision);
+void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev);
+int wave6_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param);
+
+void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos);
+int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst,
+ struct frame_buffer *fb_arr, enum tiled_map_type map_type,
+ uint32_t count);
+int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct frame_buffer fb);
+int wave6_vpu_dec_init_seq(struct vpu_instance *inst);
+int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info);
+int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option, u32 *fail_res);
+int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result);
+int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res);
+dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst);
+int wave6_vpu_dec_flush(struct vpu_instance *inst);
+
+int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
+ struct enc_open_param *param);
+int wave6_vpu_enc_init_seq(struct vpu_instance *inst);
+int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed);
+int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info);
+int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst,
+ struct frame_buffer *fb_arr);
+int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res);
+int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result);
+int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res);
+int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *pop);
+
+#endif /* __WAVE6_HW_H__ */
diff --git a/drivers/media/platform/chips-media/wave6/wave6-regdefine.h b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h
new file mode 100644
index 000000000000..05d563cf9d55
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h
@@ -0,0 +1,675 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 register definitions
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_REGDEFINE_H__
+#define __WAVE6_REGDEFINE_H__
+
+enum wave6_command {
+ W6_CMD_INIT_VPU = 0x0001,
+ W6_CMD_WAKEUP_VPU = 0x0002,
+ W6_CMD_SLEEP_VPU = 0x0004,
+ W6_CMD_CREATE_INSTANCE = 0x0008,
+ W6_CMD_FLUSH_INSTANCE = 0x0010,
+ W6_CMD_DESTROY_INSTANCE = 0x0020,
+ W6_CMD_INIT_SEQ = 0x0040,
+ W6_CMD_SET_FB = 0x0080,
+ W6_CMD_DEC_PIC = 0x0100,
+ W6_CMD_ENC_PIC = 0x0100,
+ W6_CMD_ENC_SET_PARAM = 0x0200,
+ W6_CMD_DEC_SET_DISP = 0x0400,
+ W6_CMD_INIT_WORK_BUF = 0x1000,
+ W6_CMD_QUERY = 0x4000,
+};
+
+enum wave6_init_seq_option {
+ W6_INIT_SEQ_OPT_NORMAL = 1,
+ W6_INIT_SEQ_OPT_W_THUMBNAIL = 17,
+};
+
+enum wave6_set_param_option {
+ W6_SET_PARAM_OPT_COMMON = 0,
+ W6_SET_PARAM_OPT_CHANGE_PARAM = 1,
+};
+
+enum wave6_dec_pic_option {
+ W6_DEC_PIC_OPT_NORMAL = 0,
+ W6_DEC_PIC_OPT_W_THUMBNAIL = 16,
+ W6_DEC_PIC_OPT_SKIP_NON_IRAP = 17,
+ W6_DEC_PIC_OPT_SKIP_NON_REF_PIC = 19,
+};
+
+enum wave6_enc_pic_option {
+ W6_ENC_PIC_OPT_HEADER_IMPLICIT = 1,
+ W6_ENC_PIC_OPT_VCL = 2,
+};
+
+enum wave6_query_option {
+ W6_QUERY_OPT_GET_VPU_INFO = 0,
+ W6_QUERY_OPT_GET_RESULT = 2,
+ W6_QUERY_OPT_GET_FLUSH_CMD_INFO = 10,
+};
+
+enum wave6_interrupt_bit {
+ W6_INT_BIT_INIT_VPU = 0,
+ W6_INT_BIT_WAKEUP_VPU = 1,
+ W6_INT_BIT_SLEEP_VPU = 2,
+ W6_INT_BIT_CREATE_INSTANCE = 3,
+ W6_INT_BIT_FLUSH_INSTANCE = 4,
+ W6_INT_BIT_DESTROY_INSTANCE = 5,
+ W6_INT_BIT_INIT_SEQ = 6,
+ W6_INT_BIT_SET_FB = 7,
+ W6_INT_BIT_DEC_PIC = 8,
+ W6_INT_BIT_ENC_PIC = 8,
+ W6_INT_BIT_ENC_SET_PARAM = 9,
+ W6_INT_BIT_SET_DISP = 10,
+ W6_INT_BIT_REQ_WORK_BUF = 12,
+ W6_INT_BIT_BSBUF_ERROR = 15,
+};
+
+enum wave6_param_change_enable_bit {
+ W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE = 10
+};
+
+#define W6_REG_BASE 0x00000000
+#define W6_CMD_REG_BASE 0x00000200
+#define W6_CMD_REG_END 0x00000600
+
+#define W6_VPU_VCPU_CUR_PC (W6_REG_BASE + 0x0004)
+#define W6_VPU_VINT_REASON_CLR (W6_REG_BASE + 0x0034)
+#define W6_VPU_HOST_INT_REQ (W6_REG_BASE + 0x0038)
+#define W6_VPU_VINT_CLEAR (W6_REG_BASE + 0x003C)
+#define W6_VPU_VPU_INT_STS (W6_REG_BASE + 0x0044)
+#define W6_VPU_VINT_ENABLE (W6_REG_BASE + 0x0048)
+#define W6_VPU_VINT_REASON (W6_REG_BASE + 0x004C)
+#define W6_VPU_REMAP_CTRL_GB (W6_REG_BASE + 0x0060)
+#define W6_VPU_REMAP_VADDR_GB (W6_REG_BASE + 0x0064)
+#define W6_VPU_REMAP_PADDR_GB (W6_REG_BASE + 0x0068)
+#define W6_VPU_REMAP_CORE_START_GB (W6_REG_BASE + 0x006C)
+#define W6_VPU_BUSY_STATUS (W6_REG_BASE + 0x0070)
+#define W6_VPU_RET_PRODUCT_VERSION (W6_REG_BASE + 0x0094)
+
+/* COMMON */
+#define W6_COMMAND_GB (W6_REG_BASE + 0x104)
+#define W6_COMMAND (W6_REG_BASE + 0x200)
+#define W6_QUERY_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_INSTANCE_INFO (W6_REG_BASE + 0x210)
+#define W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0 (W6_REG_BASE + 0x364)
+#define W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0 (W6_REG_BASE + 0x368)
+#define W6_CMD_SET_CTRL_WORK_BUF_ADDR (W6_REG_BASE + 0x5F0)
+#define W6_CMD_SET_CTRL_WORK_BUF_SIZE (W6_REG_BASE + 0x5F4)
+#define W6_RET_SUCCESS (W6_REG_BASE + 0x208)
+#define W6_RET_FAIL_REASON (W6_REG_BASE + 0x20C)
+#define W6_RET_INSTANCE_ID (W6_REG_BASE + 0x220)
+#define W6_RET_CQ_IN_TICK (W6_REG_BASE + 0x23C)
+#define W6_RET_FW_RUN_TICK (W6_REG_BASE + 0x240)
+#define W6_RET_HW_RUN_TICK (W6_REG_BASE + 0x244)
+#define W6_RET_HW_DONE_TICK (W6_REG_BASE + 0x248)
+#define W6_RET_FW_DONE_TICK (W6_REG_BASE + 0x24C)
+#define W6_RET_RQ_OUT_TICK (W6_REG_BASE + 0x250)
+
+/* COMMON - QUERY : GET_VPU_INFO */
+#define W6_RET_FW_VERSION (W6_REG_BASE + 0x300)
+#define W6_RET_PRODUCT_NAME (W6_REG_BASE + 0x304)
+#define W6_RET_PRODUCT_VERSION (W6_REG_BASE + 0x308)
+#define W6_RET_STD_DEF0 (W6_REG_BASE + 0x30C)
+#define W6_RET_STD_DEF1 (W6_REG_BASE + 0x310)
+#define W6_RET_CONF_FEATURE (W6_REG_BASE + 0x314)
+#define W6_RET_CONF_DATE (W6_REG_BASE + 0x318)
+#define W6_RET_CONF_REVISION (W6_REG_BASE + 0x31C)
+#define W6_RET_CONF_TYPE (W6_REG_BASE + 0x320)
+#define W6_RET_FW_API_VERSION (W6_REG_BASE + 0x32C)
+#define W6_RET_SHA_ID (W6_REG_BASE + 0x330)
+
+/* DECODER - CREATE_INSTANCE */
+#define W6_CMD_DEC_CREATE_INST_BS_PARAM (W6_REG_BASE + 0x310)
+#define W6_CMD_DEC_CREATE_INST_ADDR_EXT (W6_REG_BASE + 0x318)
+#define W6_CMD_DEC_CREATE_INST_DISP_MODE (W6_REG_BASE + 0x31C)
+#define W6_CMD_DEC_CREATE_INST_CORE_INFO (W6_REG_BASE + 0x330)
+#define W6_CMD_DEC_CREATE_INST_PRIORITY (W6_REG_BASE + 0x334)
+#define W6_CMD_DEC_CREATE_INST_TEMP_BASE (W6_REG_BASE + 0x348)
+#define W6_CMD_DEC_CREATE_INST_TEMP_SIZE (W6_REG_BASE + 0x34C)
+#define W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT (W6_REG_BASE + 0x3A8)
+
+/* DECODER - INIT_SEQ */
+#define W6_CMD_DEC_INIT_SEQ_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_DEC_INIT_SEQ_BS_RD_PTR (W6_REG_BASE + 0x300)
+#define W6_CMD_DEC_INIT_SEQ_BS_WR_PTR (W6_REG_BASE + 0x304)
+#define W6_CMD_DEC_INIT_SEQ_BS_OPTION (W6_REG_BASE + 0x308)
+
+/* DECODER - SET_FB */
+#define W6_CMD_DEC_SET_FB_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_DEC_SET_FB_COMMON_PIC_INFO (W6_REG_BASE + 0x300)
+#define W6_CMD_DEC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304)
+#define W6_CMD_DEC_SET_FB_NUM (W6_REG_BASE + 0x308)
+#define W6_CMD_DEC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310)
+#define W6_CMD_DEC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE + 0x318)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE + 0x31C)
+#define W6_CMD_DEC_SET_FB_MV_COL0 (W6_REG_BASE + 0x320)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE + 0x324)
+#define W6_CMD_DEC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328)
+#define W6_CMD_DEC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE + 0x330)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE + 0x334)
+#define W6_CMD_DEC_SET_FB_MV_COL1 (W6_REG_BASE + 0x338)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE + 0x33C)
+#define W6_CMD_DEC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340)
+#define W6_CMD_DEC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE + 0x348)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE + 0x34C)
+#define W6_CMD_DEC_SET_FB_MV_COL2 (W6_REG_BASE + 0x350)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE + 0x354)
+#define W6_CMD_DEC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358)
+#define W6_CMD_DEC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE + 0x360)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE + 0x364)
+#define W6_CMD_DEC_SET_FB_MV_COL3 (W6_REG_BASE + 0x368)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE + 0x36C)
+#define W6_CMD_DEC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370)
+#define W6_CMD_DEC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE + 0x378)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE + 0x37C)
+#define W6_CMD_DEC_SET_FB_MV_COL4 (W6_REG_BASE + 0x380)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE + 0x384)
+#define W6_CMD_DEC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388)
+#define W6_CMD_DEC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE + 0x390)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE + 0x394)
+#define W6_CMD_DEC_SET_FB_MV_COL5 (W6_REG_BASE + 0x398)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE + 0x39C)
+#define W6_CMD_DEC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0)
+#define W6_CMD_DEC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE + 0x3A8)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE + 0x3AC)
+#define W6_CMD_DEC_SET_FB_MV_COL6 (W6_REG_BASE + 0x3B0)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE + 0x3B4)
+#define W6_CMD_DEC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8)
+#define W6_CMD_DEC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE + 0x3C0)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE + 0x3C4)
+#define W6_CMD_DEC_SET_FB_MV_COL7 (W6_REG_BASE + 0x3C8)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE + 0x3CC)
+#define W6_CMD_DEC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0)
+#define W6_CMD_DEC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE + 0x3D8)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE + 0x3DC)
+#define W6_CMD_DEC_SET_FB_MV_COL8 (W6_REG_BASE + 0x3E0)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE + 0x3E4)
+#define W6_CMD_DEC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8)
+#define W6_CMD_DEC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE + 0x3F0)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE + 0x3F4)
+#define W6_CMD_DEC_SET_FB_MV_COL9 (W6_REG_BASE + 0x3F8)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE + 0x3FC)
+#define W6_CMD_DEC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400)
+#define W6_CMD_DEC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE + 0x408)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE + 0x40C)
+#define W6_CMD_DEC_SET_FB_MV_COL10 (W6_REG_BASE + 0x410)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE + 0x414)
+#define W6_CMD_DEC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418)
+#define W6_CMD_DEC_SET_FB_FBC_C11 (W6_REG_BASE + 0x41C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE + 0x420)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE + 0x424)
+#define W6_CMD_DEC_SET_FB_MV_COL11 (W6_REG_BASE + 0x428)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE + 0x42C)
+#define W6_CMD_DEC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430)
+#define W6_CMD_DEC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE + 0x438)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE + 0x43C)
+#define W6_CMD_DEC_SET_FB_MV_COL12 (W6_REG_BASE + 0x440)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE + 0x444)
+#define W6_CMD_DEC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448)
+#define W6_CMD_DEC_SET_FB_FBC_C13 (W6_REG_BASE + 0x44C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE + 0x450)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE + 0x454)
+#define W6_CMD_DEC_SET_FB_MV_COL13 (W6_REG_BASE + 0x458)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE + 0x45C)
+#define W6_CMD_DEC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460)
+#define W6_CMD_DEC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE + 0x468)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE + 0x46C)
+#define W6_CMD_DEC_SET_FB_MV_COL14 (W6_REG_BASE + 0x470)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE + 0x474)
+#define W6_CMD_DEC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478)
+#define W6_CMD_DEC_SET_FB_FBC_C15 (W6_REG_BASE + 0x47C)
+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE + 0x480)
+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE + 0x484)
+#define W6_CMD_DEC_SET_FB_MV_COL15 (W6_REG_BASE + 0x488)
+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE + 0x48C)
+#define W6_CMD_DEC_SET_FB_DEFAULT_CDF (W6_REG_BASE + 0x494)
+#define W6_CMD_DEC_SET_FB_SEGMAP (W6_REG_BASE + 0x498)
+#define W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT (W6_REG_BASE + 0x4DC)
+#define W6_CMD_DEC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE + 0x4F4)
+#define W6_CMD_DEC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE + 0x4FC)
+#define W6_CMD_DEC_SET_FB_FBC_CR2 (W6_REG_BASE + 0x500)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE + 0x504)
+#define W6_CMD_DEC_SET_FB_FBC_CR3 (W6_REG_BASE + 0x508)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE + 0x50C)
+#define W6_CMD_DEC_SET_FB_FBC_CR4 (W6_REG_BASE + 0x510)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE + 0x514)
+#define W6_CMD_DEC_SET_FB_FBC_CR5 (W6_REG_BASE + 0x518)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE + 0x51C)
+#define W6_CMD_DEC_SET_FB_FBC_CR6 (W6_REG_BASE + 0x520)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE + 0x524)
+#define W6_CMD_DEC_SET_FB_FBC_CR7 (W6_REG_BASE + 0x528)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE + 0x52C)
+#define W6_CMD_DEC_SET_FB_FBC_CR8 (W6_REG_BASE + 0x530)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE + 0x534)
+#define W6_CMD_DEC_SET_FB_FBC_CR9 (W6_REG_BASE + 0x538)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE + 0x53C)
+#define W6_CMD_DEC_SET_FB_FBC_CR10 (W6_REG_BASE + 0x540)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE + 0x544)
+#define W6_CMD_DEC_SET_FB_FBC_CR11 (W6_REG_BASE + 0x548)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE + 0x54C)
+#define W6_CMD_DEC_SET_FB_FBC_CR12 (W6_REG_BASE + 0x550)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE + 0x554)
+#define W6_CMD_DEC_SET_FB_FBC_CR13 (W6_REG_BASE + 0x558)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE + 0x55C)
+#define W6_CMD_DEC_SET_FB_FBC_CR14 (W6_REG_BASE + 0x560)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE + 0x564)
+#define W6_CMD_DEC_SET_FB_FBC_CR15 (W6_REG_BASE + 0x568)
+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE + 0x56C)
+
+/* DECODER - SET_DISP */
+#define W6_CMD_DEC_SET_DISP_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO (W6_REG_BASE + 0x300)
+#define W6_CMD_DEC_SET_DISP_PIC_SIZE (W6_REG_BASE + 0x304)
+#define W6_CMD_DEC_SET_DISP_PIC_INFO (W6_REG_BASE + 0x308)
+#define W6_CMD_DEC_SET_DISP_Y_BASE (W6_REG_BASE + 0x30C)
+#define W6_CMD_DEC_SET_DISP_CB_BASE (W6_REG_BASE + 0x310)
+#define W6_CMD_DEC_SET_DISP_CR_BASE (W6_REG_BASE + 0x314)
+#define W6_CMD_DEC_SET_DISP_SCL_PARAM (W6_REG_BASE + 0x318)
+#define W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE (W6_REG_BASE + 0x31C)
+
+/* DECODER - DEC_PIC */
+#define W6_CMD_DEC_PIC_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_DEC_PIC_BS_RD_PTR (W6_REG_BASE + 0x300)
+#define W6_CMD_DEC_PIC_BS_WR_PTR (W6_REG_BASE + 0x304)
+#define W6_CMD_DEC_PIC_BS_OPTION (W6_REG_BASE + 0x308)
+#define W6_CMD_DEC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C)
+#define W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG (W6_REG_BASE + 0x310)
+#define W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1 (W6_REG_BASE + 0x318)
+#define W6_CMD_DEC_PIC_TIMESTAMP (W6_REG_BASE + 0x32C)
+
+/* DECODER - QUERY : GET_RESULT */
+#define W6_RET_DEC_BS_RD_PTR (W6_REG_BASE + 0x30C)
+#define W6_RET_DEC_SEQ_PARAM (W6_REG_BASE + 0x310)
+#define W6_RET_DEC_COLOR_SAMPLE_INFO (W6_REG_BASE + 0x314)
+#define W6_RET_DEC_ASPECT_RATIO (W6_REG_BASE + 0x318)
+#define W6_RET_DEC_BIT_RATE (W6_REG_BASE + 0x31C)
+#define W6_RET_DEC_FRAME_RATE_NR (W6_REG_BASE + 0x320)
+#define W6_RET_DEC_FRAME_RATE_DR (W6_REG_BASE + 0x324)
+#define W6_RET_DEC_NUM_REQUIRED_FBC_FB (W6_REG_BASE + 0x328)
+#define W6_RET_DEC_NUM_REORDER_DELAY (W6_REG_BASE + 0x32C)
+#define W6_RET_DEC_NOTIFICATION (W6_REG_BASE + 0x334)
+#define W6_RET_DEC_PIC_SIZE (W6_REG_BASE + 0x33C)
+#define W6_RET_DEC_CROP_TOP_BOTTOM (W6_REG_BASE + 0x340)
+#define W6_RET_DEC_CROP_LEFT_RIGHT (W6_REG_BASE + 0x344)
+#define W6_RET_DEC_AU_START_POS (W6_REG_BASE + 0x348)
+#define W6_RET_DEC_AU_END_POS (W6_REG_BASE + 0x34C)
+#define W6_RET_DEC_PIC_TYPE (W6_REG_BASE + 0x350)
+#define W6_RET_DEC_PIC_POC (W6_REG_BASE + 0x354)
+#define W6_RET_DEC_RECOVERY_POINT (W6_REG_BASE + 0x358)
+#define W6_RET_DEC_DECODED_ADDR (W6_REG_BASE + 0x360)
+#define W6_RET_DEC_DISPLAY_ADDR (W6_REG_BASE + 0x364)
+#define W6_RET_DEC_ERR_CTB_NUM (W6_REG_BASE + 0x370)
+#define W6_RET_DEC_DISPLAY_FLAG (W6_REG_BASE + 0x3A8)
+#define W6_RET_DEC_RELEASE_IDC (W6_REG_BASE + 0x3AC)
+#define W6_RET_DEC_DISP_IDC (W6_REG_BASE + 0x3B0)
+#define W6_RET_DEC_STREAM_END (W6_REG_BASE + 0x3C0)
+#define W6_RET_DEC_DECODED_FLAG (W6_REG_BASE + 0x3C4)
+#define W6_RET_DEC_WARN_INFO (W6_REG_BASE + 0x3CC)
+#define W6_RET_DEC_ERR_INFO (W6_REG_BASE + 0x3D0)
+#define W6_RET_DEC_DECODING_SUCCESS (W6_REG_BASE + 0x3D4)
+#define W6_RET_DEC_TIMESTAMP (W6_REG_BASE + 0x3D8)
+#define W6_RET_DEC_LAST_FRAME_FLAG (W6_REG_BASE + 0x3E0)
+#define W6_RET_DEC_NUM_REQUIRED_COL_BUF (W6_REG_BASE + 0x3E4)
+#define W6_RET_DEC_DISP_LINEAR_ADDR_0 (W6_REG_BASE + 0x3E8)
+#define W6_RET_DEC_DISP_LINEAR_ADDR_30 (W6_REG_BASE + 0x460)
+#define W6_RET_DEC_COLOR_CONFIG (W6_REG_BASE + 0x57C)
+
+/* DECODER - QUERY : GET_FLUSH_CMD_INFO */
+#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 (W6_REG_BASE + 0x300)
+#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_1E (W6_REG_BASE + 0x378)
+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC (W6_REG_BASE + 0x57C)
+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC (W6_REG_BASE + 0x580)
+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC (W6_REG_BASE + 0x584)
+
+/* ENCODER - CREATE_INSTANCE */
+#define W6_CMD_ENC_CREATE_INST_BS_PARAM (W6_REG_BASE + 0x310)
+#define W6_CMD_ENC_CREATE_INST_SRC_OPT (W6_REG_BASE + 0x314)
+#define W6_CMD_ENC_CREATE_INST_ADDR_EXT (W6_REG_BASE + 0x318)
+#define W6_CMD_ENC_CREATE_INST_CORE_INFO (W6_REG_BASE + 0x330)
+#define W6_CMD_ENC_CREATE_INST_PRIORITY (W6_REG_BASE + 0x334)
+#define W6_CMD_ENC_CREATE_INST_TEMP_BASE (W6_REG_BASE + 0x348)
+#define W6_CMD_ENC_CREATE_INST_TEMP_SIZE (W6_REG_BASE + 0x34C)
+#define W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE (W6_REG_BASE + 0x358)
+#define W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT (W6_REG_BASE + 0x3A8)
+
+/* ENCODER - SET_PARAM */
+#define W6_CMD_ENC_SET_PARAM_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_ENC_SET_PARAM_ENABLE (W6_REG_BASE + 0x300)
+#define W6_CMD_ENC_SET_PARAM_SRC_SIZE (W6_REG_BASE + 0x304)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN (W6_REG_BASE + 0x308)
+#define W6_CMD_ENC_SET_PARAM_SPS_PARAM (W6_REG_BASE + 0x30C)
+#define W6_CMD_ENC_SET_PARAM_PPS_PARAM (W6_REG_BASE + 0x310)
+#define W6_CMD_ENC_SET_PARAM_GOP_PARAM (W6_REG_BASE + 0x314)
+#define W6_CMD_ENC_SET_PARAM_INTRA_PARAM (W6_REG_BASE + 0x318)
+#define W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT (W6_REG_BASE + 0x31C)
+#define W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT (W6_REG_BASE + 0x320)
+#define W6_CMD_ENC_SET_PARAM_RDO_PARAM (W6_REG_BASE + 0x324)
+#define W6_CMD_ENC_SET_PARAM_SLICE_PARAM (W6_REG_BASE + 0x328)
+#define W6_CMD_ENC_SET_PARAM_INTRA_REFRESH (W6_REG_BASE + 0x32C)
+#define W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP (W6_REG_BASE + 0x330)
+#define W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE (W6_REG_BASE + 0x334)
+#define W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE (W6_REG_BASE + 0x338)
+#define W6_CMD_ENC_SET_PARAM_RC_PARAM (W6_REG_BASE + 0x33C)
+#define W6_CMD_ENC_SET_PARAM_HVS_PARAM (W6_REG_BASE + 0x340)
+#define W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE (W6_REG_BASE + 0x344)
+#define W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE (W6_REG_BASE + 0x348)
+#define W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP (W6_REG_BASE + 0x34C)
+#define W6_CMD_ENC_SET_PARAM_ROT_PARAM (W6_REG_BASE + 0x350)
+#define W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK (W6_REG_BASE + 0x354)
+#define W6_CMD_ENC_SET_PARAM_TIME_SCALE (W6_REG_BASE + 0x358)
+#define W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE (W6_REG_BASE + 0x35C)
+#define W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT (W6_REG_BASE + 0x360)
+#define W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT (W6_REG_BASE + 0x364)
+#define W6_CMD_ENC_SET_PARAM_BG_PARAM (W6_REG_BASE + 0x36C)
+#define W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM (W6_REG_BASE + 0x370)
+#define W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR (W6_REG_BASE + 0x374)
+#define W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR (W6_REG_BASE + 0x378)
+#define W6_CMD_ENC_SET_PARAM_QROUND_OFFSET (W6_REG_BASE + 0x380)
+#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1 (W6_REG_BASE + 0x384)
+#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2 (W6_REG_BASE + 0x388)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM (W6_REG_BASE + 0x38C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0 (W6_REG_BASE + 0x390)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_1 (W6_REG_BASE + 0x394)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_2 (W6_REG_BASE + 0x398)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_3 (W6_REG_BASE + 0x39C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_4 (W6_REG_BASE + 0x3A0)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_5 (W6_REG_BASE + 0x3A4)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_6 (W6_REG_BASE + 0x3A8)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_7 (W6_REG_BASE + 0x3AC)
+#define W6_CMD_ENC_SET_PARAM_TILE_PARAM (W6_REG_BASE + 0x3D0)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0 (W6_REG_BASE + 0x3D4)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_1 (W6_REG_BASE + 0x3D8)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_2 (W6_REG_BASE + 0x3DC)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_3 (W6_REG_BASE + 0x3E0)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_4 (W6_REG_BASE + 0x3E4)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_5 (W6_REG_BASE + 0x3E8)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_6 (W6_REG_BASE + 0x3EC)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_7 (W6_REG_BASE + 0x3F0)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_8 (W6_REG_BASE + 0x3F4)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_9 (W6_REG_BASE + 0x3F8)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_10 (W6_REG_BASE + 0x3FC)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_11 (W6_REG_BASE + 0x400)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_12 (W6_REG_BASE + 0x404)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_13 (W6_REG_BASE + 0x408)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_14 (W6_REG_BASE + 0x40C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_15 (W6_REG_BASE + 0x410)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_16 (W6_REG_BASE + 0x414)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_17 (W6_REG_BASE + 0x418)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_18 (W6_REG_BASE + 0x41C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_19 (W6_REG_BASE + 0x420)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_20 (W6_REG_BASE + 0x424)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_21 (W6_REG_BASE + 0x428)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_22 (W6_REG_BASE + 0x42C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_23 (W6_REG_BASE + 0x430)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_24 (W6_REG_BASE + 0x434)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_25 (W6_REG_BASE + 0x438)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_26 (W6_REG_BASE + 0x43C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_27 (W6_REG_BASE + 0x440)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_28 (W6_REG_BASE + 0x444)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_29 (W6_REG_BASE + 0x448)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_30 (W6_REG_BASE + 0x44C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_31 (W6_REG_BASE + 0x450)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_32 (W6_REG_BASE + 0x454)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_33 (W6_REG_BASE + 0x458)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_34 (W6_REG_BASE + 0x45C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_35 (W6_REG_BASE + 0x460)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_36 (W6_REG_BASE + 0x464)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_37 (W6_REG_BASE + 0x468)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_38 (W6_REG_BASE + 0x46C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_39 (W6_REG_BASE + 0x470)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_40 (W6_REG_BASE + 0x474)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_41 (W6_REG_BASE + 0x478)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_42 (W6_REG_BASE + 0x47C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_43 (W6_REG_BASE + 0x480)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_44 (W6_REG_BASE + 0x484)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_45 (W6_REG_BASE + 0x488)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_46 (W6_REG_BASE + 0x48C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_47 (W6_REG_BASE + 0x490)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_48 (W6_REG_BASE + 0x494)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_49 (W6_REG_BASE + 0x498)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_50 (W6_REG_BASE + 0x49C)
+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_51 (W6_REG_BASE + 0x4A0)
+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP (W6_REG_BASE + 0x4A4)
+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_1_QP (W6_REG_BASE + 0x4A8)
+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_2_QP (W6_REG_BASE + 0x4AC)
+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_3_QP (W6_REG_BASE + 0x4B0)
+#define W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE (W6_REG_BASE + 0x4B4)
+#define W6_CMD_ENC_SET_PARAM_SCL_PARAM (W6_REG_BASE + 0x4B8)
+#define W6_CMD_ENC_SET_PARAM_COLOR_PARAM (W6_REG_BASE + 0x4F8)
+#define W6_CMD_ENC_SET_PARAM_SAR_PARAM (W6_REG_BASE + 0x4FC)
+#define W6_CMD_ENC_SET_PARAM_SAR_EXTENDED (W6_REG_BASE + 0x500)
+
+/* ENCODER - SET_FB */
+#define W6_CMD_ENC_SET_FB_OPTION (W6_REG_BASE + 0x204)
+#define W6_CMD_ENC_SET_FB_PIC_INFO (W6_REG_BASE + 0x300)
+#define W6_CMD_ENC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304)
+#define W6_CMD_ENC_SET_FB_NUM (W6_REG_BASE + 0x308)
+#define W6_CMD_ENC_SET_FB_FBC_STRIDE (W6_REG_BASE + 0x30C)
+#define W6_CMD_ENC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310)
+#define W6_CMD_ENC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE + 0x318)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE + 0x31C)
+#define W6_CMD_ENC_SET_FB_MV_COL0 (W6_REG_BASE + 0x320)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE + 0x324)
+#define W6_CMD_ENC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328)
+#define W6_CMD_ENC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE + 0x330)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE + 0x334)
+#define W6_CMD_ENC_SET_FB_MV_COL1 (W6_REG_BASE + 0x338)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE + 0x33C)
+#define W6_CMD_ENC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340)
+#define W6_CMD_ENC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE + 0x348)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE + 0x34C)
+#define W6_CMD_ENC_SET_FB_MV_COL2 (W6_REG_BASE + 0x350)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE + 0x354)
+#define W6_CMD_ENC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358)
+#define W6_CMD_ENC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE + 0x360)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE + 0x364)
+#define W6_CMD_ENC_SET_FB_MV_COL3 (W6_REG_BASE + 0x368)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE + 0x36C)
+#define W6_CMD_ENC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370)
+#define W6_CMD_ENC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE + 0x378)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE + 0x37C)
+#define W6_CMD_ENC_SET_FB_MV_COL4 (W6_REG_BASE + 0x380)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE + 0x384)
+#define W6_CMD_ENC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388)
+#define W6_CMD_ENC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE + 0x390)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE + 0x394)
+#define W6_CMD_ENC_SET_FB_MV_COL5 (W6_REG_BASE + 0x398)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE + 0x39C)
+#define W6_CMD_ENC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0)
+#define W6_CMD_ENC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE + 0x3A8)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE + 0x3AC)
+#define W6_CMD_ENC_SET_FB_MV_COL6 (W6_REG_BASE + 0x3B0)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE + 0x3B4)
+#define W6_CMD_ENC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8)
+#define W6_CMD_ENC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE + 0x3C0)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE + 0x3C4)
+#define W6_CMD_ENC_SET_FB_MV_COL7 (W6_REG_BASE + 0x3C8)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE + 0x3CC)
+#define W6_CMD_ENC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0)
+#define W6_CMD_ENC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE + 0x3D8)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE + 0x3DC)
+#define W6_CMD_ENC_SET_FB_MV_COL8 (W6_REG_BASE + 0x3E0)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE + 0x3E4)
+#define W6_CMD_ENC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8)
+#define W6_CMD_ENC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE + 0x3F0)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE + 0x3F4)
+#define W6_CMD_ENC_SET_FB_MV_COL9 (W6_REG_BASE + 0x3F8)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE + 0x3FC)
+#define W6_CMD_ENC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400)
+#define W6_CMD_ENC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE + 0x408)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE + 0x40C)
+#define W6_CMD_ENC_SET_FB_MV_COL10 (W6_REG_BASE + 0x410)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE + 0x414)
+#define W6_CMD_ENC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418)
+#define W6_CMD_ENC_SET_FB_FBC_C11 (W6_REG_BASE + 0x41C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE + 0x420)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE + 0x424)
+#define W6_CMD_ENC_SET_FB_MV_COL11 (W6_REG_BASE + 0x428)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE + 0x42C)
+#define W6_CMD_ENC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430)
+#define W6_CMD_ENC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE + 0x438)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE + 0x43C)
+#define W6_CMD_ENC_SET_FB_MV_COL12 (W6_REG_BASE + 0x440)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE + 0x444)
+#define W6_CMD_ENC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448)
+#define W6_CMD_ENC_SET_FB_FBC_C13 (W6_REG_BASE + 0x44C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE + 0x450)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE + 0x454)
+#define W6_CMD_ENC_SET_FB_MV_COL13 (W6_REG_BASE + 0x458)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE + 0x45C)
+#define W6_CMD_ENC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460)
+#define W6_CMD_ENC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE + 0x468)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE + 0x46C)
+#define W6_CMD_ENC_SET_FB_MV_COL14 (W6_REG_BASE + 0x470)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE + 0x474)
+#define W6_CMD_ENC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478)
+#define W6_CMD_ENC_SET_FB_FBC_C15 (W6_REG_BASE + 0x47C)
+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE + 0x480)
+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE + 0x484)
+#define W6_CMD_ENC_SET_FB_MV_COL15 (W6_REG_BASE + 0x488)
+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE + 0x48C)
+#define W6_CMD_ENC_SET_FB_DEFAULT_CDF (W6_REG_BASE + 0x494)
+#define W6_CMD_ENC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE + 0x4F4)
+#define W6_CMD_ENC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE + 0x4FC)
+#define W6_CMD_ENC_SET_FB_FBC_CR2 (W6_REG_BASE + 0x500)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE + 0x504)
+#define W6_CMD_ENC_SET_FB_FBC_CR3 (W6_REG_BASE + 0x508)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE + 0x50C)
+#define W6_CMD_ENC_SET_FB_FBC_CR4 (W6_REG_BASE + 0x510)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE + 0x514)
+#define W6_CMD_ENC_SET_FB_FBC_CR5 (W6_REG_BASE + 0x518)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE + 0x51C)
+#define W6_CMD_ENC_SET_FB_FBC_CR6 (W6_REG_BASE + 0x520)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE + 0x524)
+#define W6_CMD_ENC_SET_FB_FBC_CR7 (W6_REG_BASE + 0x528)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE + 0x52C)
+#define W6_CMD_ENC_SET_FB_FBC_CR8 (W6_REG_BASE + 0x530)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE + 0x534)
+#define W6_CMD_ENC_SET_FB_FBC_CR9 (W6_REG_BASE + 0x538)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE + 0x53C)
+#define W6_CMD_ENC_SET_FB_FBC_CR10 (W6_REG_BASE + 0x540)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE + 0x544)
+#define W6_CMD_ENC_SET_FB_FBC_CR11 (W6_REG_BASE + 0x548)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE + 0x54C)
+#define W6_CMD_ENC_SET_FB_FBC_CR12 (W6_REG_BASE + 0x550)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE + 0x554)
+#define W6_CMD_ENC_SET_FB_FBC_CR13 (W6_REG_BASE + 0x558)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE + 0x55C)
+#define W6_CMD_ENC_SET_FB_FBC_CR14 (W6_REG_BASE + 0x560)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE + 0x564)
+#define W6_CMD_ENC_SET_FB_FBC_CR15 (W6_REG_BASE + 0x568)
+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE + 0x56C)
+
+/* ENCODER - ENC_PIC */
+#define W6_CMD_ENC_PIC_BS_START (W6_REG_BASE + 0x300)
+#define W6_CMD_ENC_PIC_BS_SIZE (W6_REG_BASE + 0x304)
+#define W6_CMD_ENC_PIC_BS_OPTION (W6_REG_BASE + 0x308)
+#define W6_CMD_ENC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C)
+#define W6_CMD_ENC_PIC_REPORT_PARAM (W6_REG_BASE + 0x310)
+#define W6_CMD_ENC_PIC_MV_HISTO_CLASS0 (W6_REG_BASE + 0x318)
+#define W6_CMD_ENC_PIC_MV_HISTO_CLASS1 (W6_REG_BASE + 0x31C)
+#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM (W6_REG_BASE + 0x320)
+#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR (W6_REG_BASE + 0x324)
+#define W6_CMD_ENC_PIC_SRC_PIC_IDX (W6_REG_BASE + 0x32C)
+#define W6_CMD_ENC_PIC_SRC_ADDR_Y (W6_REG_BASE + 0x330)
+#define W6_CMD_ENC_PIC_SRC_ADDR_U (W6_REG_BASE + 0x334)
+#define W6_CMD_ENC_PIC_SRC_ADDR_V (W6_REG_BASE + 0x338)
+#define W6_CMD_ENC_PIC_SRC_STRIDE (W6_REG_BASE + 0x33C)
+#define W6_CMD_ENC_PIC_SRC_FORMAT (W6_REG_BASE + 0x340)
+#define W6_CMD_ENC_PIC_SRC_AXI_SEL (W6_REG_BASE + 0x348)
+#define W6_CMD_ENC_PIC_CODE_OPTION (W6_REG_BASE + 0x34C)
+#define W6_CMD_ENC_PIC_PIC_PARAM (W6_REG_BASE + 0x350)
+#define W6_CMD_ENC_PIC_LONGTERM_PIC (W6_REG_BASE + 0x354)
+#define W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x358)
+#define W6_CMD_ENC_PIC_PREFIX_SEI_INFO (W6_REG_BASE + 0x35C)
+#define W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x360)
+#define W6_CMD_ENC_PIC_SUFFIX_SEI_INFO (W6_REG_BASE + 0x364)
+#define W6_CMD_ENC_PIC_CSC_COEFF_0 (W6_REG_BASE + 0x374)
+#define W6_CMD_ENC_PIC_CSC_COEFF_1 (W6_REG_BASE + 0x378)
+#define W6_CMD_ENC_PIC_CSC_COEFF_2 (W6_REG_BASE + 0x37C)
+#define W6_CMD_ENC_PIC_CSC_COEFF_3 (W6_REG_BASE + 0x380)
+#define W6_CMD_ENC_PIC_TIMESTAMP (W6_REG_BASE + 0x3F8)
+
+/* ENCODER - QUERY : GET_RESULT */
+#define W6_RET_ENC_RD_PTR (W6_REG_BASE + 0x300)
+#define W6_RET_ENC_WR_PTR (W6_REG_BASE + 0x304)
+#define W6_RET_ENC_NUM_REQUIRED_FBC_FB (W6_REG_BASE + 0x308)
+#define W6_RET_ENC_MIN_SRC_BUF_NUM (W6_REG_BASE + 0x30C)
+#define W6_RET_ENC_PIC_TYPE (W6_REG_BASE + 0x310)
+#define W6_RET_ENC_PIC_POC (W6_REG_BASE + 0x314)
+#define W6_RET_ENC_PIC_IDX (W6_REG_BASE + 0x318)
+#define W6_RET_ENC_PIC_SLICE_NUM (W6_REG_BASE + 0x31C)
+#define W6_RET_ENC_PIC_SKIP (W6_REG_BASE + 0x320)
+#define W6_RET_ENC_PIC_NUM_INTRA (W6_REG_BASE + 0x324)
+#define W6_RET_ENC_PIC_NUM_MERGE (W6_REG_BASE + 0x328)
+#define W6_RET_ENC_PIC_NON_REF_PIC_FLAG (W6_REG_BASE + 0x32C)
+#define W6_RET_ENC_PIC_NUM_SKIP (W6_REG_BASE + 0x330)
+#define W6_RET_ENC_PIC_AVG_CTU_QP (W6_REG_BASE + 0x334)
+#define W6_RET_ENC_PIC_BYTE (W6_REG_BASE + 0x338)
+#define W6_RET_ENC_GOP_PIC_IDX (W6_REG_BASE + 0x33C)
+#define W6_RET_ENC_USED_SRC_IDX (W6_REG_BASE + 0x340)
+#define W6_RET_ENC_PIC_NUM (W6_REG_BASE + 0x344)
+#define W6_RET_ENC_VCL_NUT (W6_REG_BASE + 0x348)
+#define W6_RET_ENC_PIC_DIST_LOW (W6_REG_BASE + 0x350)
+#define W6_RET_ENC_PIC_DIST_HIGH (W6_REG_BASE + 0x354)
+#define W6_RET_ENC_PIC_MAX_LATENCY_PICTURES (W6_REG_BASE + 0x358)
+#define W6_RET_ENC_HISTO_CNT_0 (W6_REG_BASE + 0x360)
+#define W6_RET_ENC_HISTO_CNT_1 (W6_REG_BASE + 0x364)
+#define W6_RET_ENC_HISTO_CNT_2 (W6_REG_BASE + 0x368)
+#define W6_RET_ENC_HISTO_CNT_3 (W6_REG_BASE + 0x36C)
+#define W6_RET_ENC_HISTO_CNT_4 (W6_REG_BASE + 0x370)
+#define W6_RET_ENC_WARN_INFO (W6_REG_BASE + 0x3AC)
+#define W6_RET_ENC_ERR_INFO (W6_REG_BASE + 0x3B0)
+#define W6_RET_ENC_ENCODING_SUCCESS (W6_REG_BASE + 0x3B4)
+#define W6_RET_ENC_SUM_ME0_X_DIR_LOWER (W6_REG_BASE + 0x3B8)
+#define W6_RET_ENC_SUM_ME0_X_DIR_HIGHER (W6_REG_BASE + 0x3BC)
+#define W6_RET_ENC_SUM_ME0_Y_DIR_LOWER (W6_REG_BASE + 0x3C0)
+#define W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER (W6_REG_BASE + 0x3C4)
+#define W6_RET_ENC_SUM_ME1_X_DIR_LOWER (W6_REG_BASE + 0x3C8)
+#define W6_RET_ENC_SUM_ME1_X_DIR_HIGHER (W6_REG_BASE + 0x3CC)
+#define W6_RET_ENC_SUM_ME1_Y_DIR_LOWER (W6_REG_BASE + 0x3D0)
+#define W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER (W6_REG_BASE + 0x3D4)
+#define W6_RET_ENC_SRC_Y_ADDR (W6_REG_BASE + 0x3E8)
+#define W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR (W6_REG_BASE + 0x3EC)
+#define W6_RET_ENC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x3F0)
+#define W6_RET_ENC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x3F4)
+#define W6_RET_ENC_TIMESTAMP (W6_REG_BASE + 0x400)
+#define W6_RET_ENC_NUM_REQUIRED_COL_BUF (W6_REG_BASE + 0x404)
+
+#endif /* __WAVE6_REGDEFINE_H__ */
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.c b/drivers/media/platform/chips-media/wave6/wave6-vdi.c
new file mode 100644
index 000000000000..c255780fef0a
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - low level access interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include "wave6-vdi.h"
+#include "wave6-vpu.h"
+#include "wave6-regdefine.h"
+#include "wave6-trace.h"
+
+#define VDI_SYSTEM_ENDIAN VDI_LITTLE_ENDIAN
+#define VDI_128BIT_BUS_SYSTEM_ENDIAN VDI_128BIT_LITTLE_ENDIAN
+
+void wave6_vdi_writel(struct vpu_device *vpu_dev, unsigned int addr, unsigned int data)
+{
+ writel(data, vpu_dev->reg_base + addr);
+ trace_writel(vpu_dev->dev, addr, data);
+}
+
+unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, u32 addr)
+{
+ unsigned int data;
+
+ data = readl(vpu_dev->reg_base + addr);
+ trace_readl(vpu_dev->dev, addr, data);
+
+ return data;
+}
+
+unsigned int wave6_vdi_convert_endian(unsigned int endian)
+{
+ switch (endian) {
+ case VDI_LITTLE_ENDIAN:
+ endian = 0x00;
+ break;
+ case VDI_BIG_ENDIAN:
+ endian = 0x0f;
+ break;
+ case VDI_32BIT_LITTLE_ENDIAN:
+ endian = 0x04;
+ break;
+ case VDI_32BIT_BIG_ENDIAN:
+ endian = 0x03;
+ break;
+ }
+
+ return (endian & 0x0f);
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.h b/drivers/media/platform/chips-media/wave6/wave6-vdi.h
new file mode 100644
index 000000000000..bb43b24547ed
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - low level access interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VDI_H__
+#define __WAVE6_VDI_H__
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include "wave6-vpuconfig.h"
+
+#define vpu_write_reg(VPU_DEV, ADDR, DATA) wave6_vdi_writel(VPU_DEV, ADDR, DATA)
+#define vpu_read_reg(VPU_DEV, ADDR) wave6_vdi_readl(VPU_DEV, ADDR)
+
+struct vpu_buf {
+ size_t size;
+ dma_addr_t daddr;
+ void *vaddr;
+ struct device *dev;
+};
+
+struct vpu_dma_buf {
+ size_t size;
+ dma_addr_t dma_addr;
+ void *vaddr;
+ phys_addr_t phys_addr;
+};
+
+enum endian_mode {
+ VDI_LITTLE_ENDIAN = 0,
+ VDI_BIG_ENDIAN,
+ VDI_32BIT_LITTLE_ENDIAN,
+ VDI_32BIT_BIG_ENDIAN,
+ VDI_128BIT_LITTLE_ENDIAN = 16,
+ VDI_128BIT_LE_BYTE_SWAP,
+ VDI_128BIT_LE_WORD_SWAP,
+ VDI_128BIT_LE_WORD_BYTE_SWAP,
+ VDI_128BIT_LE_DWORD_SWAP,
+ VDI_128BIT_LE_DWORD_BYTE_SWAP,
+ VDI_128BIT_LE_DWORD_WORD_SWAP,
+ VDI_128BIT_LE_DWORD_WORD_BYTE_SWAP,
+ VDI_128BIT_BE_DWORD_WORD_BYTE_SWAP,
+ VDI_128BIT_BE_DWORD_WORD_SWAP,
+ VDI_128BIT_BE_DWORD_BYTE_SWAP,
+ VDI_128BIT_BE_DWORD_SWAP,
+ VDI_128BIT_BE_WORD_BYTE_SWAP,
+ VDI_128BIT_BE_WORD_SWAP,
+ VDI_128BIT_BE_BYTE_SWAP,
+ VDI_128BIT_BIG_ENDIAN = 31,
+ VDI_ENDIAN_MAX
+};
+
+#define VDI_128BIT_ENDIAN_MASK 0xf
+
+#endif /* __WAVE6_VDI_H__ */
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
new file mode 100644
index 000000000000..a4f278918b15
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
@@ -0,0 +1,1001 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 helper interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/bug.h>
+#include "wave6-vpuapi.h"
+#include "wave6-regdefine.h"
+#include "wave6-hw.h"
+#include "wave6-vpu-dbg.h"
+#include "wave6-trace.h"
+
+static int wave6_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param)
+{
+ struct vpu_attr *attr = &inst->dev->attr;
+
+ if (param->bs_mode != attr->support_bitstream_mode)
+ return -EINVAL;
+
+ return 0;
+}
+
+int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *pop)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = wave6_check_dec_open_param(inst, pop);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (!wave6_vpu_is_init(vpu_dev)) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENODEV;
+ }
+
+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
+ if (!inst->codec_info) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENOMEM;
+ }
+
+ p_dec_info = &inst->codec_info->dec_info;
+ memcpy(&p_dec_info->open_param, pop, sizeof(struct dec_open_param));
+
+ ret = wave6_vpu_build_up_dec_param(inst, pop);
+ if (ret)
+ goto free_codec_info;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return 0;
+
+free_codec_info:
+ kfree(inst->codec_info);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ *fail_res = 0;
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_dec_fini_seq(inst, fail_res);
+ if (ret) {
+ dev_warn(inst->dev->dev, "dec seq end timed out\n");
+
+ if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+ }
+ }
+
+ dev_dbg(inst->dev->dev, "dec seq end complete\n");
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ kfree(inst->codec_info);
+
+ return 0;
+}
+
+int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_dec_init_seq(inst);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_dec_get_seq_info(inst, info);
+ if (!ret)
+ p_dec_info->initial_info_obtained = true;
+
+ info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
+ info->wr_ptr = p_dec_info->stream_wr_ptr;
+
+ p_dec_info->initial_info = *info;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst,
+ struct dec_aux_buffer_size_info info,
+ uint32_t *size)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int width = info.width;
+ int height = info.height;
+ int buf_size, twice;
+
+ if (info.type == AUX_BUF_FBC_Y_TBL) {
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
+ break;
+ case W_AVC_DEC:
+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ buf_size = ALIGN(buf_size, 16);
+ } else if (info.type == AUX_BUF_FBC_C_TBL) {
+ if (p_dec_info->initial_info.chroma_format_idc == 2)
+ twice = 2;
+ else if (p_dec_info->initial_info.chroma_format_idc == 3)
+ twice = 4;
+ else
+ twice = 1;
+
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
+ break;
+ case W_AVC_DEC:
+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ buf_size = buf_size * twice;
+ buf_size = ALIGN(buf_size, 16);
+ } else if (info.type == AUX_BUF_MV_COL) {
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ buf_size = WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(width, height);
+ break;
+ case W_AVC_DEC:
+ buf_size = WAVE6_DEC_AVC_MVCOL_BUF_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ buf_size = ALIGN(buf_size, 16);
+ } else {
+ return -EINVAL;
+ }
+
+ *size = buf_size;
+
+ return 0;
+}
+
+int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst,
+ struct aux_buffer_info info)
+{
+ struct dec_info *p_dec_info;
+ struct aux_buffer *aux_bufs = info.buf_array;
+ struct dec_aux_buffer_size_info size_info;
+ unsigned int expected_size;
+ unsigned int i;
+ int ret;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ size_info.width = p_dec_info->initial_info.pic_width;
+ size_info.height = p_dec_info->initial_info.pic_height;
+ size_info.type = info.type;
+
+ ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info, &expected_size);
+ if (ret)
+ return ret;
+
+ switch (info.type) {
+ case AUX_BUF_FBC_Y_TBL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ case AUX_BUF_FBC_C_TBL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ case AUX_BUF_MV_COL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_dec_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_dec_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst,
+ int num_of_dec_fbs, int stride,
+ int height, int map_type)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+ struct frame_buffer *fb;
+
+ if (num_of_dec_fbs > WAVE6_MAX_FBS)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+ p_dec_info->stride = stride;
+
+ if (!p_dec_info->initial_info_obtained)
+ return -EINVAL;
+
+ if (stride < p_dec_info->initial_info.pic_width || (stride % 8) ||
+ height < p_dec_info->initial_info.pic_height)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ fb = inst->frame_buf;
+ ret = wave6_vpu_dec_register_frame_buffer(inst, &fb[0], COMPRESSED_FRAME_MAP,
+ num_of_dec_fbs);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst, struct frame_buffer fb)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ if (!p_dec_info->initial_info_obtained)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_dec_register_display_buffer(inst, fb);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *p_rd_ptr,
+ dma_addr_t *p_wr_ptr)
+{
+ struct dec_info *p_dec_info;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ struct vpu_device *vpu_dev = inst->dev;
+ int ret;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ wr_ptr = p_dec_info->stream_wr_ptr;
+
+ if (p_rd_ptr)
+ *p_rd_ptr = rd_ptr;
+ if (p_wr_ptr)
+ *p_wr_ptr = wr_ptr;
+
+ return 0;
+}
+
+int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int size)
+{
+ struct dec_info *p_dec_info;
+ dma_addr_t wr_ptr;
+ dma_addr_t rd_ptr;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+ wr_ptr = p_dec_info->stream_wr_ptr;
+ rd_ptr = p_dec_info->stream_rd_ptr;
+
+ if (size > 0) {
+ if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size)
+ return -EINVAL;
+
+ wr_ptr += size;
+
+ p_dec_info->stream_wr_ptr = wr_ptr;
+ p_dec_info->stream_rd_ptr = rd_ptr;
+ }
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ wave6_vpu_dec_set_bitstream_end(inst, (size == 0));
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct dec_param *param, u32 *res_fail)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!p_dec_info->stride)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_decode(inst, param, res_fail);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, bool update_wr_ptr)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ p_dec_info->stream_rd_ptr = addr;
+ if (update_wr_ptr)
+ p_dec_info->stream_wr_ptr = addr;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ memset(info, 0, sizeof(*info));
+
+ ret = wave6_vpu_dec_get_result(inst, info);
+ if (ret) {
+ info->rd_ptr = p_dec_info->stream_rd_ptr;
+ info->wr_ptr = p_dec_info->stream_wr_ptr;
+ goto err_out;
+ }
+
+err_out:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *param)
+{
+ struct dec_info *p_dec_info;
+
+ if (!inst || !inst->codec_info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ switch (cmd) {
+ case ENABLE_DEC_THUMBNAIL_MODE:
+ p_dec_info->thumbnail_mode = 1;
+ break;
+ case DEC_RESET_FRAMEBUF_INFO: {
+ int i;
+
+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
+ wave6_free_dma(&inst->frame_vbuf[i]);
+ memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer));
+ memset(&p_dec_info->disp_buf[i], 0, sizeof(struct frame_buffer));
+
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
+ memset(&p_dec_info->vb_mv[i], 0, sizeof(struct vpu_buf));
+
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
+ memset(&p_dec_info->vb_fbc_y_tbl[i], 0, sizeof(struct vpu_buf));
+
+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
+ memset(&p_dec_info->vb_fbc_c_tbl[i], 0, sizeof(struct vpu_buf));
+ }
+ break;
+ }
+ case DEC_GET_SEQ_INFO: {
+ struct dec_initial_info *seq_info = param;
+
+ *seq_info = p_dec_info->initial_info;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_dec_flush_instance(struct vpu_instance *inst)
+{
+ struct vpu_device *vpu_dev = inst->dev;
+ int ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_dec_flush(inst);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *pop)
+{
+ struct enc_info *p_enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = wave6_vpu_enc_check_open_param(inst, pop);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (!wave6_vpu_is_init(vpu_dev)) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENODEV;
+ }
+
+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
+ if (!inst->codec_info) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENOMEM;
+ }
+
+ p_enc_info = &inst->codec_info->enc_info;
+ p_enc_info->open_param = *pop;
+
+ ret = wave6_vpu_build_up_enc_param(vpu_dev->dev, inst, pop);
+ if (ret)
+ goto free_codec_info;
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return 0;
+
+free_codec_info:
+ kfree(inst->codec_info);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ *fail_res = 0;
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_enc_fini_seq(inst, fail_res);
+ if (ret) {
+ dev_warn(inst->dev->dev, "enc seq end timed out\n");
+
+ if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+ }
+ }
+
+ dev_dbg(inst->dev->dev, "enc seq end timed out\n");
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ kfree(inst->codec_info);
+
+ return 0;
+}
+
+int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst,
+ struct enc_aux_buffer_size_info info,
+ uint32_t *size)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int width, height, buf_size, twice;
+
+ if (inst->std == W_AVC_ENC) {
+ width = ALIGN(info.width, 16);
+ height = ALIGN(info.height, 16);
+ if (info.rotation_angle == 90 || info.rotation_angle == 270) {
+ width = ALIGN(info.height, 16);
+ height = ALIGN(info.width, 16);
+ }
+ } else {
+ width = ALIGN(info.width, 8);
+ height = ALIGN(info.height, 8);
+ if ((info.rotation_angle || info.mirror_direction) &&
+ !(info.rotation_angle == 180 && info.mirror_direction == MIRDIR_HOR_VER)) {
+ width = ALIGN(info.width, 32);
+ height = ALIGN(info.height, 32);
+ }
+ if (info.rotation_angle == 90 || info.rotation_angle == 270) {
+ width = ALIGN(info.height, 32);
+ height = ALIGN(info.width, 32);
+ }
+ }
+
+ if (info.type == AUX_BUF_FBC_Y_TBL) {
+ switch (inst->std) {
+ case W_HEVC_ENC:
+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
+ break;
+ case W_AVC_ENC:
+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (info.type == AUX_BUF_FBC_C_TBL) {
+ switch (p_enc_info->open_param.output_format) {
+ case FORMAT_422:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ twice = 2;
+ break;
+ case FORMAT_444:
+ case FORMAT_444_P10_16BIT_MSB:
+ case FORMAT_444_P10_16BIT_LSB:
+ case FORMAT_444_P10_32BIT_MSB:
+ case FORMAT_444_P10_32BIT_LSB:
+ twice = 4;
+ break;
+ default:
+ twice = 1;
+ break;
+ }
+ switch (inst->std) {
+ case W_HEVC_ENC:
+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
+ break;
+ case W_AVC_ENC:
+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ buf_size = buf_size * twice;
+ } else if (info.type == AUX_BUF_MV_COL) {
+ switch (inst->std) {
+ case W_HEVC_ENC:
+ buf_size = WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(width, height);
+ break;
+ case W_AVC_ENC:
+ buf_size = WAVE6_ENC_AVC_MVCOL_BUF_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (info.type == AUX_BUF_SUB_SAMPLE) {
+ switch (inst->std) {
+ case W_HEVC_ENC:
+ case W_AVC_ENC:
+ buf_size = WAVE6_ENC_SUBSAMPLED_SIZE(width, height);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ *size = buf_size;
+
+ return 0;
+}
+
+int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst,
+ struct aux_buffer_info info)
+{
+ struct enc_info *p_enc_info;
+ struct aux_buffer *aux_bufs = info.buf_array;
+ struct enc_aux_buffer_size_info size_info;
+ unsigned int expected_size;
+ unsigned int i;
+ int ret;
+
+ p_enc_info = &inst->codec_info->enc_info;
+
+ size_info.width = p_enc_info->width;
+ size_info.height = p_enc_info->height;
+ size_info.type = info.type;
+ size_info.rotation_angle = p_enc_info->rotation_angle;
+ size_info.mirror_direction = p_enc_info->mirror_direction;
+
+ ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info, &expected_size);
+ if (ret)
+ return ret;
+
+ switch (info.type) {
+ case AUX_BUF_FBC_Y_TBL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ case AUX_BUF_FBC_C_TBL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ case AUX_BUF_MV_COL:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_enc_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_enc_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ case AUX_BUF_SUB_SAMPLE:
+ for (i = 0; i < info.num; i++) {
+ if (expected_size > aux_bufs[i].size)
+ return -EINVAL;
+
+ p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].daddr = aux_bufs[i].addr;
+ p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].size = aux_bufs[i].size;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int num, unsigned int stride,
+ int height, enum tiled_map_type map_type)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (p_enc_info->stride)
+ return -EINVAL;
+
+ if (!p_enc_info->initial_info_obtained)
+ return -EINVAL;
+
+ if (num < p_enc_info->initial_info.min_frame_buffer_count)
+ return -EINVAL;
+
+ if (!stride || stride % 8)
+ return -EINVAL;
+
+ if (height < 0)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ p_enc_info->num_frame_buffers = num;
+ p_enc_info->stride = stride;
+
+ ret = wave6_vpu_enc_register_frame_buffer(inst, &inst->frame_buf[0]);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+static int wave6_check_enc_param(struct vpu_instance *inst, struct enc_param *param)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ bool is_rgb_format = false;
+
+ if (!param)
+ return -EINVAL;
+
+ if (!param->skip_picture && !param->source_frame)
+ return -EINVAL;
+
+ if (!p_enc_info->open_param.codec_param.bitrate && inst->std == W_HEVC_ENC) {
+ if (param->force_pic_qp_enable) {
+ if (param->force_pic_qp_i < 0 || param->force_pic_qp_i > 63)
+ return -EINVAL;
+
+ if (param->force_pic_qp_p < 0 || param->force_pic_qp_p > 63)
+ return -EINVAL;
+
+ if (param->force_pic_qp_b < 0 || param->force_pic_qp_b > 63)
+ return -EINVAL;
+ }
+ if ((param->pic_stream_buffer_addr % 16 || !param->pic_stream_buffer_size))
+ return -EINVAL;
+ }
+
+ if ((param->pic_stream_buffer_addr % 8 || !param->pic_stream_buffer_size))
+ return -EINVAL;
+
+ if (p_enc_info->open_param.src_format == FORMAT_RGB_32BIT_PACKED ||
+ p_enc_info->open_param.src_format == FORMAT_RGB_P10_32BIT_PACKED ||
+ p_enc_info->open_param.src_format == FORMAT_RGB_24BIT_PACKED)
+ is_rgb_format = true;
+
+ if (is_rgb_format) {
+ if (param->csc.coef_ry > 1023)
+ return -EINVAL;
+ if (param->csc.coef_gy > 1023)
+ return -EINVAL;
+ if (param->csc.coef_by > 1023)
+ return -EINVAL;
+ if (param->csc.coef_rcb > 1023)
+ return -EINVAL;
+ if (param->csc.coef_gcb > 1023)
+ return -EINVAL;
+ if (param->csc.coef_bcb > 1023)
+ return -EINVAL;
+ if (param->csc.coef_rcr > 1023)
+ return -EINVAL;
+ if (param->csc.coef_gcr > 1023)
+ return -EINVAL;
+ if (param->csc.coef_bcr > 1023)
+ return -EINVAL;
+ if (param->csc.offset_y > 1023)
+ return -EINVAL;
+ if (param->csc.offset_cb > 1023)
+ return -EINVAL;
+ if (param->csc.offset_cr > 1023)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, u32 *fail_res)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ *fail_res = 0;
+
+ if (!p_enc_info->stride)
+ return -EINVAL;
+
+ ret = wave6_check_enc_param(inst, param);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_encode(inst, param, fail_res);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ memset(info, 0, sizeof(*info));
+
+ ret = wave6_vpu_enc_get_result(inst, info);
+ if (ret)
+ goto unlock;
+
+unlock:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *param)
+{
+ struct enc_info *p_enc_info;
+
+ if (!inst || !inst->codec_info)
+ return -EINVAL;
+
+ p_enc_info = &inst->codec_info->enc_info;
+
+ switch (cmd) {
+ case ENABLE_ROTATION:
+ p_enc_info->rotation_enable = true;
+ break;
+ case ENABLE_MIRRORING:
+ p_enc_info->mirror_enable = true;
+ break;
+ case SET_MIRROR_DIRECTION: {
+ enum mirror_direction mir_dir;
+
+ mir_dir = *(enum mirror_direction *)param;
+ if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR &&
+ mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER)
+ return -EINVAL;
+ p_enc_info->mirror_direction = mir_dir;
+ break;
+ }
+ case SET_ROTATION_ANGLE: {
+ int angle;
+
+ angle = *(int *)param;
+ if (angle && angle != 90 && angle != 180 && angle != 270)
+ return -EINVAL;
+ if (p_enc_info->initial_info_obtained && (angle == 90 || angle == 270))
+ return -EINVAL;
+ p_enc_info->rotation_angle = angle;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_enc_init_seq(inst);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool *changed)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_enc_change_seq(inst, changed);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave6_vpu_enc_get_seq_info(inst, info);
+ if (ret) {
+ p_enc_info->initial_info_obtained = false;
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+ }
+
+ if (!p_enc_info->initial_info_obtained) {
+ p_enc_info->initial_info_obtained = true;
+ p_enc_info->initial_info = *info;
+ }
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return 0;
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
new file mode 100644
index 000000000000..93c9a7b9374c
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
@@ -0,0 +1,993 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 helper interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPUAPI_H__
+#define __WAVE6_VPUAPI_H__
+
+#include <linux/kfifo.h>
+#include <linux/idr.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ctrls.h>
+#include "wave6-vpuerror.h"
+#include "wave6-vpuconfig.h"
+#include "wave6-vdi.h"
+#include "wave6-vpu-ctrl.h"
+
+struct vpu_attr;
+
+enum vpu_instance_type {
+ VPU_INST_TYPE_DEC = 0,
+ VPU_INST_TYPE_ENC = 1
+};
+
+enum vpu_instance_state {
+ VPU_INST_STATE_NONE = 0,
+ VPU_INST_STATE_OPEN = 1,
+ VPU_INST_STATE_INIT_SEQ = 2,
+ VPU_INST_STATE_PIC_RUN = 3,
+ VPU_INST_STATE_SEEK = 4,
+ VPU_INST_STATE_STOP = 5
+};
+
+#define WAVE6_MAX_FBS 31
+
+#define WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(_w, _h) \
+ ((ALIGN((_w), 256) / 16) * (ALIGN((_h), 64) / 16) * 1 * 16)
+#define WAVE6_DEC_AVC_MVCOL_BUF_SIZE(_w, _h) \
+ ((ALIGN((_w), 64) / 16) * (ALIGN((_h), 16) / 16) * 5 * 16)
+#define WAVE6_FBC_LUMA_TABLE_SIZE(_w, _h) \
+ (ALIGN((_w), 256) * ALIGN((_h), 64) / 32)
+#define WAVE6_FBC_CHROMA_TABLE_SIZE(_w, _h) \
+ (ALIGN(((_w) / 2), 256) * ALIGN((_h), 64) / 32)
+#define WAVE6_ENC_AVC_MVCOL_BUF_SIZE(_w, _h) \
+ ((ALIGN((_w), 512) / 512) * (ALIGN((_h), 16) / 16) * 16)
+#define WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(_w, _h) \
+ ((ALIGN((_w), 64) / 64) * (ALIGN((_h), 64) / 64) * 128)
+#define WAVE6_ENC_SUBSAMPLED_SIZE(_w, _h) \
+ (ALIGN(((_w) / 4), 16) * ALIGN(((_h) / 4), 32))
+
+enum codec_std {
+ W_HEVC_DEC = 0x00,
+ W_HEVC_ENC = 0x01,
+ W_AVC_DEC = 0x02,
+ W_AVC_ENC = 0x03,
+ STD_UNKNOWN = 0xFF
+};
+
+#define HEVC_PROFILE_MAIN 1
+#define HEVC_PROFILE_MAIN10 2
+#define HEVC_PROFILE_STILLPICTURE 3
+#define HEVC_PROFILE_MAIN10_STILLPICTURE 2
+
+#define H264_PROFILE_BP 1
+#define H264_PROFILE_MP 2
+#define H264_PROFILE_EXTENDED 3
+#define H264_PROFILE_HP 4
+#define H264_PROFILE_HIGH10 5
+
+#define H264_VUI_SAR_IDC_EXTENDED 255
+
+#define DEC_REFRESH_TYPE_NON_IRAP 0
+#define DEC_REFRESH_TYPE_IDR 2
+
+#define DEFAULT_TEMP_LAYER_CNT 1
+#define DEFAULT_RC_INITIAL_LEVEL 8
+#define DEFAULT_RC_INITIAL_QP -1
+#define DEFAULT_PIC_RC_MAX_DQP 3
+#define DEFAULT_EN_ADAPTIVE_ROUND 1
+#define DEFAULT_Q_ROUND_INTER 85
+#define DEFAULT_Q_ROUND_INTRA 171
+#define DEFAULT_EN_INTRA_TRANS_SKIP 1
+#define DEFAULT_EN_ME_CENTER 1
+#define DEFAULT_INTRA_4X4 3
+#define DEFAULT_EN_AUTO_LEVEL_ADJUSTING 1
+#define DEFAULT_NUM_TICKS_POC_DIFF 100
+#define DEFAULT_RC_UPDATE_SPEED_CBR 64
+#define DEFAULT_RC_UPDATE_SPEED_VBR 16
+#define DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG 1
+#define DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG 1
+
+#define SEQ_CHANGE_ENABLE_PROFILE BIT(5)
+#define SEQ_CHANGE_ENABLE_SIZE BIT(16)
+#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18)
+#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19)
+
+#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE | \
+ SEQ_CHANGE_ENABLE_SIZE | \
+ SEQ_CHANGE_ENABLE_BITDEPTH | \
+ SEQ_CHANGE_ENABLE_DPB_COUNT)
+
+#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \
+ SEQ_CHANGE_ENABLE_BITDEPTH | \
+ SEQ_CHANGE_ENABLE_DPB_COUNT)
+
+#define DEC_NOTI_FLAG_NO_FB 0x2
+#define DEC_NOTI_FLAG_SEQ_CHANGE 0x1
+
+#define RECON_IDX_FLAG_ENC_END -1
+#define RECON_IDX_FLAG_ENC_DELAY -2
+#define RECON_IDX_FLAG_HEADER_ONLY -3
+#define RECON_IDX_FLAG_CHANGE_PARAM -4
+
+enum codec_command {
+ ENABLE_ROTATION,
+ ENABLE_MIRRORING,
+ SET_MIRROR_DIRECTION,
+ SET_ROTATION_ANGLE,
+ ENABLE_DEC_THUMBNAIL_MODE,
+ DEC_RESET_FRAMEBUF_INFO,
+ DEC_GET_SEQ_INFO,
+};
+
+enum cb_cr_order {
+ CBCR_ORDER_NORMAL,
+ CBCR_ORDER_REVERSED
+};
+
+enum mirror_direction {
+ MIRDIR_NONE,
+ MIRDIR_VER,
+ MIRDIR_HOR,
+ MIRDIR_HOR_VER
+};
+
+enum chroma_format {
+ YUV400,
+ YUV420,
+ YUV422,
+ YUV444,
+};
+
+enum frame_buffer_format {
+ FORMAT_ERR = -1,
+
+ FORMAT_420 = 0,
+ FORMAT_422,
+ FORMAT_224,
+ FORMAT_444,
+ FORMAT_400,
+
+ FORMAT_420_P10_16BIT_MSB = 5,
+ FORMAT_420_P10_16BIT_LSB,
+ FORMAT_420_P10_32BIT_MSB,
+ FORMAT_420_P10_32BIT_LSB,
+
+ FORMAT_422_P10_16BIT_MSB,
+ FORMAT_422_P10_16BIT_LSB,
+ FORMAT_422_P10_32BIT_MSB,
+ FORMAT_422_P10_32BIT_LSB,
+
+ FORMAT_444_P10_16BIT_MSB,
+ FORMAT_444_P10_16BIT_LSB,
+ FORMAT_444_P10_32BIT_MSB,
+ FORMAT_444_P10_32BIT_LSB,
+
+ FORMAT_400_P10_16BIT_MSB,
+ FORMAT_400_P10_16BIT_LSB,
+ FORMAT_400_P10_32BIT_MSB,
+ FORMAT_400_P10_32BIT_LSB,
+
+ FORMAT_YUYV,
+ FORMAT_YUYV_P10_16BIT_MSB,
+ FORMAT_YUYV_P10_16BIT_LSB,
+ FORMAT_YUYV_P10_32BIT_MSB,
+ FORMAT_YUYV_P10_32BIT_LSB,
+
+ FORMAT_YVYU,
+ FORMAT_YVYU_P10_16BIT_MSB,
+ FORMAT_YVYU_P10_16BIT_LSB,
+ FORMAT_YVYU_P10_32BIT_MSB,
+ FORMAT_YVYU_P10_32BIT_LSB,
+
+ FORMAT_UYVY,
+ FORMAT_UYVY_P10_16BIT_MSB,
+ FORMAT_UYVY_P10_16BIT_LSB,
+ FORMAT_UYVY_P10_32BIT_MSB,
+ FORMAT_UYVY_P10_32BIT_LSB,
+
+ FORMAT_VYUY,
+ FORMAT_VYUY_P10_16BIT_MSB,
+ FORMAT_VYUY_P10_16BIT_LSB,
+ FORMAT_VYUY_P10_32BIT_MSB,
+ FORMAT_VYUY_P10_32BIT_LSB,
+
+ FORMAT_RGB_32BIT_PACKED = 90,
+ FORMAT_YUV444_32BIT_PACKED,
+ FORMAT_RGB_P10_32BIT_PACKED,
+ FORMAT_YUV444_P10_32BIT_PACKED,
+
+ FORMAT_RGB_24BIT_PACKED = 95,
+ FORMAT_YUV444_24BIT_PACKED,
+ FORMAT_YUV444_24BIT,
+
+ FORMAT_MAX,
+};
+
+enum packed_format_num {
+ NOT_PACKED = 0,
+ PACKED_YUYV,
+ PACKED_YVYU,
+ PACKED_UYVY,
+ PACKED_VYUY,
+};
+
+enum pic_type {
+ PIC_TYPE_I = 0,
+ PIC_TYPE_P = 1,
+ PIC_TYPE_B = 2,
+ PIC_TYPE_IDR = 5,
+ PIC_TYPE_MAX
+};
+
+enum enc_force_pic_type {
+ ENC_FORCE_PIC_TYPE_I = 0,
+ ENC_FORCE_PIC_TYPE_P = 1,
+ ENC_FORCE_PIC_TYPE_B = 2,
+ ENC_FORCE_PIC_TYPE_IDR = 3,
+ ENC_FORCE_PIC_TYPE_DISABLED = 4,
+};
+
+enum bitstream_mode {
+ BS_MODE_INTERRUPT,
+ BS_MODE_RESERVED,
+ BS_MODE_PIC_END,
+};
+
+enum display_mode {
+ DISP_MODE_DISP_ORDER,
+ DISP_MODE_DEC_ORDER,
+};
+
+enum sw_reset_mode {
+ SW_RESET_SAFETY,
+ SW_RESET_FORCE,
+ SW_RESET_ON_BOOT
+};
+
+enum tiled_map_type {
+ LINEAR_FRAME_MAP = 0,
+ COMPRESSED_FRAME_MAP = 17,
+};
+
+enum temporal_id_mode {
+ TEMPORAL_ID_MODE_ABSOLUTE,
+ TEMPORAL_ID_MODE_RELATIVE,
+};
+
+enum aux_buffer_type {
+ AUX_BUF_FBC_Y_TBL,
+ AUX_BUF_FBC_C_TBL,
+ AUX_BUF_MV_COL,
+ AUX_BUF_SUB_SAMPLE,
+ AUX_BUF_TYPE_MAX,
+};
+
+enum intra_refresh_mode {
+ INTRA_REFRESH_NONE = 0,
+ INTRA_REFRESH_ROW = 1,
+ INTRA_REFRESH_COLUMN = 2,
+};
+
+struct vpu_attr {
+ u32 product_id;
+ char product_name[8];
+ u32 product_version;
+ u32 fw_version;
+ u32 fw_revision;
+ u32 support_decoders;
+ u32 support_encoders;
+ u32 support_bitstream_mode;
+ bool support_avc10bit_enc;
+ bool support_hevc10bit_enc;
+ bool support_dual_core;
+};
+
+struct frame_buffer {
+ dma_addr_t buf_y;
+ dma_addr_t buf_cb;
+ dma_addr_t buf_cr;
+ enum tiled_map_type map_type;
+ unsigned int stride;
+ unsigned int width;
+ unsigned int height;
+ int index;
+ u32 luma_bitdepth: 4;
+ u32 chroma_bitdepth: 4;
+ u32 chroma_format_idc: 2;
+};
+
+struct vpu_rect {
+ u32 left;
+ u32 top;
+ u32 right;
+ u32 bottom;
+};
+
+struct timestamp_info {
+ u32 hour;
+ u32 min;
+ u32 sec;
+ u32 ms;
+};
+
+struct sar_info {
+ u32 enable;
+ u32 idc;
+ u32 width;
+ u32 height;
+};
+
+struct aux_buffer {
+ int index;
+ int size;
+ dma_addr_t addr;
+};
+
+struct aux_buffer_info {
+ int num;
+ struct aux_buffer *buf_array;
+ enum aux_buffer_type type;
+};
+
+struct instance_buffer {
+ dma_addr_t temp_base;
+ u32 temp_size;
+ dma_addr_t ar_base;
+};
+
+struct report_cycle {
+ u32 host_cmd_s;
+ u32 host_cmd_e;
+ u32 proc_s;
+ u32 proc_e;
+ u32 vpu_s;
+ u32 vpu_e;
+ u32 frame_cycle;
+ u32 proc_cycle;
+ u32 vpu_cycle;
+};
+
+struct color_param {
+ u32 chroma_sample_position;
+ u32 color_range;
+ u32 matrix_coefficients;
+ u32 transfer_characteristics;
+ u32 color_primaries;
+ bool color_description_present;
+ bool video_signal_type_present;
+};
+
+struct sec_axi_info {
+ bool use_dec_ip;
+ bool use_dec_lf_row;
+ bool use_enc_rdo;
+ bool use_enc_lf;
+};
+
+struct dec_aux_buffer_size_info {
+ int width;
+ int height;
+ enum aux_buffer_type type;
+};
+
+struct dec_scaler_info {
+ bool enable;
+ int width;
+ int height;
+ u32 scale_mode;
+};
+
+struct dec_open_param {
+ enum cb_cr_order cbcr_order;
+ enum endian_mode frame_endian;
+ enum endian_mode stream_endian;
+ enum bitstream_mode bs_mode;
+ enum display_mode disp_mode;
+ bool enable_non_ref_fbc_write;
+ u32 ext_addr_vcpu: 8;
+ bool is_secure_inst;
+ u32 inst_priority: 5;
+ struct instance_buffer inst_buffer;
+};
+
+struct dec_initial_info {
+ u32 pic_width;
+ u32 pic_height;
+ u32 f_rate_numerator;
+ u32 f_rate_denominator;
+ struct vpu_rect pic_crop_rect;
+ u32 min_frame_buffer_count;
+ u32 req_mv_buffer_count;
+ u32 frame_buf_delay;
+ u32 profile;
+ u32 level;
+ u32 tier;
+ bool is_ext_sar;
+ u32 aspect_rate_info;
+ u32 bitrate;
+ u32 chroma_format_idc;
+ u32 luma_bitdepth;
+ u32 chroma_bitdepth;
+ u32 err_reason;
+ int warn_info;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ unsigned int sequence_no;
+ struct color_param color;
+};
+
+#define WAVE_SKIPMODE_WAVE_NONE 0
+#define WAVE_SKIPMODE_NON_IRAP 1
+#define WAVE_SKIPMODE_NON_REF 2
+
+struct dec_param {
+ int skipframe_mode;
+ bool decode_cra_as_bla;
+ bool disable_film_grain;
+ struct timestamp_info timestamp;
+};
+
+struct h265_rp_sei {
+ unsigned int exist;
+ int recovery_poc_cnt;
+ bool exact_match;
+ bool broken_link;
+};
+
+struct dec_output_info {
+ int nal_type;
+ int pic_type;
+ int num_of_err_m_bs;
+ int num_of_tot_m_bs;
+ int num_of_err_m_bs_in_disp;
+ int num_of_tot_m_bs_in_disp;
+ int disp_pic_width;
+ int disp_pic_height;
+ int dec_pic_width;
+ int dec_pic_height;
+ int decoded_poc;
+ int display_poc;
+ struct h265_rp_sei h265_rp_sei;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ dma_addr_t byte_pos_frame_start;
+ dma_addr_t byte_pos_frame_end;
+ dma_addr_t frame_decoded_addr;
+ dma_addr_t frame_display_addr;
+ int error_reason;
+ int warn_info;
+ unsigned int sequence_no;
+ struct report_cycle cycle;
+ dma_addr_t release_disp_frame_addr[WAVE6_MAX_FBS];
+ dma_addr_t disp_frame_addr[WAVE6_MAX_FBS];
+ struct timestamp_info timestamp;
+ u32 notification_flags;
+ u32 release_disp_frame_num: 5;
+ u32 disp_frame_num: 5;
+ u32 ctu_size: 2;
+ bool frame_display;
+ bool frame_decoded;
+ bool stream_end;
+ bool last_frame_in_au;
+ bool decoding_success;
+};
+
+struct dec_info {
+ struct dec_open_param open_param;
+ struct dec_initial_info initial_info;
+ dma_addr_t stream_wr_ptr;
+ dma_addr_t stream_rd_ptr;
+ bool stream_end;
+ struct vpu_buf vb_mv[WAVE6_MAX_FBS];
+ struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS];
+ struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS];
+ struct frame_buffer disp_buf[WAVE6_MAX_FBS];
+ int stride;
+ bool initial_info_obtained;
+ struct sec_axi_info sec_axi_info;
+ struct dec_output_info dec_out_info[WAVE6_MAX_FBS];
+ bool thumbnail_mode;
+ int seq_change_mask;
+ u32 cycle_per_tick;
+ enum frame_buffer_format wtl_format;
+};
+
+#define MAX_CUSTOM_LAMBDA_NUM 52
+#define MAX_NUM_TEMPORAL_LAYER 7
+#define MAX_GOP_NUM 8
+#define MAX_NUM_CHANGEABLE_TEMPORAL_LAYER 4
+
+struct custom_gop_pic_param {
+ int pic_type;
+ int poc_offset;
+ int pic_qp;
+ int use_multi_ref_p;
+ int ref_poc_l0;
+ int ref_poc_l1;
+ int temporal_id;
+};
+
+struct custom_gop_param {
+ int custom_gop_size;
+ struct custom_gop_pic_param pic_param[MAX_GOP_NUM];
+};
+
+struct temporal_layer_param {
+ bool change_qp;
+ u32 qp_i;
+ u32 qp_p;
+ u32 qp_b;
+};
+
+struct enc_aux_buffer_size_info {
+ int width;
+ int height;
+ enum aux_buffer_type type;
+ enum mirror_direction mirror_direction;
+ int rotation_angle;
+};
+
+struct enc_scaler_info {
+ bool enable;
+ int width;
+ int height;
+ int coef_mode;
+};
+
+struct enc_codec_param {
+ u32 internal_bit_depth;
+ u32 decoding_refresh_type;
+ u32 idr_period;
+ u32 intra_period;
+ u32 gop_preset_idx;
+ u32 frame_rate;
+ u32 bitrate;
+ u32 cpb_size;
+ u32 hvs_qp_scale_div2;
+ u32 max_delta_qp;
+ int rc_initial_qp;
+ u32 rc_update_speed;
+ u32 max_bitrate;
+ u32 rc_mode;
+ u32 rc_initial_level;
+ u32 pic_rc_max_dqp;
+ u32 bg_th_diff;
+ u32 bg_th_mean_diff;
+ int bg_delta_qp;
+ u32 intra_refresh_mode;
+ u32 intra_refresh_arg;
+ int beta_offset_div2;
+ int tc_offset_div2;
+ u32 qp;
+ u32 min_qp_i;
+ u32 max_qp_i;
+ u32 min_qp_p;
+ u32 max_qp_p;
+ u32 min_qp_b;
+ u32 max_qp_b;
+ int cb_qp_offset;
+ int cr_qp_offset;
+ u32 q_round_intra;
+ u32 q_round_inter;
+ int lambda_dqp_intra;
+ int lambda_dqp_inter;
+ u32 slice_mode;
+ u32 slice_arg;
+ u32 level;
+ u32 tier;
+ u32 profile;
+ struct vpu_rect conf_win;
+ u32 forced_idr_header;
+ u16 custom_lambda_ssd[MAX_CUSTOM_LAMBDA_NUM];
+ u16 custom_lambda_sad[MAX_CUSTOM_LAMBDA_NUM];
+ struct custom_gop_param gop_param;
+ struct temporal_layer_param temp_layer[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER];
+ u32 temp_layer_cnt;
+ u32 report_mv_histo_threshold0;
+ u32 report_mv_histo_threshold1;
+ u32 report_mv_histo_threshold2;
+ u32 report_mv_histo_threshold3;
+ enum endian_mode custom_map_endian;
+ u32 num_units_in_tick;
+ u32 time_scale;
+ u32 num_ticks_poc_diff_one;
+ struct color_param color;
+ struct sar_info sar;
+ u32 max_intra_pic_bit;
+ u32 max_inter_pic_bit;
+ u32 intra_4x4;
+
+ u32 en_constrained_intra_pred: 1;
+ u32 en_long_term: 1;
+ u32 en_intra_trans_skip: 1;
+ u32 en_me_center: 1;
+ u32 en_rate_control: 1;
+ u32 en_transform8x8: 1;
+ u32 en_hvs_qp: 1;
+ u32 en_bg_detect: 1;
+ u32 en_temporal_mvp: 1;
+ u32 en_cabac: 1;
+ u32 en_dbk: 1;
+ u32 en_sao: 1;
+ u32 en_lf_cross_slice_boundary: 1;
+ u32 en_scaling_list: 1;
+ u32 en_adaptive_round: 1;
+ u32 en_qp_map: 1;
+ u32 en_mode_map: 1;
+ u32 en_q_round_offset: 1;
+ u32 en_still_picture: 1;
+ u32 en_strong_intra_smoothing: 1;
+ u32 en_custom_lambda: 1;
+ u32 en_report_mv_histo: 1;
+ u32 dis_coef_clear: 1;
+ u32 en_cu_level_rate_control: 1;
+ u32 en_vbv_overflow_drop_frame: 1;
+ u32 en_auto_level_adjusting: 1;
+};
+
+struct enc_open_param {
+ int pic_width;
+ int pic_height;
+ struct enc_codec_param codec_param;
+ enum cb_cr_order cbcr_order;
+ enum endian_mode stream_endian;
+ enum endian_mode source_endian;
+ bool line_buf_int_en;
+ enum packed_format_num packed_format;
+ enum frame_buffer_format src_format;
+ enum frame_buffer_format output_format;
+ bool enable_non_ref_fbc_write;
+ bool enc_hrd_rbsp_in_vps;
+ u32 hrd_rbsp_data_size;
+ dma_addr_t hrd_rbsp_data_addr;
+ u32 ext_addr_vcpu: 8;
+ bool is_secure_inst;
+ u32 inst_priority: 5;
+ struct instance_buffer inst_buffer;
+ bool enc_aud;
+};
+
+struct enc_initial_info {
+ u32 min_frame_buffer_count;
+ u32 min_src_frame_count;
+ u32 req_mv_buffer_count;
+ int max_latency_pictures;
+ int err_reason;
+ int warn_info;
+};
+
+struct enc_csc_param {
+ u32 format_order;
+ u32 coef_ry;
+ u32 coef_gy;
+ u32 coef_by;
+ u32 coef_rcb;
+ u32 coef_gcb;
+ u32 coef_bcb;
+ u32 coef_rcr;
+ u32 coef_gcr;
+ u32 coef_bcr;
+ u32 offset_y;
+ u32 offset_cb;
+ u32 offset_cr;
+};
+
+struct enc_param {
+ struct frame_buffer *source_frame;
+ bool skip_picture;
+ dma_addr_t pic_stream_buffer_addr;
+ int pic_stream_buffer_size;
+ bool force_pic_qp_enable;
+ int force_pic_qp_i;
+ int force_pic_qp_p;
+ int force_pic_qp_b;
+ bool force_pic_type_enable;
+ int force_pic_type;
+ int src_idx;
+ bool src_end;
+ u32 bitrate;
+ struct enc_csc_param csc;
+ struct timestamp_info timestamp;
+};
+
+struct enc_report_fme_sum {
+ u32 lower_x0;
+ u32 higher_x0;
+ u32 lower_y0;
+ u32 higher_y0;
+ u32 lower_x1;
+ u32 higher_x1;
+ u32 lower_y1;
+ u32 higher_y1;
+};
+
+struct enc_report_mv_histo {
+ u32 cnt0;
+ u32 cnt1;
+ u32 cnt2;
+ u32 cnt3;
+ u32 cnt4;
+};
+
+struct enc_output_info {
+ dma_addr_t bitstream_buffer;
+ u32 bitstream_size;
+ int bitstream_wrap_around;
+ int pic_type;
+ int num_of_slices;
+ int recon_frame_index;
+ struct frame_buffer recon_frame;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ int pic_skipped;
+ int num_of_intra;
+ int num_of_merge;
+ int num_of_skip_block;
+ int avg_ctu_qp;
+ int enc_pic_byte;
+ int enc_gop_pic_idx;
+ int enc_pic_poc;
+ int enc_src_idx;
+ int enc_vcl_nut;
+ int enc_pic_cnt;
+ int error_reason;
+ int warn_info;
+ u32 pic_distortion_low;
+ u32 pic_distortion_high;
+ bool non_ref_pic;
+ bool encoding_success;
+ struct enc_report_fme_sum fme_sum;
+ struct enc_report_mv_histo mv_histo;
+ struct report_cycle cycle;
+ struct timestamp_info timestamp;
+ dma_addr_t src_y_addr;
+ dma_addr_t custom_map_addr;
+ dma_addr_t prefix_sei_nal_addr;
+ dma_addr_t suffix_sei_nal_addr;
+};
+
+enum gop_preset_idx {
+ PRESET_IDX_CUSTOM_GOP = 0,
+ PRESET_IDX_ALL_I = 1,
+ PRESET_IDX_IPP = 2,
+ PRESET_IDX_IBBB = 3,
+ PRESET_IDX_IBPBP = 4,
+ PRESET_IDX_IBBBP = 5,
+ PRESET_IDX_IPPPP = 6,
+ PRESET_IDX_IBBBB = 7,
+ PRESET_IDX_RA_IB = 8,
+ PRESET_IDX_IPP_SINGLE = 9,
+ PRESET_IDX_MAX,
+};
+
+struct enc_info {
+ struct enc_open_param open_param;
+ struct enc_initial_info initial_info;
+ int num_frame_buffers;
+ int stride;
+ bool rotation_enable;
+ bool mirror_enable;
+ enum mirror_direction mirror_direction;
+ int rotation_angle;
+ bool initial_info_obtained;
+ struct sec_axi_info sec_axi_info;
+ bool line_buf_int_en;
+ struct vpu_buf vb_mv[WAVE6_MAX_FBS];
+ struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS];
+ struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS];
+ struct vpu_buf vb_sub_sam_buf[WAVE6_MAX_FBS];
+ u32 cycle_per_tick;
+ u32 width;
+ u32 height;
+ struct enc_scaler_info scaler_info;
+ int color_format;
+};
+
+struct h264_enc_controls {
+ u32 profile;
+ u32 level;
+ u32 min_qp;
+ u32 max_qp;
+ u32 i_frame_qp;
+ u32 p_frame_qp;
+ u32 b_frame_qp;
+ u32 loop_filter_mode;
+ u32 loop_filter_beta;
+ u32 loop_filter_alpha;
+ u32 _8x8_transform;
+ u32 constrained_intra_prediction;
+ u32 chroma_qp_index_offset;
+ u32 entropy_mode;
+ u32 i_period;
+ u32 vui_sar_enable;
+ u32 vui_sar_idc;
+ u32 vui_ext_sar_width;
+ u32 vui_ext_sar_height;
+ u32 cpb_size;
+};
+
+struct hevc_enc_controls {
+ u32 profile;
+ u32 level;
+ u32 min_qp;
+ u32 max_qp;
+ u32 i_frame_qp;
+ u32 p_frame_qp;
+ u32 b_frame_qp;
+ u32 loop_filter_mode;
+ u32 lf_beta_offset_div2;
+ u32 lf_tc_offset_div2;
+ u32 refresh_type;
+ u32 refresh_period;
+ u32 const_intra_pred;
+ u32 strong_smoothing;
+ u32 tmv_prediction;
+};
+
+struct enc_controls {
+ u32 rot_angle;
+ u32 mirror_direction;
+ u32 bitrate;
+ u32 bitrate_mode;
+ u32 gop_size;
+ u32 frame_rc_enable;
+ u32 mb_rc_enable;
+ u32 slice_mode;
+ u32 slice_max_mb;
+ u32 prepend_spspps_to_idr;
+ u32 intra_refresh_period;
+ struct h264_enc_controls h264;
+ struct hevc_enc_controls hevc;
+ u32 force_key_frame;
+ u32 frame_skip_mode;
+};
+
+struct vpu_device {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct video_device *video_dev_dec;
+ struct video_device *video_dev_enc;
+ struct mutex dev_lock; /* the lock for the src,dst v4l2 queues */
+ struct mutex hw_lock; /* lock hw configurations */
+ int irq;
+ u32 fw_version;
+ u32 fw_revision;
+ u32 hw_version;
+ struct vpu_attr attr;
+ u32 last_performance_cycles;
+ void __iomem *reg_base;
+ struct device *ctrl;
+ int product_code;
+ struct vpu_buf temp_vbuf;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct clk *clk_vpu;
+ struct completion irq_done;
+ struct kfifo irq_status;
+ struct delayed_work task_timer;
+ struct wave6_vpu_entity entity;
+ bool active;
+ int pause_request;
+ struct mutex pause_lock; /* the lock for the pause/resume m2m job. */
+ const struct wave6_match_data *res;
+ struct dentry *debugfs;
+};
+
+struct vpu_instance;
+
+struct vpu_instance_ops {
+ int (*start_process)(struct vpu_instance *inst);
+ void (*finish_process)(struct vpu_instance *inst, bool error);
+};
+
+struct vpu_performance_info {
+ ktime_t ts_first;
+ ktime_t ts_last;
+ s64 latency_first;
+ s64 latency_max;
+ s64 min_process_time;
+ s64 max_process_time;
+ u64 total_sw_time;
+ u64 total_hw_time;
+};
+
+struct vpu_instance {
+ struct v4l2_fh v4l2_fh;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
+ struct vpu_device *dev;
+
+ struct v4l2_pix_format_mplane src_fmt;
+ struct v4l2_pix_format_mplane dst_fmt;
+ struct v4l2_rect crop;
+ struct v4l2_rect codec_rect;
+ enum v4l2_colorspace colorspace;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+
+ enum vpu_instance_state state;
+ enum vpu_instance_state state_in_seek;
+ enum vpu_instance_type type;
+ const struct vpu_instance_ops *ops;
+
+ enum codec_std std;
+ u32 id;
+ union {
+ struct enc_info enc_info;
+ struct dec_info dec_info;
+ } *codec_info;
+ struct frame_buffer frame_buf[WAVE6_MAX_FBS];
+ struct vpu_buf frame_vbuf[WAVE6_MAX_FBS];
+ u32 queued_src_buf_num;
+ u32 queued_dst_buf_num;
+ u32 processed_buf_num;
+ u32 error_buf_num;
+ u32 sequence;
+ bool next_buf_last;
+ bool cbcr_interleave;
+ bool nv21;
+ bool eos;
+
+ struct vpu_buf aux_vbuf[AUX_BUF_TYPE_MAX][WAVE6_MAX_FBS];
+ struct vpu_buf ar_vbuf;
+ bool thumbnail_mode;
+ enum display_mode disp_mode;
+
+ unsigned int frame_rate;
+ struct enc_controls enc_ctrls;
+ struct dec_scaler_info scaler_info;
+ bool error_recovery;
+
+ struct vpu_performance_info performance;
+
+ struct dentry *debugfs;
+};
+
+void wave6_vdi_writel(struct vpu_device *vpu_device, unsigned int addr, unsigned int data);
+unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, unsigned int addr);
+unsigned int wave6_vdi_convert_endian(unsigned int endian);
+
+int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *pop);
+int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res);
+int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst);
+int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info);
+int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst,
+ struct dec_aux_buffer_size_info info,
+ uint32_t *size);
+int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst, struct aux_buffer_info info);
+int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_dec_fbs,
+ int stride, int height, int map_type);
+int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst, struct frame_buffer fb);
+int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct dec_param *param,
+ u32 *res_fail);
+int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info);
+int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, bool update_wr_ptr);
+int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter);
+int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *p_rd_ptr,
+ dma_addr_t *p_wr_ptr);
+int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int size);
+int wave6_vpu_dec_flush_instance(struct vpu_instance *inst);
+
+int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *enc_op_param);
+int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res);
+int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst);
+int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool *changed);
+int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info);
+int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst,
+ struct enc_aux_buffer_size_info info,
+ uint32_t *size);
+int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst, struct aux_buffer_info info);
+int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int num, unsigned int stride,
+ int height, enum tiled_map_type map_type);
+int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param,
+ u32 *fail_res);
+int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info);
+int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter);
+
+#endif /* __WAVE6_VPUAPI_H__ */
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
new file mode 100644
index 000000000000..9078f3741644
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - product config definitions
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPUCONFIG_H__
+#define __WAVE6_VPUCONFIG_H__
+
+#define WAVE617_CODE 0x6170
+#define WAVE627_CODE 0x6270
+#define WAVE633_CODE 0x6330
+#define WAVE637_CODE 0x6370
+#define WAVE663_CODE 0x6630
+#define WAVE677_CODE 0x6670
+
+#define PRODUCT_CODE_W_SERIES(x) ({ \
+ int c = x; \
+ ((c) == WAVE617_CODE || (c) == WAVE627_CODE || \
+ (c) == WAVE633_CODE || (c) == WAVE637_CODE || \
+ (c) == WAVE663_CODE || (c) == WAVE677_CODE); \
+})
+
+#define WAVE627ENC_WORKBUF_SIZE (512 * 1024)
+#define WAVE637DEC_WORKBUF_SIZE (2 * 512 * 1024)
+#define WAVE637DEC_WORKBUF_SIZE_FOR_CQ (3 * 512 * 1024)
+
+#define MAX_NUM_INSTANCE 32
+
+#define W6_MAX_PIC_STRIDE (4096U * 4)
+#define W6_DEF_DEC_PIC_WIDTH 720U
+#define W6_DEF_DEC_PIC_HEIGHT 480U
+#define W6_MIN_DEC_PIC_WIDTH 64U
+#define W6_MIN_DEC_PIC_HEIGHT 64U
+#define W6_MAX_DEC_PIC_WIDTH 4096U
+#define W6_MAX_DEC_PIC_HEIGHT 4096U
+#define W6_DEC_PIC_SIZE_STEP 1
+
+#define W6_DEF_ENC_PIC_WIDTH 416U
+#define W6_DEF_ENC_PIC_HEIGHT 240U
+#define W6_MIN_ENC_PIC_WIDTH 256U
+#define W6_MIN_ENC_PIC_HEIGHT 128U
+#define W6_MAX_ENC_PIC_WIDTH 4096U
+#define W6_MAX_ENC_PIC_HEIGHT 4096U
+#define W6_ENC_PIC_SIZE_STEP 8
+#define W6_ENC_CROP_X_POS_STEP 32
+#define W6_ENC_CROP_Y_POS_STEP 2
+#define W6_ENC_CROP_STEP 2
+
+#define W6_VPU_POLL_TIMEOUT 300000
+#define W6_BOOT_WAIT_TIMEOUT 10000
+#define W6_VPU_TIMEOUT 6000
+#define W6_VPU_TIMEOUT_CYCLE_COUNT (8000000 * 4 * 4)
+
+#define HOST_ENDIAN VDI_128BIT_LITTLE_ENDIAN
+#define VPU_FRAME_ENDIAN HOST_ENDIAN
+#define VPU_STREAM_ENDIAN HOST_ENDIAN
+#define VPU_USER_DATA_ENDIAN HOST_ENDIAN
+#define VPU_SOURCE_ENDIAN HOST_ENDIAN
+
+#define USE_SRC_PRP_AXI 0
+#define USE_SRC_PRI_AXI 1
+#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI
+
+#define COMMAND_QUEUE_DEPTH (1)
+
+#define W6_REMAP_INDEX0 0
+#define W6_REMAP_INDEX1 1
+#define W6_REMAP_MAX_SIZE (1024 * 1024)
+
+#define WAVE6_ARBUF_SIZE (1024)
+#define WAVE6_MAX_CODE_BUF_SIZE (4 * 1024 * 1024)
+#define WAVE6_CODE_BUF_SIZE (1 * 1024 * 1024)
+#define WAVE6_EXTRA_CODE_BUF_SIZE (256 * 1024)
+#define WAVE6_TEMPBUF_SIZE (3 * 1024 * 1024)
+
+#define WAVE6_UPPER_PROC_AXI_ID 0x0
+
+#endif /* __WAVE6_VPUCONFIG_H__ */
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
new file mode 100644
index 000000000000..8bf2e1e9522d
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
@@ -0,0 +1,262 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 vpu error values
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPUERROR_H__
+#define __WAVE6_VPUERROR_H__
+
+/* WAVE6 COMMON SYSTEM ERROR (FAIL_REASON) */
+#define WAVE6_SYSERR_QUEUEING_FAIL 0x00000001
+#define WAVE6_SYSERR_DECODER_FUSE 0x00000002
+#define WAVE6_SYSERR_INSTRUCTION_ACCESS_VIOLATION 0x00000004
+#define WAVE6_SYSERR_PRIVILEDGE_VIOLATION 0x00000008
+#define WAVE6_SYSERR_DATA_ADDR_ALIGNMENT 0x00000010
+#define WAVE6_SYSERR_DATA_ACCESS_VIOLATION 0x00000020
+#define WAVE6_SYSERR_ACCESS_VIOLATION_HW 0x00000040
+#define WAVE6_SYSERR_INSTRUCTION_ADDR_ALIGNMENT 0x00000080
+#define WAVE6_SYSERR_UNKNOWN 0x00000100
+#define WAVE6_SYSERR_BUS_ERROR 0x00000200
+#define WAVE6_SYSERR_DOUBLE_FAULT 0x00000400
+#define WAVE6_SYSERR_RESULT_NOT_READY 0x00000800
+#define WAVE6_SYSERR_VPU_STILL_RUNNING 0x00001000
+#define WAVE6_SYSERR_UNKNOWN_CMD 0x00002000
+#define WAVE6_SYSERR_UNKNOWN_CODEC_STD 0x00004000
+#define WAVE6_SYSERR_UNKNOWN_QUERY_OPTION 0x00008000
+#define WAVE6_SYSERR_WATCHDOG_TIMEOUT 0x00020000
+#define WAVE6_SYSERR_NOT_SUPPORT 0x00100000
+#define WAVE6_SYSERR_TEMP_SEC_BUF_OVERFLOW 0x00200000
+#define WAVE6_SYSERR_NOT_SUPPORT_PROFILE 0x00400000
+#define WAVE6_SYSERR_TIMEOUT_CODEC_FW 0x40000000
+#define WAVE6_SYSERR_FATAL_VPU_HANGUP 0xf0000000
+
+/* WAVE6 COMMAND QUEUE ERROR (FAIL_REASON) */
+#define WAVE6_CMDQ_ERR_NOT_QUEABLE_CMD 0x00000001
+#define WAVE6_CMDQ_ERR_SKIP_MODE_ENABLE 0x00000002
+#define WAVE6_CMDQ_ERR_INST_FLUSHING 0x00000003
+#define WAVE6_CMDQ_ERR_INST_INACTIVE 0x00000004
+#define WAVE6_CMDQ_ERR_QUEUE_FAIL 0x00000005
+#define WAVE6_CMDQ_ERR_CMD_BUF_FULL 0x00000006
+
+/* WAVE6 ERROR ON DECODER (ERR_INFO) */
+#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000
+#define HEVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001
+#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002
+#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003
+#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004
+#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005
+#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006
+#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007
+#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008
+#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009
+#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 0x0000100A
+#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B
+#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C
+#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE 0x0000100D
+#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3 0x0000100E
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE 0x0000100F
+#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2 0x00001010
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE 0x00001011
+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER 0x00001012
+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA 0x00001013
+#define HEVC_SPSERR_SCALING_LIST 0x00001014
+#define HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3 0x00001015
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE 0x00001016
+#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS 0x00001017
+#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS 0x00001018
+#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019
+#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A
+#define HEVC_SPSERR_VUI_ERROR 0x0000101B
+#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C
+#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D
+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000
+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001
+#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002
+#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003
+#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004
+#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH 0x00002005
+#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
+#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
+#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1 0x00002008
+#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1 0x00002009
+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1 0x0000200A
+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B
+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C
+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D
+#define HEVC_PPSERR_SCALING_LIST 0x0000200E
+#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2 0x0000200F
+#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT 0x00002010
+#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT 0x00002011
+#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012
+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013
+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014
+#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015
+#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016
+#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017
+#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018
+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT 0x00002019
+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT 0x00002020
+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT 0x00002021
+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT 0x00002022
+#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000
+#define HEVC_SHERR_ACTIVATE_PPS 0x00003001
+#define HEVC_SHERR_ACTIVATE_SPS 0x00003002
+#define HEVC_SHERR_SLICE_TYPE 0x00003003
+#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE 0x00003004
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG 0x00003005
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET 0x00003006
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX 0x00003007
+#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008
+#define HEVC_SHERR_NUM_LONG_TERM_PICS 0x00003009
+#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A
+#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT 0x0000300B
+#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C
+#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D
+#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E
+#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
+#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND 0x00003010
+#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011
+#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE 0x00003012
+#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013
+#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014
+#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
+#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
+#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS 0x00003017
+#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018
+#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH 0x00003019
+#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE 0x0000301A
+#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE 0x0000301B
+#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE 0x0000301C
+#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000
+#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001
+#define HEVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002
+#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003
+#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004
+#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005
+#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000
+#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001
+#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
+#define HEVC_ETCERR_INPLACE_V 0x0000500F
+
+#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000
+#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001
+#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002
+#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003
+#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004
+#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005
+#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006
+#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007
+#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008
+#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009
+#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B
+#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C
+#define AVC_SPSERR_SCALING_LIST 0x00001014
+#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019
+#define AVC_SPSERR_VUI_ERROR 0x0000101B
+#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C
+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000
+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001
+#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002
+#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003
+#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004
+#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
+#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
+#define AVC_PPSERR_SCALING_LIST 0x0000200E
+#define AVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012
+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013
+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014
+#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015
+#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016
+#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017
+#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018
+#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000
+#define AVC_SHERR_ACTIVATE_PPS 0x00003001
+#define AVC_SHERR_ACTIVATE_SPS 0x00003002
+#define AVC_SHERR_SLICE_TYPE 0x00003003
+#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004
+#define AVC_SHERR_RPLM 0x00003006
+#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A
+#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C
+#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D
+#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
+#define AVC_SHERR_SLICE_QP_DELTA 0x00003011
+#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
+#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
+#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC 0x00003017
+#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000
+#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001
+#define AVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002
+#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003
+#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004
+#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005
+#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000
+#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001
+#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
+#define AVC_ETCERR_ASO 0x00005004
+#define AVC_ETCERR_FMO 0x00005005
+#define AVC_ETCERR_INPLACE_V 0x0000500F
+
+/* WAVE6 WARNING ON DECODER (WARN_INFO) */
+#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1 0x00000001
+#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS 0x00000002
+#define HEVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004
+#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS 0x00000008
+#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
+#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER 0x00000020
+#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
+#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080
+#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000
+#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS 0x02000000
+#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
+#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS 0x00000200
+#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG 0x00001000
+#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000
+#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000
+#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT 0x00008000
+#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000
+#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000
+#define HEVC_ETCWARN_WRONG_TEMPORAL_ID 0x00040000
+#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000
+#define HEVC_SPECWARN_OVER_PROFILE 0x00100000
+#define HEVC_SPECWARN_OVER_LEVEL 0x00200000
+#define HEVC_PRESWARN_PARSING_ERR 0x04000000
+#define HEVC_PRESWARN_MVD_OUT_OF_RANGE 0x08000000
+#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE 0x09000000
+#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE 0x0A000000
+#define HEVC_PRESWARN_PCM_ERR 0x0B000000
+#define HEVC_PRESWARN_OVERCONSUME 0x0C000000
+#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR 0x10000000
+#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG 0x20000000
+
+#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004
+#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
+#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
+#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
+#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000
+#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000
+#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000
+#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000
+#define AVC_SPECWARN_OVER_PROFILE 0x00100000
+#define AVC_SPECWARN_OVER_LEVEL 0x00200000
+#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000
+#define AVC_PRESWARN_MB_QPD_RANGE_OUT 0x00500000
+#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000
+#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000
+#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT 0x00800000
+#define AVC_PRESWARN_MB_TYPE_RANGE_OUT 0x00900000
+#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT 0x00A00000
+#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000
+#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT 0x00C00000
+#define AVC_PRESWARN_REF_IDX_RANGE_OUT 0x00D00000
+#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT 0x00E00000
+#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT 0x00F00000
+#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT 0x01000000
+#define AVC_PRESWARN_OVERCONSUME 0x01100000
+#define AVC_PRESWARN_MISSING_SLICE 0x01200000
+
+/* WAVE6 WARNING ON ENCODER (WARN_INFO) */
+#define WAVE6_ETCWARN_FORCED_SPLIT_BY_CU8X8 0x000000001
+
+#endif /* __WAVE6_VPUERROR_H__ */
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* RE: [EXT] [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface
2025-02-10 9:07 ` [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface Nas Chung
@ 2025-02-28 8:33 ` Ming Qian
0 siblings, 0 replies; 34+ messages in thread
From: Ming Qian @ 2025-02-28 8:33 UTC (permalink / raw)
To: Nas Chung, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, dl-linux-imx,
linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com,
lafley.kim@chipsnmedia.com
Hi Nas,
>+static int wave6_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int
>addr)
>+{
>+ u32 data;
>+
>+ return read_poll_timeout(wave6_vdi_readl, data, !data,
>+ 0, W6_VPU_POLL_TIMEOUT, false, vpu_dev, addr);
In our test, setting the delay interval to 0, it likely make the read_poll_timeout() in high loading.
And it may led to CREATE_INSTANCE cmd timeout.
Sometimes the decoder may fail to display the Carplay video stream.
Thanks,
Ming
>+}
>+
>+void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev)
>+{
>+ u32 data;
>+
>+ data = BIT(W6_INT_BIT_ENC_SET_PARAM);
>+ data |= BIT(W6_INT_BIT_ENC_PIC);
>+ data |= BIT(W6_INT_BIT_INIT_SEQ);
>+ data |= BIT(W6_INT_BIT_DEC_PIC);
>+ data |= BIT(W6_INT_BIT_BSBUF_ERROR);
>+ data |= BIT(W6_INT_BIT_REQ_WORK_BUF);
>+
>+ vpu_write_reg(vpu_dev, W6_VPU_VINT_ENABLE, data);
>+}
>+
>+void wave6_vpu_check_state(struct vpu_device *vpu_dev)
>+{
>+ if (vpu_dev->ctrl) {
>+ int state = wave6_vpu_ctrl_get_state(vpu_dev->ctrl);
>+
>+ if (state == WAVE6_VPU_STATE_PREPARE)
>+ wave6_vpu_ctrl_wait_done(vpu_dev->ctrl);
>+ } else {
>+ u32 val;
>+ int ret;
>+
>+ ret = read_poll_timeout(vpu_read_reg, val, val != 0, 0,
>+ W6_VPU_POLL_TIMEOUT, false,
>+ vpu_dev, W6_VPU_VCPU_CUR_PC);
>+ if (!ret)
>+ vpu_dev->entity.on_boot(vpu_dev->dev);
>+ }
>+}
>+
>+bool wave6_vpu_is_init(struct vpu_device *vpu_dev)
>+{
>+ return vpu_read_reg(vpu_dev, W6_VPU_VCPU_CUR_PC) != 0;
>+}
>+
>+static int32_t wave6_vpu_get_product_id(struct vpu_device *vpu_dev)
>+{
>+ u32 product_id = PRODUCT_ID_NONE;
>+ u32 val;
>+
>+ val = vpu_read_reg(vpu_dev, W6_VPU_RET_PRODUCT_VERSION);
>+
>+ switch (val) {
>+ case WAVE617_CODE:
>+ product_id = PRODUCT_ID_617; break;
>+ case WAVE627_CODE:
>+ product_id = PRODUCT_ID_627; break;
>+ case WAVE633_CODE:
>+ case WAVE637_CODE:
>+ case WAVE663_CODE:
>+ case WAVE677_CODE:
>+ product_id = PRODUCT_ID_637; break;
>+ default:
>+ dev_err(vpu_dev->dev, "Invalid product (%x)\n", val);
>+ break;
>+ }
>+
>+ return product_id;
>+}
>+
>+static void wave6_send_command(struct vpu_device *vpu_dev, u32 id, u32
>std, u32 cmd)
>+{
>+ if (cmd == W6_CMD_CREATE_INSTANCE) {
>+ vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16));
>+
>+ vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1);
>+ vpu_write_reg(vpu_dev, W6_COMMAND, cmd);
>+
>+ vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1);
>+ } else {
>+ vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16) | (id
>& 0xffff));
>+
>+ vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1);
>+ vpu_write_reg(vpu_dev, W6_COMMAND, cmd);
>+
>+ vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1);
>+ }
>+
>+ trace_send_command(vpu_dev, id, std, cmd);
>+}
>+
>+static int wave6_send_query(struct vpu_device *vpu_dev, u32 id, u32 std,
>+ enum wave6_query_option query_opt)
>+{
>+ int ret;
>+ u32 reg_val;
>+
>+ vpu_write_reg(vpu_dev, W6_QUERY_OPTION, query_opt);
>+ wave6_send_command(vpu_dev, id, std, W6_CMD_QUERY);
>+
>+ ret = wave6_wait_vpu_busy(vpu_dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(vpu_dev->dev, "query timed out opt=0x%x\n", query_opt);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(vpu_dev, W6_RET_SUCCESS)) {
>+ reg_val = vpu_read_reg(vpu_dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(vpu_dev, reg_val);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_get_version(struct vpu_device *vpu_dev, uint32_t
>*version_info,
>+ uint32_t *revision)
>+{
>+ struct vpu_attr *attr = &vpu_dev->attr;
>+ u32 reg_val;
>+ u8 *str;
>+ int ret;
>+ u32 hw_config_def1, hw_config_feature;
>+
>+ ret = wave6_send_query(vpu_dev, 0, 0,
>W6_QUERY_OPT_GET_VPU_INFO);
>+ if (ret)
>+ return ret;
>+
>+ reg_val = vpu_read_reg(vpu_dev, W6_RET_PRODUCT_NAME);
>+ str = (u8 *)®_val;
>+ attr->product_name[0] = str[3];
>+ attr->product_name[1] = str[2];
>+ attr->product_name[2] = str[1];
>+ attr->product_name[3] = str[0];
>+ attr->product_name[4] = 0;
>+
>+ attr->product_id = wave6_vpu_get_product_id(vpu_dev);
>+ attr->product_version = vpu_read_reg(vpu_dev,
>W6_RET_PRODUCT_VERSION);
>+ attr->fw_version = vpu_read_reg(vpu_dev, W6_RET_FW_API_VERSION);
>+ attr->fw_revision = vpu_read_reg(vpu_dev, W6_RET_FW_VERSION);
>+ hw_config_def1 = vpu_read_reg(vpu_dev, W6_RET_STD_DEF1);
>+ hw_config_feature = vpu_read_reg(vpu_dev, W6_RET_CONF_FEATURE);
>+
>+ attr->support_hevc10bit_enc = (hw_config_feature >> 3) & 1;
>+ attr->support_avc10bit_enc = (hw_config_feature >> 11) & 1;
>+
>+ attr->support_decoders = 0;
>+ attr->support_encoders = 0;
>+ if (attr->product_id == PRODUCT_ID_617) {
>+ attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) <<
>STD_HEVC);
>+ attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) <<
>STD_AVC);
>+ } else if (attr->product_id == PRODUCT_ID_627) {
>+ attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) <<
>STD_HEVC);
>+ attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) <<
>STD_AVC);
>+ } else if (attr->product_id == PRODUCT_ID_637) {
>+ attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) <<
>STD_HEVC);
>+ attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) <<
>STD_AVC);
>+ attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) <<
>STD_HEVC);
>+ attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) <<
>STD_AVC);
>+ }
>+
>+ attr->support_dual_core = (hw_config_def1 >> 26) & 0x01;
>+ attr->support_bitstream_mode = BS_MODE_PIC_END;
>+
>+ if (version_info)
>+ *version_info = attr->fw_version;
>+ if (revision)
>+ *revision = attr->fw_revision;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_build_up_dec_param(struct vpu_instance *inst,
>+ struct dec_open_param *param)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ u32 reg_val;
>+ int ret;
>+
>+ p_dec_info->cycle_per_tick = 256;
>+ p_dec_info->sec_axi_info.use_dec_ip = true;
>+ p_dec_info->sec_axi_info.use_dec_lf_row = true;
>+ switch (inst->std) {
>+ case W_HEVC_DEC:
>+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC;
>+ break;
>+ case W_AVC_DEC:
>+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC;
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_BASE,
>param->inst_buffer.temp_base);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_SIZE,
>param->inst_buffer.temp_size);
>+
>+ reg_val = wave6_vdi_convert_endian(param->stream_endian);
>+ reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_BS_PARAM,
>reg_val);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_ADDR_EXT,
>param->ext_addr_vcpu);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_DISP_MODE,
>param->disp_mode);
>+
>+ reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_CORE_INFO,
>reg_val);
>+
>+ reg_val = (param->is_secure_inst << 8) | (param->inst_priority);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_PRIORITY,
>reg_val);
>+ vpu_write_reg(inst->dev,
>W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT,
>+ W6_VPU_TIMEOUT_CYCLE_COUNT);
>+
>+ wave6_send_command(inst->dev, 0, inst->std,
>W6_CMD_CREATE_INSTANCE);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+
>+ wave6_print_reg_err(inst->dev, reason_code);
>+ return -EIO;
>+ }
>+
>+ inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID);
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_init_seq(struct vpu_instance *inst)
>+{
>+ struct dec_info *p_dec_info;
>+ u32 cmd_option = W6_INIT_SEQ_OPT_NORMAL, bs_option;
>+ int ret;
>+
>+ if (!inst->codec_info)
>+ return -EINVAL;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+ if (p_dec_info->thumbnail_mode)
>+ cmd_option = W6_INIT_SEQ_OPT_W_THUMBNAIL;
>+
>+ bs_option = 0;
>+ switch (p_dec_info->open_param.bs_mode) {
>+ case BS_MODE_INTERRUPT:
>+ bs_option = 0;
>+ break;
>+ case BS_MODE_PIC_END:
>+ bs_option = BSOPTION_ENABLE_EXPLICIT_END;
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_RD_PTR,
>p_dec_info->stream_rd_ptr);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_WR_PTR,
>p_dec_info->stream_wr_ptr);
>+
>+ if (p_dec_info->stream_end)
>+ bs_option = 3;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_OPTION,
>bs_option);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_OPTION,
>cmd_option);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_INIT_SEQ);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+
>+ wave6_print_reg_err(inst->dev, reason_code);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+static void wave6_get_dec_seq_result(struct vpu_instance *inst, struct
>dec_initial_info *info)
>+{
>+ u32 reg_val;
>+ u32 profile_compatibility;
>+ u32 left, right, top, bottom;
>+
>+ info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE);
>+ info->pic_width = ((reg_val >> 16) & 0xffff);
>+ info->pic_height = (reg_val & 0xffff);
>+ info->min_frame_buffer_count = vpu_read_reg(inst->dev,
>W6_RET_DEC_NUM_REQUIRED_FBC_FB);
>+ info->frame_buf_delay = vpu_read_reg(inst->dev,
>W6_RET_DEC_NUM_REORDER_DELAY);
>+ info->req_mv_buffer_count = vpu_read_reg(inst->dev,
>W6_RET_DEC_NUM_REQUIRED_COL_BUF);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_LEFT_RIGHT);
>+ left = (reg_val >> 16) & 0xffff;
>+ right = reg_val & 0xffff;
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_TOP_BOTTOM);
>+ top = (reg_val >> 16) & 0xffff;
>+ bottom = reg_val & 0xffff;
>+
>+ info->pic_crop_rect.left = left;
>+ info->pic_crop_rect.right = info->pic_width - right;
>+ info->pic_crop_rect.top = top;
>+ info->pic_crop_rect.bottom = info->pic_height - bottom;
>+
>+ info->f_rate_numerator = vpu_read_reg(inst->dev,
>W6_RET_DEC_FRAME_RATE_NR);
>+ info->f_rate_denominator = vpu_read_reg(inst->dev,
>W6_RET_DEC_FRAME_RATE_DR);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_SAMPLE_INFO);
>+ info->luma_bitdepth = (reg_val >> 0) & 0x0f;
>+ info->chroma_bitdepth = (reg_val >> 4) & 0x0f;
>+ info->chroma_format_idc = (reg_val >> 8) & 0x0f;
>+ info->aspect_rate_info = (reg_val >> 16) & 0xff;
>+ info->is_ext_sar = (info->aspect_rate_info ==
>H264_VUI_SAR_IDC_EXTENDED ? true : false);
>+ if (info->is_ext_sar)
>+ info->aspect_rate_info = vpu_read_reg(inst->dev,
>W6_RET_DEC_ASPECT_RATIO);
>+ info->bitrate = vpu_read_reg(inst->dev, W6_RET_DEC_BIT_RATE);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_SEQ_PARAM);
>+ info->level = reg_val & 0xff;
>+ profile_compatibility = (reg_val >> 12) & 0xff;
>+ info->profile = (reg_val >> 24) & 0x1f;
>+ info->tier = (reg_val >> 29) & 0x01;
>+
>+ if (inst->std == W_HEVC_DEC) {
>+ if (!info->profile) {
>+ if ((profile_compatibility & 0x06) == 0x06)
>+ info->profile = HEVC_PROFILE_MAIN;
>+ else if ((profile_compatibility & 0x04) == 0x04)
>+ info->profile = HEVC_PROFILE_MAIN10;
>+ else if ((profile_compatibility & 0x08) == 0x08)
>+ info->profile = HEVC_PROFILE_STILLPICTURE;
>+ else
>+ info->profile = HEVC_PROFILE_MAIN;
>+ }
>+ } else if (inst->std == W_AVC_DEC) {
>+ info->profile = (reg_val >> 24) & 0x7f;
>+ }
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_CONFIG);
>+ if (reg_val) {
>+ info->color.video_signal_type_present = true;
>+ info->color.color_description_present = reg_val & 0x1;
>+ info->color.color_primaries = (reg_val >> 1) & 0xFF;
>+ info->color.transfer_characteristics = (reg_val >> 9) & 0xFF;
>+ info->color.matrix_coefficients = (reg_val >> 17) & 0xFF;
>+ info->color.color_range = (reg_val >> 25) & 0x1;
>+ info->color.chroma_sample_position = (reg_val >> 26) & 0x3;
>+ } else {
>+ info->color.video_signal_type_present = false;
>+ }
>+}
>+
>+int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct
>dec_initial_info *info)
>+{
>+ int ret;
>+
>+ ret = wave6_send_query(inst->dev, inst->id, inst->std,
>W6_QUERY_OPT_GET_RESULT);
>+ if (ret)
>+ return ret;
>+
>+ if (vpu_read_reg(inst->dev, W6_RET_DEC_DECODING_SUCCESS) != 1) {
>+ info->err_reason = vpu_read_reg(inst->dev,
>W6_RET_DEC_ERR_INFO);
>+ ret = -EIO;
>+ } else {
>+ info->warn_info = vpu_read_reg(inst->dev,
>W6_RET_DEC_WARN_INFO);
>+ }
>+
>+ wave6_get_dec_seq_result(inst, info);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst,
>+ struct frame_buffer *fb_arr,
>+ enum tiled_map_type map_type, u32 count)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ size_t fbc_remain, mv_remain, fbc_idx = 0, mv_idx = 0;
>+ size_t i, k, group_num, mv_count;
>+ dma_addr_t fbc_cr_tbl_addr;
>+ u32 reg_val;
>+ u32 endian;
>+ int ret;
>+
>+ mv_count = p_dec_info->initial_info.req_mv_buffer_count;
>+
>+ for (i = 0; i < count; i++) {
>+ if (!p_dec_info->vb_fbc_y_tbl[i].daddr)
>+ return -EINVAL;
>+ if (!p_dec_info->vb_fbc_c_tbl[i].daddr)
>+ return -EINVAL;
>+ }
>+ for (i = 0; i < mv_count; i++) {
>+ if (!p_dec_info->vb_mv[i].daddr)
>+ return -EINVAL;
>+ }
>+
>+ endian = wave6_vdi_convert_endian(p_dec_info-
>>open_param.frame_endian);
>+
>+ reg_val = (p_dec_info->initial_info.pic_width << 16) |
>+ (p_dec_info->initial_info.pic_height);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_PIC_SIZE, reg_val);
>+ reg_val = (p_dec_info->initial_info.chroma_format_idc << 25) |
>+ (p_dec_info->initial_info.luma_bitdepth << 21) |
>+ (p_dec_info->initial_info.chroma_bitdepth << 17);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_COMMON_PIC_INFO,
>reg_val);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_DEFAULT_CDF, 0);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_SEGMAP, 0);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT, 0);
>+
>+ fbc_remain = count;
>+ mv_remain = mv_count;
>+ group_num = (count > mv_count) ? ((ALIGN(count, 16) / 16) - 1) :
>+ ((ALIGN(mv_count, 16) / 16) - 1);
>+ for (i = 0; i <= group_num; i++) {
>+ bool first_group = (i == 0) ? true : false;
>+ bool last_group = (i == group_num) ? true : false;
>+ u32 set_fbc_num = (fbc_remain >= 16) ? 16 : fbc_remain;
>+ u32 set_mv_num = (mv_remain >= 16) ? 16 : mv_remain;
>+ u32 fbc_start_no = i * 16;
>+ u32 fbc_end_no = fbc_start_no + set_fbc_num - 1;
>+ u32 mv_start_no = i * 16;
>+ u32 mv_end_no = mv_start_no + set_mv_num - 1;
>+
>+ reg_val = (p_dec_info->open_param.enable_non_ref_fbc_write <<
>26) |
>+ (endian << 16) |
>+ (last_group << 4) |
>+ (first_group << 3);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_OPTION, reg_val);
>+
>+ reg_val = (fbc_start_no << 24) | (fbc_end_no << 16) |
>+ (mv_start_no << 5) | mv_end_no;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_NUM, reg_val);
>+
>+ for (k = 0; k < set_fbc_num; k++) {
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_Y0 + (k *
>24),
>+ fb_arr[fbc_idx].buf_y);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_C0 + (k *
>24),
>+ fb_arr[fbc_idx].buf_cb);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_CR0 + (k *
>8),
>+ fb_arr[fbc_idx].buf_cr);
>+ vpu_write_reg(inst->dev,
>W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 + (k * 24),
>+ p_dec_info->vb_fbc_y_tbl[fbc_idx].daddr);
>+ vpu_write_reg(inst->dev,
>W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 + (k * 24),
>+ p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr);
>+ fbc_cr_tbl_addr = p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr +
>+ (p_dec_info->vb_fbc_c_tbl[fbc_idx].size >> 1);
>+ vpu_write_reg(inst->dev,
>W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 + (k * 8),
>+ fbc_cr_tbl_addr);
>+ fbc_idx++;
>+ }
>+ fbc_remain -= k;
>+
>+ for (k = 0; k < set_mv_num; k++) {
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL0 + (k
>* 24),
>+ p_dec_info->vb_mv[mv_idx].daddr);
>+ mv_idx++;
>+ }
>+ mv_remain -= k;
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_SET_FB);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS))
>+ return -EIO;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct
>frame_buffer fb)
>+{
>+ int ret;
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ u32 reg_val, cbcr_interleave, nv21;
>+ u32 endian;
>+ u32 addr_y, addr_cb, addr_cr;
>+ u32 color_format;
>+ u32 justified = WTL_RIGHT_JUSTIFIED;
>+ u32 format_no = WTL_PIXEL_8BIT;
>+
>+ cbcr_interleave = inst->cbcr_interleave;
>+ nv21 = inst->nv21;
>+
>+ endian = wave6_vdi_convert_endian(p_dec_info-
>>open_param.frame_endian);
>+
>+ switch (p_dec_info->wtl_format) {
>+ case FORMAT_420:
>+ case FORMAT_420_P10_16BIT_MSB:
>+ case FORMAT_420_P10_16BIT_LSB:
>+ case FORMAT_420_P10_32BIT_MSB:
>+ case FORMAT_420_P10_32BIT_LSB:
>+ color_format = 1;
>+ break;
>+ case FORMAT_422:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ color_format = 2;
>+ break;
>+ case FORMAT_444:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ color_format = 3;
>+ break;
>+ case FORMAT_400:
>+ case FORMAT_400_P10_16BIT_MSB:
>+ case FORMAT_400_P10_16BIT_LSB:
>+ case FORMAT_400_P10_32BIT_MSB:
>+ case FORMAT_400_P10_32BIT_LSB:
>+ color_format = 0;
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ reg_val = (color_format << 3) |
>+ (inst->scaler_info.scale_mode << 1) |
>+ (inst->scaler_info.enable);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PARAM, reg_val);
>+ reg_val = (inst->scaler_info.width << 16) |
>+ (inst->scaler_info.height);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE,
>reg_val);
>+ reg_val = (p_dec_info->initial_info.pic_width << 16) |
>+ (p_dec_info->initial_info.pic_height);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_SIZE, reg_val);
>+
>+ switch (p_dec_info->wtl_format) {
>+ case FORMAT_420_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_400_P10_16BIT_MSB:
>+ justified = WTL_RIGHT_JUSTIFIED;
>+ format_no = WTL_PIXEL_16BIT;
>+ break;
>+ case FORMAT_420_P10_16BIT_LSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ case FORMAT_400_P10_16BIT_LSB:
>+ justified = WTL_LEFT_JUSTIFIED;
>+ format_no = WTL_PIXEL_16BIT;
>+ break;
>+ case FORMAT_420_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_400_P10_32BIT_MSB:
>+ justified = WTL_RIGHT_JUSTIFIED;
>+ format_no = WTL_PIXEL_32BIT;
>+ break;
>+ case FORMAT_420_P10_32BIT_LSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ case FORMAT_400_P10_32BIT_LSB:
>+ justified = WTL_LEFT_JUSTIFIED;
>+ format_no = WTL_PIXEL_32BIT;
>+ break;
>+ default:
>+ break;
>+ }
>+
>+ reg_val = (REGISTER_DISPLAY_BUFFER << 28) | (color_format << 24) |
>+ (DEFAULT_PIXEL_ORDER << 23) | (justified << 22) | (format_no <<
>20) |
>+ (nv21 << 17) | (cbcr_interleave << 16) | (fb.stride);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO,
>reg_val);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_OPTION, (endian <<
>16));
>+ reg_val = (fb.luma_bitdepth << 22) |
>+ (fb.chroma_bitdepth << 18) |
>+ (fb.chroma_format_idc << 16);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_INFO, reg_val);
>+
>+ if (p_dec_info->open_param.cbcr_order == CBCR_ORDER_REVERSED) {
>+ addr_y = fb.buf_y;
>+ addr_cb = fb.buf_cr;
>+ addr_cr = fb.buf_cb;
>+ } else {
>+ addr_y = fb.buf_y;
>+ addr_cb = fb.buf_cb;
>+ addr_cr = fb.buf_cr;
>+ }
>+
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_Y_BASE, addr_y);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CB_BASE, addr_cb);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CR_BASE, addr_cr);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_DEC_SET_DISP);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS))
>+ return -EIO;
>+
>+ wave6_dec_set_display_buffer(inst, fb);
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option,
>u32 *fail_res)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ struct dec_open_param *p_open_param = &p_dec_info->open_param;
>+ u32 mode_option = W6_DEC_PIC_OPT_NORMAL, bs_option, reg_val;
>+ int ret;
>+
>+ if (p_dec_info->thumbnail_mode) {
>+ mode_option = W6_DEC_PIC_OPT_W_THUMBNAIL;
>+ } else if (option->skipframe_mode) {
>+ switch (option->skipframe_mode) {
>+ case WAVE_SKIPMODE_NON_IRAP:
>+ mode_option = W6_DEC_PIC_OPT_SKIP_NON_IRAP;
>+ break;
>+ case WAVE_SKIPMODE_NON_REF:
>+ mode_option = W6_DEC_PIC_OPT_SKIP_NON_REF_PIC;
>+ break;
>+ default:
>+ break;
>+ }
>+ }
>+
>+ bs_option = 0;
>+ switch (p_open_param->bs_mode) {
>+ case BS_MODE_INTERRUPT:
>+ bs_option = 0;
>+ break;
>+ case BS_MODE_PIC_END:
>+ bs_option = BSOPTION_ENABLE_EXPLICIT_END;
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_RD_PTR, p_dec_info-
>>stream_rd_ptr);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_WR_PTR, p_dec_info-
>>stream_wr_ptr);
>+ if (p_dec_info->stream_end)
>+ bs_option = 3;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_OPTION, bs_option);
>+
>+ reg_val = (p_dec_info->sec_axi_info.use_dec_ip << 1) |
>+ p_dec_info->sec_axi_info.use_dec_lf_row;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_USE_SEC_AXI, reg_val);
>+
>+ reg_val = (option->disable_film_grain << 6) |
>+ (option->decode_cra_as_bla << 5) |
>+ mode_option;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_OPTION, reg_val);
>+ reg_val = (DECODE_ALL_SPATIAL_LAYERS << 9) |
>+ (TEMPORAL_ID_MODE_ABSOLUTE << 8) |
>+ DECODE_ALL_TEMPORAL_LAYERS;
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1,
>reg_val);
>+ vpu_write_reg(inst->dev,
>W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG,
>+ p_dec_info->seq_change_mask);
>+ reg_val = ((option->timestamp.hour & 0x1F) << 26) |
>+ ((option->timestamp.min & 0x3F) << 20) |
>+ ((option->timestamp.sec & 0x3F) << 14) |
>+ (option->timestamp.ms & 0x3FFF);
>+ vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TIMESTAMP, reg_val);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DEC_PIC);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(inst->dev, *fail_res);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct
>dec_output_info *result)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ u32 reg_val, nal_unit_type, i;
>+ int decoded_index = -1, display_index = -1;
>+ int ret;
>+
>+ ret = wave6_send_query(inst->dev, inst->id, inst->std,
>W6_QUERY_OPT_GET_RESULT);
>+ if (ret)
>+ return ret;
>+
>+ result->decoding_success = vpu_read_reg(inst->dev,
>W6_RET_DEC_DECODING_SUCCESS);
>+ if (!result->decoding_success)
>+ result->error_reason = vpu_read_reg(inst->dev,
>W6_RET_DEC_ERR_INFO);
>+ else
>+ result->warn_info = vpu_read_reg(inst->dev,
>W6_RET_DEC_WARN_INFO);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_TYPE);
>+ nal_unit_type = (reg_val & 0x3f0) >> 4;
>+ result->nal_type = nal_unit_type;
>+
>+ if (inst->std == W_HEVC_DEC) {
>+ if (reg_val & 0x04)
>+ result->pic_type = PIC_TYPE_B;
>+ else if (reg_val & 0x02)
>+ result->pic_type = PIC_TYPE_P;
>+ else if (reg_val & 0x01)
>+ result->pic_type = PIC_TYPE_I;
>+ else
>+ result->pic_type = PIC_TYPE_MAX;
>+ if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type
>== PIC_TYPE_I)
>+ result->pic_type = PIC_TYPE_IDR;
>+ } else if (inst->std == W_AVC_DEC) {
>+ if (reg_val & 0x04)
>+ result->pic_type = PIC_TYPE_B;
>+ else if (reg_val & 0x02)
>+ result->pic_type = PIC_TYPE_P;
>+ else if (reg_val & 0x01)
>+ result->pic_type = PIC_TYPE_I;
>+ else
>+ result->pic_type = PIC_TYPE_MAX;
>+ if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I)
>+ result->pic_type = PIC_TYPE_IDR;
>+ }
>+ result->ctu_size = 16 << ((reg_val >> 10) & 0x3);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DECODED_FLAG);
>+ if (reg_val) {
>+ struct frame_buffer fb;
>+ dma_addr_t addr = vpu_read_reg(inst->dev,
>W6_RET_DEC_DECODED_ADDR);
>+
>+ fb = wave6_dec_get_display_buffer(inst, addr, false);
>+ result->frame_decoded_addr = addr;
>+ result->frame_decoded = true;
>+ decoded_index = fb.index;
>+ }
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISPLAY_FLAG);
>+ if (reg_val) {
>+ struct frame_buffer fb;
>+ dma_addr_t addr = vpu_read_reg(inst->dev,
>W6_RET_DEC_DISPLAY_ADDR);
>+
>+ fb = wave6_dec_get_display_buffer(inst, addr, false);
>+ result->frame_display_addr = addr;
>+ result->frame_display = true;
>+ display_index = fb.index;
>+ }
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISP_IDC);
>+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
>+ if (reg_val & (1 << i)) {
>+ dma_addr_t addr = vpu_read_reg(inst->dev,
>+ W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4);
>+
>+ result->disp_frame_addr[result->disp_frame_num] = addr;
>+ result->disp_frame_num++;
>+ }
>+ }
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RELEASE_IDC);
>+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
>+ if (reg_val & (1 << i)) {
>+ struct frame_buffer fb;
>+ dma_addr_t addr = vpu_read_reg(inst->dev,
>+ W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4);
>+
>+ fb = wave6_dec_get_display_buffer(inst, addr, true);
>+ result->release_disp_frame_addr[result-
>>release_disp_frame_num] = fb.buf_y;
>+ result->release_disp_frame_num++;
>+ }
>+ }
>+
>+ result->stream_end = vpu_read_reg(inst->dev,
>W6_RET_DEC_STREAM_END);
>+ result->notification_flags = vpu_read_reg(inst->dev,
>W6_RET_DEC_NOTIFICATION);
>+
>+ if (inst->std == W_HEVC_DEC) {
>+ result->decoded_poc = -1;
>+ result->display_poc = -1;
>+ if (decoded_index >= 0)
>+ result->decoded_poc = vpu_read_reg(inst->dev,
>W6_RET_DEC_PIC_POC);
>+ } else if (inst->std == W_AVC_DEC) {
>+ result->decoded_poc = -1;
>+ result->display_poc = -1;
>+ if (decoded_index >= 0)
>+ result->decoded_poc = vpu_read_reg(inst->dev,
>W6_RET_DEC_PIC_POC);
>+ }
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE);
>+ result->dec_pic_width = reg_val >> 16;
>+ result->dec_pic_height = reg_val & 0xffff;
>+
>+ result->num_of_err_m_bs = vpu_read_reg(inst->dev,
>W6_RET_DEC_ERR_CTB_NUM) >> 16;
>+ result->num_of_tot_m_bs = vpu_read_reg(inst->dev,
>W6_RET_DEC_ERR_CTB_NUM) & 0xffff;
>+ result->byte_pos_frame_start = vpu_read_reg(inst->dev,
>W6_RET_DEC_AU_START_POS);
>+ result->byte_pos_frame_end = vpu_read_reg(inst->dev,
>W6_RET_DEC_AU_END_POS);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RECOVERY_POINT);
>+ result->h265_rp_sei.recovery_poc_cnt = reg_val & 0xFFFF;
>+ result->h265_rp_sei.exact_match = (reg_val >> 16) & 0x01;
>+ result->h265_rp_sei.broken_link = (reg_val >> 17) & 0x01;
>+ result->h265_rp_sei.exist = (reg_val >> 18) & 0x01;
>+ if (!result->h265_rp_sei.exist) {
>+ result->h265_rp_sei.recovery_poc_cnt = 0;
>+ result->h265_rp_sei.exact_match = false;
>+ result->h265_rp_sei.broken_link = false;
>+ }
>+
>+ result->last_frame_in_au = vpu_read_reg(inst->dev,
>W6_RET_DEC_LAST_FRAME_FLAG);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_TIMESTAMP);
>+ result->timestamp.hour = (reg_val >> 26) & 0x1F;
>+ result->timestamp.min = (reg_val >> 20) & 0x3F;
>+ result->timestamp.sec = (reg_val >> 14) & 0x3F;
>+ result->timestamp.ms = reg_val & 0x3FFF;
>+
>+ result->cycle.host_cmd_s = vpu_read_reg(inst->dev,
>W6_RET_CQ_IN_TICK);
>+ result->cycle.host_cmd_e = vpu_read_reg(inst->dev,
>W6_RET_RQ_OUT_TICK);
>+ result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK);
>+ result->cycle.proc_e = vpu_read_reg(inst->dev,
>W6_RET_HW_DONE_TICK);
>+ result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK);
>+ result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK);
>+ result->cycle.frame_cycle = (result->cycle.vpu_e - result-
>>cycle.host_cmd_s) *
>+ p_dec_info->cycle_per_tick;
>+ result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) *
>+ p_dec_info->cycle_per_tick;
>+ result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) -
>+ (result->cycle.proc_e - result->cycle.proc_s)) *
>+ p_dec_info->cycle_per_tick;
>+
>+ if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS) {
>+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC)
>+ p_dec_info->dec_out_info[decoded_index].decoded_poc =
>result->decoded_poc;
>+ }
>+
>+ if (display_index >= 0 && display_index < WAVE6_MAX_FBS) {
>+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC)
>+ result->display_poc = p_dec_info-
>>dec_out_info[display_index].decoded_poc;
>+
>+ result->disp_pic_width = p_dec_info-
>>dec_out_info[display_index].dec_pic_width;
>+ result->disp_pic_height = p_dec_info-
>>dec_out_info[display_index].dec_pic_height;
>+ }
>+
>+ result->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
>+ result->wr_ptr = p_dec_info->stream_wr_ptr;
>+
>+ result->sequence_no = p_dec_info->initial_info.sequence_no;
>+ if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS)
>+ p_dec_info->dec_out_info[decoded_index] = *result;
>+
>+ if (display_index >= 0 && display_index < WAVE6_MAX_FBS) {
>+ result->num_of_tot_m_bs_in_disp =
>+ p_dec_info->dec_out_info[display_index].num_of_tot_m_bs;
>+ result->num_of_err_m_bs_in_disp =
>+ p_dec_info->dec_out_info[display_index].num_of_err_m_bs;
>+ } else {
>+ result->num_of_tot_m_bs_in_disp = 0;
>+ result->num_of_err_m_bs_in_disp = 0;
>+ }
>+
>+ if (result->notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) {
>+ wave6_get_dec_seq_result(inst, &p_dec_info->initial_info);
>+ p_dec_info->initial_info.sequence_no++;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res)
>+{
>+ int ret;
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_DESTROY_INSTANCE);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret)
>+ return -ETIMEDOUT;
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(inst->dev, *fail_res);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+
>+ p_dec_info->stream_end = eos ? true : false;
>+}
>+
>+dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst)
>+{
>+ return vpu_read_reg(inst->dev, W6_RET_DEC_BS_RD_PTR);
>+}
>+
>+int wave6_vpu_dec_flush(struct vpu_instance *inst)
>+{
>+ int ret, index;
>+ u32 unused_idc;
>+ u32 used_idc;
>+ u32 using_idc;
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_FLUSH_INSTANCE);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret)
>+ return -ETIMEDOUT;
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reg_val;
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(inst->dev, reg_val);
>+ return -EIO;
>+ }
>+
>+ ret = wave6_send_query(inst->dev, inst->id, inst->std,
>W6_QUERY_OPT_GET_FLUSH_CMD_INFO);
>+ if (ret)
>+ return ret;
>+
>+ unused_idc = vpu_read_reg(inst->dev,
>W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC);
>+ if (unused_idc)
>+ dev_dbg(inst->dev->dev, "%s: unused_idc %d\n", __func__,
>unused_idc);
>+
>+ used_idc = vpu_read_reg(inst->dev,
>W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC);
>+ if (used_idc)
>+ dev_dbg(inst->dev->dev, "%s: used_idc %d\n", __func__, used_idc);
>+
>+ using_idc = vpu_read_reg(inst->dev,
>W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC);
>+ if (using_idc)
>+ dev_err(inst->dev->dev, "%s: using_idc %d\n", __func__, using_idc);
>+
>+ for (index = 0; index < WAVE6_MAX_FBS; index++) {
>+ struct frame_buffer fb;
>+ bool remove = false;
>+ dma_addr_t addr = vpu_read_reg(inst->dev,
>+ W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 + index *
>4);
>+
>+ if ((unused_idc >> index) & 0x1)
>+ remove = true;
>+ if ((used_idc >> index) & 0x1)
>+ remove = true;
>+
>+ fb = wave6_dec_get_display_buffer(inst, addr, remove);
>+ }
>+
>+ return 0;
>+}
>+
>+struct enc_cmd_set_param_reg {
>+ u32 enable;
>+ u32 src_size;
>+ u32 custom_map_endian;
>+ u32 sps_param;
>+ u32 pps_param;
>+ u32 gop_param;
>+ u32 intra_param;
>+ u32 conf_win_top_bot;
>+ u32 conf_win_left_right;
>+ u32 rdo_param;
>+ u32 slice_param;
>+ u32 intra_refresh;
>+ u32 intra_min_max_qp;
>+ u32 rc_frame_rate;
>+ u32 rc_target_rate;
>+ u32 rc_param;
>+ u32 hvs_param;
>+ u32 rc_max_bitrate;
>+ u32 rc_vbv_buffer_size;
>+ u32 inter_min_max_qp;
>+ u32 rot_param;
>+ u32 num_units_in_tick;
>+ u32 time_scale;
>+ u32 num_ticks_poc_diff_one;
>+ u32 max_intra_pic_bit;
>+ u32 max_inter_pic_bit;
>+ u32 bg_param;
>+ u32 non_vcl_param;
>+ u32 vui_rbsp_addr;
>+ u32 hrd_rbsp_addr;
>+ u32 qround_offset;
>+ u32 quant_param_1;
>+ u32 quant_param_2;
>+ u32 custom_gop_param;
>+ u32 custom_gop_pic_param[MAX_GOP_NUM];
>+ u32 tile_param;
>+ u32 custom_lambda[MAX_CUSTOM_LAMBDA_NUM];
>+ u32 temporal_layer_qp[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER];
>+ u32 scl_src_size;
>+ u32 scl_param;
>+ u32 color_param;
>+ u32 sar_param;
>+ u32 sar_extended;
>+};
>+
>+struct enc_cmd_change_param_reg {
>+ u32 enable;
>+ u32 rc_target_rate;
>+};
>+
>+int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance
>*inst,
>+ struct enc_open_param *param)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ u32 reg_val;
>+ int ret;
>+
>+ p_enc_info->cycle_per_tick = 256;
>+ p_enc_info->line_buf_int_en = param->line_buf_int_en;
>+ p_enc_info->stride = 0;
>+ p_enc_info->initial_info_obtained = false;
>+ p_enc_info->sec_axi_info.use_enc_rdo = true;
>+ p_enc_info->sec_axi_info.use_enc_lf = true;
>+
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_BASE,
>param->inst_buffer.temp_base);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_SIZE,
>param->inst_buffer.temp_size);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE,
>param->inst_buffer.ar_base);
>+
>+ reg_val = wave6_vdi_convert_endian(param->stream_endian);
>+ reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_BS_PARAM,
>reg_val);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_SRC_OPT, 0);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_ADDR_EXT,
>param->ext_addr_vcpu);
>+
>+ reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1;
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_CORE_INFO,
>reg_val);
>+
>+ reg_val = (param->is_secure_inst << 8) | (param->inst_priority);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_PRIORITY,
>reg_val);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT,
>+ W6_VPU_TIMEOUT_CYCLE_COUNT);
>+
>+ wave6_send_command(inst->dev, 0, inst->std,
>W6_CMD_CREATE_INSTANCE);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+
>+ wave6_print_reg_err(inst->dev, reason_code);
>+ return -EIO;
>+ }
>+
>+ inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID);
>+
>+ return 0;
>+}
>+
>+static int wave6_set_enc_crop_info(u32 codec, struct enc_codec_param
>*param, int rot_mode,
>+ int width, int height)
>+{
>+ int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(width, 32) :
>ALIGN(width, 16);
>+ int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(height, 32) :
>ALIGN(height, 16);
>+ int pad_right, pad_bot;
>+ int crop_right, crop_left, crop_top, crop_bot;
>+ int prp_mode = rot_mode >> 1;
>+
>+ if (codec == W_HEVC_ENC &&
>+ (!rot_mode || prp_mode == 14))
>+ return 0;
>+
>+ pad_right = aligned_width - width;
>+ pad_bot = aligned_height - height;
>+
>+ if (param->conf_win.right > 0)
>+ crop_right = param->conf_win.right + pad_right;
>+ else
>+ crop_right = pad_right;
>+
>+ if (param->conf_win.bottom > 0)
>+ crop_bot = param->conf_win.bottom + pad_bot;
>+ else
>+ crop_bot = pad_bot;
>+
>+ crop_top = param->conf_win.top;
>+ crop_left = param->conf_win.left;
>+
>+ param->conf_win.top = crop_top;
>+ param->conf_win.left = crop_left;
>+ param->conf_win.bottom = crop_bot;
>+ param->conf_win.right = crop_right;
>+
>+ if (prp_mode == 1 || prp_mode == 15) {
>+ param->conf_win.top = crop_right;
>+ param->conf_win.left = crop_top;
>+ param->conf_win.bottom = crop_left;
>+ param->conf_win.right = crop_bot;
>+ } else if (prp_mode == 2 || prp_mode == 12) {
>+ param->conf_win.top = crop_bot;
>+ param->conf_win.left = crop_right;
>+ param->conf_win.bottom = crop_top;
>+ param->conf_win.right = crop_left;
>+ } else if (prp_mode == 3 || prp_mode == 13) {
>+ param->conf_win.top = crop_left;
>+ param->conf_win.left = crop_bot;
>+ param->conf_win.bottom = crop_right;
>+ param->conf_win.right = crop_top;
>+ } else if (prp_mode == 4 || prp_mode == 10) {
>+ param->conf_win.top = crop_bot;
>+ param->conf_win.bottom = crop_top;
>+ } else if (prp_mode == 8 || prp_mode == 6) {
>+ param->conf_win.left = crop_right;
>+ param->conf_win.right = crop_left;
>+ } else if (prp_mode == 5 || prp_mode == 11) {
>+ param->conf_win.top = crop_left;
>+ param->conf_win.left = crop_top;
>+ param->conf_win.bottom = crop_right;
>+ param->conf_win.right = crop_bot;
>+ } else if (prp_mode == 7 || prp_mode == 9) {
>+ param->conf_win.top = crop_right;
>+ param->conf_win.left = crop_bot;
>+ param->conf_win.bottom = crop_left;
>+ param->conf_win.right = crop_top;
>+ }
>+
>+ return 0;
>+}
>+
>+static bool wave6_update_enc_info(struct enc_info *p_enc_info)
>+{
>+ struct enc_open_param open_param = p_enc_info->open_param;
>+
>+ p_enc_info->width = open_param.pic_width;
>+ p_enc_info->height = open_param.pic_height;
>+
>+ switch (open_param.output_format) {
>+ case FORMAT_420:
>+ case FORMAT_420_P10_16BIT_MSB:
>+ case FORMAT_420_P10_16BIT_LSB:
>+ case FORMAT_420_P10_32BIT_MSB:
>+ case FORMAT_420_P10_32BIT_LSB:
>+ p_enc_info->color_format = 1;
>+ break;
>+ case FORMAT_422:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ p_enc_info->color_format = 2;
>+ break;
>+ case FORMAT_444:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ p_enc_info->color_format = 3;
>+ break;
>+ case FORMAT_400:
>+ case FORMAT_400_P10_16BIT_MSB:
>+ case FORMAT_400_P10_16BIT_LSB:
>+ case FORMAT_400_P10_32BIT_MSB:
>+ case FORMAT_400_P10_32BIT_LSB:
>+ p_enc_info->color_format = 0;
>+ break;
>+ default:
>+ return false;
>+ }
>+
>+ return true;
>+}
>+
>+static void wave6_gen_set_param_reg_common(struct enc_info *p_enc_info,
>enum codec_std std,
>+ struct enc_cmd_set_param_reg *reg)
>+{
>+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
>+ struct enc_codec_param *p_param = &p_open_param->codec_param;
>+ unsigned int i, endian;
>+ u32 rot_mir_mode = 0;
>+
>+ endian = wave6_vdi_convert_endian(p_param->custom_map_endian);
>+ endian = (~endian & VDI_128BIT_ENDIAN_MASK);
>+
>+ if (p_enc_info->rotation_enable) {
>+ switch (p_enc_info->rotation_angle) {
>+ case 0:
>+ rot_mir_mode |= 0x0; break;
>+ case 90:
>+ rot_mir_mode |= 0x3; break;
>+ case 180:
>+ rot_mir_mode |= 0x5; break;
>+ case 270:
>+ rot_mir_mode |= 0x7; break;
>+ }
>+ }
>+
>+ if (p_enc_info->mirror_enable) {
>+ switch (p_enc_info->mirror_direction) {
>+ case MIRDIR_NONE:
>+ rot_mir_mode |= 0x0; break;
>+ case MIRDIR_VER:
>+ rot_mir_mode |= 0x9; break;
>+ case MIRDIR_HOR:
>+ rot_mir_mode |= 0x11; break;
>+ case MIRDIR_HOR_VER:
>+ rot_mir_mode |= 0x19; break;
>+ }
>+ }
>+
>+ wave6_set_enc_crop_info(std, p_param, rot_mir_mode, p_enc_info-
>>width, p_enc_info->height);
>+
>+ reg->src_size = (p_enc_info->height << 16) | p_enc_info->width;
>+ reg->custom_map_endian = endian;
>+ reg->gop_param = (p_param->temp_layer_cnt << 16) |
>+ (p_param->temp_layer[3].change_qp << 11) |
>+ (p_param->temp_layer[2].change_qp << 10) |
>+ (p_param->temp_layer[1].change_qp << 9) |
>+ (p_param->temp_layer[0].change_qp << 8) |
>+ p_param->gop_preset_idx;
>+ reg->intra_refresh = (p_param->intra_refresh_arg << 16) | p_param-
>>intra_refresh_mode;
>+ reg->intra_min_max_qp = (p_param->max_qp_i << 6) | p_param-
>>min_qp_i;
>+ reg->rc_frame_rate = p_param->frame_rate;
>+ reg->rc_target_rate = p_param->bitrate;
>+ reg->rc_param = (p_param->rc_update_speed << 24) |
>+ (p_param->rc_initial_level << 20) |
>+ ((p_param->rc_initial_qp & 0x3f) << 14) |
>+ (p_param->rc_mode << 13) |
>+ (p_param->pic_rc_max_dqp << 7) |
>+ (p_param->en_vbv_overflow_drop_frame << 3) |
>+ (p_param->en_cu_level_rate_control << 1) |
>+ p_param->en_rate_control;
>+ reg->hvs_param = (p_param->max_delta_qp << 12) | p_param-
>>hvs_qp_scale_div2;
>+ reg->rc_max_bitrate = p_param->max_bitrate;
>+ reg->rc_vbv_buffer_size = p_param->cpb_size;
>+ reg->inter_min_max_qp = (p_param->max_qp_b << 18) |
>+ (p_param->min_qp_b << 12) |
>+ (p_param->max_qp_p << 6) |
>+ p_param->min_qp_p;
>+ reg->rot_param = rot_mir_mode;
>+ reg->conf_win_top_bot = (p_param->conf_win.bottom << 16) | p_param-
>>conf_win.top;
>+ reg->conf_win_left_right = (p_param->conf_win.right << 16) | p_param-
>>conf_win.left;
>+ reg->num_units_in_tick = p_param->num_units_in_tick;
>+ reg->time_scale = p_param->time_scale;
>+ reg->num_ticks_poc_diff_one = p_param->num_ticks_poc_diff_one;
>+ reg->max_intra_pic_bit = p_param->max_intra_pic_bit;
>+ reg->max_inter_pic_bit = p_param->max_inter_pic_bit;
>+ reg->bg_param = ((p_param->bg_delta_qp & 0x3F) << 24) |
>+ (p_param->bg_th_mean_diff << 10) |
>+ (p_param->bg_th_diff << 1) |
>+ p_param->en_bg_detect;
>+ reg->qround_offset = (p_param->q_round_inter << 13) |
>+ (p_param->q_round_intra << 2);
>+ reg->custom_gop_param = p_param->gop_param.custom_gop_size;
>+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
>+ struct custom_gop_pic_param pic_param = p_param-
>>gop_param.pic_param[i];
>+
>+ reg->custom_gop_pic_param[i] = (pic_param.temporal_id << 26) |
>+ ((pic_param.ref_poc_l1 & 0x3F) << 20) |
>+ ((pic_param.ref_poc_l0 & 0x3F) << 14) |
>+ (pic_param.use_multi_ref_p << 13) |
>+ (pic_param.pic_qp << 7) |
>+ (pic_param.poc_offset << 2) |
>+ pic_param.pic_type;
>+ }
>+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) {
>+ reg->custom_lambda[i] = (p_param->custom_lambda_ssd[i] << 7) |
>+ p_param->custom_lambda_sad[i];
>+ }
>+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) {
>+ reg->temporal_layer_qp[i] = (p_param->temp_layer[i].qp_b << 12) |
>+ (p_param->temp_layer[i].qp_p << 6) |
>+ p_param->temp_layer[i].qp_i;
>+ }
>+ reg->scl_src_size = (p_open_param->pic_height << 16) | p_open_param-
>>pic_width;
>+ reg->scl_param = (p_enc_info->scaler_info.coef_mode << 1) | p_enc_info-
>>scaler_info.enable;
>+ reg->color_param = ((p_param->color.chroma_sample_position & 0x3) <<
>26) |
>+ (p_param->color.color_range << 25) |
>+ ((p_param->color.matrix_coefficients & 0xFF) << 17) |
>+ ((p_param->color.transfer_characteristics & 0xFF) << 9) |
>+ ((p_param->color.color_primaries & 0xFF) << 1) |
>+ p_param->color.color_description_present;
>+ reg->sar_param = ((p_param->sar.idc & 0xFF) << 1) |
>+ (p_param->sar.enable & 0x1);
>+ reg->sar_extended = ((p_param->sar.height & 0xFFFF) << 16) |
>+ (p_param->sar.width & 0xFFFF);
>+}
>+
>+static void wave6_gen_set_param_reg_hevc(struct enc_info *p_enc_info,
>+ struct enc_cmd_set_param_reg *reg)
>+{
>+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
>+ struct enc_codec_param *p_param = &p_open_param->codec_param;
>+
>+ reg->sps_param = (p_param->en_scaling_list << 31) |
>+ (p_param->en_still_picture << 30) |
>+ (p_param->en_auto_level_adjusting << 28) |
>+ (p_param->en_strong_intra_smoothing << 27) |
>+ (p_param->en_intra_trans_skip << 25) |
>+ (p_param->en_sao << 24) |
>+ (p_param->en_temporal_mvp << 23) |
>+ (p_param->en_long_term << 21) |
>+ (p_enc_info->color_format << 19) |
>+ (p_param->internal_bit_depth << 14) |
>+ (p_param->tier << 12) |
>+ (p_param->level << 3) |
>+ p_param->profile;
>+ reg->pps_param = ((p_param->cr_qp_offset & 0x1F) << 19) |
>+ ((p_param->cb_qp_offset & 0x1F) << 14) |
>+ ((p_param->tc_offset_div2 & 0xF) << 10) |
>+ ((p_param->beta_offset_div2 & 0xF) << 6) |
>+ ((!p_param->en_dbk) << 5) |
>+ (p_param->en_lf_cross_slice_boundary << 2) |
>+ (p_param->en_constrained_intra_pred << 1);
>+ reg->intra_param = (p_param->intra_period << 16) |
>+ (p_param->forced_idr_header << 9) |
>+ (p_param->qp << 3) |
>+ p_param->decoding_refresh_type;
>+ reg->rdo_param = (p_param->en_custom_lambda << 22) |
>+ (p_param->en_me_center << 21) |
>+ (p_param->en_qp_map << 20) |
>+ (p_param->en_mode_map << 19) |
>+ (p_param->en_q_round_offset << 17) |
>+ (p_param->dis_coef_clear << 4) |
>+ (p_param->en_adaptive_round << 3) |
>+ (p_param->en_hvs_qp << 2);
>+ reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode;
>+ reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) |
>+ ((p_param->lambda_dqp_intra & 0x3F) << 8);
>+ reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) |
>+ (p_open_param->enc_hrd_rbsp_in_vps << 2) |
>+ (NON_VCL_PARAM_ENCODE_VUI) |
>+ p_open_param->enc_aud;
>+ reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr;
>+}
>+
>+static void wave6_gen_set_param_reg_avc(struct enc_info *p_enc_info,
>+ struct enc_cmd_set_param_reg *reg)
>+{
>+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
>+ struct enc_codec_param *p_param = &p_open_param->codec_param;
>+
>+ reg->sps_param = (p_param->en_scaling_list << 31) |
>+ (p_param->en_auto_level_adjusting << 28) |
>+ (p_param->en_long_term << 21) |
>+ (p_enc_info->color_format << 19) |
>+ (p_param->internal_bit_depth << 14) |
>+ (p_param->level << 3) |
>+ p_param->profile;
>+ reg->pps_param = (p_param->en_cabac << 30) |
>+ (p_param->en_transform8x8 << 29) |
>+ ((p_param->cr_qp_offset & 0x1F) << 19) |
>+ ((p_param->cb_qp_offset & 0x1F) << 14) |
>+ ((p_param->tc_offset_div2 & 0xF) << 10) |
>+ ((p_param->beta_offset_div2 & 0xF) << 6) |
>+ ((!p_param->en_dbk) << 5) |
>+ (p_param->en_lf_cross_slice_boundary << 2) |
>+ (p_param->en_constrained_intra_pred << 1);
>+ reg->intra_param = (p_param->forced_idr_header << 28) |
>+ (p_param->idr_period << 17) |
>+ (p_param->intra_period << 6) |
>+ p_param->qp;
>+ reg->rdo_param = (p_param->en_custom_lambda << 22) |
>+ (p_param->en_me_center << 21) |
>+ (p_param->en_qp_map << 20) |
>+ (p_param->en_mode_map << 19) |
>+ (p_param->en_q_round_offset << 17) |
>+ (p_param->dis_coef_clear << 4) |
>+ (p_param->en_adaptive_round << 3) |
>+ (p_param->en_hvs_qp << 2);
>+ reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode;
>+ reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) |
>+ ((p_param->lambda_dqp_intra & 0x3F) << 8);
>+ reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) |
>+ (p_open_param->enc_hrd_rbsp_in_vps << 2) |
>+ (NON_VCL_PARAM_ENCODE_VUI) |
>+ p_open_param->enc_aud;
>+ reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr;
>+}
>+
>+static void wave6_gen_change_param_reg_common(struct vpu_instance
>*inst,
>+ struct enc_info *p_enc_info,
>+ struct enc_cmd_change_param_reg *reg)
>+{
>+ if (p_enc_info->open_param.codec_param.bitrate != inst-
>>enc_ctrls.bitrate) {
>+ reg->enable |=
>BIT(W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE);
>+ reg->rc_target_rate = inst->enc_ctrls.bitrate;
>+ p_enc_info->open_param.codec_param.bitrate = inst-
>>enc_ctrls.bitrate;
>+ }
>+}
>+
>+int wave6_vpu_enc_init_seq(struct vpu_instance *inst)
>+{
>+ struct enc_cmd_set_param_reg reg;
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ u32 i;
>+ int ret;
>+
>+ memset(®, 0, sizeof(struct enc_cmd_set_param_reg));
>+
>+ if (!wave6_update_enc_info(p_enc_info))
>+ return -EINVAL;
>+
>+ wave6_gen_set_param_reg_common(p_enc_info, inst->std, ®);
>+ if (inst->std == W_HEVC_ENC)
>+ wave6_gen_set_param_reg_hevc(p_enc_info, ®);
>+ else if (inst->std == W_AVC_ENC)
>+ wave6_gen_set_param_reg_avc(p_enc_info, ®);
>+
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION,
>W6_SET_PARAM_OPT_COMMON);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE,
>reg.enable);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SRC_SIZE,
>reg.src_size);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN,
>reg.custom_map_endian);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SPS_PARAM,
>reg.sps_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_PPS_PARAM,
>reg.pps_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_GOP_PARAM,
>reg.gop_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_PARAM,
>reg.intra_param);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT, reg.conf_win_top_bot);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT,
>reg.conf_win_left_right);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RDO_PARAM,
>reg.rdo_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SLICE_PARAM,
>reg.slice_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_REFRESH,
>reg.intra_refresh);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP, reg.intra_min_max_qp);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE,
>reg.rc_frame_rate);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE,
>reg.rc_target_rate);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_PARAM,
>reg.rc_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HVS_PARAM,
>reg.hvs_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE,
>reg.rc_max_bitrate);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE, reg.rc_vbv_buffer_size);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP, reg.inter_min_max_qp);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ROT_PARAM,
>reg.rot_param);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK, reg.num_units_in_tick);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TIME_SCALE,
>reg.time_scale);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE,
>+ reg.num_ticks_poc_diff_one);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT, reg.max_intra_pic_bit);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT, reg.max_inter_pic_bit);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_BG_PARAM,
>reg.bg_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM,
>reg.non_vcl_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR,
>reg.vui_rbsp_addr);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR,
>reg.hrd_rbsp_addr);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QROUND_OFFSET,
>reg.qround_offset);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1,
>reg.quant_param_1);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2,
>reg.quant_param_2);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM, reg.custom_gop_param);
>+ for (i = 0; i < MAX_GOP_NUM; i++)
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0 + (i * 4),
>+ reg.custom_gop_pic_param[i]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TILE_PARAM,
>reg.tile_param);
>+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++)
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0 + (i * 4),
>+ reg.custom_lambda[i]);
>+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++)
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP + (i * 4),
>+ reg.temporal_layer_qp[i]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE,
>reg.scl_src_size);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_PARAM,
>reg.scl_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_COLOR_PARAM,
>reg.color_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_PARAM,
>reg.sar_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_EXTENDED,
>reg.sar_extended);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_ENC_SET_PARAM);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+
>+ wave6_print_reg_err(inst->dev, reason_code);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct
>enc_initial_info *info)
>+{
>+ int ret;
>+
>+ ret = wave6_send_query(inst->dev, inst->id, inst->std,
>W6_QUERY_OPT_GET_RESULT);
>+ if (ret)
>+ return ret;
>+
>+ if (vpu_read_reg(inst->dev, W6_RET_ENC_ENCODING_SUCCESS) != 1) {
>+ info->err_reason = vpu_read_reg(inst->dev,
>W6_RET_ENC_ERR_INFO);
>+ ret = -EIO;
>+ } else {
>+ info->warn_info = vpu_read_reg(inst->dev,
>W6_RET_ENC_WARN_INFO);
>+ }
>+
>+ info->min_frame_buffer_count = vpu_read_reg(inst->dev,
>W6_RET_ENC_NUM_REQUIRED_FBC_FB);
>+ info->min_src_frame_count = vpu_read_reg(inst->dev,
>W6_RET_ENC_MIN_SRC_BUF_NUM);
>+ info->max_latency_pictures = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_MAX_LATENCY_PICTURES);
>+ info->req_mv_buffer_count = vpu_read_reg(inst->dev,
>W6_RET_ENC_NUM_REQUIRED_COL_BUF);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed)
>+{
>+ struct enc_cmd_change_param_reg reg;
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int ret;
>+
>+ memset(®, 0, sizeof(struct enc_cmd_change_param_reg));
>+
>+ wave6_gen_change_param_reg_common(inst, p_enc_info, ®);
>+
>+ if (!reg.enable)
>+ return 0;
>+
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION,
>W6_SET_PARAM_OPT_CHANGE_PARAM);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE,
>reg.enable);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE,
>reg.rc_target_rate);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_ENC_SET_PARAM);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_warn(inst->dev->dev, "enc set param timed out\n");
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+
>+ wave6_print_reg_err(inst->dev, reason_code);
>+ return -EIO;
>+ }
>+
>+ *changed = true;
>+
>+ return 0;
>+}
>+
>+struct enc_cmd_set_fb_reg {
>+ u32 option;
>+ u32 pic_info;
>+ u32 pic_size;
>+ u32 num_fb;
>+ u32 fbc_stride;
>+ u32 fbc_y[WAVE6_MAX_FBS];
>+ u32 fbc_c[WAVE6_MAX_FBS];
>+ u32 fbc_cr[WAVE6_MAX_FBS];
>+ u32 fbc_y_offset[WAVE6_MAX_FBS];
>+ u32 fbc_c_offset[WAVE6_MAX_FBS];
>+ u32 fbc_cr_offset[WAVE6_MAX_FBS];
>+ u32 mv_col[WAVE6_MAX_FBS];
>+ u32 sub_sampled[WAVE6_MAX_FBS];
>+ u32 default_cdf;
>+};
>+
>+static void wave6_gen_set_fb_reg(struct enc_info *p_enc_info, enum
>codec_std std,
>+ struct frame_buffer *fb_arr, struct enc_cmd_set_fb_reg
>*reg)
>+{
>+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
>+ u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count;
>+ u32 buf_width, buf_height;
>+ u32 stride_l, stride_c, i;
>+
>+ if (std == W_AVC_ENC) {
>+ buf_width = ALIGN(p_enc_info->width, 16);
>+ buf_height = ALIGN(p_enc_info->height, 16);
>+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle
>== 270) {
>+ buf_width = ALIGN(p_enc_info->height, 16);
>+ buf_height = ALIGN(p_enc_info->width, 16);
>+ }
>+ } else {
>+ buf_width = ALIGN(p_enc_info->width, 8);
>+ buf_height = ALIGN(p_enc_info->height, 8);
>+ if ((p_enc_info->rotation_angle != 0 || p_enc_info-
>>mirror_direction != 0) &&
>+ !(p_enc_info->rotation_angle == 180 &&
>+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
>+ buf_width = ALIGN(p_enc_info->width, 32);
>+ buf_height = ALIGN(p_enc_info->height, 32);
>+ }
>+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle
>== 270) {
>+ buf_width = ALIGN(p_enc_info->height, 32);
>+ buf_height = ALIGN(p_enc_info->width, 32);
>+ }
>+ }
>+
>+ if ((p_enc_info->rotation_angle != 0 || p_enc_info->mirror_direction != 0)
>&&
>+ !(p_enc_info->rotation_angle == 180 &&
>+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
>+ stride_l = ALIGN((buf_width + 63), 64);
>+ stride_c = ALIGN((buf_width + 31), 32) / 2;
>+ } else {
>+ stride_l = ALIGN((p_enc_info->width) + 63, 64);
>+ stride_c = ALIGN((p_enc_info->width) + 31, 32) / 2;
>+ }
>+
>+ reg->option = (p_open_param->enable_non_ref_fbc_write << 26) | (1 <<
>4) | (1 << 3);
>+ reg->pic_info = p_enc_info->stride;
>+ reg->pic_size = (buf_width << 16) | buf_height;
>+ reg->num_fb = ((p_enc_info->num_frame_buffers - 1) << 16) | (mv_count
>- 1);
>+ reg->fbc_stride = (stride_l << 16) | stride_c;
>+ reg->default_cdf = 0;
>+
>+ for (i = 0; i < p_enc_info->num_frame_buffers; i++) {
>+ reg->fbc_y[i] = fb_arr[i].buf_y;
>+ reg->fbc_c[i] = fb_arr[i].buf_cb;
>+ reg->fbc_cr[i] = fb_arr[i].buf_cr;
>+ reg->fbc_y_offset[i] = p_enc_info->vb_fbc_y_tbl[i].daddr;
>+ reg->fbc_c_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr;
>+ reg->fbc_cr_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr +
>+ (p_enc_info->vb_fbc_c_tbl[i].size >> 1);
>+ reg->sub_sampled[i] = p_enc_info->vb_sub_sam_buf[i].daddr;
>+ }
>+ for (i = 0; i < mv_count; i++)
>+ reg->mv_col[i] = p_enc_info->vb_mv[i].daddr;
>+}
>+
>+int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst, struct
>frame_buffer *fb_arr)
>+{
>+ struct enc_cmd_set_fb_reg *reg;
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count;
>+ int ret;
>+ u32 idx;
>+
>+ for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) {
>+ if (!p_enc_info->vb_fbc_y_tbl[idx].daddr)
>+ return -EINVAL;
>+ if (!p_enc_info->vb_fbc_c_tbl[idx].daddr)
>+ return -EINVAL;
>+ if (!p_enc_info->vb_sub_sam_buf[idx].daddr)
>+ return -EINVAL;
>+ }
>+ for (idx = 0; idx < mv_count; idx++) {
>+ if (!p_enc_info->vb_mv[idx].daddr)
>+ return -EINVAL;
>+ }
>+
>+ reg = kzalloc(sizeof(*reg), GFP_KERNEL);
>+ if (!reg)
>+ return -ENOMEM;
>+
>+ wave6_gen_set_fb_reg(p_enc_info, inst->std, fb_arr, reg);
>+
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_OPTION, reg->option);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_INFO, reg-
>>pic_info);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_SIZE, reg->pic_size);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_NUM, reg->num_fb);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_STRIDE, reg-
>>fbc_stride);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_DEFAULT_CDF, reg-
>>default_cdf);
>+ for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) {
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y0 + (idx * 24),
>reg->fbc_y[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C0 + (idx * 24),
>reg->fbc_c[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR0 + (idx *
>8), reg->fbc_cr[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 +
>(idx * 24),
>+ reg->fbc_y_offset[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 +
>(idx * 24),
>+ reg->fbc_c_offset[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 +
>(idx * 8),
>+ reg->fbc_cr_offset[idx]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_SUB_SAMPLED0 +
>(idx * 24),
>+ reg->sub_sampled[idx]);
>+ }
>+ for (idx = 0; idx < mv_count; idx++)
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_MV_COL0 + (idx *
>24), reg->mv_col[idx]);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_SET_FB);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ kfree(reg);
>+ return ret;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ kfree(reg);
>+ return -EIO;
>+ }
>+
>+ kfree(reg);
>+ return 0;
>+}
>+
>+struct enc_cmd_enc_pic_reg {
>+ u32 bs_start;
>+ u32 bs_size;
>+ u32 bs_option;
>+ u32 use_sec_axi;
>+ u32 report_param;
>+ u32 mv_histo_class0;
>+ u32 mv_histo_class1;
>+ u32 custom_map_param;
>+ u32 custom_map_addr;
>+ u32 src_pic_idx;
>+ u32 src_addr_y;
>+ u32 src_addr_u;
>+ u32 src_addr_v;
>+ u32 src_stride;
>+ u32 src_format;
>+ u32 src_axi_sel;
>+ u32 code_option;
>+ u32 pic_param;
>+ u32 longterm_pic;
>+ u32 prefix_sei_nal_addr;
>+ u32 prefix_sei_info;
>+ u32 suffix_sei_nal_addr;
>+ u32 suffix_sei_info;
>+ u32 timestamp;
>+ u32 csc_coeff[MAX_CSC_COEFF_NUM];
>+};
>+
>+static bool is_format_conv(enum frame_buffer_format in_fmt,
>+ enum frame_buffer_format out_fmt)
>+{
>+ if (in_fmt == FORMAT_420 ||
>+ in_fmt == FORMAT_420_P10_16BIT_MSB ||
>+ in_fmt == FORMAT_420_P10_16BIT_LSB ||
>+ in_fmt == FORMAT_420_P10_32BIT_MSB ||
>+ in_fmt == FORMAT_420_P10_32BIT_LSB) {
>+ if (out_fmt != FORMAT_420 &&
>+ out_fmt != FORMAT_420_P10_16BIT_MSB &&
>+ out_fmt != FORMAT_420_P10_16BIT_LSB &&
>+ out_fmt != FORMAT_420_P10_32BIT_MSB &&
>+ out_fmt != FORMAT_420_P10_32BIT_LSB)
>+ return true;
>+ } else if (in_fmt == FORMAT_422 ||
>+ in_fmt == FORMAT_422_P10_16BIT_MSB ||
>+ in_fmt == FORMAT_422_P10_16BIT_LSB ||
>+ in_fmt == FORMAT_422_P10_32BIT_MSB ||
>+ in_fmt == FORMAT_422_P10_32BIT_LSB) {
>+ if (out_fmt != FORMAT_422 &&
>+ out_fmt != FORMAT_422_P10_16BIT_MSB &&
>+ out_fmt != FORMAT_422_P10_16BIT_LSB &&
>+ out_fmt != FORMAT_422_P10_32BIT_MSB &&
>+ out_fmt != FORMAT_422_P10_32BIT_LSB)
>+ return true;
>+ } else if (in_fmt == FORMAT_444 ||
>+ in_fmt == FORMAT_444_P10_16BIT_MSB ||
>+ in_fmt == FORMAT_444_P10_16BIT_LSB ||
>+ in_fmt == FORMAT_444_P10_32BIT_MSB ||
>+ in_fmt == FORMAT_444_P10_32BIT_LSB) {
>+ if (out_fmt != FORMAT_444 &&
>+ out_fmt != FORMAT_444_P10_16BIT_MSB &&
>+ out_fmt != FORMAT_444_P10_16BIT_LSB &&
>+ out_fmt != FORMAT_444_P10_32BIT_MSB &&
>+ out_fmt != FORMAT_444_P10_32BIT_LSB)
>+ return true;
>+ }
>+
>+ return false;
>+}
>+
>+static void wave6_gen_enc_pic_reg(struct enc_info *p_enc_info, bool
>cbcr_interleave, bool nv21,
>+ struct enc_param *opt, struct enc_cmd_enc_pic_reg *reg)
>+{
>+ struct enc_open_param open = p_enc_info->open_param;
>+ struct enc_codec_param param = open.codec_param;
>+ bool is_lsb = false;
>+ bool is_10bit = false;
>+ bool is_3p4b = false;
>+ u32 stride_c;
>+ u32 src_frame_format;
>+ u32 endian;
>+ u32 color_format;
>+ bool is_ayuv = false;
>+ bool is_csc_format = false;
>+ bool is_24bit = false;
>+ bool format_conv;
>+
>+ endian = wave6_vdi_convert_endian(open.source_endian);
>+ endian = (~endian & VDI_128BIT_ENDIAN_MASK);
>+ format_conv = is_format_conv(open.src_format, open.output_format);
>+
>+ switch (open.src_format) {
>+ case FORMAT_420:
>+ case FORMAT_420_P10_16BIT_MSB:
>+ case FORMAT_420_P10_16BIT_LSB:
>+ color_format = 1;
>+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
>+ (opt->source_frame->stride / 2);
>+ break;
>+ case FORMAT_420_P10_32BIT_MSB:
>+ case FORMAT_420_P10_32BIT_LSB:
>+ color_format = 1;
>+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
>+ ALIGN((opt->source_frame->stride / 2), 16);
>+ break;
>+ case FORMAT_422:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ color_format = 2;
>+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
>+ (opt->source_frame->stride / 2);
>+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
>+ break;
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ color_format = 2;
>+ stride_c = (cbcr_interleave) ? opt->source_frame->stride :
>+ ALIGN((opt->source_frame->stride / 2), 16);
>+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
>+ break;
>+ case FORMAT_444:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ color_format = 3;
>+ stride_c = (cbcr_interleave) ? (opt->source_frame->stride * 2) :
>+ opt->source_frame->stride;
>+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
>+ break;
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ color_format = 3;
>+ stride_c = (cbcr_interleave) ? ALIGN((opt->source_frame->stride * 2),
>16) :
>+ opt->source_frame->stride;
>+ stride_c = (format_conv) ? (stride_c * 2) : stride_c;
>+ break;
>+ case FORMAT_YUV444_24BIT:
>+ color_format = 0;
>+ stride_c = ALIGN((opt->source_frame->stride * 2), 16);
>+ break;
>+ case FORMAT_RGB_24BIT_PACKED:
>+ case FORMAT_YUV444_24BIT_PACKED:
>+ case FORMAT_RGB_32BIT_PACKED:
>+ case FORMAT_RGB_P10_32BIT_PACKED:
>+ case FORMAT_YUV444_32BIT_PACKED:
>+ case FORMAT_YUV444_P10_32BIT_PACKED:
>+ color_format = 4;
>+ stride_c = 0;
>+ break;
>+ case FORMAT_YUYV:
>+ case FORMAT_YVYU:
>+ case FORMAT_UYVY:
>+ case FORMAT_VYUY:
>+ case FORMAT_YUYV_P10_16BIT_MSB:
>+ case FORMAT_YVYU_P10_16BIT_MSB:
>+ case FORMAT_UYVY_P10_16BIT_MSB:
>+ case FORMAT_VYUY_P10_16BIT_MSB:
>+ case FORMAT_YUYV_P10_16BIT_LSB:
>+ case FORMAT_YVYU_P10_16BIT_LSB:
>+ case FORMAT_UYVY_P10_16BIT_LSB:
>+ case FORMAT_VYUY_P10_16BIT_LSB:
>+ case FORMAT_YUYV_P10_32BIT_MSB:
>+ case FORMAT_YVYU_P10_32BIT_MSB:
>+ case FORMAT_UYVY_P10_32BIT_MSB:
>+ case FORMAT_VYUY_P10_32BIT_MSB:
>+ case FORMAT_YUYV_P10_32BIT_LSB:
>+ case FORMAT_YVYU_P10_32BIT_LSB:
>+ case FORMAT_UYVY_P10_32BIT_LSB:
>+ case FORMAT_VYUY_P10_32BIT_LSB:
>+ color_format = 2;
>+ stride_c = 0;
>+ break;
>+ default:
>+ color_format = 0;
>+ stride_c = 0;
>+ break;
>+ }
>+
>+ switch (open.src_format) {
>+ case FORMAT_420:
>+ case FORMAT_422:
>+ case FORMAT_444:
>+ case FORMAT_400:
>+ case FORMAT_YUYV:
>+ case FORMAT_YVYU:
>+ case FORMAT_UYVY:
>+ case FORMAT_VYUY:
>+ is_lsb = false;
>+ is_3p4b = false;
>+ break;
>+ case FORMAT_420_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_400_P10_16BIT_MSB:
>+ case FORMAT_YUYV_P10_16BIT_MSB:
>+ case FORMAT_YVYU_P10_16BIT_MSB:
>+ case FORMAT_UYVY_P10_16BIT_MSB:
>+ case FORMAT_VYUY_P10_16BIT_MSB:
>+ is_lsb = false;
>+ is_10bit = true;
>+ is_3p4b = false;
>+ break;
>+ case FORMAT_420_P10_16BIT_LSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ case FORMAT_400_P10_16BIT_LSB:
>+ case FORMAT_YUYV_P10_16BIT_LSB:
>+ case FORMAT_YVYU_P10_16BIT_LSB:
>+ case FORMAT_UYVY_P10_16BIT_LSB:
>+ case FORMAT_VYUY_P10_16BIT_LSB:
>+ is_lsb = true;
>+ is_10bit = true;
>+ is_3p4b = false;
>+ break;
>+ case FORMAT_420_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_400_P10_32BIT_MSB:
>+ case FORMAT_YUYV_P10_32BIT_MSB:
>+ case FORMAT_YVYU_P10_32BIT_MSB:
>+ case FORMAT_UYVY_P10_32BIT_MSB:
>+ case FORMAT_VYUY_P10_32BIT_MSB:
>+ is_lsb = false;
>+ is_10bit = true;
>+ is_3p4b = true;
>+ break;
>+ case FORMAT_420_P10_32BIT_LSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ case FORMAT_400_P10_32BIT_LSB:
>+ case FORMAT_YUYV_P10_32BIT_LSB:
>+ case FORMAT_YVYU_P10_32BIT_LSB:
>+ case FORMAT_UYVY_P10_32BIT_LSB:
>+ case FORMAT_VYUY_P10_32BIT_LSB:
>+ is_lsb = true;
>+ is_10bit = true;
>+ is_3p4b = true;
>+ break;
>+ case FORMAT_RGB_32BIT_PACKED:
>+ is_ayuv = false;
>+ is_csc_format = true;
>+ break;
>+ case FORMAT_RGB_P10_32BIT_PACKED:
>+ is_ayuv = false;
>+ is_csc_format = true;
>+ is_10bit = true;
>+ break;
>+ case FORMAT_YUV444_32BIT_PACKED:
>+ is_ayuv = true;
>+ is_csc_format = true;
>+ break;
>+ case FORMAT_YUV444_P10_32BIT_PACKED:
>+ is_ayuv = true;
>+ is_csc_format = true;
>+ is_10bit = true;
>+ break;
>+ case FORMAT_RGB_24BIT_PACKED:
>+ is_ayuv = false;
>+ is_csc_format = true;
>+ is_24bit = true;
>+ break;
>+ case FORMAT_YUV444_24BIT_PACKED:
>+ is_ayuv = true;
>+ is_csc_format = true;
>+ is_24bit = true;
>+ break;
>+ case FORMAT_YUV444_24BIT:
>+ is_ayuv = true;
>+ break;
>+ default:
>+ break;
>+ }
>+
>+ src_frame_format = (nv21 << 2) | (cbcr_interleave << 1);
>+ switch (open.packed_format) {
>+ case PACKED_YUYV:
>+ src_frame_format = 1; break;
>+ case PACKED_YVYU:
>+ src_frame_format = 5; break;
>+ case PACKED_UYVY:
>+ src_frame_format = 9; break;
>+ case PACKED_VYUY:
>+ src_frame_format = 13; break;
>+ default:
>+ break;
>+ }
>+
>+ reg->bs_start = opt->pic_stream_buffer_addr;
>+ reg->bs_size = opt->pic_stream_buffer_size;
>+ reg->bs_option = (p_enc_info->line_buf_int_en << 6);
>+ reg->use_sec_axi = (p_enc_info->sec_axi_info.use_enc_rdo << 1) |
>+ p_enc_info->sec_axi_info.use_enc_lf;
>+ reg->report_param = (param.en_report_mv_histo << 1);
>+ reg->mv_histo_class0 = (param.report_mv_histo_threshold0 << 16) |
>+ param.report_mv_histo_threshold1;
>+ reg->mv_histo_class1 = (param.report_mv_histo_threshold2 << 16) |
>+ param.report_mv_histo_threshold3;
>+
>+ reg->src_pic_idx = opt->src_idx;
>+ if (opt->src_end)
>+ reg->src_pic_idx = 0xFFFFFFFF;
>+
>+ reg->src_addr_y = opt->source_frame->buf_y;
>+ if (open.cbcr_order == CBCR_ORDER_NORMAL) {
>+ reg->src_addr_u = opt->source_frame->buf_cb;
>+ reg->src_addr_v = opt->source_frame->buf_cr;
>+ } else {
>+ reg->src_addr_u = opt->source_frame->buf_cr;
>+ reg->src_addr_v = opt->source_frame->buf_cb;
>+ }
>+ reg->src_stride = (opt->source_frame->stride << 16) | stride_c;
>+ reg->src_format = (color_format << 28) |
>+ (is_24bit << 25) |
>+ (is_ayuv << 24) |
>+ (is_csc_format << 20) |
>+ (opt->csc.format_order << 16) |
>+ (endian << 12) |
>+ (is_lsb << 6) |
>+ (is_3p4b << 5) |
>+ (is_10bit << 4) |
>+ src_frame_format;
>+ reg->src_axi_sel = DEFAULT_SRC_AXI;
>+ reg->code_option = (opt->src_end << 10) |
>+ (W6_ENC_PIC_OPT_VCL) |
>+ (W6_ENC_PIC_OPT_HEADER_IMPLICIT);
>+ reg->pic_param = (param.intra_4x4 << 28) |
>+ (opt->force_pic_type << 21) |
>+ (opt->force_pic_type_enable << 20) |
>+ (opt->force_pic_qp_b << 14) |
>+ (opt->force_pic_qp_p << 8) |
>+ (opt->force_pic_qp_i << 2) |
>+ (opt->force_pic_qp_enable << 1) |
>+ opt->skip_picture;
>+ reg->timestamp = ((opt->timestamp.hour & 0x1F) << 26) |
>+ ((opt->timestamp.min & 0x3F) << 20) |
>+ ((opt->timestamp.sec & 0x3F) << 14) |
>+ ((opt->timestamp.ms & 0x3FFF));
>+ reg->csc_coeff[0] = ((opt->csc.coef_ry & 0x3FF) << 20) |
>+ ((opt->csc.coef_gy & 0x3FF) << 10) |
>+ (opt->csc.coef_by & 0x3FF);
>+ reg->csc_coeff[1] = ((opt->csc.coef_rcb & 0x3FF) << 20) |
>+ ((opt->csc.coef_gcb & 0x3FF) << 10) |
>+ (opt->csc.coef_bcb & 0x3FF);
>+ reg->csc_coeff[2] = ((opt->csc.coef_rcr & 0x3FF) << 20) |
>+ ((opt->csc.coef_gcr & 0x3FF) << 10) |
>+ (opt->csc.coef_bcr & 0x3FF);
>+ reg->csc_coeff[3] = ((opt->csc.offset_y & 0x3FF) << 20) |
>+ ((opt->csc.offset_cb & 0x3FF) << 10) |
>+ (opt->csc.offset_cr & 0x3FF);
>+}
>+
>+int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option,
>u32 *fail_res)
>+{
>+ struct enc_cmd_enc_pic_reg reg;
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int ret;
>+
>+ memset(®, 0, sizeof(struct enc_cmd_enc_pic_reg));
>+
>+ wave6_gen_enc_pic_reg(p_enc_info, inst->cbcr_interleave,
>+ inst->nv21, option, ®);
>+
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_START, reg.bs_start);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_SIZE, reg.bs_size);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_OPTION, reg.bs_option);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_USE_SEC_AXI,
>reg.use_sec_axi);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_REPORT_PARAM,
>reg.report_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS0,
>reg.mv_histo_class0);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS1,
>reg.mv_histo_class1);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM,
>reg.custom_map_param);
>+ vpu_write_reg(inst->dev,
>W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, reg.custom_map_addr);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_PIC_IDX,
>reg.src_pic_idx);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_Y,
>reg.src_addr_y);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_U,
>reg.src_addr_u);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_V,
>reg.src_addr_v);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_STRIDE, reg.src_stride);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_FORMAT,
>reg.src_format);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_AXI_SEL,
>reg.src_axi_sel);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CODE_OPTION,
>reg.code_option);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PIC_PARAM,
>reg.pic_param);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_LONGTERM_PIC,
>reg.longterm_pic);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR,
>reg.prefix_sei_nal_addr);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_INFO,
>reg.prefix_sei_info);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR,
>reg.suffix_sei_nal_addr);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_INFO,
>reg.suffix_sei_info);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_TIMESTAMP,
>reg.timestamp);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_0,
>reg.csc_coeff[0]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_1,
>reg.csc_coeff[1]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_2,
>reg.csc_coeff[2]);
>+ vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_3,
>reg.csc_coeff[3]);
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_PIC);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret) {
>+ dev_err(inst->dev->dev, "%s: timeout\n", __func__);
>+ return -ETIMEDOUT;
>+ }
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(inst->dev, *fail_res);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct
>enc_output_info *result)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ u32 reg_val;
>+ int ret;
>+
>+ ret = wave6_send_query(inst->dev, inst->id, inst->std,
>W6_QUERY_OPT_GET_RESULT);
>+ if (ret)
>+ return ret;
>+
>+ result->encoding_success = vpu_read_reg(inst->dev,
>W6_RET_ENC_ENCODING_SUCCESS);
>+ if (!result->encoding_success)
>+ result->error_reason = vpu_read_reg(inst->dev,
>W6_RET_ENC_ERR_INFO);
>+ else
>+ result->warn_info = vpu_read_reg(inst->dev,
>W6_RET_DEC_WARN_INFO);
>+
>+ result->enc_pic_cnt = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM);
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_TYPE);
>+ result->pic_type = reg_val & 0xFFFF;
>+
>+ result->enc_vcl_nut = vpu_read_reg(inst->dev, W6_RET_ENC_VCL_NUT);
>+ result->recon_frame_index = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_IDX);
>+ if (result->recon_frame_index >= 0)
>+ result->recon_frame = inst->frame_buf[result->recon_frame_index];
>+
>+ result->non_ref_pic = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_NON_REF_PIC_FLAG);
>+ result->num_of_slices = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_SLICE_NUM);
>+ result->pic_skipped = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_SKIP);
>+ result->num_of_intra = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_NUM_INTRA);
>+ result->num_of_merge = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_NUM_MERGE);
>+ result->num_of_skip_block = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_NUM_SKIP);
>+ result->bitstream_wrap_around = 0;
>+
>+ result->avg_ctu_qp = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_AVG_CTU_QP);
>+ result->enc_pic_byte = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_BYTE);
>+
>+ result->enc_gop_pic_idx = vpu_read_reg(inst->dev,
>W6_RET_ENC_GOP_PIC_IDX);
>+ result->enc_pic_poc = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_POC);
>+ result->enc_src_idx = vpu_read_reg(inst->dev,
>W6_RET_ENC_USED_SRC_IDX);
>+ result->wr_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_WR_PTR);
>+ result->rd_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_RD_PTR);
>+
>+ result->pic_distortion_low = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_DIST_LOW);
>+ result->pic_distortion_high = vpu_read_reg(inst->dev,
>W6_RET_ENC_PIC_DIST_HIGH);
>+
>+ result->mv_histo.cnt0 = vpu_read_reg(inst->dev,
>W6_RET_ENC_HISTO_CNT_0);
>+ result->mv_histo.cnt1 = vpu_read_reg(inst->dev,
>W6_RET_ENC_HISTO_CNT_1);
>+ result->mv_histo.cnt2 = vpu_read_reg(inst->dev,
>W6_RET_ENC_HISTO_CNT_2);
>+ result->mv_histo.cnt3 = vpu_read_reg(inst->dev,
>W6_RET_ENC_HISTO_CNT_3);
>+ result->mv_histo.cnt4 = vpu_read_reg(inst->dev,
>W6_RET_ENC_HISTO_CNT_4);
>+
>+ result->fme_sum.lower_x0 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME0_X_DIR_LOWER);
>+ result->fme_sum.higher_x0 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME0_X_DIR_HIGHER);
>+ result->fme_sum.lower_y0 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME0_Y_DIR_LOWER);
>+ result->fme_sum.higher_y0 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER);
>+ result->fme_sum.lower_x1 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME1_X_DIR_LOWER);
>+ result->fme_sum.higher_x1 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME1_X_DIR_HIGHER);
>+ result->fme_sum.lower_y1 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME1_Y_DIR_LOWER);
>+ result->fme_sum.higher_y1 = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER);
>+
>+ result->src_y_addr = vpu_read_reg(inst->dev,
>W6_RET_ENC_SRC_Y_ADDR);
>+ result->custom_map_addr = vpu_read_reg(inst->dev,
>W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR);
>+ result->prefix_sei_nal_addr = vpu_read_reg(inst->dev,
>W6_RET_ENC_PREFIX_SEI_NAL_ADDR);
>+ result->suffix_sei_nal_addr = vpu_read_reg(inst->dev,
>W6_RET_ENC_SUFFIX_SEI_NAL_ADDR);
>+
>+ reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_TIMESTAMP);
>+ result->timestamp.hour = (reg_val >> 26) & 0x1F;
>+ result->timestamp.min = (reg_val >> 20) & 0x3F;
>+ result->timestamp.sec = (reg_val >> 14) & 0x3F;
>+ result->timestamp.ms = reg_val & 0x3FFF;
>+
>+ result->bitstream_buffer = vpu_read_reg(inst->dev,
>W6_RET_ENC_RD_PTR);
>+
>+ if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY)
>+ result->bitstream_size = result->enc_pic_byte;
>+ else if (result->recon_frame_index < 0)
>+ result->bitstream_size = 0;
>+ else
>+ result->bitstream_size = result->enc_pic_byte;
>+
>+ result->cycle.host_cmd_s = vpu_read_reg(inst->dev,
>W6_RET_CQ_IN_TICK);
>+ result->cycle.host_cmd_e = vpu_read_reg(inst->dev,
>W6_RET_RQ_OUT_TICK);
>+ result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK);
>+ result->cycle.proc_e = vpu_read_reg(inst->dev,
>W6_RET_HW_DONE_TICK);
>+ result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK);
>+ result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK);
>+ result->cycle.frame_cycle = (result->cycle.vpu_e - result-
>>cycle.host_cmd_s) *
>+ p_enc_info->cycle_per_tick;
>+ result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) *
>+ p_enc_info->cycle_per_tick;
>+ result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) -
>+ (result->cycle.proc_e - result->cycle.proc_s)) *
>+ p_enc_info->cycle_per_tick;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res)
>+{
>+ int ret;
>+
>+ wave6_send_command(inst->dev, inst->id, inst->std,
>W6_CMD_DESTROY_INSTANCE);
>+ ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS);
>+ if (ret)
>+ return -ETIMEDOUT;
>+
>+ if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) {
>+ *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON);
>+ wave6_print_reg_err(inst->dev, *fail_res);
>+ return -EIO;
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_gop_param(struct vpu_instance *inst, struct
>enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+ int i;
>+ bool low_delay = true;
>+
>+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) {
>+ if (p_param->gop_param.custom_gop_size > 1) {
>+ int min_val = p_param->gop_param.pic_param[0].poc_offset;
>+
>+ for (i = 1; i < p_param->gop_param.custom_gop_size; i++) {
>+ if (min_val > p_param-
>>gop_param.pic_param[i].poc_offset) {
>+ low_delay = false;
>+ break;
>+ }
>+ min_val = p_param->gop_param.pic_param[i].poc_offset;
>+ }
>+ }
>+ } else if (p_param->gop_preset_idx == PRESET_IDX_ALL_I ||
>+ p_param->gop_preset_idx == PRESET_IDX_IPP ||
>+ p_param->gop_preset_idx == PRESET_IDX_IBBB ||
>+ p_param->gop_preset_idx == PRESET_IDX_IPPPP ||
>+ p_param->gop_preset_idx == PRESET_IDX_IBBBB ||
>+ p_param->gop_preset_idx == PRESET_IDX_IPP_SINGLE) {
>+ }
>+
>+ if (p_param->gop_preset_idx >= PRESET_IDX_MAX) {
>+ dev_err(dev, "gop_preset_idx: %d\n", p_param->gop_preset_idx);
>+ return -EINVAL;
>+ }
>+
>+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) {
>+ if (p_param->gop_param.custom_gop_size < 1 ||
>+ p_param->gop_param.custom_gop_size > MAX_GOP_NUM) {
>+ dev_err(dev, "custom_gop_size: %d\n", p_param-
>>gop_param.custom_gop_size);
>+ return -EINVAL;
>+ }
>+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
>+ struct custom_gop_pic_param pic_param = p_param-
>>gop_param.pic_param[i];
>+
>+ if (pic_param.pic_type != PIC_TYPE_I &&
>+ pic_param.pic_type != PIC_TYPE_P &&
>+ pic_param.pic_type != PIC_TYPE_B) {
>+ dev_err(dev, "pic_param[%d].pic_type: %d\n", i,
>pic_param.pic_type);
>+ return -EINVAL;
>+ }
>+ if (pic_param.poc_offset < 1 ||
>+ pic_param.poc_offset > p_param-
>>gop_param.custom_gop_size) {
>+ dev_err(dev, "pic_param[%d].poc_offset: %d\n",
>+ i, pic_param.poc_offset);
>+ return -EINVAL;
>+ }
>+ if (pic_param.use_multi_ref_p < 0 ||
>pic_param.use_multi_ref_p > 1) {
>+ dev_err(dev, "pic_param[%d].use_multi_ref_p: %d\n",
>+ i, pic_param.use_multi_ref_p);
>+ return -EINVAL;
>+ }
>+ if (pic_param.temporal_id < 0 || pic_param.temporal_id > 3) {
>+ dev_err(dev, "pic_param[%d].temporal_id: %d\n",
>+ i, pic_param.temporal_id);
>+ return -EINVAL;
>+ }
>+ }
>+ if (inst->std == W_AVC_ENC && !low_delay) {
>+ for (i = 0; i < p_param->gop_param.custom_gop_size; i++) {
>+ if (p_param->gop_param.pic_param[i].temporal_id > 0) {
>+ dev_err(dev, "std: %d,
>pic_param[%d].temporal_id: %d\n",
>+ inst->std, i,
>+ p_param->gop_param.pic_param[i].temporal_id);
>+ return -EINVAL;
>+ }
>+ }
>+ }
>+ }
>+
>+ if (inst->std == W_HEVC_ENC) {
>+ if (p_param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) {
>+ dev_err(dev, "decoding_refresh_type: %d\n", p_param-
>>decoding_refresh_type);
>+ return -EINVAL;
>+ }
>+ } else {
>+ if (p_param->decoding_refresh_type !=
>DEC_REFRESH_TYPE_NON_IRAP) {
>+ dev_err(dev, "decoding_refresh_type: %d\n", p_param-
>>decoding_refresh_type);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_tile_slice_param(struct vpu_instance *inst,
>+ int width, int height,
>+ struct enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+
>+ if (p_param->slice_mode > 2) {
>+ dev_err(dev, "slice_mode: %d\n", p_param->slice_mode);
>+ return -EINVAL;
>+ }
>+ if (p_param->slice_mode == 1) {
>+ unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
>+ unsigned int mb_num = ((width + ctu_size - 1) / ctu_size) *
>+ ((height + ctu_size - 1) / ctu_size);
>+
>+ if (p_param->slice_arg < 1 || p_param->slice_arg > 0x3FFFF) {
>+ dev_err(dev, "slice_arg: %d\n", p_param->slice_arg);
>+ return -EINVAL;
>+ }
>+ if (p_param->slice_arg > mb_num) {
>+ dev_info(dev, "slice_arg: %d, mb_num: %d\n",
>+ p_param->slice_arg, mb_num);
>+ p_param->slice_arg = mb_num;
>+ }
>+ if (inst->std == W_AVC_ENC && p_param->slice_arg < 4) {
>+ dev_info(dev, "std: %d, slice_arg: %d\n",
>+ inst->std, p_param->slice_arg);
>+ p_param->slice_arg = 4;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_rc_param(struct vpu_instance *inst, struct
>enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+
>+ if (p_param->frame_rate < 1 || p_param->frame_rate > 960) {
>+ dev_err(dev, "frame_rate: %d\n", p_param->frame_rate);
>+ return -EINVAL;
>+ }
>+ if (p_param->bitrate > 1500000000) {
>+ dev_err(dev, "bitrate: %d\n", p_param->bitrate);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp > 51) {
>+ dev_err(dev, "qp: %d\n", p_param->qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->min_qp_i > 51 || p_param->min_qp_p > 51 || p_param-
>>min_qp_b > 51) {
>+ dev_err(dev, "min_qp_i: %d, min_qp_p: %d, min_qp_b: %d\n",
>+ p_param->min_qp_i, p_param->min_qp_p, p_param-
>>min_qp_b);
>+ return -EINVAL;
>+ }
>+ if (p_param->max_qp_i > 51 || p_param->max_qp_p > 51 || p_param-
>>max_qp_b > 51) {
>+ dev_err(dev, "max_qp_i: %d, max_qp_p: %d, max_qp_b: %d\n",
>+ p_param->max_qp_i, p_param->max_qp_p, p_param-
>>max_qp_b);
>+ return -EINVAL;
>+ }
>+ if (p_param->min_qp_i > p_param->max_qp_i) {
>+ dev_err(dev, "min_qp_i: %d, max_qp_i: %d\n", p_param->min_qp_i,
>p_param->max_qp_i);
>+ return -EINVAL;
>+ }
>+ if (p_param->min_qp_p > p_param->max_qp_p) {
>+ dev_err(dev, "min_qp_p: %d, max_qp_p: %d\n", p_param-
>>min_qp_p, p_param->max_qp_p);
>+ return -EINVAL;
>+ }
>+ if (p_param->min_qp_b > p_param->max_qp_b) {
>+ dev_err(dev, "min_qp_b: %d, max_qp_b: %d\n", p_param-
>>min_qp_b, p_param->max_qp_b);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_initial_qp < -1 || p_param->rc_initial_qp > 51) {
>+ dev_err(dev, "rc_initial_qp: %d\n", p_param->rc_initial_qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_rate_control != 1 && p_param->en_rate_control != 0) {
>+ dev_err(dev, "en_rate_control: %d\n", p_param->en_rate_control);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_mode > 1) {
>+ dev_err(dev, "rc_mode: %d\n", p_param->rc_mode);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_rate_control) {
>+ if (p_param->bitrate <= p_param->frame_rate) {
>+ dev_err(dev, "bitrate: %d, frame_rate: %d\n",
>+ p_param->bitrate, p_param->frame_rate);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_initial_qp != -1) {
>+ if (p_param->rc_initial_qp < p_param->min_qp_i) {
>+ dev_err(dev, "rc_initial_qp: %d, min_qp_i: %d\n",
>+ p_param->rc_initial_qp, p_param->min_qp_i);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_initial_qp > p_param->max_qp_i) {
>+ dev_err(dev, "rc_initial_qp: %d, max_qp_i: %d\n",
>+ p_param->rc_initial_qp, p_param->max_qp_i);
>+ return -EINVAL;
>+ }
>+ }
>+ } else {
>+ if (p_param->qp < p_param->min_qp_i) {
>+ dev_err(dev, "qp: %d, min_qp_i: %d\n", p_param->qp, p_param-
>>min_qp_i);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp < p_param->min_qp_p) {
>+ dev_err(dev, "qp: %d, min_qp_p: %d\n", p_param->qp,
>p_param->min_qp_p);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp < p_param->min_qp_b) {
>+ dev_err(dev, "qp: %d, min_qp_b: %d\n", p_param->qp,
>p_param->min_qp_b);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp > p_param->max_qp_i) {
>+ dev_err(dev, "qp: %d, max_qp_i: %d\n", p_param->qp,
>p_param->max_qp_i);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp > p_param->max_qp_p) {
>+ dev_err(dev, "qp: %d, max_qp_p: %d\n", p_param->qp,
>p_param->max_qp_p);
>+ return -EINVAL;
>+ }
>+ if (p_param->qp > p_param->max_qp_b) {
>+ dev_err(dev, "qp: %d, max_qp_b: %d\n", p_param->qp,
>p_param->max_qp_b);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_intra_param(struct vpu_instance *inst,
>+ int width, int height,
>+ struct enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+ unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64;
>+ unsigned int num_ctu_col = (width + ctu_size - 1) / ctu_size;
>+ unsigned int num_ctu_row = (height + ctu_size - 1) / ctu_size;
>+
>+ if (p_param->intra_refresh_mode > INTRA_REFRESH_COLUMN) {
>+ dev_err(dev, "intra_refresh_mode: %d\n", p_param-
>>intra_refresh_mode);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_refresh_mode != INTRA_REFRESH_NONE) {
>+ if (p_param->intra_refresh_arg < 1 || p_param->intra_refresh_arg >
>511) {
>+ dev_err(dev, "intra_refresh_arg: %d\n", p_param-
>>intra_refresh_arg);
>+ return -EINVAL;
>+ }
>+ }
>+ if (p_param->intra_refresh_mode == INTRA_REFRESH_ROW &&
>+ p_param->intra_refresh_arg > num_ctu_row) {
>+ dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n",
>+ p_param->intra_refresh_mode, p_param->intra_refresh_arg);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_refresh_mode == INTRA_REFRESH_COLUMN &&
>+ p_param->intra_refresh_arg > num_ctu_col) {
>+ dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n",
>+ p_param->intra_refresh_mode, p_param->intra_refresh_arg);
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_custom_param(struct vpu_instance *inst,
>+ struct enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+ int i;
>+
>+ if (p_param->en_qp_map != 1 && p_param->en_qp_map != 0) {
>+ dev_err(dev, "en_qp_map: %d\n", p_param->en_qp_map);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_mode_map != 1 && p_param->en_mode_map != 0) {
>+ dev_err(dev, "en_mode_map: %d\n", p_param->en_mode_map);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_custom_lambda != 1 && p_param-
>>en_custom_lambda != 0) {
>+ dev_err(dev, "en_custom_lambda: %d\n", p_param-
>>en_custom_lambda);
>+ return -EINVAL;
>+ }
>+ for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) {
>+ if (p_param->custom_lambda_ssd[i] > 16383) {
>+ dev_err(dev, "custom_lambda_ssd[%d]: %d\n",
>+ i, p_param->custom_lambda_ssd[i]);
>+ return -EINVAL;
>+ }
>+ if (p_param->custom_lambda_sad[i] > 127) {
>+ dev_err(dev, "custom_lambda_sad[%d]: %d\n",
>+ i, p_param->custom_lambda_sad[i]);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_conf_win_size_param(struct vpu_instance
>*inst,
>+ int width, int height,
>+ struct vpu_rect conf_win)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+
>+ if (conf_win.left % 2 || conf_win.top % 2 || conf_win.right % 2 ||
>conf_win.bottom % 2) {
>+ dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n",
>+ conf_win.left, conf_win.top, conf_win.right, conf_win.bottom);
>+ return -EINVAL;
>+ }
>+ if (conf_win.left > 8192 || conf_win.top > 8192 ||
>+ conf_win.right > 8192 || conf_win.bottom > 8192) {
>+ dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n",
>+ conf_win.left, conf_win.top, conf_win.right, conf_win.bottom);
>+ return -EINVAL;
>+ }
>+ if ((conf_win.right + conf_win.left) > width) {
>+ dev_err(dev, "conf_win.left: %d, conf_win.right: %d, width: %d\n",
>+ conf_win.left, conf_win.right, width);
>+ return -EINVAL;
>+ }
>+ if ((conf_win.bottom + conf_win.top) > height) {
>+ dev_err(dev, "conf_win.top: %d, conf_win.bottom: %d,
>height: %d\n",
>+ conf_win.top, conf_win.bottom, height);
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+static int wave6_vpu_enc_check_temporal_layer_param(struct vpu_instance
>*inst,
>+ struct enc_codec_param *p_param)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+ int i;
>+
>+ if (p_param->temp_layer_cnt < 1 || p_param->temp_layer_cnt > 4) {
>+ dev_err(dev, "temp_layer_cnt: %d\n", p_param->temp_layer_cnt);
>+ return -EINVAL;
>+ }
>+ if (p_param->temp_layer_cnt > 1) {
>+ if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP ||
>+ p_param->gop_preset_idx == PRESET_IDX_ALL_I) {
>+ dev_err(dev, "temp_layer_cnt: %d, gop_preset_idx: %d\n",
>+ p_param->temp_layer_cnt, p_param->gop_preset_idx);
>+ return -EINVAL;
>+ }
>+ }
>+ for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) {
>+ if (p_param->temp_layer[i].change_qp != 1 &&
>+ p_param->temp_layer[i].change_qp != 0) {
>+ dev_err(dev, "temp_layer[%d].change_qp: %d\n",
>+ i, p_param->temp_layer[i].change_qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->temp_layer[i].qp_b > 51) {
>+ dev_err(dev, "temp_layer[%d].qp_b: %d\n", i, p_param-
>>temp_layer[i].qp_b);
>+ return -EINVAL;
>+ }
>+ if (p_param->temp_layer[i].qp_p > 51) {
>+ dev_err(dev, "temp_layer[%d].qp_p: %d\n", i, p_param-
>>temp_layer[i].qp_p);
>+ return -EINVAL;
>+ }
>+ if (p_param->temp_layer[i].qp_i > 51) {
>+ dev_err(dev, "temp_layer[%d].qp_i: %d\n", i, p_param-
>>temp_layer[i].qp_i);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct
>enc_open_param *pop)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct device *dev = vpu_dev->dev;
>+ struct vpu_attr *attr = &inst->dev->attr;
>+ struct enc_codec_param *p_param = &pop->codec_param;
>+
>+ if (inst->std != W_HEVC_ENC && inst->std != W_AVC_ENC) {
>+ dev_err(dev, "std %d\n", inst->std);
>+ return -EOPNOTSUPP;
>+ }
>+
>+ if (pop->pic_width % W6_ENC_PIC_SIZE_STEP || pop->pic_height %
>W6_ENC_PIC_SIZE_STEP) {
>+ dev_err(dev, "pic_width: %d | pic_height: %d\n", pop->pic_width,
>pop->pic_height);
>+ return -EINVAL;
>+ }
>+ if (pop->pic_width < W6_MIN_ENC_PIC_WIDTH || pop->pic_width >
>W6_MAX_ENC_PIC_WIDTH) {
>+ dev_err(dev, "pic_width: %d\n", pop->pic_width);
>+ return -EINVAL;
>+ }
>+ if (pop->pic_height < W6_MIN_ENC_PIC_HEIGHT || pop->pic_height >
>W6_MAX_ENC_PIC_HEIGHT) {
>+ dev_err(dev, "pic_height: %d\n", pop->pic_height);
>+ return -EINVAL;
>+ }
>+
>+ if (pop->packed_format && inst->cbcr_interleave == 1) {
>+ dev_err(dev, "packed_format: %d, cbcr_interleave: %d\n",
>+ pop->packed_format, inst->cbcr_interleave);
>+ return -EINVAL;
>+ }
>+ if (pop->packed_format && inst->nv21 == 1) {
>+ dev_err(dev, "packed_format: %d, nv21: %d\n", pop->packed_format,
>inst->nv21);
>+ return -EINVAL;
>+ }
>+ if (pop->src_format == FORMAT_RGB_32BIT_PACKED ||
>+ pop->src_format == FORMAT_YUV444_32BIT_PACKED ||
>+ pop->src_format == FORMAT_RGB_P10_32BIT_PACKED ||
>+ pop->src_format == FORMAT_YUV444_P10_32BIT_PACKED) {
>+ if (!inst->cbcr_interleave) {
>+ dev_err(dev, "src_format: %d, cbcr_interleave: %d\n",
>+ pop->src_format, inst->cbcr_interleave);
>+ return -EINVAL;
>+ }
>+ if (inst->nv21 == 1) {
>+ dev_err(dev, "src_format: %d, nv21: %d\n", pop->src_format,
>inst->nv21);
>+ return -EINVAL;
>+ }
>+ }
>+ if (pop->src_format == FORMAT_RGB_24BIT_PACKED ||
>+ pop->src_format == FORMAT_YUV444_24BIT_PACKED) {
>+ if (!inst->cbcr_interleave || inst->nv21 == 1) {
>+ dev_err(dev, "src_format: %d, cbcr_interleave: %d, nv21: %d\n",
>+ pop->src_format, inst->cbcr_interleave, inst->nv21);
>+ return -EINVAL;
>+ }
>+ }
>+ if (pop->src_format == FORMAT_YUV444_24BIT) {
>+ if (!inst->cbcr_interleave) {
>+ dev_err(dev, "src_format: %d, cbcr_interleave: %d\n",
>+ pop->src_format, inst->cbcr_interleave);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ if (wave6_vpu_enc_check_gop_param(inst, p_param)) {
>+ dev_err(dev, "failed wave6_vpu_enc_check_gop_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_tile_slice_param(inst, pop->pic_width, pop-
>>pic_height, p_param)) {
>+ dev_err(dev, "failed wave6_vpu_enc_check_tile_slice_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_rc_param(inst, p_param)) {
>+ dev_err(dev, "failed wave6_vpu_enc_check_rc_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_intra_param(inst, pop->pic_width, pop-
>>pic_height, p_param)) {
>+ dev_err(dev, "failed wave6_vpu_enc_check_intra_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_custom_param(inst, p_param)) {
>+ dev_err(dev, "failed wave6_vpu_enc_check_custom_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_conf_win_size_param(inst, pop->pic_width,
>pop->pic_height,
>+ p_param->conf_win)) {
>+ dev_err(dev, "failed
>wave6_vpu_enc_check_conf_win_size_param()\n");
>+ return -EINVAL;
>+ }
>+ if (wave6_vpu_enc_check_temporal_layer_param(inst, p_param)) {
>+ dev_err(dev, "failed
>wave6_vpu_enc_check_temporal_layer_param()\n");
>+ return -EINVAL;
>+ }
>+
>+ if (p_param->internal_bit_depth != 8 && p_param->internal_bit_depth !=
>10) {
>+ dev_err(dev, "internal_bit_depth: %d\n", p_param-
>>internal_bit_depth);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_period > 2047) {
>+ dev_err(dev, "intra_period: %d\n", p_param->intra_period);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_period == 1 && p_param->gop_preset_idx ==
>PRESET_IDX_ALL_I) {
>+ dev_err(dev, "intra_period: %d, gop_preset_idx: %d\n",
>+ p_param->intra_period, p_param->gop_preset_idx);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_long_term != 1 && p_param->en_long_term != 0) {
>+ dev_err(dev, "en_long_term: %d\n", p_param->en_long_term);
>+ return -EINVAL;
>+ }
>+ if (p_param->cpb_size < 10 || p_param->cpb_size > 100000) {
>+ dev_err(dev, "cpb_size: %d\n", p_param->cpb_size);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_cu_level_rate_control != 1 && p_param-
>>en_cu_level_rate_control != 0) {
>+ dev_err(dev, "en_cu_level_rate_control: %d\n", p_param-
>>en_cu_level_rate_control);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_vbv_overflow_drop_frame != 1 && p_param-
>>en_vbv_overflow_drop_frame != 0) {
>+ dev_err(dev, "en_vbv_overflow_drop_frame: %d\n",
>+ p_param->en_vbv_overflow_drop_frame);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_hvs_qp != 1 && p_param->en_hvs_qp != 0) {
>+ dev_err(dev, "en_hvs_qp: %d\n", p_param->en_hvs_qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_hvs_qp) {
>+ if (p_param->hvs_qp_scale_div2 < 1 || p_param-
>>hvs_qp_scale_div2 > 4) {
>+ dev_err(dev, "hvs_qp_scale_div2: %d\n", p_param-
>>hvs_qp_scale_div2);
>+ return -EINVAL;
>+ }
>+ }
>+ if (p_param->max_delta_qp > 12) {
>+ dev_err(dev, "max_delta_qp: %d\n", p_param->max_delta_qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_update_speed > 255) {
>+ dev_err(dev, "rc_update_speed: %d\n", p_param-
>>rc_update_speed);
>+ return -EINVAL;
>+ }
>+ if (p_param->max_bitrate > 1500000000) {
>+ dev_err(dev, "max_bitrate: %d\n", p_param->max_bitrate);
>+ return -EINVAL;
>+ }
>+ if (p_param->rc_initial_level > 15) {
>+ dev_err(dev, "rc_initial_level: %d\n", p_param->rc_initial_level);
>+ return -EINVAL;
>+ }
>+ if (p_param->pic_rc_max_dqp > 51) {
>+ dev_err(dev, "pic_rc_max_dqp: %d\n", p_param->pic_rc_max_dqp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_bg_detect != 1 && p_param->en_bg_detect != 0) {
>+ dev_err(dev, "en_bg_detect: %d\n", p_param->en_bg_detect);
>+ return -EINVAL;
>+ }
>+ if (p_param->bg_th_diff > 255) {
>+ dev_err(dev, "bg_th_diff: %d\n", p_param->bg_th_diff);
>+ return -EINVAL;
>+ }
>+ if (p_param->bg_th_mean_diff > 255) {
>+ dev_err(dev, "bg_th_mean_diff: %d\n", p_param-
>>bg_th_mean_diff);
>+ return -EINVAL;
>+ }
>+ if (p_param->bg_delta_qp < -16 || p_param->bg_delta_qp > 15) {
>+ dev_err(dev, "bg_delta_qp: %d\n", p_param->bg_delta_qp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_me_center != 1 && p_param->en_me_center != 0) {
>+ dev_err(dev, "en_me_center: %d\n", p_param->en_me_center);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_dbk != 1 && p_param->en_dbk != 0) {
>+ dev_err(dev, "en_dbk: %d\n", p_param->en_dbk);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_scaling_list != 1 && p_param->en_scaling_list != 0) {
>+ dev_err(dev, "en_scaling_list: %d\n", p_param->en_scaling_list);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_adaptive_round != 1 && p_param-
>>en_adaptive_round != 0) {
>+ dev_err(dev, "en_adaptive_round: %d\n", p_param-
>>en_adaptive_round);
>+ return -EINVAL;
>+ }
>+ if (p_param->q_round_intra > 255) {
>+ dev_err(dev, "q_round_intra: %d\n", p_param->q_round_intra);
>+ return -EINVAL;
>+ }
>+ if (p_param->q_round_inter > 255) {
>+ dev_err(dev, "q_round_inter: %d\n", p_param->q_round_inter);
>+ return -EINVAL;
>+ }
>+ if (p_param->dis_coef_clear != 1 && p_param->dis_coef_clear != 0) {
>+ dev_err(dev, "dis_coef_clear: %d\n", p_param->dis_coef_clear);
>+ return -EINVAL;
>+ }
>+ if (p_param->lambda_dqp_intra < -32 || p_param->lambda_dqp_intra >
>31) {
>+ dev_err(dev, "lambda_dqp_intra: %d\n", p_param-
>>lambda_dqp_intra);
>+ return -EINVAL;
>+ }
>+ if (p_param->lambda_dqp_inter < -32 || p_param->lambda_dqp_inter >
>31) {
>+ dev_err(dev, "lambda_dqp_inter: %d\n", p_param-
>>lambda_dqp_inter);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_q_round_offset != 1 && p_param-
>>en_q_round_offset != 0) {
>+ dev_err(dev, "en_q_round_offset: %d\n", p_param-
>>en_q_round_offset);
>+ return -EINVAL;
>+ }
>+ if (p_param->forced_idr_header > 2) {
>+ dev_err(dev, "forced_idr_header: %d\n", p_param-
>>forced_idr_header);
>+ return -EINVAL;
>+ }
>+ if (p_param->num_units_in_tick > INT_MAX) {
>+ dev_err(dev, "num_units_in_tick: %d\n", p_param-
>>num_units_in_tick);
>+ return -EINVAL;
>+ }
>+ if (p_param->time_scale > INT_MAX) {
>+ dev_err(dev, "time_scale: %d\n", p_param->time_scale);
>+ return -EINVAL;
>+ }
>+ if (p_param->max_intra_pic_bit > 1500000000) {
>+ dev_err(dev, "max_intra_pic_bit: %d\n", p_param-
>>max_intra_pic_bit);
>+ return -EINVAL;
>+ }
>+ if (p_param->max_inter_pic_bit > 1500000000) {
>+ dev_err(dev, "max_inter_pic_bit: %d\n", p_param-
>>max_inter_pic_bit);
>+ return -EINVAL;
>+ }
>+
>+ if (p_param->color.color_range > 1) {
>+ dev_err(dev, "color_range: %d\n", p_param->color.color_range);
>+ return -EINVAL;
>+ }
>+ if (p_param->color.matrix_coefficients > 255) {
>+ dev_err(dev, "matrix_coefficients: %d\n", p_param-
>>color.matrix_coefficients);
>+ return -EINVAL;
>+ }
>+ if (p_param->color.transfer_characteristics > 255) {
>+ dev_err(dev, "transfer_characteristics: %d\n",
>+ p_param->color.transfer_characteristics);
>+ return -EINVAL;
>+ }
>+ if (p_param->color.color_primaries > 255) {
>+ dev_err(dev, "color_primaries: %d\n", p_param-
>>color.color_primaries);
>+ return -EINVAL;
>+ }
>+ if (inst->std == W_HEVC_ENC) {
>+ if (p_param->internal_bit_depth == 10 && !attr-
>>support_hevc10bit_enc) {
>+ dev_err(dev, "internal_bit_depth: %d,
>support_hevc10bit_enc: %d\n",
>+ p_param->internal_bit_depth, attr-
>>support_hevc10bit_enc);
>+ return -EOPNOTSUPP;
>+ }
>+ if (p_param->idr_period != 0) {
>+ dev_err(dev, "idr_period: %d\n", p_param->idr_period);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_strong_intra_smoothing != 1 &&
>+ p_param->en_strong_intra_smoothing != 0) {
>+ dev_err(dev, "en_strong_intra_smoothing: %d\n",
>+ p_param->en_strong_intra_smoothing);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_constrained_intra_pred != 1 &&
>+ p_param->en_constrained_intra_pred != 0) {
>+ dev_err(dev, "en_constrained_intra_pred: %d\n",
>+ p_param->en_constrained_intra_pred);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_intra_trans_skip != 1 && p_param-
>>en_intra_trans_skip != 0) {
>+ dev_err(dev, "en_intra_trans_skip: %d\n", p_param-
>>en_intra_trans_skip);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_temporal_mvp != 1 && p_param-
>>en_temporal_mvp != 0) {
>+ dev_err(dev, "en_temporal_mvp: %d\n", p_param-
>>en_temporal_mvp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_cabac != 0) {
>+ dev_err(dev, "en_cabac: %d\n", p_param->en_cabac);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_transform8x8 != 0) {
>+ dev_err(dev, "en_transform8x8: %d\n", p_param-
>>en_transform8x8);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_lf_cross_slice_boundary != 1 &&
>+ p_param->en_lf_cross_slice_boundary != 0) {
>+ dev_err(dev, "en_lf_cross_slice_boundary: %d\n",
>+ p_param->en_lf_cross_slice_boundary);
>+ return -EINVAL;
>+ }
>+ if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 >
>6) {
>+ dev_err(dev, "beta_offset_div2: %d\n", p_param-
>>beta_offset_div2);
>+ return -EINVAL;
>+ }
>+ if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) {
>+ dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_sao != 1 && p_param->en_sao != 0) {
>+ dev_err(dev, "en_sao: %d\n", p_param->en_sao);
>+ return -EINVAL;
>+ }
>+ if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) {
>+ dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset);
>+ return -EINVAL;
>+ }
>+ if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) {
>+ dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_still_picture != 1 && p_param->en_still_picture != 0)
>{
>+ dev_err(dev, "en_still_picture: %d\n", p_param-
>>en_still_picture);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_auto_level_adjusting != 1 &&
>+ p_param->en_auto_level_adjusting != 0) {
>+ dev_err(dev, "en_auto_level_adjusting: %d\n",
>+ p_param->en_auto_level_adjusting);
>+ return -EINVAL;
>+ }
>+ if (p_param->tier > 1) {
>+ dev_err(dev, "tier: %d\n", p_param->tier);
>+ return -EINVAL;
>+ }
>+ if (p_param->profile > HEVC_PROFILE_STILLPICTURE) {
>+ dev_err(dev, "profile: %d\n", p_param->profile);
>+ return -EINVAL;
>+ }
>+ if (p_param->internal_bit_depth == 10 && p_param->profile ==
>HEVC_PROFILE_MAIN) {
>+ dev_err(dev, "internal_bit_depth: %d, profile: %d\n",
>+ p_param->internal_bit_depth, p_param->profile);
>+ return -EINVAL;
>+ }
>+ if (p_param->num_ticks_poc_diff_one < 1 ||
>+ p_param->num_ticks_poc_diff_one > 65535) {
>+ dev_err(dev, "num_ticks_poc_diff_one: %d\n",
>+ p_param->num_ticks_poc_diff_one);
>+ return -EINVAL;
>+ }
>+ if (p_param->color.chroma_sample_position != 0) {
>+ dev_err(dev, "chroma_sample_position: %d\n",
>+ p_param->color.chroma_sample_position);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_4x4 > 3 || p_param->intra_4x4 == 1) {
>+ dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4);
>+ return -EINVAL;
>+ }
>+ } else if (inst->std == W_AVC_ENC) {
>+ if (p_param->internal_bit_depth == 10 && !attr-
>>support_avc10bit_enc) {
>+ dev_err(dev, "internal_bit_depth: %d,
>support_avc10bit_enc: %d\n",
>+ p_param->internal_bit_depth, attr->support_avc10bit_enc);
>+ return -EOPNOTSUPP;
>+ }
>+ if (p_param->idr_period > 2047) {
>+ dev_err(dev, "idr_period: %d\n", p_param->idr_period);
>+ return -EINVAL;
>+ }
>+ if (p_param->idr_period == 1 && p_param->gop_preset_idx ==
>PRESET_IDX_ALL_I) {
>+ dev_err(dev, "idr_period: %d, gop_preset_idx: %d\n",
>+ p_param->idr_period, p_param->gop_preset_idx);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_strong_intra_smoothing != 0) {
>+ dev_err(dev, "en_strong_intra_smoothing: %d\n",
>+ p_param->en_strong_intra_smoothing);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_constrained_intra_pred != 1 &&
>+ p_param->en_constrained_intra_pred != 0) {
>+ dev_err(dev, "en_constrained_intra_pred: %d\n",
>+ p_param->en_constrained_intra_pred);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_intra_trans_skip != 0) {
>+ dev_err(dev, "en_intra_trans_skip: %d\n", p_param-
>>en_intra_trans_skip);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_temporal_mvp != 0) {
>+ dev_err(dev, "en_temporal_mvp: %d\n", p_param-
>>en_temporal_mvp);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_cabac != 1 && p_param->en_cabac != 0) {
>+ dev_err(dev, "en_cabac: %d\n", p_param->en_cabac);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_transform8x8 != 1 && p_param-
>>en_transform8x8 != 0) {
>+ dev_err(dev, "en_transform8x8: %d\n", p_param-
>>en_transform8x8);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_lf_cross_slice_boundary != 1 &&
>+ p_param->en_lf_cross_slice_boundary != 0) {
>+ dev_err(dev, "en_lf_cross_slice_boundary: %d\n",
>+ p_param->en_lf_cross_slice_boundary);
>+ return -EINVAL;
>+ }
>+ if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 >
>6) {
>+ dev_err(dev, "beta_offset_div2: %d\n", p_param-
>>beta_offset_div2);
>+ return -EINVAL;
>+ }
>+ if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) {
>+ dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_sao != 0) {
>+ dev_err(dev, "en_sao: %d\n", p_param->en_sao);
>+ return -EINVAL;
>+ }
>+ if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) {
>+ dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset);
>+ return -EINVAL;
>+ }
>+ if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) {
>+ dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_still_picture != 0) {
>+ dev_err(dev, "en_still_picture: %d\n", p_param-
>>en_still_picture);
>+ return -EINVAL;
>+ }
>+ if (p_param->en_auto_level_adjusting != 1 &&
>+ p_param->en_auto_level_adjusting != 0) {
>+ dev_err(dev, "en_auto_level_adjusting: %d\n",
>+ p_param->en_auto_level_adjusting);
>+ return -EINVAL;
>+ }
>+ if (p_param->tier != 0) {
>+ dev_err(dev, "tier: %d\n", p_param->tier);
>+ return -EINVAL;
>+ }
>+ if (p_param->profile > H264_PROFILE_HIGH10) {
>+ dev_err(dev, "profile: %d\n", p_param->profile);
>+ return -EINVAL;
>+ }
>+ if (p_param->profile) {
>+ if (p_param->internal_bit_depth == 10 &&
>+ p_param->profile != H264_PROFILE_HIGH10) {
>+ dev_err(dev, "internal_bit_depth: %d, profile: %d\n",
>+ p_param->internal_bit_depth, p_param->profile);
>+ return -EINVAL;
>+ }
>+ }
>+ if (p_param->num_ticks_poc_diff_one != 0) {
>+ dev_err(dev, "num_ticks_poc_diff_one: %d\n",
>+ p_param->num_ticks_poc_diff_one);
>+ return -EINVAL;
>+ }
>+ if (p_param->color.chroma_sample_position != 0) {
>+ dev_err(dev, "chroma_sample_position: %d\n",
>+ p_param->color.chroma_sample_position);
>+ return -EINVAL;
>+ }
>+ if (p_param->intra_4x4 != 0) {
>+ dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ return 0;
>+}
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-hw.h
>b/drivers/media/platform/chips-media/wave6/wave6-hw.h
>new file mode 100644
>index 000000000000..a40477dc023e
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-hw.h
>@@ -0,0 +1,69 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - wave6 backend interface
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_HW_H__
>+#define __WAVE6_HW_H__
>+
>+#define STD_AVC 0
>+#define STD_HEVC 12
>+
>+enum product_id {
>+ PRODUCT_ID_617,
>+ PRODUCT_ID_627,
>+ PRODUCT_ID_637,
>+ PRODUCT_ID_NONE,
>+};
>+
>+#define BSOPTION_ENABLE_EXPLICIT_END BIT(0)
>+#define NON_VCL_PARAM_ENCODE_VUI BIT(1)
>+
>+#define DECODE_ALL_TEMPORAL_LAYERS 0
>+#define DECODE_ALL_SPATIAL_LAYERS 0
>+
>+#define REGISTER_DISPLAY_BUFFER 1
>+#define DEFAULT_PIXEL_ORDER 1
>+
>+#define WTL_RIGHT_JUSTIFIED 0
>+#define WTL_LEFT_JUSTIFIED 1
>+#define WTL_PIXEL_8BIT 0
>+#define WTL_PIXEL_16BIT 1
>+#define WTL_PIXEL_32BIT 2
>+
>+#define MAX_CSC_COEFF_NUM 4
>+
>+bool wave6_vpu_is_init(struct vpu_device *vpu_dev);
>+void wave6_vpu_check_state(struct vpu_device *vpu_dev);
>+int wave6_vpu_get_version(struct vpu_device *vpu_dev, u32 *version_info,
>uint32_t *revision);
>+void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev);
>+int wave6_vpu_build_up_dec_param(struct vpu_instance *inst, struct
>dec_open_param *param);
>+
>+void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos);
>+int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst,
>+ struct frame_buffer *fb_arr, enum tiled_map_type
>map_type,
>+ uint32_t count);
>+int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct
>frame_buffer fb);
>+int wave6_vpu_dec_init_seq(struct vpu_instance *inst);
>+int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct
>dec_initial_info *info);
>+int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option,
>u32 *fail_res);
>+int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct
>dec_output_info *result);
>+int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res);
>+dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst);
>+int wave6_vpu_dec_flush(struct vpu_instance *inst);
>+
>+int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance
>*inst,
>+ struct enc_open_param *param);
>+int wave6_vpu_enc_init_seq(struct vpu_instance *inst);
>+int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed);
>+int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct
>enc_initial_info *info);
>+int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst,
>+ struct frame_buffer *fb_arr);
>+int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option,
>u32 *fail_res);
>+int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct
>enc_output_info *result);
>+int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res);
>+int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct
>enc_open_param *pop);
>+
>+#endif /* __WAVE6_HW_H__ */
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-regdefine.h
>b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h
>new file mode 100644
>index 000000000000..05d563cf9d55
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h
>@@ -0,0 +1,675 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - wave6 register definitions
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_REGDEFINE_H__
>+#define __WAVE6_REGDEFINE_H__
>+
>+enum wave6_command {
>+ W6_CMD_INIT_VPU = 0x0001,
>+ W6_CMD_WAKEUP_VPU = 0x0002,
>+ W6_CMD_SLEEP_VPU = 0x0004,
>+ W6_CMD_CREATE_INSTANCE = 0x0008,
>+ W6_CMD_FLUSH_INSTANCE = 0x0010,
>+ W6_CMD_DESTROY_INSTANCE = 0x0020,
>+ W6_CMD_INIT_SEQ = 0x0040,
>+ W6_CMD_SET_FB = 0x0080,
>+ W6_CMD_DEC_PIC = 0x0100,
>+ W6_CMD_ENC_PIC = 0x0100,
>+ W6_CMD_ENC_SET_PARAM = 0x0200,
>+ W6_CMD_DEC_SET_DISP = 0x0400,
>+ W6_CMD_INIT_WORK_BUF = 0x1000,
>+ W6_CMD_QUERY = 0x4000,
>+};
>+
>+enum wave6_init_seq_option {
>+ W6_INIT_SEQ_OPT_NORMAL = 1,
>+ W6_INIT_SEQ_OPT_W_THUMBNAIL = 17,
>+};
>+
>+enum wave6_set_param_option {
>+ W6_SET_PARAM_OPT_COMMON = 0,
>+ W6_SET_PARAM_OPT_CHANGE_PARAM = 1,
>+};
>+
>+enum wave6_dec_pic_option {
>+ W6_DEC_PIC_OPT_NORMAL = 0,
>+ W6_DEC_PIC_OPT_W_THUMBNAIL = 16,
>+ W6_DEC_PIC_OPT_SKIP_NON_IRAP = 17,
>+ W6_DEC_PIC_OPT_SKIP_NON_REF_PIC = 19,
>+};
>+
>+enum wave6_enc_pic_option {
>+ W6_ENC_PIC_OPT_HEADER_IMPLICIT = 1,
>+ W6_ENC_PIC_OPT_VCL = 2,
>+};
>+
>+enum wave6_query_option {
>+ W6_QUERY_OPT_GET_VPU_INFO = 0,
>+ W6_QUERY_OPT_GET_RESULT = 2,
>+ W6_QUERY_OPT_GET_FLUSH_CMD_INFO = 10,
>+};
>+
>+enum wave6_interrupt_bit {
>+ W6_INT_BIT_INIT_VPU = 0,
>+ W6_INT_BIT_WAKEUP_VPU = 1,
>+ W6_INT_BIT_SLEEP_VPU = 2,
>+ W6_INT_BIT_CREATE_INSTANCE = 3,
>+ W6_INT_BIT_FLUSH_INSTANCE = 4,
>+ W6_INT_BIT_DESTROY_INSTANCE = 5,
>+ W6_INT_BIT_INIT_SEQ = 6,
>+ W6_INT_BIT_SET_FB = 7,
>+ W6_INT_BIT_DEC_PIC = 8,
>+ W6_INT_BIT_ENC_PIC = 8,
>+ W6_INT_BIT_ENC_SET_PARAM = 9,
>+ W6_INT_BIT_SET_DISP = 10,
>+ W6_INT_BIT_REQ_WORK_BUF = 12,
>+ W6_INT_BIT_BSBUF_ERROR = 15,
>+};
>+
>+enum wave6_param_change_enable_bit {
>+ W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE = 10
>+};
>+
>+#define W6_REG_BASE 0x00000000
>+#define W6_CMD_REG_BASE 0x00000200
>+#define W6_CMD_REG_END 0x00000600
>+
>+#define W6_VPU_VCPU_CUR_PC (W6_REG_BASE + 0x0004)
>+#define W6_VPU_VINT_REASON_CLR (W6_REG_BASE + 0x0034)
>+#define W6_VPU_HOST_INT_REQ (W6_REG_BASE + 0x0038)
>+#define W6_VPU_VINT_CLEAR (W6_REG_BASE + 0x003C)
>+#define W6_VPU_VPU_INT_STS (W6_REG_BASE + 0x0044)
>+#define W6_VPU_VINT_ENABLE (W6_REG_BASE + 0x0048)
>+#define W6_VPU_VINT_REASON (W6_REG_BASE + 0x004C)
>+#define W6_VPU_REMAP_CTRL_GB (W6_REG_BASE + 0x0060)
>+#define W6_VPU_REMAP_VADDR_GB (W6_REG_BASE + 0x0064)
>+#define W6_VPU_REMAP_PADDR_GB (W6_REG_BASE + 0x0068)
>+#define W6_VPU_REMAP_CORE_START_GB (W6_REG_BASE +
>0x006C)
>+#define W6_VPU_BUSY_STATUS (W6_REG_BASE + 0x0070)
>+#define W6_VPU_RET_PRODUCT_VERSION (W6_REG_BASE +
>0x0094)
>+
>+/* COMMON */
>+#define W6_COMMAND_GB (W6_REG_BASE + 0x104)
>+#define W6_COMMAND (W6_REG_BASE + 0x200)
>+#define W6_QUERY_OPTION (W6_REG_BASE + 0x204)
>+#define W6_CMD_INSTANCE_INFO (W6_REG_BASE + 0x210)
>+#define W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0 (W6_REG_BASE +
>0x364)
>+#define W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0 (W6_REG_BASE +
>0x368)
>+#define W6_CMD_SET_CTRL_WORK_BUF_ADDR (W6_REG_BASE +
>0x5F0)
>+#define W6_CMD_SET_CTRL_WORK_BUF_SIZE (W6_REG_BASE +
>0x5F4)
>+#define W6_RET_SUCCESS (W6_REG_BASE + 0x208)
>+#define W6_RET_FAIL_REASON (W6_REG_BASE + 0x20C)
>+#define W6_RET_INSTANCE_ID (W6_REG_BASE + 0x220)
>+#define W6_RET_CQ_IN_TICK (W6_REG_BASE + 0x23C)
>+#define W6_RET_FW_RUN_TICK (W6_REG_BASE + 0x240)
>+#define W6_RET_HW_RUN_TICK (W6_REG_BASE + 0x244)
>+#define W6_RET_HW_DONE_TICK (W6_REG_BASE + 0x248)
>+#define W6_RET_FW_DONE_TICK (W6_REG_BASE + 0x24C)
>+#define W6_RET_RQ_OUT_TICK (W6_REG_BASE + 0x250)
>+
>+/* COMMON - QUERY : GET_VPU_INFO */
>+#define W6_RET_FW_VERSION (W6_REG_BASE + 0x300)
>+#define W6_RET_PRODUCT_NAME (W6_REG_BASE + 0x304)
>+#define W6_RET_PRODUCT_VERSION (W6_REG_BASE + 0x308)
>+#define W6_RET_STD_DEF0 (W6_REG_BASE + 0x30C)
>+#define W6_RET_STD_DEF1 (W6_REG_BASE + 0x310)
>+#define W6_RET_CONF_FEATURE (W6_REG_BASE + 0x314)
>+#define W6_RET_CONF_DATE (W6_REG_BASE + 0x318)
>+#define W6_RET_CONF_REVISION (W6_REG_BASE + 0x31C)
>+#define W6_RET_CONF_TYPE (W6_REG_BASE + 0x320)
>+#define W6_RET_FW_API_VERSION (W6_REG_BASE + 0x32C)
>+#define W6_RET_SHA_ID (W6_REG_BASE + 0x330)
>+
>+/* DECODER - CREATE_INSTANCE */
>+#define W6_CMD_DEC_CREATE_INST_BS_PARAM (W6_REG_BASE +
>0x310)
>+#define W6_CMD_DEC_CREATE_INST_ADDR_EXT (W6_REG_BASE +
>0x318)
>+#define W6_CMD_DEC_CREATE_INST_DISP_MODE (W6_REG_BASE +
>0x31C)
>+#define W6_CMD_DEC_CREATE_INST_CORE_INFO (W6_REG_BASE +
>0x330)
>+#define W6_CMD_DEC_CREATE_INST_PRIORITY (W6_REG_BASE +
>0x334)
>+#define W6_CMD_DEC_CREATE_INST_TEMP_BASE (W6_REG_BASE +
>0x348)
>+#define W6_CMD_DEC_CREATE_INST_TEMP_SIZE (W6_REG_BASE +
>0x34C)
>+#define W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT
>(W6_REG_BASE + 0x3A8)
>+
>+/* DECODER - INIT_SEQ */
>+#define W6_CMD_DEC_INIT_SEQ_OPTION (W6_REG_BASE +
>0x204)
>+#define W6_CMD_DEC_INIT_SEQ_BS_RD_PTR (W6_REG_BASE +
>0x300)
>+#define W6_CMD_DEC_INIT_SEQ_BS_WR_PTR (W6_REG_BASE +
>0x304)
>+#define W6_CMD_DEC_INIT_SEQ_BS_OPTION (W6_REG_BASE +
>0x308)
>+
>+/* DECODER - SET_FB */
>+#define W6_CMD_DEC_SET_FB_OPTION (W6_REG_BASE + 0x204)
>+#define W6_CMD_DEC_SET_FB_COMMON_PIC_INFO (W6_REG_BASE
>+ 0x300)
>+#define W6_CMD_DEC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304)
>+#define W6_CMD_DEC_SET_FB_NUM (W6_REG_BASE + 0x308)
>+#define W6_CMD_DEC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310)
>+#define W6_CMD_DEC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE +
>0x318)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE +
>0x31C)
>+#define W6_CMD_DEC_SET_FB_MV_COL0 (W6_REG_BASE +
>0x320)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE +
>0x324)
>+#define W6_CMD_DEC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328)
>+#define W6_CMD_DEC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE +
>0x330)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE +
>0x334)
>+#define W6_CMD_DEC_SET_FB_MV_COL1 (W6_REG_BASE +
>0x338)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE +
>0x33C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340)
>+#define W6_CMD_DEC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE +
>0x348)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE +
>0x34C)
>+#define W6_CMD_DEC_SET_FB_MV_COL2 (W6_REG_BASE +
>0x350)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE +
>0x354)
>+#define W6_CMD_DEC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358)
>+#define W6_CMD_DEC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE +
>0x360)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE +
>0x364)
>+#define W6_CMD_DEC_SET_FB_MV_COL3 (W6_REG_BASE +
>0x368)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE +
>0x36C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370)
>+#define W6_CMD_DEC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE +
>0x378)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE +
>0x37C)
>+#define W6_CMD_DEC_SET_FB_MV_COL4 (W6_REG_BASE +
>0x380)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE +
>0x384)
>+#define W6_CMD_DEC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388)
>+#define W6_CMD_DEC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE +
>0x390)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE +
>0x394)
>+#define W6_CMD_DEC_SET_FB_MV_COL5 (W6_REG_BASE +
>0x398)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE +
>0x39C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0)
>+#define W6_CMD_DEC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE +
>0x3A8)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE +
>0x3AC)
>+#define W6_CMD_DEC_SET_FB_MV_COL6 (W6_REG_BASE +
>0x3B0)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE +
>0x3B4)
>+#define W6_CMD_DEC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8)
>+#define W6_CMD_DEC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE +
>0x3C0)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE +
>0x3C4)
>+#define W6_CMD_DEC_SET_FB_MV_COL7 (W6_REG_BASE +
>0x3C8)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE +
>0x3CC)
>+#define W6_CMD_DEC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0)
>+#define W6_CMD_DEC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE +
>0x3D8)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE +
>0x3DC)
>+#define W6_CMD_DEC_SET_FB_MV_COL8 (W6_REG_BASE +
>0x3E0)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE +
>0x3E4)
>+#define W6_CMD_DEC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8)
>+#define W6_CMD_DEC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE +
>0x3F0)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE +
>0x3F4)
>+#define W6_CMD_DEC_SET_FB_MV_COL9 (W6_REG_BASE +
>0x3F8)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE +
>0x3FC)
>+#define W6_CMD_DEC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400)
>+#define W6_CMD_DEC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE +
>0x408)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE +
>0x40C)
>+#define W6_CMD_DEC_SET_FB_MV_COL10 (W6_REG_BASE +
>0x410)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE +
>0x414)
>+#define W6_CMD_DEC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418)
>+#define W6_CMD_DEC_SET_FB_FBC_C11 (W6_REG_BASE + 0x41C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE +
>0x420)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE +
>0x424)
>+#define W6_CMD_DEC_SET_FB_MV_COL11 (W6_REG_BASE +
>0x428)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE +
>0x42C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430)
>+#define W6_CMD_DEC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE +
>0x438)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE +
>0x43C)
>+#define W6_CMD_DEC_SET_FB_MV_COL12 (W6_REG_BASE +
>0x440)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE +
>0x444)
>+#define W6_CMD_DEC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448)
>+#define W6_CMD_DEC_SET_FB_FBC_C13 (W6_REG_BASE + 0x44C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE +
>0x450)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE +
>0x454)
>+#define W6_CMD_DEC_SET_FB_MV_COL13 (W6_REG_BASE +
>0x458)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE +
>0x45C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460)
>+#define W6_CMD_DEC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE +
>0x468)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE +
>0x46C)
>+#define W6_CMD_DEC_SET_FB_MV_COL14 (W6_REG_BASE +
>0x470)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE +
>0x474)
>+#define W6_CMD_DEC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478)
>+#define W6_CMD_DEC_SET_FB_FBC_C15 (W6_REG_BASE + 0x47C)
>+#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE +
>0x480)
>+#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE +
>0x484)
>+#define W6_CMD_DEC_SET_FB_MV_COL15 (W6_REG_BASE +
>0x488)
>+#define W6_CMD_DEC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE +
>0x48C)
>+#define W6_CMD_DEC_SET_FB_DEFAULT_CDF (W6_REG_BASE +
>0x494)
>+#define W6_CMD_DEC_SET_FB_SEGMAP (W6_REG_BASE +
>0x498)
>+#define W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT (W6_REG_BASE +
>0x4DC)
>+#define W6_CMD_DEC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE +
>0x4F4)
>+#define W6_CMD_DEC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE +
>0x4FC)
>+#define W6_CMD_DEC_SET_FB_FBC_CR2 (W6_REG_BASE + 0x500)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE +
>0x504)
>+#define W6_CMD_DEC_SET_FB_FBC_CR3 (W6_REG_BASE + 0x508)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE +
>0x50C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR4 (W6_REG_BASE + 0x510)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE +
>0x514)
>+#define W6_CMD_DEC_SET_FB_FBC_CR5 (W6_REG_BASE + 0x518)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE +
>0x51C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR6 (W6_REG_BASE + 0x520)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE +
>0x524)
>+#define W6_CMD_DEC_SET_FB_FBC_CR7 (W6_REG_BASE + 0x528)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE +
>0x52C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR8 (W6_REG_BASE + 0x530)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE +
>0x534)
>+#define W6_CMD_DEC_SET_FB_FBC_CR9 (W6_REG_BASE + 0x538)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE +
>0x53C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR10 (W6_REG_BASE +
>0x540)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE +
>0x544)
>+#define W6_CMD_DEC_SET_FB_FBC_CR11 (W6_REG_BASE +
>0x548)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE +
>0x54C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR12 (W6_REG_BASE +
>0x550)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE +
>0x554)
>+#define W6_CMD_DEC_SET_FB_FBC_CR13 (W6_REG_BASE +
>0x558)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE +
>0x55C)
>+#define W6_CMD_DEC_SET_FB_FBC_CR14 (W6_REG_BASE +
>0x560)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE +
>0x564)
>+#define W6_CMD_DEC_SET_FB_FBC_CR15 (W6_REG_BASE +
>0x568)
>+#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE +
>0x56C)
>+
>+/* DECODER - SET_DISP */
>+#define W6_CMD_DEC_SET_DISP_OPTION (W6_REG_BASE +
>0x204)
>+#define W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO (W6_REG_BASE
>+ 0x300)
>+#define W6_CMD_DEC_SET_DISP_PIC_SIZE (W6_REG_BASE +
>0x304)
>+#define W6_CMD_DEC_SET_DISP_PIC_INFO (W6_REG_BASE +
>0x308)
>+#define W6_CMD_DEC_SET_DISP_Y_BASE (W6_REG_BASE +
>0x30C)
>+#define W6_CMD_DEC_SET_DISP_CB_BASE (W6_REG_BASE +
>0x310)
>+#define W6_CMD_DEC_SET_DISP_CR_BASE (W6_REG_BASE +
>0x314)
>+#define W6_CMD_DEC_SET_DISP_SCL_PARAM (W6_REG_BASE +
>0x318)
>+#define W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE (W6_REG_BASE +
>0x31C)
>+
>+/* DECODER - DEC_PIC */
>+#define W6_CMD_DEC_PIC_OPTION (W6_REG_BASE + 0x204)
>+#define W6_CMD_DEC_PIC_BS_RD_PTR (W6_REG_BASE + 0x300)
>+#define W6_CMD_DEC_PIC_BS_WR_PTR (W6_REG_BASE + 0x304)
>+#define W6_CMD_DEC_PIC_BS_OPTION (W6_REG_BASE + 0x308)
>+#define W6_CMD_DEC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C)
>+#define W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG
>(W6_REG_BASE + 0x310)
>+#define W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1 (W6_REG_BASE +
>0x318)
>+#define W6_CMD_DEC_PIC_TIMESTAMP (W6_REG_BASE + 0x32C)
>+
>+/* DECODER - QUERY : GET_RESULT */
>+#define W6_RET_DEC_BS_RD_PTR (W6_REG_BASE + 0x30C)
>+#define W6_RET_DEC_SEQ_PARAM (W6_REG_BASE + 0x310)
>+#define W6_RET_DEC_COLOR_SAMPLE_INFO (W6_REG_BASE +
>0x314)
>+#define W6_RET_DEC_ASPECT_RATIO (W6_REG_BASE + 0x318)
>+#define W6_RET_DEC_BIT_RATE (W6_REG_BASE + 0x31C)
>+#define W6_RET_DEC_FRAME_RATE_NR (W6_REG_BASE + 0x320)
>+#define W6_RET_DEC_FRAME_RATE_DR (W6_REG_BASE + 0x324)
>+#define W6_RET_DEC_NUM_REQUIRED_FBC_FB (W6_REG_BASE +
>0x328)
>+#define W6_RET_DEC_NUM_REORDER_DELAY (W6_REG_BASE +
>0x32C)
>+#define W6_RET_DEC_NOTIFICATION (W6_REG_BASE + 0x334)
>+#define W6_RET_DEC_PIC_SIZE (W6_REG_BASE + 0x33C)
>+#define W6_RET_DEC_CROP_TOP_BOTTOM (W6_REG_BASE +
>0x340)
>+#define W6_RET_DEC_CROP_LEFT_RIGHT (W6_REG_BASE + 0x344)
>+#define W6_RET_DEC_AU_START_POS (W6_REG_BASE + 0x348)
>+#define W6_RET_DEC_AU_END_POS (W6_REG_BASE + 0x34C)
>+#define W6_RET_DEC_PIC_TYPE (W6_REG_BASE + 0x350)
>+#define W6_RET_DEC_PIC_POC (W6_REG_BASE + 0x354)
>+#define W6_RET_DEC_RECOVERY_POINT (W6_REG_BASE + 0x358)
>+#define W6_RET_DEC_DECODED_ADDR (W6_REG_BASE + 0x360)
>+#define W6_RET_DEC_DISPLAY_ADDR (W6_REG_BASE + 0x364)
>+#define W6_RET_DEC_ERR_CTB_NUM (W6_REG_BASE + 0x370)
>+#define W6_RET_DEC_DISPLAY_FLAG (W6_REG_BASE + 0x3A8)
>+#define W6_RET_DEC_RELEASE_IDC (W6_REG_BASE + 0x3AC)
>+#define W6_RET_DEC_DISP_IDC (W6_REG_BASE + 0x3B0)
>+#define W6_RET_DEC_STREAM_END (W6_REG_BASE + 0x3C0)
>+#define W6_RET_DEC_DECODED_FLAG (W6_REG_BASE + 0x3C4)
>+#define W6_RET_DEC_WARN_INFO (W6_REG_BASE + 0x3CC)
>+#define W6_RET_DEC_ERR_INFO (W6_REG_BASE + 0x3D0)
>+#define W6_RET_DEC_DECODING_SUCCESS (W6_REG_BASE +
>0x3D4)
>+#define W6_RET_DEC_TIMESTAMP (W6_REG_BASE + 0x3D8)
>+#define W6_RET_DEC_LAST_FRAME_FLAG (W6_REG_BASE +
>0x3E0)
>+#define W6_RET_DEC_NUM_REQUIRED_COL_BUF (W6_REG_BASE +
>0x3E4)
>+#define W6_RET_DEC_DISP_LINEAR_ADDR_0 (W6_REG_BASE +
>0x3E8)
>+#define W6_RET_DEC_DISP_LINEAR_ADDR_30 (W6_REG_BASE +
>0x460)
>+#define W6_RET_DEC_COLOR_CONFIG (W6_REG_BASE + 0x57C)
>+
>+/* DECODER - QUERY : GET_FLUSH_CMD_INFO */
>+#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 (W6_REG_BASE +
>0x300)
>+#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_1E (W6_REG_BASE +
>0x378)
>+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC
>(W6_REG_BASE + 0x57C)
>+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC
>(W6_REG_BASE + 0x580)
>+#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC
>(W6_REG_BASE + 0x584)
>+
>+/* ENCODER - CREATE_INSTANCE */
>+#define W6_CMD_ENC_CREATE_INST_BS_PARAM (W6_REG_BASE +
>0x310)
>+#define W6_CMD_ENC_CREATE_INST_SRC_OPT (W6_REG_BASE +
>0x314)
>+#define W6_CMD_ENC_CREATE_INST_ADDR_EXT (W6_REG_BASE +
>0x318)
>+#define W6_CMD_ENC_CREATE_INST_CORE_INFO (W6_REG_BASE +
>0x330)
>+#define W6_CMD_ENC_CREATE_INST_PRIORITY (W6_REG_BASE +
>0x334)
>+#define W6_CMD_ENC_CREATE_INST_TEMP_BASE (W6_REG_BASE +
>0x348)
>+#define W6_CMD_ENC_CREATE_INST_TEMP_SIZE (W6_REG_BASE +
>0x34C)
>+#define W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE (W6_REG_BASE
>+ 0x358)
>+#define W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT
>(W6_REG_BASE + 0x3A8)
>+
>+/* ENCODER - SET_PARAM */
>+#define W6_CMD_ENC_SET_PARAM_OPTION (W6_REG_BASE +
>0x204)
>+#define W6_CMD_ENC_SET_PARAM_ENABLE (W6_REG_BASE +
>0x300)
>+#define W6_CMD_ENC_SET_PARAM_SRC_SIZE (W6_REG_BASE +
>0x304)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN
>(W6_REG_BASE + 0x308)
>+#define W6_CMD_ENC_SET_PARAM_SPS_PARAM (W6_REG_BASE +
>0x30C)
>+#define W6_CMD_ENC_SET_PARAM_PPS_PARAM (W6_REG_BASE +
>0x310)
>+#define W6_CMD_ENC_SET_PARAM_GOP_PARAM (W6_REG_BASE +
>0x314)
>+#define W6_CMD_ENC_SET_PARAM_INTRA_PARAM (W6_REG_BASE +
>0x318)
>+#define W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT
>(W6_REG_BASE + 0x31C)
>+#define W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT
>(W6_REG_BASE + 0x320)
>+#define W6_CMD_ENC_SET_PARAM_RDO_PARAM (W6_REG_BASE +
>0x324)
>+#define W6_CMD_ENC_SET_PARAM_SLICE_PARAM (W6_REG_BASE +
>0x328)
>+#define W6_CMD_ENC_SET_PARAM_INTRA_REFRESH (W6_REG_BASE
>+ 0x32C)
>+#define W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP
>(W6_REG_BASE + 0x330)
>+#define W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE (W6_REG_BASE
>+ 0x334)
>+#define W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE (W6_REG_BASE
>+ 0x338)
>+#define W6_CMD_ENC_SET_PARAM_RC_PARAM (W6_REG_BASE +
>0x33C)
>+#define W6_CMD_ENC_SET_PARAM_HVS_PARAM (W6_REG_BASE +
>0x340)
>+#define W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE (W6_REG_BASE
>+ 0x344)
>+#define W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE
>(W6_REG_BASE + 0x348)
>+#define W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP
>(W6_REG_BASE + 0x34C)
>+#define W6_CMD_ENC_SET_PARAM_ROT_PARAM (W6_REG_BASE +
>0x350)
>+#define W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK
>(W6_REG_BASE + 0x354)
>+#define W6_CMD_ENC_SET_PARAM_TIME_SCALE (W6_REG_BASE +
>0x358)
>+#define W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE
>(W6_REG_BASE + 0x35C)
>+#define W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT
>(W6_REG_BASE + 0x360)
>+#define W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT
>(W6_REG_BASE + 0x364)
>+#define W6_CMD_ENC_SET_PARAM_BG_PARAM (W6_REG_BASE +
>0x36C)
>+#define W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM
>(W6_REG_BASE + 0x370)
>+#define W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR (W6_REG_BASE
>+ 0x374)
>+#define W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR (W6_REG_BASE
>+ 0x378)
>+#define W6_CMD_ENC_SET_PARAM_QROUND_OFFSET
>(W6_REG_BASE + 0x380)
>+#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1
>(W6_REG_BASE + 0x384)
>+#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2
>(W6_REG_BASE + 0x388)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM
>(W6_REG_BASE + 0x38C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0
>(W6_REG_BASE + 0x390)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_1
>(W6_REG_BASE + 0x394)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_2
>(W6_REG_BASE + 0x398)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_3
>(W6_REG_BASE + 0x39C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_4
>(W6_REG_BASE + 0x3A0)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_5
>(W6_REG_BASE + 0x3A4)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_6
>(W6_REG_BASE + 0x3A8)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_7
>(W6_REG_BASE + 0x3AC)
>+#define W6_CMD_ENC_SET_PARAM_TILE_PARAM (W6_REG_BASE +
>0x3D0)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0
>(W6_REG_BASE + 0x3D4)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_1
>(W6_REG_BASE + 0x3D8)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_2
>(W6_REG_BASE + 0x3DC)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_3
>(W6_REG_BASE + 0x3E0)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_4
>(W6_REG_BASE + 0x3E4)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_5
>(W6_REG_BASE + 0x3E8)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_6
>(W6_REG_BASE + 0x3EC)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_7
>(W6_REG_BASE + 0x3F0)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_8
>(W6_REG_BASE + 0x3F4)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_9
>(W6_REG_BASE + 0x3F8)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_10
>(W6_REG_BASE + 0x3FC)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_11
>(W6_REG_BASE + 0x400)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_12
>(W6_REG_BASE + 0x404)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_13
>(W6_REG_BASE + 0x408)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_14
>(W6_REG_BASE + 0x40C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_15
>(W6_REG_BASE + 0x410)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_16
>(W6_REG_BASE + 0x414)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_17
>(W6_REG_BASE + 0x418)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_18
>(W6_REG_BASE + 0x41C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_19
>(W6_REG_BASE + 0x420)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_20
>(W6_REG_BASE + 0x424)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_21
>(W6_REG_BASE + 0x428)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_22
>(W6_REG_BASE + 0x42C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_23
>(W6_REG_BASE + 0x430)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_24
>(W6_REG_BASE + 0x434)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_25
>(W6_REG_BASE + 0x438)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_26
>(W6_REG_BASE + 0x43C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_27
>(W6_REG_BASE + 0x440)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_28
>(W6_REG_BASE + 0x444)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_29
>(W6_REG_BASE + 0x448)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_30
>(W6_REG_BASE + 0x44C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_31
>(W6_REG_BASE + 0x450)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_32
>(W6_REG_BASE + 0x454)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_33
>(W6_REG_BASE + 0x458)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_34
>(W6_REG_BASE + 0x45C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_35
>(W6_REG_BASE + 0x460)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_36
>(W6_REG_BASE + 0x464)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_37
>(W6_REG_BASE + 0x468)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_38
>(W6_REG_BASE + 0x46C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_39
>(W6_REG_BASE + 0x470)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_40
>(W6_REG_BASE + 0x474)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_41
>(W6_REG_BASE + 0x478)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_42
>(W6_REG_BASE + 0x47C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_43
>(W6_REG_BASE + 0x480)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_44
>(W6_REG_BASE + 0x484)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_45
>(W6_REG_BASE + 0x488)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_46
>(W6_REG_BASE + 0x48C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_47
>(W6_REG_BASE + 0x490)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_48
>(W6_REG_BASE + 0x494)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_49
>(W6_REG_BASE + 0x498)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_50
>(W6_REG_BASE + 0x49C)
>+#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_51
>(W6_REG_BASE + 0x4A0)
>+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP
>(W6_REG_BASE + 0x4A4)
>+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_1_QP
>(W6_REG_BASE + 0x4A8)
>+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_2_QP
>(W6_REG_BASE + 0x4AC)
>+#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_3_QP
>(W6_REG_BASE + 0x4B0)
>+#define W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE (W6_REG_BASE +
>0x4B4)
>+#define W6_CMD_ENC_SET_PARAM_SCL_PARAM (W6_REG_BASE +
>0x4B8)
>+#define W6_CMD_ENC_SET_PARAM_COLOR_PARAM (W6_REG_BASE
>+ 0x4F8)
>+#define W6_CMD_ENC_SET_PARAM_SAR_PARAM (W6_REG_BASE +
>0x4FC)
>+#define W6_CMD_ENC_SET_PARAM_SAR_EXTENDED (W6_REG_BASE
>+ 0x500)
>+
>+/* ENCODER - SET_FB */
>+#define W6_CMD_ENC_SET_FB_OPTION (W6_REG_BASE + 0x204)
>+#define W6_CMD_ENC_SET_FB_PIC_INFO (W6_REG_BASE +
>0x300)
>+#define W6_CMD_ENC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304)
>+#define W6_CMD_ENC_SET_FB_NUM (W6_REG_BASE + 0x308)
>+#define W6_CMD_ENC_SET_FB_FBC_STRIDE (W6_REG_BASE +
>0x30C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310)
>+#define W6_CMD_ENC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE +
>0x318)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE +
>0x31C)
>+#define W6_CMD_ENC_SET_FB_MV_COL0 (W6_REG_BASE +
>0x320)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE +
>0x324)
>+#define W6_CMD_ENC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328)
>+#define W6_CMD_ENC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE +
>0x330)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE +
>0x334)
>+#define W6_CMD_ENC_SET_FB_MV_COL1 (W6_REG_BASE +
>0x338)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE +
>0x33C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340)
>+#define W6_CMD_ENC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE +
>0x348)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE +
>0x34C)
>+#define W6_CMD_ENC_SET_FB_MV_COL2 (W6_REG_BASE +
>0x350)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE +
>0x354)
>+#define W6_CMD_ENC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358)
>+#define W6_CMD_ENC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE +
>0x360)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE +
>0x364)
>+#define W6_CMD_ENC_SET_FB_MV_COL3 (W6_REG_BASE +
>0x368)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE +
>0x36C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370)
>+#define W6_CMD_ENC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE +
>0x378)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE +
>0x37C)
>+#define W6_CMD_ENC_SET_FB_MV_COL4 (W6_REG_BASE +
>0x380)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE +
>0x384)
>+#define W6_CMD_ENC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388)
>+#define W6_CMD_ENC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE +
>0x390)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE +
>0x394)
>+#define W6_CMD_ENC_SET_FB_MV_COL5 (W6_REG_BASE +
>0x398)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE +
>0x39C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0)
>+#define W6_CMD_ENC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE +
>0x3A8)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE +
>0x3AC)
>+#define W6_CMD_ENC_SET_FB_MV_COL6 (W6_REG_BASE +
>0x3B0)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE +
>0x3B4)
>+#define W6_CMD_ENC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8)
>+#define W6_CMD_ENC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE +
>0x3C0)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE +
>0x3C4)
>+#define W6_CMD_ENC_SET_FB_MV_COL7 (W6_REG_BASE +
>0x3C8)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE +
>0x3CC)
>+#define W6_CMD_ENC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0)
>+#define W6_CMD_ENC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE +
>0x3D8)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE +
>0x3DC)
>+#define W6_CMD_ENC_SET_FB_MV_COL8 (W6_REG_BASE +
>0x3E0)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE +
>0x3E4)
>+#define W6_CMD_ENC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8)
>+#define W6_CMD_ENC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE +
>0x3F0)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE +
>0x3F4)
>+#define W6_CMD_ENC_SET_FB_MV_COL9 (W6_REG_BASE +
>0x3F8)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE +
>0x3FC)
>+#define W6_CMD_ENC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400)
>+#define W6_CMD_ENC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE +
>0x408)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE +
>0x40C)
>+#define W6_CMD_ENC_SET_FB_MV_COL10 (W6_REG_BASE +
>0x410)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE +
>0x414)
>+#define W6_CMD_ENC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418)
>+#define W6_CMD_ENC_SET_FB_FBC_C11 (W6_REG_BASE +
>0x41C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE +
>0x420)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE +
>0x424)
>+#define W6_CMD_ENC_SET_FB_MV_COL11 (W6_REG_BASE +
>0x428)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE +
>0x42C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430)
>+#define W6_CMD_ENC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE +
>0x438)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE +
>0x43C)
>+#define W6_CMD_ENC_SET_FB_MV_COL12 (W6_REG_BASE +
>0x440)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE +
>0x444)
>+#define W6_CMD_ENC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448)
>+#define W6_CMD_ENC_SET_FB_FBC_C13 (W6_REG_BASE +
>0x44C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE +
>0x450)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE +
>0x454)
>+#define W6_CMD_ENC_SET_FB_MV_COL13 (W6_REG_BASE +
>0x458)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE +
>0x45C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460)
>+#define W6_CMD_ENC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE +
>0x468)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE +
>0x46C)
>+#define W6_CMD_ENC_SET_FB_MV_COL14 (W6_REG_BASE +
>0x470)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE +
>0x474)
>+#define W6_CMD_ENC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478)
>+#define W6_CMD_ENC_SET_FB_FBC_C15 (W6_REG_BASE +
>0x47C)
>+#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE +
>0x480)
>+#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE +
>0x484)
>+#define W6_CMD_ENC_SET_FB_MV_COL15 (W6_REG_BASE +
>0x488)
>+#define W6_CMD_ENC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE +
>0x48C)
>+#define W6_CMD_ENC_SET_FB_DEFAULT_CDF (W6_REG_BASE +
>0x494)
>+#define W6_CMD_ENC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE +
>0x4F4)
>+#define W6_CMD_ENC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE +
>0x4FC)
>+#define W6_CMD_ENC_SET_FB_FBC_CR2 (W6_REG_BASE +
>0x500)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE +
>0x504)
>+#define W6_CMD_ENC_SET_FB_FBC_CR3 (W6_REG_BASE +
>0x508)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE +
>0x50C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR4 (W6_REG_BASE +
>0x510)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE +
>0x514)
>+#define W6_CMD_ENC_SET_FB_FBC_CR5 (W6_REG_BASE +
>0x518)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE +
>0x51C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR6 (W6_REG_BASE +
>0x520)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE +
>0x524)
>+#define W6_CMD_ENC_SET_FB_FBC_CR7 (W6_REG_BASE +
>0x528)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE +
>0x52C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR8 (W6_REG_BASE +
>0x530)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE +
>0x534)
>+#define W6_CMD_ENC_SET_FB_FBC_CR9 (W6_REG_BASE +
>0x538)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE +
>0x53C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR10 (W6_REG_BASE +
>0x540)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE +
>0x544)
>+#define W6_CMD_ENC_SET_FB_FBC_CR11 (W6_REG_BASE +
>0x548)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE +
>0x54C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR12 (W6_REG_BASE +
>0x550)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE +
>0x554)
>+#define W6_CMD_ENC_SET_FB_FBC_CR13 (W6_REG_BASE +
>0x558)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE +
>0x55C)
>+#define W6_CMD_ENC_SET_FB_FBC_CR14 (W6_REG_BASE +
>0x560)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE +
>0x564)
>+#define W6_CMD_ENC_SET_FB_FBC_CR15 (W6_REG_BASE +
>0x568)
>+#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE +
>0x56C)
>+
>+/* ENCODER - ENC_PIC */
>+#define W6_CMD_ENC_PIC_BS_START (W6_REG_BASE + 0x300)
>+#define W6_CMD_ENC_PIC_BS_SIZE (W6_REG_BASE + 0x304)
>+#define W6_CMD_ENC_PIC_BS_OPTION (W6_REG_BASE + 0x308)
>+#define W6_CMD_ENC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C)
>+#define W6_CMD_ENC_PIC_REPORT_PARAM (W6_REG_BASE +
>0x310)
>+#define W6_CMD_ENC_PIC_MV_HISTO_CLASS0 (W6_REG_BASE +
>0x318)
>+#define W6_CMD_ENC_PIC_MV_HISTO_CLASS1 (W6_REG_BASE +
>0x31C)
>+#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM
>(W6_REG_BASE + 0x320)
>+#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR
>(W6_REG_BASE + 0x324)
>+#define W6_CMD_ENC_PIC_SRC_PIC_IDX (W6_REG_BASE + 0x32C)
>+#define W6_CMD_ENC_PIC_SRC_ADDR_Y (W6_REG_BASE +
>0x330)
>+#define W6_CMD_ENC_PIC_SRC_ADDR_U (W6_REG_BASE +
>0x334)
>+#define W6_CMD_ENC_PIC_SRC_ADDR_V (W6_REG_BASE +
>0x338)
>+#define W6_CMD_ENC_PIC_SRC_STRIDE (W6_REG_BASE + 0x33C)
>+#define W6_CMD_ENC_PIC_SRC_FORMAT (W6_REG_BASE +
>0x340)
>+#define W6_CMD_ENC_PIC_SRC_AXI_SEL (W6_REG_BASE + 0x348)
>+#define W6_CMD_ENC_PIC_CODE_OPTION (W6_REG_BASE +
>0x34C)
>+#define W6_CMD_ENC_PIC_PIC_PARAM (W6_REG_BASE + 0x350)
>+#define W6_CMD_ENC_PIC_LONGTERM_PIC (W6_REG_BASE +
>0x354)
>+#define W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE +
>0x358)
>+#define W6_CMD_ENC_PIC_PREFIX_SEI_INFO (W6_REG_BASE +
>0x35C)
>+#define W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE +
>0x360)
>+#define W6_CMD_ENC_PIC_SUFFIX_SEI_INFO (W6_REG_BASE +
>0x364)
>+#define W6_CMD_ENC_PIC_CSC_COEFF_0 (W6_REG_BASE +
>0x374)
>+#define W6_CMD_ENC_PIC_CSC_COEFF_1 (W6_REG_BASE +
>0x378)
>+#define W6_CMD_ENC_PIC_CSC_COEFF_2 (W6_REG_BASE +
>0x37C)
>+#define W6_CMD_ENC_PIC_CSC_COEFF_3 (W6_REG_BASE +
>0x380)
>+#define W6_CMD_ENC_PIC_TIMESTAMP (W6_REG_BASE + 0x3F8)
>+
>+/* ENCODER - QUERY : GET_RESULT */
>+#define W6_RET_ENC_RD_PTR (W6_REG_BASE + 0x300)
>+#define W6_RET_ENC_WR_PTR (W6_REG_BASE + 0x304)
>+#define W6_RET_ENC_NUM_REQUIRED_FBC_FB (W6_REG_BASE +
>0x308)
>+#define W6_RET_ENC_MIN_SRC_BUF_NUM (W6_REG_BASE +
>0x30C)
>+#define W6_RET_ENC_PIC_TYPE (W6_REG_BASE + 0x310)
>+#define W6_RET_ENC_PIC_POC (W6_REG_BASE + 0x314)
>+#define W6_RET_ENC_PIC_IDX (W6_REG_BASE + 0x318)
>+#define W6_RET_ENC_PIC_SLICE_NUM (W6_REG_BASE + 0x31C)
>+#define W6_RET_ENC_PIC_SKIP (W6_REG_BASE + 0x320)
>+#define W6_RET_ENC_PIC_NUM_INTRA (W6_REG_BASE + 0x324)
>+#define W6_RET_ENC_PIC_NUM_MERGE (W6_REG_BASE +
>0x328)
>+#define W6_RET_ENC_PIC_NON_REF_PIC_FLAG (W6_REG_BASE +
>0x32C)
>+#define W6_RET_ENC_PIC_NUM_SKIP (W6_REG_BASE + 0x330)
>+#define W6_RET_ENC_PIC_AVG_CTU_QP (W6_REG_BASE + 0x334)
>+#define W6_RET_ENC_PIC_BYTE (W6_REG_BASE + 0x338)
>+#define W6_RET_ENC_GOP_PIC_IDX (W6_REG_BASE + 0x33C)
>+#define W6_RET_ENC_USED_SRC_IDX (W6_REG_BASE + 0x340)
>+#define W6_RET_ENC_PIC_NUM (W6_REG_BASE + 0x344)
>+#define W6_RET_ENC_VCL_NUT (W6_REG_BASE + 0x348)
>+#define W6_RET_ENC_PIC_DIST_LOW (W6_REG_BASE + 0x350)
>+#define W6_RET_ENC_PIC_DIST_HIGH (W6_REG_BASE + 0x354)
>+#define W6_RET_ENC_PIC_MAX_LATENCY_PICTURES (W6_REG_BASE +
>0x358)
>+#define W6_RET_ENC_HISTO_CNT_0 (W6_REG_BASE + 0x360)
>+#define W6_RET_ENC_HISTO_CNT_1 (W6_REG_BASE + 0x364)
>+#define W6_RET_ENC_HISTO_CNT_2 (W6_REG_BASE + 0x368)
>+#define W6_RET_ENC_HISTO_CNT_3 (W6_REG_BASE + 0x36C)
>+#define W6_RET_ENC_HISTO_CNT_4 (W6_REG_BASE + 0x370)
>+#define W6_RET_ENC_WARN_INFO (W6_REG_BASE + 0x3AC)
>+#define W6_RET_ENC_ERR_INFO (W6_REG_BASE + 0x3B0)
>+#define W6_RET_ENC_ENCODING_SUCCESS (W6_REG_BASE +
>0x3B4)
>+#define W6_RET_ENC_SUM_ME0_X_DIR_LOWER (W6_REG_BASE +
>0x3B8)
>+#define W6_RET_ENC_SUM_ME0_X_DIR_HIGHER (W6_REG_BASE +
>0x3BC)
>+#define W6_RET_ENC_SUM_ME0_Y_DIR_LOWER (W6_REG_BASE +
>0x3C0)
>+#define W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER (W6_REG_BASE +
>0x3C4)
>+#define W6_RET_ENC_SUM_ME1_X_DIR_LOWER (W6_REG_BASE +
>0x3C8)
>+#define W6_RET_ENC_SUM_ME1_X_DIR_HIGHER (W6_REG_BASE +
>0x3CC)
>+#define W6_RET_ENC_SUM_ME1_Y_DIR_LOWER (W6_REG_BASE +
>0x3D0)
>+#define W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER (W6_REG_BASE +
>0x3D4)
>+#define W6_RET_ENC_SRC_Y_ADDR (W6_REG_BASE + 0x3E8)
>+#define W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR (W6_REG_BASE
>+ 0x3EC)
>+#define W6_RET_ENC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE +
>0x3F0)
>+#define W6_RET_ENC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE +
>0x3F4)
>+#define W6_RET_ENC_TIMESTAMP (W6_REG_BASE + 0x400)
>+#define W6_RET_ENC_NUM_REQUIRED_COL_BUF (W6_REG_BASE +
>0x404)
>+
>+#endif /* __WAVE6_REGDEFINE_H__ */
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.c
>b/drivers/media/platform/chips-media/wave6/wave6-vdi.c
>new file mode 100644
>index 000000000000..c255780fef0a
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.c
>@@ -0,0 +1,52 @@
>+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>+/*
>+ * Wave6 series multi-standard codec IP - low level access interface
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#include <linux/delay.h>
>+#include <linux/bug.h>
>+#include "wave6-vdi.h"
>+#include "wave6-vpu.h"
>+#include "wave6-regdefine.h"
>+#include "wave6-trace.h"
>+
>+#define VDI_SYSTEM_ENDIAN VDI_LITTLE_ENDIAN
>+#define VDI_128BIT_BUS_SYSTEM_ENDIAN VDI_128BIT_LITTLE_ENDIAN
>+
>+void wave6_vdi_writel(struct vpu_device *vpu_dev, unsigned int addr,
>unsigned int data)
>+{
>+ writel(data, vpu_dev->reg_base + addr);
>+ trace_writel(vpu_dev->dev, addr, data);
>+}
>+
>+unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, u32 addr)
>+{
>+ unsigned int data;
>+
>+ data = readl(vpu_dev->reg_base + addr);
>+ trace_readl(vpu_dev->dev, addr, data);
>+
>+ return data;
>+}
>+
>+unsigned int wave6_vdi_convert_endian(unsigned int endian)
>+{
>+ switch (endian) {
>+ case VDI_LITTLE_ENDIAN:
>+ endian = 0x00;
>+ break;
>+ case VDI_BIG_ENDIAN:
>+ endian = 0x0f;
>+ break;
>+ case VDI_32BIT_LITTLE_ENDIAN:
>+ endian = 0x04;
>+ break;
>+ case VDI_32BIT_BIG_ENDIAN:
>+ endian = 0x03;
>+ break;
>+ }
>+
>+ return (endian & 0x0f);
>+}
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.h
>b/drivers/media/platform/chips-media/wave6/wave6-vdi.h
>new file mode 100644
>index 000000000000..bb43b24547ed
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.h
>@@ -0,0 +1,59 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - low level access interface
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_VDI_H__
>+#define __WAVE6_VDI_H__
>+
>+#include <linux/string.h>
>+#include <linux/slab.h>
>+#include <linux/device.h>
>+#include "wave6-vpuconfig.h"
>+
>+#define vpu_write_reg(VPU_DEV, ADDR, DATA) wave6_vdi_writel(VPU_DEV,
>ADDR, DATA)
>+#define vpu_read_reg(VPU_DEV, ADDR) wave6_vdi_readl(VPU_DEV, ADDR)
>+
>+struct vpu_buf {
>+ size_t size;
>+ dma_addr_t daddr;
>+ void *vaddr;
>+ struct device *dev;
>+};
>+
>+struct vpu_dma_buf {
>+ size_t size;
>+ dma_addr_t dma_addr;
>+ void *vaddr;
>+ phys_addr_t phys_addr;
>+};
>+
>+enum endian_mode {
>+ VDI_LITTLE_ENDIAN = 0,
>+ VDI_BIG_ENDIAN,
>+ VDI_32BIT_LITTLE_ENDIAN,
>+ VDI_32BIT_BIG_ENDIAN,
>+ VDI_128BIT_LITTLE_ENDIAN = 16,
>+ VDI_128BIT_LE_BYTE_SWAP,
>+ VDI_128BIT_LE_WORD_SWAP,
>+ VDI_128BIT_LE_WORD_BYTE_SWAP,
>+ VDI_128BIT_LE_DWORD_SWAP,
>+ VDI_128BIT_LE_DWORD_BYTE_SWAP,
>+ VDI_128BIT_LE_DWORD_WORD_SWAP,
>+ VDI_128BIT_LE_DWORD_WORD_BYTE_SWAP,
>+ VDI_128BIT_BE_DWORD_WORD_BYTE_SWAP,
>+ VDI_128BIT_BE_DWORD_WORD_SWAP,
>+ VDI_128BIT_BE_DWORD_BYTE_SWAP,
>+ VDI_128BIT_BE_DWORD_SWAP,
>+ VDI_128BIT_BE_WORD_BYTE_SWAP,
>+ VDI_128BIT_BE_WORD_SWAP,
>+ VDI_128BIT_BE_BYTE_SWAP,
>+ VDI_128BIT_BIG_ENDIAN = 31,
>+ VDI_ENDIAN_MAX
>+};
>+
>+#define VDI_128BIT_ENDIAN_MASK 0xf
>+
>+#endif /* __WAVE6_VDI_H__ */
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
>b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
>new file mode 100644
>index 000000000000..a4f278918b15
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
>@@ -0,0 +1,1001 @@
>+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>+/*
>+ * Wave6 series multi-standard codec IP - wave6 helper interface
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#include <linux/bug.h>
>+#include "wave6-vpuapi.h"
>+#include "wave6-regdefine.h"
>+#include "wave6-hw.h"
>+#include "wave6-vpu-dbg.h"
>+#include "wave6-trace.h"
>+
>+static int wave6_check_dec_open_param(struct vpu_instance *inst, struct
>dec_open_param *param)
>+{
>+ struct vpu_attr *attr = &inst->dev->attr;
>+
>+ if (param->bs_mode != attr->support_bitstream_mode)
>+ return -EINVAL;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param
>*pop)
>+{
>+ struct dec_info *p_dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = wave6_check_dec_open_param(inst, pop);
>+ if (ret)
>+ return ret;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ if (!wave6_vpu_is_init(vpu_dev)) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return -ENODEV;
>+ }
>+
>+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
>+ if (!inst->codec_info) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return -ENOMEM;
>+ }
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+ memcpy(&p_dec_info->open_param, pop, sizeof(struct
>dec_open_param));
>+
>+ ret = wave6_vpu_build_up_dec_param(inst, pop);
>+ if (ret)
>+ goto free_codec_info;
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return 0;
>+
>+free_codec_info:
>+ kfree(inst->codec_info);
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ *fail_res = 0;
>+ if (!inst->codec_info)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_dec_fini_seq(inst, fail_res);
>+ if (ret) {
>+ dev_warn(inst->dev->dev, "dec seq end timed out\n");
>+
>+ if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return ret;
>+ }
>+ }
>+
>+ dev_dbg(inst->dev->dev, "dec seq end complete\n");
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ kfree(inst->codec_info);
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_dec_init_seq(inst);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct
>dec_initial_info *info)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_dec_get_seq_info(inst, info);
>+ if (!ret)
>+ p_dec_info->initial_info_obtained = true;
>+
>+ info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
>+ info->wr_ptr = p_dec_info->stream_wr_ptr;
>+
>+ p_dec_info->initial_info = *info;
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst,
>+ struct dec_aux_buffer_size_info info,
>+ uint32_t *size)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ int width = info.width;
>+ int height = info.height;
>+ int buf_size, twice;
>+
>+ if (info.type == AUX_BUF_FBC_Y_TBL) {
>+ switch (inst->std) {
>+ case W_HEVC_DEC:
>+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
>+ break;
>+ case W_AVC_DEC:
>+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ buf_size = ALIGN(buf_size, 16);
>+ } else if (info.type == AUX_BUF_FBC_C_TBL) {
>+ if (p_dec_info->initial_info.chroma_format_idc == 2)
>+ twice = 2;
>+ else if (p_dec_info->initial_info.chroma_format_idc == 3)
>+ twice = 4;
>+ else
>+ twice = 1;
>+
>+ switch (inst->std) {
>+ case W_HEVC_DEC:
>+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
>+ break;
>+ case W_AVC_DEC:
>+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ buf_size = buf_size * twice;
>+ buf_size = ALIGN(buf_size, 16);
>+ } else if (info.type == AUX_BUF_MV_COL) {
>+ switch (inst->std) {
>+ case W_HEVC_DEC:
>+ buf_size = WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(width, height);
>+ break;
>+ case W_AVC_DEC:
>+ buf_size = WAVE6_DEC_AVC_MVCOL_BUF_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ buf_size = ALIGN(buf_size, 16);
>+ } else {
>+ return -EINVAL;
>+ }
>+
>+ *size = buf_size;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst,
>+ struct aux_buffer_info info)
>+{
>+ struct dec_info *p_dec_info;
>+ struct aux_buffer *aux_bufs = info.buf_array;
>+ struct dec_aux_buffer_size_info size_info;
>+ unsigned int expected_size;
>+ unsigned int i;
>+ int ret;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+
>+ size_info.width = p_dec_info->initial_info.pic_width;
>+ size_info.height = p_dec_info->initial_info.pic_height;
>+ size_info.type = info.type;
>+
>+ ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info,
>&expected_size);
>+ if (ret)
>+ return ret;
>+
>+ switch (info.type) {
>+ case AUX_BUF_FBC_Y_TBL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr =
>aux_bufs[i].addr;
>+ p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].size =
>aux_bufs[i].size;
>+ }
>+ break;
>+ case AUX_BUF_FBC_C_TBL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr =
>aux_bufs[i].addr;
>+ p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].size =
>aux_bufs[i].size;
>+ }
>+ break;
>+ case AUX_BUF_MV_COL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_dec_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr;
>+ p_dec_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size;
>+ }
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst,
>+ int num_of_dec_fbs, int stride,
>+ int height, int map_type)
>+{
>+ struct dec_info *p_dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+ struct frame_buffer *fb;
>+
>+ if (num_of_dec_fbs > WAVE6_MAX_FBS)
>+ return -EINVAL;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+ p_dec_info->stride = stride;
>+
>+ if (!p_dec_info->initial_info_obtained)
>+ return -EINVAL;
>+
>+ if (stride < p_dec_info->initial_info.pic_width || (stride % 8) ||
>+ height < p_dec_info->initial_info.pic_height)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ fb = inst->frame_buf;
>+ ret = wave6_vpu_dec_register_frame_buffer(inst, &fb[0],
>COMPRESSED_FRAME_MAP,
>+ num_of_dec_fbs);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst,
>struct frame_buffer fb)
>+{
>+ struct dec_info *p_dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+
>+ if (!p_dec_info->initial_info_obtained)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_dec_register_display_buffer(inst, fb);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst,
>dma_addr_t *p_rd_ptr,
>+ dma_addr_t *p_wr_ptr)
>+{
>+ struct dec_info *p_dec_info;
>+ dma_addr_t rd_ptr;
>+ dma_addr_t wr_ptr;
>+ struct vpu_device *vpu_dev = inst->dev;
>+ int ret;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ rd_ptr = wave6_vpu_dec_get_rd_ptr(inst);
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ wr_ptr = p_dec_info->stream_wr_ptr;
>+
>+ if (p_rd_ptr)
>+ *p_rd_ptr = rd_ptr;
>+ if (p_wr_ptr)
>+ *p_wr_ptr = wr_ptr;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int
>size)
>+{
>+ struct dec_info *p_dec_info;
>+ dma_addr_t wr_ptr;
>+ dma_addr_t rd_ptr;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (!inst->codec_info)
>+ return -EINVAL;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+ wr_ptr = p_dec_info->stream_wr_ptr;
>+ rd_ptr = p_dec_info->stream_rd_ptr;
>+
>+ if (size > 0) {
>+ if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size)
>+ return -EINVAL;
>+
>+ wr_ptr += size;
>+
>+ p_dec_info->stream_wr_ptr = wr_ptr;
>+ p_dec_info->stream_rd_ptr = rd_ptr;
>+ }
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ wave6_vpu_dec_set_bitstream_end(inst, (size == 0));
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct
>dec_param *param, u32 *res_fail)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (!p_dec_info->stride)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_decode(inst, param, res_fail);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr,
>bool update_wr_ptr)
>+{
>+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ p_dec_info->stream_rd_ptr = addr;
>+ if (update_wr_ptr)
>+ p_dec_info->stream_wr_ptr = addr;
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct
>dec_output_info *info)
>+{
>+ struct dec_info *p_dec_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (!info)
>+ return -EINVAL;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ memset(info, 0, sizeof(*info));
>+
>+ ret = wave6_vpu_dec_get_result(inst, info);
>+ if (ret) {
>+ info->rd_ptr = p_dec_info->stream_rd_ptr;
>+ info->wr_ptr = p_dec_info->stream_wr_ptr;
>+ goto err_out;
>+ }
>+
>+err_out:
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum
>codec_command cmd, void *param)
>+{
>+ struct dec_info *p_dec_info;
>+
>+ if (!inst || !inst->codec_info)
>+ return -EINVAL;
>+
>+ p_dec_info = &inst->codec_info->dec_info;
>+
>+ switch (cmd) {
>+ case ENABLE_DEC_THUMBNAIL_MODE:
>+ p_dec_info->thumbnail_mode = 1;
>+ break;
>+ case DEC_RESET_FRAMEBUF_INFO: {
>+ int i;
>+
>+ for (i = 0; i < WAVE6_MAX_FBS; i++) {
>+ wave6_free_dma(&inst->frame_vbuf[i]);
>+ memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer));
>+ memset(&p_dec_info->disp_buf[i], 0, sizeof(struct
>frame_buffer));
>+
>+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]);
>+ memset(&p_dec_info->vb_mv[i], 0, sizeof(struct vpu_buf));
>+
>+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]);
>+ memset(&p_dec_info->vb_fbc_y_tbl[i], 0, sizeof(struct
>vpu_buf));
>+
>+ wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]);
>+ memset(&p_dec_info->vb_fbc_c_tbl[i], 0, sizeof(struct
>vpu_buf));
>+ }
>+ break;
>+ }
>+ case DEC_GET_SEQ_INFO: {
>+ struct dec_initial_info *seq_info = param;
>+
>+ *seq_info = p_dec_info->initial_info;
>+ break;
>+ }
>+
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_dec_flush_instance(struct vpu_instance *inst)
>+{
>+ struct vpu_device *vpu_dev = inst->dev;
>+ int ret;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_dec_flush(inst);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param
>*pop)
>+{
>+ struct enc_info *p_enc_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = wave6_vpu_enc_check_open_param(inst, pop);
>+ if (ret)
>+ return ret;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ if (!wave6_vpu_is_init(vpu_dev)) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return -ENODEV;
>+ }
>+
>+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
>+ if (!inst->codec_info) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return -ENOMEM;
>+ }
>+
>+ p_enc_info = &inst->codec_info->enc_info;
>+ p_enc_info->open_param = *pop;
>+
>+ ret = wave6_vpu_build_up_enc_param(vpu_dev->dev, inst, pop);
>+ if (ret)
>+ goto free_codec_info;
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return 0;
>+
>+free_codec_info:
>+ kfree(inst->codec_info);
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ *fail_res = 0;
>+ if (!inst->codec_info)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_enc_fini_seq(inst, fail_res);
>+ if (ret) {
>+ dev_warn(inst->dev->dev, "enc seq end timed out\n");
>+
>+ if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) {
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return ret;
>+ }
>+ }
>+
>+ dev_dbg(inst->dev->dev, "enc seq end timed out\n");
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ kfree(inst->codec_info);
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst,
>+ struct enc_aux_buffer_size_info info,
>+ uint32_t *size)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int width, height, buf_size, twice;
>+
>+ if (inst->std == W_AVC_ENC) {
>+ width = ALIGN(info.width, 16);
>+ height = ALIGN(info.height, 16);
>+ if (info.rotation_angle == 90 || info.rotation_angle == 270) {
>+ width = ALIGN(info.height, 16);
>+ height = ALIGN(info.width, 16);
>+ }
>+ } else {
>+ width = ALIGN(info.width, 8);
>+ height = ALIGN(info.height, 8);
>+ if ((info.rotation_angle || info.mirror_direction) &&
>+ !(info.rotation_angle == 180 && info.mirror_direction ==
>MIRDIR_HOR_VER)) {
>+ width = ALIGN(info.width, 32);
>+ height = ALIGN(info.height, 32);
>+ }
>+ if (info.rotation_angle == 90 || info.rotation_angle == 270) {
>+ width = ALIGN(info.height, 32);
>+ height = ALIGN(info.width, 32);
>+ }
>+ }
>+
>+ if (info.type == AUX_BUF_FBC_Y_TBL) {
>+ switch (inst->std) {
>+ case W_HEVC_ENC:
>+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
>+ break;
>+ case W_AVC_ENC:
>+ buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ } else if (info.type == AUX_BUF_FBC_C_TBL) {
>+ switch (p_enc_info->open_param.output_format) {
>+ case FORMAT_422:
>+ case FORMAT_422_P10_16BIT_MSB:
>+ case FORMAT_422_P10_16BIT_LSB:
>+ case FORMAT_422_P10_32BIT_MSB:
>+ case FORMAT_422_P10_32BIT_LSB:
>+ twice = 2;
>+ break;
>+ case FORMAT_444:
>+ case FORMAT_444_P10_16BIT_MSB:
>+ case FORMAT_444_P10_16BIT_LSB:
>+ case FORMAT_444_P10_32BIT_MSB:
>+ case FORMAT_444_P10_32BIT_LSB:
>+ twice = 4;
>+ break;
>+ default:
>+ twice = 1;
>+ break;
>+ }
>+ switch (inst->std) {
>+ case W_HEVC_ENC:
>+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
>+ break;
>+ case W_AVC_ENC:
>+ buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ buf_size = buf_size * twice;
>+ } else if (info.type == AUX_BUF_MV_COL) {
>+ switch (inst->std) {
>+ case W_HEVC_ENC:
>+ buf_size = WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(width, height);
>+ break;
>+ case W_AVC_ENC:
>+ buf_size = WAVE6_ENC_AVC_MVCOL_BUF_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ } else if (info.type == AUX_BUF_SUB_SAMPLE) {
>+ switch (inst->std) {
>+ case W_HEVC_ENC:
>+ case W_AVC_ENC:
>+ buf_size = WAVE6_ENC_SUBSAMPLED_SIZE(width, height);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ } else {
>+ return -EINVAL;
>+ }
>+
>+ *size = buf_size;
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst,
>+ struct aux_buffer_info info)
>+{
>+ struct enc_info *p_enc_info;
>+ struct aux_buffer *aux_bufs = info.buf_array;
>+ struct enc_aux_buffer_size_info size_info;
>+ unsigned int expected_size;
>+ unsigned int i;
>+ int ret;
>+
>+ p_enc_info = &inst->codec_info->enc_info;
>+
>+ size_info.width = p_enc_info->width;
>+ size_info.height = p_enc_info->height;
>+ size_info.type = info.type;
>+ size_info.rotation_angle = p_enc_info->rotation_angle;
>+ size_info.mirror_direction = p_enc_info->mirror_direction;
>+
>+ ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info,
>&expected_size);
>+ if (ret)
>+ return ret;
>+
>+ switch (info.type) {
>+ case AUX_BUF_FBC_Y_TBL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr =
>aux_bufs[i].addr;
>+ p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].size =
>aux_bufs[i].size;
>+ }
>+ break;
>+ case AUX_BUF_FBC_C_TBL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr =
>aux_bufs[i].addr;
>+ p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].size =
>aux_bufs[i].size;
>+ }
>+ break;
>+ case AUX_BUF_MV_COL:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_enc_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr;
>+ p_enc_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size;
>+ }
>+ break;
>+ case AUX_BUF_SUB_SAMPLE:
>+ for (i = 0; i < info.num; i++) {
>+ if (expected_size > aux_bufs[i].size)
>+ return -EINVAL;
>+
>+ p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].daddr =
>aux_bufs[i].addr;
>+ p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].size =
>aux_bufs[i].size;
>+ }
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int
>num, unsigned int stride,
>+ int height, enum tiled_map_type map_type)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (p_enc_info->stride)
>+ return -EINVAL;
>+
>+ if (!p_enc_info->initial_info_obtained)
>+ return -EINVAL;
>+
>+ if (num < p_enc_info->initial_info.min_frame_buffer_count)
>+ return -EINVAL;
>+
>+ if (!stride || stride % 8)
>+ return -EINVAL;
>+
>+ if (height < 0)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ p_enc_info->num_frame_buffers = num;
>+ p_enc_info->stride = stride;
>+
>+ ret = wave6_vpu_enc_register_frame_buffer(inst, &inst->frame_buf[0]);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+static int wave6_check_enc_param(struct vpu_instance *inst, struct
>enc_param *param)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ bool is_rgb_format = false;
>+
>+ if (!param)
>+ return -EINVAL;
>+
>+ if (!param->skip_picture && !param->source_frame)
>+ return -EINVAL;
>+
>+ if (!p_enc_info->open_param.codec_param.bitrate && inst->std ==
>W_HEVC_ENC) {
>+ if (param->force_pic_qp_enable) {
>+ if (param->force_pic_qp_i < 0 || param->force_pic_qp_i > 63)
>+ return -EINVAL;
>+
>+ if (param->force_pic_qp_p < 0 || param->force_pic_qp_p > 63)
>+ return -EINVAL;
>+
>+ if (param->force_pic_qp_b < 0 || param->force_pic_qp_b > 63)
>+ return -EINVAL;
>+ }
>+ if ((param->pic_stream_buffer_addr % 16 || !param-
>>pic_stream_buffer_size))
>+ return -EINVAL;
>+ }
>+
>+ if ((param->pic_stream_buffer_addr % 8 || !param-
>>pic_stream_buffer_size))
>+ return -EINVAL;
>+
>+ if (p_enc_info->open_param.src_format == FORMAT_RGB_32BIT_PACKED
>||
>+ p_enc_info->open_param.src_format ==
>FORMAT_RGB_P10_32BIT_PACKED ||
>+ p_enc_info->open_param.src_format == FORMAT_RGB_24BIT_PACKED)
>+ is_rgb_format = true;
>+
>+ if (is_rgb_format) {
>+ if (param->csc.coef_ry > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_gy > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_by > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_rcb > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_gcb > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_bcb > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_rcr > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_gcr > 1023)
>+ return -EINVAL;
>+ if (param->csc.coef_bcr > 1023)
>+ return -EINVAL;
>+ if (param->csc.offset_y > 1023)
>+ return -EINVAL;
>+ if (param->csc.offset_cb > 1023)
>+ return -EINVAL;
>+ if (param->csc.offset_cr > 1023)
>+ return -EINVAL;
>+ }
>+
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct
>enc_param *param, u32 *fail_res)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ *fail_res = 0;
>+
>+ if (!p_enc_info->stride)
>+ return -EINVAL;
>+
>+ ret = wave6_check_enc_param(inst, param);
>+ if (ret)
>+ return ret;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_encode(inst, param, fail_res);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct
>enc_output_info *info)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (!info)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ memset(info, 0, sizeof(*info));
>+
>+ ret = wave6_vpu_enc_get_result(inst, info);
>+ if (ret)
>+ goto unlock;
>+
>+unlock:
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum
>codec_command cmd, void *param)
>+{
>+ struct enc_info *p_enc_info;
>+
>+ if (!inst || !inst->codec_info)
>+ return -EINVAL;
>+
>+ p_enc_info = &inst->codec_info->enc_info;
>+
>+ switch (cmd) {
>+ case ENABLE_ROTATION:
>+ p_enc_info->rotation_enable = true;
>+ break;
>+ case ENABLE_MIRRORING:
>+ p_enc_info->mirror_enable = true;
>+ break;
>+ case SET_MIRROR_DIRECTION: {
>+ enum mirror_direction mir_dir;
>+
>+ mir_dir = *(enum mirror_direction *)param;
>+ if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR &&
>+ mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER)
>+ return -EINVAL;
>+ p_enc_info->mirror_direction = mir_dir;
>+ break;
>+ }
>+ case SET_ROTATION_ANGLE: {
>+ int angle;
>+
>+ angle = *(int *)param;
>+ if (angle && angle != 90 && angle != 180 && angle != 270)
>+ return -EINVAL;
>+ if (p_enc_info->initial_info_obtained && (angle == 90 || angle ==
>270))
>+ return -EINVAL;
>+ p_enc_info->rotation_angle = angle;
>+ break;
>+ }
>+ default:
>+ return -EINVAL;
>+ }
>+ return 0;
>+}
>+
>+int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_enc_init_seq(inst);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool
>*changed)
>+{
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_enc_change_seq(inst, changed);
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return ret;
>+}
>+
>+int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct
>enc_initial_info *info)
>+{
>+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
>+ int ret;
>+ struct vpu_device *vpu_dev = inst->dev;
>+
>+ if (!info)
>+ return -EINVAL;
>+
>+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
>+ if (ret)
>+ return ret;
>+
>+ ret = wave6_vpu_enc_get_seq_info(inst, info);
>+ if (ret) {
>+ p_enc_info->initial_info_obtained = false;
>+ mutex_unlock(&vpu_dev->hw_lock);
>+ return ret;
>+ }
>+
>+ if (!p_enc_info->initial_info_obtained) {
>+ p_enc_info->initial_info_obtained = true;
>+ p_enc_info->initial_info = *info;
>+ }
>+
>+ mutex_unlock(&vpu_dev->hw_lock);
>+
>+ return 0;
>+}
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
>b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
>new file mode 100644
>index 000000000000..93c9a7b9374c
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
>@@ -0,0 +1,993 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - wave6 helper interface
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_VPUAPI_H__
>+#define __WAVE6_VPUAPI_H__
>+
>+#include <linux/kfifo.h>
>+#include <linux/idr.h>
>+#include <media/v4l2-device.h>
>+#include <media/v4l2-mem2mem.h>
>+#include <media/v4l2-ctrls.h>
>+#include "wave6-vpuerror.h"
>+#include "wave6-vpuconfig.h"
>+#include "wave6-vdi.h"
>+#include "wave6-vpu-ctrl.h"
>+
>+struct vpu_attr;
>+
>+enum vpu_instance_type {
>+ VPU_INST_TYPE_DEC = 0,
>+ VPU_INST_TYPE_ENC = 1
>+};
>+
>+enum vpu_instance_state {
>+ VPU_INST_STATE_NONE = 0,
>+ VPU_INST_STATE_OPEN = 1,
>+ VPU_INST_STATE_INIT_SEQ = 2,
>+ VPU_INST_STATE_PIC_RUN = 3,
>+ VPU_INST_STATE_SEEK = 4,
>+ VPU_INST_STATE_STOP = 5
>+};
>+
>+#define WAVE6_MAX_FBS 31
>+
>+#define WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(_w, _h) \
>+ ((ALIGN((_w), 256) / 16) * (ALIGN((_h), 64) / 16) * 1 * 16)
>+#define WAVE6_DEC_AVC_MVCOL_BUF_SIZE(_w, _h) \
>+ ((ALIGN((_w), 64) / 16) * (ALIGN((_h), 16) / 16) * 5 * 16)
>+#define WAVE6_FBC_LUMA_TABLE_SIZE(_w, _h) \
>+ (ALIGN((_w), 256) * ALIGN((_h), 64) / 32)
>+#define WAVE6_FBC_CHROMA_TABLE_SIZE(_w, _h) \
>+ (ALIGN(((_w) / 2), 256) * ALIGN((_h), 64) / 32)
>+#define WAVE6_ENC_AVC_MVCOL_BUF_SIZE(_w, _h) \
>+ ((ALIGN((_w), 512) / 512) * (ALIGN((_h), 16) / 16) * 16)
>+#define WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(_w, _h) \
>+ ((ALIGN((_w), 64) / 64) * (ALIGN((_h), 64) / 64) * 128)
>+#define WAVE6_ENC_SUBSAMPLED_SIZE(_w, _h) \
>+ (ALIGN(((_w) / 4), 16) * ALIGN(((_h) / 4), 32))
>+
>+enum codec_std {
>+ W_HEVC_DEC = 0x00,
>+ W_HEVC_ENC = 0x01,
>+ W_AVC_DEC = 0x02,
>+ W_AVC_ENC = 0x03,
>+ STD_UNKNOWN = 0xFF
>+};
>+
>+#define HEVC_PROFILE_MAIN 1
>+#define HEVC_PROFILE_MAIN10 2
>+#define HEVC_PROFILE_STILLPICTURE 3
>+#define HEVC_PROFILE_MAIN10_STILLPICTURE 2
>+
>+#define H264_PROFILE_BP 1
>+#define H264_PROFILE_MP 2
>+#define H264_PROFILE_EXTENDED 3
>+#define H264_PROFILE_HP 4
>+#define H264_PROFILE_HIGH10 5
>+
>+#define H264_VUI_SAR_IDC_EXTENDED 255
>+
>+#define DEC_REFRESH_TYPE_NON_IRAP 0
>+#define DEC_REFRESH_TYPE_IDR 2
>+
>+#define DEFAULT_TEMP_LAYER_CNT 1
>+#define DEFAULT_RC_INITIAL_LEVEL 8
>+#define DEFAULT_RC_INITIAL_QP -1
>+#define DEFAULT_PIC_RC_MAX_DQP 3
>+#define DEFAULT_EN_ADAPTIVE_ROUND 1
>+#define DEFAULT_Q_ROUND_INTER 85
>+#define DEFAULT_Q_ROUND_INTRA 171
>+#define DEFAULT_EN_INTRA_TRANS_SKIP 1
>+#define DEFAULT_EN_ME_CENTER 1
>+#define DEFAULT_INTRA_4X4 3
>+#define DEFAULT_EN_AUTO_LEVEL_ADJUSTING 1
>+#define DEFAULT_NUM_TICKS_POC_DIFF 100
>+#define DEFAULT_RC_UPDATE_SPEED_CBR 64
>+#define DEFAULT_RC_UPDATE_SPEED_VBR 16
>+#define DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG 1
>+#define DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG 1
>+
>+#define SEQ_CHANGE_ENABLE_PROFILE BIT(5)
>+#define SEQ_CHANGE_ENABLE_SIZE BIT(16)
>+#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18)
>+#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19)
>+
>+#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE |
>\
>+ SEQ_CHANGE_ENABLE_SIZE | \
>+ SEQ_CHANGE_ENABLE_BITDEPTH | \
>+ SEQ_CHANGE_ENABLE_DPB_COUNT)
>+
>+#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \
>+ SEQ_CHANGE_ENABLE_BITDEPTH | \
>+ SEQ_CHANGE_ENABLE_DPB_COUNT)
>+
>+#define DEC_NOTI_FLAG_NO_FB 0x2
>+#define DEC_NOTI_FLAG_SEQ_CHANGE 0x1
>+
>+#define RECON_IDX_FLAG_ENC_END -1
>+#define RECON_IDX_FLAG_ENC_DELAY -2
>+#define RECON_IDX_FLAG_HEADER_ONLY -3
>+#define RECON_IDX_FLAG_CHANGE_PARAM -4
>+
>+enum codec_command {
>+ ENABLE_ROTATION,
>+ ENABLE_MIRRORING,
>+ SET_MIRROR_DIRECTION,
>+ SET_ROTATION_ANGLE,
>+ ENABLE_DEC_THUMBNAIL_MODE,
>+ DEC_RESET_FRAMEBUF_INFO,
>+ DEC_GET_SEQ_INFO,
>+};
>+
>+enum cb_cr_order {
>+ CBCR_ORDER_NORMAL,
>+ CBCR_ORDER_REVERSED
>+};
>+
>+enum mirror_direction {
>+ MIRDIR_NONE,
>+ MIRDIR_VER,
>+ MIRDIR_HOR,
>+ MIRDIR_HOR_VER
>+};
>+
>+enum chroma_format {
>+ YUV400,
>+ YUV420,
>+ YUV422,
>+ YUV444,
>+};
>+
>+enum frame_buffer_format {
>+ FORMAT_ERR = -1,
>+
>+ FORMAT_420 = 0,
>+ FORMAT_422,
>+ FORMAT_224,
>+ FORMAT_444,
>+ FORMAT_400,
>+
>+ FORMAT_420_P10_16BIT_MSB = 5,
>+ FORMAT_420_P10_16BIT_LSB,
>+ FORMAT_420_P10_32BIT_MSB,
>+ FORMAT_420_P10_32BIT_LSB,
>+
>+ FORMAT_422_P10_16BIT_MSB,
>+ FORMAT_422_P10_16BIT_LSB,
>+ FORMAT_422_P10_32BIT_MSB,
>+ FORMAT_422_P10_32BIT_LSB,
>+
>+ FORMAT_444_P10_16BIT_MSB,
>+ FORMAT_444_P10_16BIT_LSB,
>+ FORMAT_444_P10_32BIT_MSB,
>+ FORMAT_444_P10_32BIT_LSB,
>+
>+ FORMAT_400_P10_16BIT_MSB,
>+ FORMAT_400_P10_16BIT_LSB,
>+ FORMAT_400_P10_32BIT_MSB,
>+ FORMAT_400_P10_32BIT_LSB,
>+
>+ FORMAT_YUYV,
>+ FORMAT_YUYV_P10_16BIT_MSB,
>+ FORMAT_YUYV_P10_16BIT_LSB,
>+ FORMAT_YUYV_P10_32BIT_MSB,
>+ FORMAT_YUYV_P10_32BIT_LSB,
>+
>+ FORMAT_YVYU,
>+ FORMAT_YVYU_P10_16BIT_MSB,
>+ FORMAT_YVYU_P10_16BIT_LSB,
>+ FORMAT_YVYU_P10_32BIT_MSB,
>+ FORMAT_YVYU_P10_32BIT_LSB,
>+
>+ FORMAT_UYVY,
>+ FORMAT_UYVY_P10_16BIT_MSB,
>+ FORMAT_UYVY_P10_16BIT_LSB,
>+ FORMAT_UYVY_P10_32BIT_MSB,
>+ FORMAT_UYVY_P10_32BIT_LSB,
>+
>+ FORMAT_VYUY,
>+ FORMAT_VYUY_P10_16BIT_MSB,
>+ FORMAT_VYUY_P10_16BIT_LSB,
>+ FORMAT_VYUY_P10_32BIT_MSB,
>+ FORMAT_VYUY_P10_32BIT_LSB,
>+
>+ FORMAT_RGB_32BIT_PACKED = 90,
>+ FORMAT_YUV444_32BIT_PACKED,
>+ FORMAT_RGB_P10_32BIT_PACKED,
>+ FORMAT_YUV444_P10_32BIT_PACKED,
>+
>+ FORMAT_RGB_24BIT_PACKED = 95,
>+ FORMAT_YUV444_24BIT_PACKED,
>+ FORMAT_YUV444_24BIT,
>+
>+ FORMAT_MAX,
>+};
>+
>+enum packed_format_num {
>+ NOT_PACKED = 0,
>+ PACKED_YUYV,
>+ PACKED_YVYU,
>+ PACKED_UYVY,
>+ PACKED_VYUY,
>+};
>+
>+enum pic_type {
>+ PIC_TYPE_I = 0,
>+ PIC_TYPE_P = 1,
>+ PIC_TYPE_B = 2,
>+ PIC_TYPE_IDR = 5,
>+ PIC_TYPE_MAX
>+};
>+
>+enum enc_force_pic_type {
>+ ENC_FORCE_PIC_TYPE_I = 0,
>+ ENC_FORCE_PIC_TYPE_P = 1,
>+ ENC_FORCE_PIC_TYPE_B = 2,
>+ ENC_FORCE_PIC_TYPE_IDR = 3,
>+ ENC_FORCE_PIC_TYPE_DISABLED = 4,
>+};
>+
>+enum bitstream_mode {
>+ BS_MODE_INTERRUPT,
>+ BS_MODE_RESERVED,
>+ BS_MODE_PIC_END,
>+};
>+
>+enum display_mode {
>+ DISP_MODE_DISP_ORDER,
>+ DISP_MODE_DEC_ORDER,
>+};
>+
>+enum sw_reset_mode {
>+ SW_RESET_SAFETY,
>+ SW_RESET_FORCE,
>+ SW_RESET_ON_BOOT
>+};
>+
>+enum tiled_map_type {
>+ LINEAR_FRAME_MAP = 0,
>+ COMPRESSED_FRAME_MAP = 17,
>+};
>+
>+enum temporal_id_mode {
>+ TEMPORAL_ID_MODE_ABSOLUTE,
>+ TEMPORAL_ID_MODE_RELATIVE,
>+};
>+
>+enum aux_buffer_type {
>+ AUX_BUF_FBC_Y_TBL,
>+ AUX_BUF_FBC_C_TBL,
>+ AUX_BUF_MV_COL,
>+ AUX_BUF_SUB_SAMPLE,
>+ AUX_BUF_TYPE_MAX,
>+};
>+
>+enum intra_refresh_mode {
>+ INTRA_REFRESH_NONE = 0,
>+ INTRA_REFRESH_ROW = 1,
>+ INTRA_REFRESH_COLUMN = 2,
>+};
>+
>+struct vpu_attr {
>+ u32 product_id;
>+ char product_name[8];
>+ u32 product_version;
>+ u32 fw_version;
>+ u32 fw_revision;
>+ u32 support_decoders;
>+ u32 support_encoders;
>+ u32 support_bitstream_mode;
>+ bool support_avc10bit_enc;
>+ bool support_hevc10bit_enc;
>+ bool support_dual_core;
>+};
>+
>+struct frame_buffer {
>+ dma_addr_t buf_y;
>+ dma_addr_t buf_cb;
>+ dma_addr_t buf_cr;
>+ enum tiled_map_type map_type;
>+ unsigned int stride;
>+ unsigned int width;
>+ unsigned int height;
>+ int index;
>+ u32 luma_bitdepth: 4;
>+ u32 chroma_bitdepth: 4;
>+ u32 chroma_format_idc: 2;
>+};
>+
>+struct vpu_rect {
>+ u32 left;
>+ u32 top;
>+ u32 right;
>+ u32 bottom;
>+};
>+
>+struct timestamp_info {
>+ u32 hour;
>+ u32 min;
>+ u32 sec;
>+ u32 ms;
>+};
>+
>+struct sar_info {
>+ u32 enable;
>+ u32 idc;
>+ u32 width;
>+ u32 height;
>+};
>+
>+struct aux_buffer {
>+ int index;
>+ int size;
>+ dma_addr_t addr;
>+};
>+
>+struct aux_buffer_info {
>+ int num;
>+ struct aux_buffer *buf_array;
>+ enum aux_buffer_type type;
>+};
>+
>+struct instance_buffer {
>+ dma_addr_t temp_base;
>+ u32 temp_size;
>+ dma_addr_t ar_base;
>+};
>+
>+struct report_cycle {
>+ u32 host_cmd_s;
>+ u32 host_cmd_e;
>+ u32 proc_s;
>+ u32 proc_e;
>+ u32 vpu_s;
>+ u32 vpu_e;
>+ u32 frame_cycle;
>+ u32 proc_cycle;
>+ u32 vpu_cycle;
>+};
>+
>+struct color_param {
>+ u32 chroma_sample_position;
>+ u32 color_range;
>+ u32 matrix_coefficients;
>+ u32 transfer_characteristics;
>+ u32 color_primaries;
>+ bool color_description_present;
>+ bool video_signal_type_present;
>+};
>+
>+struct sec_axi_info {
>+ bool use_dec_ip;
>+ bool use_dec_lf_row;
>+ bool use_enc_rdo;
>+ bool use_enc_lf;
>+};
>+
>+struct dec_aux_buffer_size_info {
>+ int width;
>+ int height;
>+ enum aux_buffer_type type;
>+};
>+
>+struct dec_scaler_info {
>+ bool enable;
>+ int width;
>+ int height;
>+ u32 scale_mode;
>+};
>+
>+struct dec_open_param {
>+ enum cb_cr_order cbcr_order;
>+ enum endian_mode frame_endian;
>+ enum endian_mode stream_endian;
>+ enum bitstream_mode bs_mode;
>+ enum display_mode disp_mode;
>+ bool enable_non_ref_fbc_write;
>+ u32 ext_addr_vcpu: 8;
>+ bool is_secure_inst;
>+ u32 inst_priority: 5;
>+ struct instance_buffer inst_buffer;
>+};
>+
>+struct dec_initial_info {
>+ u32 pic_width;
>+ u32 pic_height;
>+ u32 f_rate_numerator;
>+ u32 f_rate_denominator;
>+ struct vpu_rect pic_crop_rect;
>+ u32 min_frame_buffer_count;
>+ u32 req_mv_buffer_count;
>+ u32 frame_buf_delay;
>+ u32 profile;
>+ u32 level;
>+ u32 tier;
>+ bool is_ext_sar;
>+ u32 aspect_rate_info;
>+ u32 bitrate;
>+ u32 chroma_format_idc;
>+ u32 luma_bitdepth;
>+ u32 chroma_bitdepth;
>+ u32 err_reason;
>+ int warn_info;
>+ dma_addr_t rd_ptr;
>+ dma_addr_t wr_ptr;
>+ unsigned int sequence_no;
>+ struct color_param color;
>+};
>+
>+#define WAVE_SKIPMODE_WAVE_NONE 0
>+#define WAVE_SKIPMODE_NON_IRAP 1
>+#define WAVE_SKIPMODE_NON_REF 2
>+
>+struct dec_param {
>+ int skipframe_mode;
>+ bool decode_cra_as_bla;
>+ bool disable_film_grain;
>+ struct timestamp_info timestamp;
>+};
>+
>+struct h265_rp_sei {
>+ unsigned int exist;
>+ int recovery_poc_cnt;
>+ bool exact_match;
>+ bool broken_link;
>+};
>+
>+struct dec_output_info {
>+ int nal_type;
>+ int pic_type;
>+ int num_of_err_m_bs;
>+ int num_of_tot_m_bs;
>+ int num_of_err_m_bs_in_disp;
>+ int num_of_tot_m_bs_in_disp;
>+ int disp_pic_width;
>+ int disp_pic_height;
>+ int dec_pic_width;
>+ int dec_pic_height;
>+ int decoded_poc;
>+ int display_poc;
>+ struct h265_rp_sei h265_rp_sei;
>+ dma_addr_t rd_ptr;
>+ dma_addr_t wr_ptr;
>+ dma_addr_t byte_pos_frame_start;
>+ dma_addr_t byte_pos_frame_end;
>+ dma_addr_t frame_decoded_addr;
>+ dma_addr_t frame_display_addr;
>+ int error_reason;
>+ int warn_info;
>+ unsigned int sequence_no;
>+ struct report_cycle cycle;
>+ dma_addr_t release_disp_frame_addr[WAVE6_MAX_FBS];
>+ dma_addr_t disp_frame_addr[WAVE6_MAX_FBS];
>+ struct timestamp_info timestamp;
>+ u32 notification_flags;
>+ u32 release_disp_frame_num: 5;
>+ u32 disp_frame_num: 5;
>+ u32 ctu_size: 2;
>+ bool frame_display;
>+ bool frame_decoded;
>+ bool stream_end;
>+ bool last_frame_in_au;
>+ bool decoding_success;
>+};
>+
>+struct dec_info {
>+ struct dec_open_param open_param;
>+ struct dec_initial_info initial_info;
>+ dma_addr_t stream_wr_ptr;
>+ dma_addr_t stream_rd_ptr;
>+ bool stream_end;
>+ struct vpu_buf vb_mv[WAVE6_MAX_FBS];
>+ struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS];
>+ struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS];
>+ struct frame_buffer disp_buf[WAVE6_MAX_FBS];
>+ int stride;
>+ bool initial_info_obtained;
>+ struct sec_axi_info sec_axi_info;
>+ struct dec_output_info dec_out_info[WAVE6_MAX_FBS];
>+ bool thumbnail_mode;
>+ int seq_change_mask;
>+ u32 cycle_per_tick;
>+ enum frame_buffer_format wtl_format;
>+};
>+
>+#define MAX_CUSTOM_LAMBDA_NUM 52
>+#define MAX_NUM_TEMPORAL_LAYER 7
>+#define MAX_GOP_NUM 8
>+#define MAX_NUM_CHANGEABLE_TEMPORAL_LAYER 4
>+
>+struct custom_gop_pic_param {
>+ int pic_type;
>+ int poc_offset;
>+ int pic_qp;
>+ int use_multi_ref_p;
>+ int ref_poc_l0;
>+ int ref_poc_l1;
>+ int temporal_id;
>+};
>+
>+struct custom_gop_param {
>+ int custom_gop_size;
>+ struct custom_gop_pic_param pic_param[MAX_GOP_NUM];
>+};
>+
>+struct temporal_layer_param {
>+ bool change_qp;
>+ u32 qp_i;
>+ u32 qp_p;
>+ u32 qp_b;
>+};
>+
>+struct enc_aux_buffer_size_info {
>+ int width;
>+ int height;
>+ enum aux_buffer_type type;
>+ enum mirror_direction mirror_direction;
>+ int rotation_angle;
>+};
>+
>+struct enc_scaler_info {
>+ bool enable;
>+ int width;
>+ int height;
>+ int coef_mode;
>+};
>+
>+struct enc_codec_param {
>+ u32 internal_bit_depth;
>+ u32 decoding_refresh_type;
>+ u32 idr_period;
>+ u32 intra_period;
>+ u32 gop_preset_idx;
>+ u32 frame_rate;
>+ u32 bitrate;
>+ u32 cpb_size;
>+ u32 hvs_qp_scale_div2;
>+ u32 max_delta_qp;
>+ int rc_initial_qp;
>+ u32 rc_update_speed;
>+ u32 max_bitrate;
>+ u32 rc_mode;
>+ u32 rc_initial_level;
>+ u32 pic_rc_max_dqp;
>+ u32 bg_th_diff;
>+ u32 bg_th_mean_diff;
>+ int bg_delta_qp;
>+ u32 intra_refresh_mode;
>+ u32 intra_refresh_arg;
>+ int beta_offset_div2;
>+ int tc_offset_div2;
>+ u32 qp;
>+ u32 min_qp_i;
>+ u32 max_qp_i;
>+ u32 min_qp_p;
>+ u32 max_qp_p;
>+ u32 min_qp_b;
>+ u32 max_qp_b;
>+ int cb_qp_offset;
>+ int cr_qp_offset;
>+ u32 q_round_intra;
>+ u32 q_round_inter;
>+ int lambda_dqp_intra;
>+ int lambda_dqp_inter;
>+ u32 slice_mode;
>+ u32 slice_arg;
>+ u32 level;
>+ u32 tier;
>+ u32 profile;
>+ struct vpu_rect conf_win;
>+ u32 forced_idr_header;
>+ u16 custom_lambda_ssd[MAX_CUSTOM_LAMBDA_NUM];
>+ u16 custom_lambda_sad[MAX_CUSTOM_LAMBDA_NUM];
>+ struct custom_gop_param gop_param;
>+ struct temporal_layer_param
>temp_layer[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER];
>+ u32 temp_layer_cnt;
>+ u32 report_mv_histo_threshold0;
>+ u32 report_mv_histo_threshold1;
>+ u32 report_mv_histo_threshold2;
>+ u32 report_mv_histo_threshold3;
>+ enum endian_mode custom_map_endian;
>+ u32 num_units_in_tick;
>+ u32 time_scale;
>+ u32 num_ticks_poc_diff_one;
>+ struct color_param color;
>+ struct sar_info sar;
>+ u32 max_intra_pic_bit;
>+ u32 max_inter_pic_bit;
>+ u32 intra_4x4;
>+
>+ u32 en_constrained_intra_pred: 1;
>+ u32 en_long_term: 1;
>+ u32 en_intra_trans_skip: 1;
>+ u32 en_me_center: 1;
>+ u32 en_rate_control: 1;
>+ u32 en_transform8x8: 1;
>+ u32 en_hvs_qp: 1;
>+ u32 en_bg_detect: 1;
>+ u32 en_temporal_mvp: 1;
>+ u32 en_cabac: 1;
>+ u32 en_dbk: 1;
>+ u32 en_sao: 1;
>+ u32 en_lf_cross_slice_boundary: 1;
>+ u32 en_scaling_list: 1;
>+ u32 en_adaptive_round: 1;
>+ u32 en_qp_map: 1;
>+ u32 en_mode_map: 1;
>+ u32 en_q_round_offset: 1;
>+ u32 en_still_picture: 1;
>+ u32 en_strong_intra_smoothing: 1;
>+ u32 en_custom_lambda: 1;
>+ u32 en_report_mv_histo: 1;
>+ u32 dis_coef_clear: 1;
>+ u32 en_cu_level_rate_control: 1;
>+ u32 en_vbv_overflow_drop_frame: 1;
>+ u32 en_auto_level_adjusting: 1;
>+};
>+
>+struct enc_open_param {
>+ int pic_width;
>+ int pic_height;
>+ struct enc_codec_param codec_param;
>+ enum cb_cr_order cbcr_order;
>+ enum endian_mode stream_endian;
>+ enum endian_mode source_endian;
>+ bool line_buf_int_en;
>+ enum packed_format_num packed_format;
>+ enum frame_buffer_format src_format;
>+ enum frame_buffer_format output_format;
>+ bool enable_non_ref_fbc_write;
>+ bool enc_hrd_rbsp_in_vps;
>+ u32 hrd_rbsp_data_size;
>+ dma_addr_t hrd_rbsp_data_addr;
>+ u32 ext_addr_vcpu: 8;
>+ bool is_secure_inst;
>+ u32 inst_priority: 5;
>+ struct instance_buffer inst_buffer;
>+ bool enc_aud;
>+};
>+
>+struct enc_initial_info {
>+ u32 min_frame_buffer_count;
>+ u32 min_src_frame_count;
>+ u32 req_mv_buffer_count;
>+ int max_latency_pictures;
>+ int err_reason;
>+ int warn_info;
>+};
>+
>+struct enc_csc_param {
>+ u32 format_order;
>+ u32 coef_ry;
>+ u32 coef_gy;
>+ u32 coef_by;
>+ u32 coef_rcb;
>+ u32 coef_gcb;
>+ u32 coef_bcb;
>+ u32 coef_rcr;
>+ u32 coef_gcr;
>+ u32 coef_bcr;
>+ u32 offset_y;
>+ u32 offset_cb;
>+ u32 offset_cr;
>+};
>+
>+struct enc_param {
>+ struct frame_buffer *source_frame;
>+ bool skip_picture;
>+ dma_addr_t pic_stream_buffer_addr;
>+ int pic_stream_buffer_size;
>+ bool force_pic_qp_enable;
>+ int force_pic_qp_i;
>+ int force_pic_qp_p;
>+ int force_pic_qp_b;
>+ bool force_pic_type_enable;
>+ int force_pic_type;
>+ int src_idx;
>+ bool src_end;
>+ u32 bitrate;
>+ struct enc_csc_param csc;
>+ struct timestamp_info timestamp;
>+};
>+
>+struct enc_report_fme_sum {
>+ u32 lower_x0;
>+ u32 higher_x0;
>+ u32 lower_y0;
>+ u32 higher_y0;
>+ u32 lower_x1;
>+ u32 higher_x1;
>+ u32 lower_y1;
>+ u32 higher_y1;
>+};
>+
>+struct enc_report_mv_histo {
>+ u32 cnt0;
>+ u32 cnt1;
>+ u32 cnt2;
>+ u32 cnt3;
>+ u32 cnt4;
>+};
>+
>+struct enc_output_info {
>+ dma_addr_t bitstream_buffer;
>+ u32 bitstream_size;
>+ int bitstream_wrap_around;
>+ int pic_type;
>+ int num_of_slices;
>+ int recon_frame_index;
>+ struct frame_buffer recon_frame;
>+ dma_addr_t rd_ptr;
>+ dma_addr_t wr_ptr;
>+ int pic_skipped;
>+ int num_of_intra;
>+ int num_of_merge;
>+ int num_of_skip_block;
>+ int avg_ctu_qp;
>+ int enc_pic_byte;
>+ int enc_gop_pic_idx;
>+ int enc_pic_poc;
>+ int enc_src_idx;
>+ int enc_vcl_nut;
>+ int enc_pic_cnt;
>+ int error_reason;
>+ int warn_info;
>+ u32 pic_distortion_low;
>+ u32 pic_distortion_high;
>+ bool non_ref_pic;
>+ bool encoding_success;
>+ struct enc_report_fme_sum fme_sum;
>+ struct enc_report_mv_histo mv_histo;
>+ struct report_cycle cycle;
>+ struct timestamp_info timestamp;
>+ dma_addr_t src_y_addr;
>+ dma_addr_t custom_map_addr;
>+ dma_addr_t prefix_sei_nal_addr;
>+ dma_addr_t suffix_sei_nal_addr;
>+};
>+
>+enum gop_preset_idx {
>+ PRESET_IDX_CUSTOM_GOP = 0,
>+ PRESET_IDX_ALL_I = 1,
>+ PRESET_IDX_IPP = 2,
>+ PRESET_IDX_IBBB = 3,
>+ PRESET_IDX_IBPBP = 4,
>+ PRESET_IDX_IBBBP = 5,
>+ PRESET_IDX_IPPPP = 6,
>+ PRESET_IDX_IBBBB = 7,
>+ PRESET_IDX_RA_IB = 8,
>+ PRESET_IDX_IPP_SINGLE = 9,
>+ PRESET_IDX_MAX,
>+};
>+
>+struct enc_info {
>+ struct enc_open_param open_param;
>+ struct enc_initial_info initial_info;
>+ int num_frame_buffers;
>+ int stride;
>+ bool rotation_enable;
>+ bool mirror_enable;
>+ enum mirror_direction mirror_direction;
>+ int rotation_angle;
>+ bool initial_info_obtained;
>+ struct sec_axi_info sec_axi_info;
>+ bool line_buf_int_en;
>+ struct vpu_buf vb_mv[WAVE6_MAX_FBS];
>+ struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS];
>+ struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS];
>+ struct vpu_buf vb_sub_sam_buf[WAVE6_MAX_FBS];
>+ u32 cycle_per_tick;
>+ u32 width;
>+ u32 height;
>+ struct enc_scaler_info scaler_info;
>+ int color_format;
>+};
>+
>+struct h264_enc_controls {
>+ u32 profile;
>+ u32 level;
>+ u32 min_qp;
>+ u32 max_qp;
>+ u32 i_frame_qp;
>+ u32 p_frame_qp;
>+ u32 b_frame_qp;
>+ u32 loop_filter_mode;
>+ u32 loop_filter_beta;
>+ u32 loop_filter_alpha;
>+ u32 _8x8_transform;
>+ u32 constrained_intra_prediction;
>+ u32 chroma_qp_index_offset;
>+ u32 entropy_mode;
>+ u32 i_period;
>+ u32 vui_sar_enable;
>+ u32 vui_sar_idc;
>+ u32 vui_ext_sar_width;
>+ u32 vui_ext_sar_height;
>+ u32 cpb_size;
>+};
>+
>+struct hevc_enc_controls {
>+ u32 profile;
>+ u32 level;
>+ u32 min_qp;
>+ u32 max_qp;
>+ u32 i_frame_qp;
>+ u32 p_frame_qp;
>+ u32 b_frame_qp;
>+ u32 loop_filter_mode;
>+ u32 lf_beta_offset_div2;
>+ u32 lf_tc_offset_div2;
>+ u32 refresh_type;
>+ u32 refresh_period;
>+ u32 const_intra_pred;
>+ u32 strong_smoothing;
>+ u32 tmv_prediction;
>+};
>+
>+struct enc_controls {
>+ u32 rot_angle;
>+ u32 mirror_direction;
>+ u32 bitrate;
>+ u32 bitrate_mode;
>+ u32 gop_size;
>+ u32 frame_rc_enable;
>+ u32 mb_rc_enable;
>+ u32 slice_mode;
>+ u32 slice_max_mb;
>+ u32 prepend_spspps_to_idr;
>+ u32 intra_refresh_period;
>+ struct h264_enc_controls h264;
>+ struct hevc_enc_controls hevc;
>+ u32 force_key_frame;
>+ u32 frame_skip_mode;
>+};
>+
>+struct vpu_device {
>+ struct device *dev;
>+ struct v4l2_device v4l2_dev;
>+ struct v4l2_m2m_dev *m2m_dev;
>+ struct video_device *video_dev_dec;
>+ struct video_device *video_dev_enc;
>+ struct mutex dev_lock; /* the lock for the src,dst v4l2 queues */
>+ struct mutex hw_lock; /* lock hw configurations */
>+ int irq;
>+ u32 fw_version;
>+ u32 fw_revision;
>+ u32 hw_version;
>+ struct vpu_attr attr;
>+ u32 last_performance_cycles;
>+ void __iomem *reg_base;
>+ struct device *ctrl;
>+ int product_code;
>+ struct vpu_buf temp_vbuf;
>+ struct clk_bulk_data *clks;
>+ int num_clks;
>+ struct clk *clk_vpu;
>+ struct completion irq_done;
>+ struct kfifo irq_status;
>+ struct delayed_work task_timer;
>+ struct wave6_vpu_entity entity;
>+ bool active;
>+ int pause_request;
>+ struct mutex pause_lock; /* the lock for the pause/resume m2m job. */
>+ const struct wave6_match_data *res;
>+ struct dentry *debugfs;
>+};
>+
>+struct vpu_instance;
>+
>+struct vpu_instance_ops {
>+ int (*start_process)(struct vpu_instance *inst);
>+ void (*finish_process)(struct vpu_instance *inst, bool error);
>+};
>+
>+struct vpu_performance_info {
>+ ktime_t ts_first;
>+ ktime_t ts_last;
>+ s64 latency_first;
>+ s64 latency_max;
>+ s64 min_process_time;
>+ s64 max_process_time;
>+ u64 total_sw_time;
>+ u64 total_hw_time;
>+};
>+
>+struct vpu_instance {
>+ struct v4l2_fh v4l2_fh;
>+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
>+ struct vpu_device *dev;
>+
>+ struct v4l2_pix_format_mplane src_fmt;
>+ struct v4l2_pix_format_mplane dst_fmt;
>+ struct v4l2_rect crop;
>+ struct v4l2_rect codec_rect;
>+ enum v4l2_colorspace colorspace;
>+ enum v4l2_xfer_func xfer_func;
>+ enum v4l2_ycbcr_encoding ycbcr_enc;
>+ enum v4l2_quantization quantization;
>+
>+ enum vpu_instance_state state;
>+ enum vpu_instance_state state_in_seek;
>+ enum vpu_instance_type type;
>+ const struct vpu_instance_ops *ops;
>+
>+ enum codec_std std;
>+ u32 id;
>+ union {
>+ struct enc_info enc_info;
>+ struct dec_info dec_info;
>+ } *codec_info;
>+ struct frame_buffer frame_buf[WAVE6_MAX_FBS];
>+ struct vpu_buf frame_vbuf[WAVE6_MAX_FBS];
>+ u32 queued_src_buf_num;
>+ u32 queued_dst_buf_num;
>+ u32 processed_buf_num;
>+ u32 error_buf_num;
>+ u32 sequence;
>+ bool next_buf_last;
>+ bool cbcr_interleave;
>+ bool nv21;
>+ bool eos;
>+
>+ struct vpu_buf aux_vbuf[AUX_BUF_TYPE_MAX][WAVE6_MAX_FBS];
>+ struct vpu_buf ar_vbuf;
>+ bool thumbnail_mode;
>+ enum display_mode disp_mode;
>+
>+ unsigned int frame_rate;
>+ struct enc_controls enc_ctrls;
>+ struct dec_scaler_info scaler_info;
>+ bool error_recovery;
>+
>+ struct vpu_performance_info performance;
>+
>+ struct dentry *debugfs;
>+};
>+
>+void wave6_vdi_writel(struct vpu_device *vpu_device, unsigned int addr,
>unsigned int data);
>+unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, unsigned int
>addr);
>+unsigned int wave6_vdi_convert_endian(unsigned int endian);
>+
>+int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param
>*pop);
>+int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res);
>+int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst);
>+int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct
>dec_initial_info *info);
>+int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst,
>+ struct dec_aux_buffer_size_info info,
>+ uint32_t *size);
>+int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst, struct
>aux_buffer_info info);
>+int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int
>num_of_dec_fbs,
>+ int stride, int height, int map_type);
>+int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst,
>struct frame_buffer fb);
>+int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct
>dec_param *param,
>+ u32 *res_fail);
>+int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct
>dec_output_info *info);
>+int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr,
>bool update_wr_ptr);
>+int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum
>codec_command cmd, void *parameter);
>+int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst,
>dma_addr_t *p_rd_ptr,
>+ dma_addr_t *p_wr_ptr);
>+int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int
>size);
>+int wave6_vpu_dec_flush_instance(struct vpu_instance *inst);
>+
>+int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param
>*enc_op_param);
>+int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res);
>+int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst);
>+int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool
>*changed);
>+int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct
>enc_initial_info *info);
>+int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst,
>+ struct enc_aux_buffer_size_info info,
>+ uint32_t *size);
>+int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst, struct
>aux_buffer_info info);
>+int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int
>num, unsigned int stride,
>+ int height, enum tiled_map_type map_type);
>+int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct
>enc_param *param,
>+ u32 *fail_res);
>+int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct
>enc_output_info *info);
>+int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum
>codec_command cmd, void *parameter);
>+
>+#endif /* __WAVE6_VPUAPI_H__ */
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
>b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
>new file mode 100644
>index 000000000000..9078f3741644
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
>@@ -0,0 +1,80 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - product config definitions
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_VPUCONFIG_H__
>+#define __WAVE6_VPUCONFIG_H__
>+
>+#define WAVE617_CODE 0x6170
>+#define WAVE627_CODE 0x6270
>+#define WAVE633_CODE 0x6330
>+#define WAVE637_CODE 0x6370
>+#define WAVE663_CODE 0x6630
>+#define WAVE677_CODE 0x6670
>+
>+#define PRODUCT_CODE_W_SERIES(x) ({ \
>+ int c = x; \
>+ ((c) == WAVE617_CODE || (c) == WAVE627_CODE || \
>+ (c) == WAVE633_CODE || (c) == WAVE637_CODE || \
>+ (c) == WAVE663_CODE || (c) == WAVE677_CODE); \
>+})
>+
>+#define WAVE627ENC_WORKBUF_SIZE (512 * 1024)
>+#define WAVE637DEC_WORKBUF_SIZE (2 * 512 * 1024)
>+#define WAVE637DEC_WORKBUF_SIZE_FOR_CQ (3 * 512 * 1024)
>+
>+#define MAX_NUM_INSTANCE 32
>+
>+#define W6_MAX_PIC_STRIDE (4096U * 4)
>+#define W6_DEF_DEC_PIC_WIDTH 720U
>+#define W6_DEF_DEC_PIC_HEIGHT 480U
>+#define W6_MIN_DEC_PIC_WIDTH 64U
>+#define W6_MIN_DEC_PIC_HEIGHT 64U
>+#define W6_MAX_DEC_PIC_WIDTH 4096U
>+#define W6_MAX_DEC_PIC_HEIGHT 4096U
>+#define W6_DEC_PIC_SIZE_STEP 1
>+
>+#define W6_DEF_ENC_PIC_WIDTH 416U
>+#define W6_DEF_ENC_PIC_HEIGHT 240U
>+#define W6_MIN_ENC_PIC_WIDTH 256U
>+#define W6_MIN_ENC_PIC_HEIGHT 128U
>+#define W6_MAX_ENC_PIC_WIDTH 4096U
>+#define W6_MAX_ENC_PIC_HEIGHT 4096U
>+#define W6_ENC_PIC_SIZE_STEP 8
>+#define W6_ENC_CROP_X_POS_STEP 32
>+#define W6_ENC_CROP_Y_POS_STEP 2
>+#define W6_ENC_CROP_STEP 2
>+
>+#define W6_VPU_POLL_TIMEOUT 300000
>+#define W6_BOOT_WAIT_TIMEOUT 10000
>+#define W6_VPU_TIMEOUT 6000
>+#define W6_VPU_TIMEOUT_CYCLE_COUNT (8000000 * 4 * 4)
>+
>+#define HOST_ENDIAN VDI_128BIT_LITTLE_ENDIAN
>+#define VPU_FRAME_ENDIAN HOST_ENDIAN
>+#define VPU_STREAM_ENDIAN HOST_ENDIAN
>+#define VPU_USER_DATA_ENDIAN HOST_ENDIAN
>+#define VPU_SOURCE_ENDIAN HOST_ENDIAN
>+
>+#define USE_SRC_PRP_AXI 0
>+#define USE_SRC_PRI_AXI 1
>+#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI
>+
>+#define COMMAND_QUEUE_DEPTH (1)
>+
>+#define W6_REMAP_INDEX0 0
>+#define W6_REMAP_INDEX1 1
>+#define W6_REMAP_MAX_SIZE (1024 * 1024)
>+
>+#define WAVE6_ARBUF_SIZE (1024)
>+#define WAVE6_MAX_CODE_BUF_SIZE (4 * 1024 * 1024)
>+#define WAVE6_CODE_BUF_SIZE (1 * 1024 * 1024)
>+#define WAVE6_EXTRA_CODE_BUF_SIZE (256 * 1024)
>+#define WAVE6_TEMPBUF_SIZE (3 * 1024 * 1024)
>+
>+#define WAVE6_UPPER_PROC_AXI_ID 0x0
>+
>+#endif /* __WAVE6_VPUCONFIG_H__ */
>diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
>b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
>new file mode 100644
>index 000000000000..8bf2e1e9522d
>--- /dev/null
>+++ b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
>@@ -0,0 +1,262 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
>+/*
>+ * Wave6 series multi-standard codec IP - wave6 vpu error values
>+ *
>+ * Copyright (C) 2025 CHIPS&MEDIA INC
>+ */
>+
>+#ifndef __WAVE6_VPUERROR_H__
>+#define __WAVE6_VPUERROR_H__
>+
>+/* WAVE6 COMMON SYSTEM ERROR (FAIL_REASON) */
>+#define WAVE6_SYSERR_QUEUEING_FAIL 0x00000001
>+#define WAVE6_SYSERR_DECODER_FUSE 0x00000002
>+#define WAVE6_SYSERR_INSTRUCTION_ACCESS_VIOLATION
>0x00000004
>+#define WAVE6_SYSERR_PRIVILEDGE_VIOLATION 0x00000008
>+#define WAVE6_SYSERR_DATA_ADDR_ALIGNMENT
>0x00000010
>+#define WAVE6_SYSERR_DATA_ACCESS_VIOLATION
>0x00000020
>+#define WAVE6_SYSERR_ACCESS_VIOLATION_HW
>0x00000040
>+#define WAVE6_SYSERR_INSTRUCTION_ADDR_ALIGNMENT
>0x00000080
>+#define WAVE6_SYSERR_UNKNOWN 0x00000100
>+#define WAVE6_SYSERR_BUS_ERROR 0x00000200
>+#define WAVE6_SYSERR_DOUBLE_FAULT 0x00000400
>+#define WAVE6_SYSERR_RESULT_NOT_READY 0x00000800
>+#define WAVE6_SYSERR_VPU_STILL_RUNNING 0x00001000
>+#define WAVE6_SYSERR_UNKNOWN_CMD 0x00002000
>+#define WAVE6_SYSERR_UNKNOWN_CODEC_STD
>0x00004000
>+#define WAVE6_SYSERR_UNKNOWN_QUERY_OPTION
>0x00008000
>+#define WAVE6_SYSERR_WATCHDOG_TIMEOUT
>0x00020000
>+#define WAVE6_SYSERR_NOT_SUPPORT 0x00100000
>+#define WAVE6_SYSERR_TEMP_SEC_BUF_OVERFLOW
>0x00200000
>+#define WAVE6_SYSERR_NOT_SUPPORT_PROFILE
>0x00400000
>+#define WAVE6_SYSERR_TIMEOUT_CODEC_FW
>0x40000000
>+#define WAVE6_SYSERR_FATAL_VPU_HANGUP 0xf0000000
>+
>+/* WAVE6 COMMAND QUEUE ERROR (FAIL_REASON) */
>+#define WAVE6_CMDQ_ERR_NOT_QUEABLE_CMD
>0x00000001
>+#define WAVE6_CMDQ_ERR_SKIP_MODE_ENABLE
>0x00000002
>+#define WAVE6_CMDQ_ERR_INST_FLUSHING 0x00000003
>+#define WAVE6_CMDQ_ERR_INST_INACTIVE 0x00000004
>+#define WAVE6_CMDQ_ERR_QUEUE_FAIL 0x00000005
>+#define WAVE6_CMDQ_ERR_CMD_BUF_FULL 0x00000006
>+
>+/* WAVE6 ERROR ON DECODER (ERR_INFO) */
>+#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID
>0x00001000
>+#define HEVC_SPSERR_CHROMA_FORMAT_IDC
>0x00001001
>+#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES
>0x00001002
>+#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES
>0x00001003
>+#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET
>0x00001004
>+#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET
>0x00001005
>+#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET
>0x00001006
>+#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET
>0x00001007
>+#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8
>0x00001008
>+#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8
>0x00001009
>+#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4
>0x0000100A
>+#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING
>0x0000100B
>+#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS
>0x0000100C
>+#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE
>0x0000100D
>+#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3
>0x0000100E
>+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE
>0x0000100F
>+#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2
>0x00001010
>+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE
>0x00001011
>+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER
>0x00001012
>+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA
>0x00001013
>+#define HEVC_SPSERR_SCALING_LIST 0x00001014
>+#define
>HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3
>0x00001015
>+#define
>HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE
>0x00001016
>+#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS
>0x00001017
>+#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS
>0x00001018
>+#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019
>+#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A
>+#define HEVC_SPSERR_VUI_ERROR 0x0000101B
>+#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C
>+#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D
>+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID
>0x00002000
>+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID
>0x00002001
>+#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1
>0x00002002
>+#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1
>0x00002003
>+#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004
>+#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH
>0x00002005
>+#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
>+#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
>+#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1
>0x00002008
>+#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1
>0x00002009
>+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1
>0x0000200A
>+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B
>+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C
>+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D
>+#define HEVC_PPSERR_SCALING_LIST 0x0000200E
>+#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2
>0x0000200F
>+#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT
>0x00002010
>+#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT
>0x00002011
>+#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR
>0x00002012
>+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT
>0x00002013
>+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT
>0x00002014
>+#define
>HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT
>0x00002015
>+#define
>HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT
>0x00002016
>+#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT
>0x00002017
>+#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT
>0x00002018
>+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT
>0x00002019
>+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT
>0x00002020
>+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT
>0x00002021
>+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT
>0x00002022
>+#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID
>0x00003000
>+#define HEVC_SHERR_ACTIVATE_PPS 0x00003001
>+#define HEVC_SHERR_ACTIVATE_SPS 0x00003002
>+#define HEVC_SHERR_SLICE_TYPE 0x00003003
>+#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE
>0x00003004
>+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG
>0x00003005
>+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET
>0x00003006
>+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX
>0x00003007
>+#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008
>+#define HEVC_SHERR_NUM_LONG_TERM_PICS
>0x00003009
>+#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE
>0x0000300A
>+#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT
>0x0000300B
>+#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1
>0x0000300C
>+#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1
>0x0000300D
>+#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E
>+#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
>+#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND
>0x00003010
>+#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011
>+#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE
>0x00003012
>+#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013
>+#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014
>+#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
>+#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
>+#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS
>0x00003017
>+#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018
>+#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH
>0x00003019
>+#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE
>0x0000301A
>+#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE
>0x0000301B
>+#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE
>0x0000301C
>+#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE
>0x00004000
>+#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE
>0x00004001
>+#define HEVC_SPECERR_OVER_CHROMA_FORMAT
>0x00004002
>+#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003
>+#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW
>0x00004004
>+#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS
>0x00004005
>+#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND
>0x00005000
>+#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND
>0x00005001
>+#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
>+#define HEVC_ETCERR_INPLACE_V 0x0000500F
>+
>+#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000
>+#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001
>+#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES
>0x00001002
>+#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES
>0x00001003
>+#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004
>+#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET
>0x00001005
>+#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006
>+#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET
>0x00001007
>+#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8
>0x00001008
>+#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8
>0x00001009
>+#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING
>0x0000100B
>+#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS
>0x0000100C
>+#define AVC_SPSERR_SCALING_LIST 0x00001014
>+#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019
>+#define AVC_SPSERR_VUI_ERROR 0x0000101B
>+#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C
>+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID
>0x00002000
>+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID
>0x00002001
>+#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1
>0x00002002
>+#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1
>0x00002003
>+#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004
>+#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
>+#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
>+#define AVC_PPSERR_SCALING_LIST 0x0000200E
>+#define AVC_PPSERR_MORE_RBSP_DATA_ERROR
>0x00002012
>+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT
>0x00002013
>+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT
>0x00002014
>+#define
>AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT
>0x00002015
>+#define
>AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT
>0x00002016
>+#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT
>0x00002017
>+#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT
>0x00002018
>+#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID
>0x00003000
>+#define AVC_SHERR_ACTIVATE_PPS 0x00003001
>+#define AVC_SHERR_ACTIVATE_SPS 0x00003002
>+#define AVC_SHERR_SLICE_TYPE 0x00003003
>+#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004
>+#define AVC_SHERR_RPLM 0x00003006
>+#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE
>0x0000300A
>+#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1
>0x0000300C
>+#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1
>0x0000300D
>+#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
>+#define AVC_SHERR_SLICE_QP_DELTA 0x00003011
>+#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
>+#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
>+#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC
>0x00003017
>+#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE
>0x00004000
>+#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE
>0x00004001
>+#define AVC_SPECERR_OVER_CHROMA_FORMAT
>0x00004002
>+#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003
>+#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW
>0x00004004
>+#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS
>0x00004005
>+#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND
>0x00005000
>+#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND
>0x00005001
>+#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
>+#define AVC_ETCERR_ASO 0x00005004
>+#define AVC_ETCERR_FMO 0x00005005
>+#define AVC_ETCERR_INPLACE_V 0x0000500F
>+
>+/* WAVE6 WARNING ON DECODER (WARN_INFO) */
>+#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1
>0x00000001
>+#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS
>0x00000002
>+#define HEVC_SPSWARN_RESERVED_ZERO_2BITS
>0x00000004
>+#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS
>0x00000008
>+#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
>+#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER
>0x00000020
>+#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
>+#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080
>+#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000
>+#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS
>0x02000000
>+#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
>+#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS
>0x00000200
>+#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG
>0x00001000
>+#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG
>0x00002000
>+#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000
>+#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT
>0x00008000
>+#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND
>0x00010000
>+#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE
>0x00020000
>+#define HEVC_ETCWARN_WRONG_TEMPORAL_ID
>0x00040000
>+#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED
>0x00080000
>+#define HEVC_SPECWARN_OVER_PROFILE 0x00100000
>+#define HEVC_SPECWARN_OVER_LEVEL 0x00200000
>+#define HEVC_PRESWARN_PARSING_ERR 0x04000000
>+#define HEVC_PRESWARN_MVD_OUT_OF_RANGE
>0x08000000
>+#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE
>0x09000000
>+#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE
>0x0A000000
>+#define HEVC_PRESWARN_PCM_ERR 0x0B000000
>+#define HEVC_PRESWARN_OVERCONSUME 0x0C000000
>+#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR
>0x10000000
>+#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG
>0x20000000
>+
>+#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004
>+#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
>+#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
>+#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
>+#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG
>0x00002000
>+#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND
>0x00010000
>+#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE
>0x00020000
>+#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED
>0x00080000
>+#define AVC_SPECWARN_OVER_PROFILE 0x00100000
>+#define AVC_SPECWARN_OVER_LEVEL 0x00200000
>+#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000
>+#define AVC_PRESWARN_MB_QPD_RANGE_OUT
>0x00500000
>+#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000
>+#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000
>+#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT
>0x00800000
>+#define AVC_PRESWARN_MB_TYPE_RANGE_OUT
>0x00900000
>+#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT
>0x00A00000
>+#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000
>+#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT
>0x00C00000
>+#define AVC_PRESWARN_REF_IDX_RANGE_OUT
>0x00D00000
>+#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT
>0x00E00000
>+#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT
>0x00F00000
>+#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT
>0x01000000
>+#define AVC_PRESWARN_OVERCONSUME 0x01100000
>+#define AVC_PRESWARN_MISSING_SLICE 0x01200000
>+
>+/* WAVE6 WARNING ON ENCODER (WARN_INFO) */
>+#define WAVE6_ETCWARN_FORCED_SPLIT_BY_CU8X8
>0x000000001
>+
>+#endif /* __WAVE6_VPUERROR_H__ */
>--
>2.31.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (5 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-10 17:37 ` Krzysztof Kozlowski
` (2 more replies)
2025-02-10 9:07 ` [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities Nas Chung
` (2 subsequent siblings)
9 siblings, 3 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Chips&Media Wave6 control driver.
The control driver manages shared resources such as firmware
access and power domains and clock.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../chips-media/wave6/wave6-vpu-ctrl.c | 1020 +++++++++++++++++
.../chips-media/wave6/wave6-vpu-ctrl.h | 38 +
2 files changed, 1058 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
new file mode 100644
index 000000000000..fa7bf5ccc0d0
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
@@ -0,0 +1,1020 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - wave6 control driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/genalloc.h>
+#include <linux/thermal.h>
+#include <linux/units.h>
+#include <linux/pm_opp.h>
+#include <linux/freezer.h>
+
+#include "wave6-vpuconfig.h"
+#include "wave6-regdefine.h"
+#include "wave6-vdi.h"
+#include "wave6-vpu-ctrl.h"
+
+#define VPU_CTRL_PLATFORM_DEVICE_NAME "wave6-vpu-ctrl"
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+
+static bool wave6_cooling_disable;
+module_param(wave6_cooling_disable, bool, 0644);
+MODULE_PARM_DESC(wave6_cooling_disable, "enable or disable cooling");
+
+#define dprintk(dev, fmt, arg...) \
+ do { \
+ if (debug) \
+ dev_info(dev, fmt, ## arg); \
+ } while (0)
+
+#define wave6_wait_event_freezable_timeout(wq_head, condition, timeout) \
+({ \
+ int wave6_wait_ret = 0; \
+ unsigned long _timeout = timeout; \
+ unsigned long stop; \
+ stop = jiffies + _timeout; \
+ do { \
+ if (wave6_wait_ret == -ERESTARTSYS && freezing(current)) \
+ clear_thread_flag(TIF_SIGPENDING); \
+ _timeout = stop - jiffies; \
+ if ((long)_timeout <= 0) { \
+ wave6_wait_ret = -ERESTARTSYS; \
+ break; \
+ } \
+ wave6_wait_ret = wait_event_freezable_timeout(wq_head, condition, _timeout); \
+ } while (wave6_wait_ret == -ERESTARTSYS && freezing(current)); \
+ wave6_wait_ret; \
+})
+
+struct vpu_ctrl_resource {
+ const char *fw_name;
+ u32 sram_size;
+};
+
+struct vpu_ctrl_buf {
+ struct list_head list;
+ struct vpu_buf buf;
+};
+
+struct vpu_ctrl {
+ struct device *dev;
+ void __iomem *reg_base;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct vpu_dma_buf boot_mem;
+ u32 state;
+ struct mutex ctrl_lock; /* the lock for vpu control device */
+ struct wave6_vpu_entity *current_entity;
+ struct list_head entities;
+ const struct vpu_ctrl_resource *res;
+ struct gen_pool *sram_pool;
+ struct vpu_dma_buf sram_buf;
+ struct list_head buffers;
+ bool support_follower;
+ wait_queue_head_t load_fw_wq;
+ int thermal_event;
+ int thermal_max;
+ struct thermal_cooling_device *cooling;
+ struct dev_pm_domain_list *pd_list;
+ struct device *dev_perf;
+ int clk_id;
+ unsigned long *freq_table;
+};
+
+#define DOMAIN_VPU_PWR 0
+#define DOMAIN_VPU_PERF 1
+
+static const struct vpu_ctrl_resource wave633c_ctrl_data = {
+ .fw_name = "wave633c_codec_fw.bin",
+ /* For HEVC, AVC, 4096x4096, 8bit */
+ .sram_size = 0x14800,
+};
+
+static void wave6_vpu_ctrl_writel(struct device *dev, u32 addr, u32 data)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ writel(data, ctrl->reg_base + addr);
+}
+
+int wave6_alloc_dma(struct device *dev, struct vpu_buf *vb)
+{
+ void *vaddr;
+ dma_addr_t daddr;
+
+ if (!vb || !vb->size)
+ return -EINVAL;
+
+ vaddr = dma_alloc_coherent(dev, vb->size, &daddr, GFP_KERNEL);
+ if (!vaddr)
+ return -ENOMEM;
+
+ vb->vaddr = vaddr;
+ vb->daddr = daddr;
+ vb->dev = dev;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wave6_alloc_dma);
+
+void wave6_free_dma(struct vpu_buf *vb)
+{
+ if (!vb || !vb->size || !vb->vaddr)
+ return;
+
+ dma_free_coherent(vb->dev, vb->size, vb->vaddr, vb->daddr);
+ memset(vb, 0, sizeof(*vb));
+}
+EXPORT_SYMBOL_GPL(wave6_free_dma);
+
+static const char *wave6_vpu_ctrl_state_name(u32 state)
+{
+ switch (state) {
+ case WAVE6_VPU_STATE_OFF:
+ return "off";
+ case WAVE6_VPU_STATE_PREPARE:
+ return "prepare";
+ case WAVE6_VPU_STATE_ON:
+ return "on";
+ case WAVE6_VPU_STATE_SLEEP:
+ return "sleep";
+ default:
+ return "unknown";
+ }
+}
+
+static void wave6_vpu_ctrl_set_state(struct vpu_ctrl *ctrl, u32 state)
+{
+ dprintk(ctrl->dev, "set state: %s -> %s\n",
+ wave6_vpu_ctrl_state_name(ctrl->state), wave6_vpu_ctrl_state_name(state));
+ ctrl->state = state;
+}
+
+static int wave6_vpu_ctrl_wait_busy(struct wave6_vpu_entity *entity)
+{
+ u32 val;
+
+ return read_poll_timeout(entity->read_reg, val, !val,
+ 10, W6_VPU_POLL_TIMEOUT, false,
+ entity->dev, W6_VPU_BUSY_STATUS);
+}
+
+static int wave6_vpu_ctrl_check_result(struct wave6_vpu_entity *entity)
+{
+ if (entity->read_reg(entity->dev, W6_RET_SUCCESS))
+ return 0;
+
+ return entity->read_reg(entity->dev, W6_RET_FAIL_REASON);
+}
+
+static u32 wave6_vpu_ctrl_get_code_buf_size(struct vpu_ctrl *ctrl)
+{
+ return min_t(u32, ctrl->boot_mem.size, WAVE6_MAX_CODE_BUF_SIZE);
+}
+
+static void wave6_vpu_ctrl_remap_code_buffer(struct vpu_ctrl *ctrl)
+{
+ dma_addr_t code_base = ctrl->boot_mem.dma_addr;
+ u32 i, reg_val, remap_size;
+
+ for (i = 0; i < wave6_vpu_ctrl_get_code_buf_size(ctrl) / W6_REMAP_MAX_SIZE; i++) {
+ remap_size = (W6_REMAP_MAX_SIZE >> 12) & 0x1ff;
+ reg_val = 0x80000000 |
+ (WAVE6_UPPER_PROC_AXI_ID << 20) |
+ (0 << 16) |
+ (i << 12) |
+ BIT(11) |
+ remap_size;
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CTRL_GB, reg_val);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_VADDR_GB, i * W6_REMAP_MAX_SIZE);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_PADDR_GB,
+ code_base + i * W6_REMAP_MAX_SIZE);
+ }
+}
+
+static int wave6_vpu_ctrl_init_vpu(struct vpu_ctrl *ctrl)
+{
+ struct wave6_vpu_entity *entity = ctrl->current_entity;
+ int ret;
+
+ dprintk(ctrl->dev, "cold boot vpu\n");
+
+ entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1);
+ entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0,
+ ctrl->sram_buf.dma_addr);
+ entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0,
+ ctrl->sram_buf.size);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_COMMAND_GB, W6_CMD_INIT_VPU);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CORE_START_GB, 1);
+
+ ret = wave6_vpu_ctrl_wait_busy(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "init vpu timeout\n");
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_ctrl_check_result(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "init vpu fail, reason 0x%x\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void wave6_vpu_ctrl_on_boot(struct wave6_vpu_entity *entity)
+{
+ if (!entity->on_boot)
+ return;
+
+ if (!entity->booted) {
+ entity->on_boot(entity->dev);
+ entity->booted = true;
+ }
+}
+
+static void wave6_vpu_ctrl_clear_firmware_buffers(struct vpu_ctrl *ctrl,
+ struct wave6_vpu_entity *entity)
+{
+ int ret;
+
+ dprintk(ctrl->dev, "clear firmware work buffers\n");
+
+ entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1);
+ entity->write_reg(entity->dev, W6_COMMAND, W6_CMD_INIT_WORK_BUF);
+ entity->write_reg(entity->dev, W6_VPU_HOST_INT_REQ, 1);
+
+ ret = wave6_vpu_ctrl_wait_busy(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "set buffer failed\n");
+ return;
+ }
+
+ ret = wave6_vpu_ctrl_check_result(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "set buffer failed, reason 0x%x\n", ret);
+ return;
+ }
+}
+
+int wave6_vpu_ctrl_require_buffer(struct device *dev, struct wave6_vpu_entity *entity)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+ struct vpu_ctrl_buf *pbuf;
+ u32 size;
+ int ret = -ENOMEM;
+
+ if (!ctrl || !entity)
+ return -EINVAL;
+
+ size = entity->read_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_SIZE);
+ if (!size)
+ return 0;
+
+ pbuf = kzalloc(sizeof(*pbuf), GFP_KERNEL);
+ if (!pbuf)
+ goto exit;
+
+ pbuf->buf.size = size;
+ ret = wave6_alloc_dma(ctrl->dev, &pbuf->buf);
+ if (ret) {
+ kfree(pbuf);
+ goto exit;
+ }
+
+ list_add_tail(&pbuf->list, &ctrl->buffers);
+ entity->write_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_ADDR, pbuf->buf.daddr);
+exit:
+ entity->write_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_SIZE, 0);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_require_buffer);
+
+static void wave6_vpu_ctrl_clear_buffers(struct vpu_ctrl *ctrl)
+{
+ struct wave6_vpu_entity *entity;
+ struct vpu_ctrl_buf *pbuf, *tmp;
+
+ dprintk(ctrl->dev, "clear all buffers\n");
+
+ entity = list_first_entry_or_null(&ctrl->entities,
+ struct wave6_vpu_entity, list);
+ if (entity)
+ wave6_vpu_ctrl_clear_firmware_buffers(ctrl, entity);
+
+ list_for_each_entry_safe(pbuf, tmp, &ctrl->buffers, list) {
+ list_del(&pbuf->list);
+ wave6_free_dma(&pbuf->buf);
+ kfree(pbuf);
+ }
+}
+
+static void wave6_vpu_ctrl_boot_done(struct vpu_ctrl *ctrl, int wakeup)
+{
+ struct wave6_vpu_entity *entity;
+
+ if (ctrl->state == WAVE6_VPU_STATE_ON)
+ return;
+
+ if (!wakeup)
+ wave6_vpu_ctrl_clear_buffers(ctrl);
+
+ list_for_each_entry(entity, &ctrl->entities, list)
+ wave6_vpu_ctrl_on_boot(entity);
+
+ dprintk(ctrl->dev, "boot done from %s\n", wakeup ? "wakeup" : "cold boot");
+
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_ON);
+}
+
+static bool wave6_vpu_ctrl_find_entity(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity)
+{
+ struct wave6_vpu_entity *tmp;
+
+ list_for_each_entry(tmp, &ctrl->entities, list) {
+ if (tmp == entity)
+ return true;
+ }
+
+ return false;
+}
+
+static void wave6_vpu_ctrl_load_firmware(const struct firmware *fw, void *context)
+{
+ struct vpu_ctrl *ctrl = context;
+ struct wave6_vpu_entity *entity = ctrl->current_entity;
+ u32 product_code;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ctrl->dev);
+ if (ret) {
+ dev_err(ctrl->dev, "pm runtime resume fail, ret = %d\n", ret);
+ mutex_lock(&ctrl->ctrl_lock);
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ ctrl->current_entity = NULL;
+ mutex_unlock(&ctrl->ctrl_lock);
+ release_firmware(fw);
+ return;
+ }
+
+ if (!fw || !fw->data) {
+ dev_err(ctrl->dev, "No firmware.\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (fw->size + WAVE6_EXTRA_CODE_BUF_SIZE > wave6_vpu_ctrl_get_code_buf_size(ctrl)) {
+ dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
+ fw->size, ctrl->boot_mem.size);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ product_code = entity->read_reg(entity->dev, W6_VPU_RET_PRODUCT_VERSION);
+ if (!PRODUCT_CODE_W_SERIES(product_code)) {
+ dev_err(ctrl->dev, "unknown product : %08x\n", product_code);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(ctrl->boot_mem.vaddr, fw->data, fw->size);
+
+exit:
+ mutex_lock(&ctrl->ctrl_lock);
+ if (!ret && wave6_vpu_ctrl_find_entity(ctrl, ctrl->current_entity)) {
+ wave6_vpu_ctrl_remap_code_buffer(ctrl);
+ ret = wave6_vpu_ctrl_init_vpu(ctrl);
+ } else {
+ ret = -EINVAL;
+ }
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ pm_runtime_put_sync(ctrl->dev);
+ release_firmware(fw);
+
+ mutex_lock(&ctrl->ctrl_lock);
+ ctrl->current_entity = NULL;
+ if (ret)
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ else
+ wave6_vpu_ctrl_boot_done(ctrl, 0);
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ wake_up_interruptible_all(&ctrl->load_fw_wq);
+}
+
+static int wave6_vpu_ctrl_sleep(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity)
+{
+ int ret;
+
+ dprintk(ctrl->dev, "sleep firmware\n");
+
+ entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1);
+ entity->write_reg(entity->dev, W6_CMD_INSTANCE_INFO, 0);
+ entity->write_reg(entity->dev, W6_COMMAND, W6_CMD_SLEEP_VPU);
+ entity->write_reg(entity->dev, W6_VPU_HOST_INT_REQ, 1);
+
+ ret = wave6_vpu_ctrl_wait_busy(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "sleep vpu timeout\n");
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_ctrl_check_result(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "sleep vpu fail, reason 0x%x\n", ret);
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ return -EIO;
+ }
+
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_SLEEP);
+
+ return 0;
+}
+
+static int wave6_vpu_ctrl_wakeup(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity)
+{
+ int ret;
+
+ dprintk(ctrl->dev, "wakeup firmware\n");
+
+ wave6_vpu_ctrl_remap_code_buffer(ctrl);
+
+ entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1);
+ entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0,
+ ctrl->sram_buf.dma_addr);
+ entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0,
+ ctrl->sram_buf.size);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_COMMAND_GB, W6_CMD_WAKEUP_VPU);
+ wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CORE_START_GB, 1);
+
+ ret = wave6_vpu_ctrl_wait_busy(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "wakeup vpu timeout\n");
+ return -EINVAL;
+ }
+
+ ret = wave6_vpu_ctrl_check_result(entity);
+ if (ret) {
+ dev_err(ctrl->dev, "wakeup vpu fail, reason 0x%x\n", ret);
+ return -EIO;
+ }
+
+ wave6_vpu_ctrl_boot_done(ctrl, 1);
+
+ return 0;
+}
+
+static int wave6_vpu_ctrl_try_boot(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity)
+{
+ int ret;
+
+ if (ctrl->state != WAVE6_VPU_STATE_OFF && ctrl->state != WAVE6_VPU_STATE_SLEEP)
+ return 0;
+
+ if (entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC)) {
+ dprintk(ctrl->dev, "try boot directly as firmware is running\n");
+ wave6_vpu_ctrl_boot_done(ctrl, ctrl->state == WAVE6_VPU_STATE_SLEEP);
+ return 0;
+ }
+
+ if (ctrl->state == WAVE6_VPU_STATE_SLEEP) {
+ ret = wave6_vpu_ctrl_wakeup(ctrl, entity);
+ return ret;
+ }
+
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_PREPARE);
+ ctrl->current_entity = entity;
+ ret = request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_UEVENT,
+ ctrl->res->fw_name,
+ ctrl->dev, GFP_KERNEL,
+ ctrl,
+ wave6_vpu_ctrl_load_firmware);
+ if (ret) {
+ dev_err(ctrl->dev, "request firmware %s fail, ret = %d\n", ctrl->res->fw_name, ret);
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ return ret;
+ }
+
+ return 0;
+}
+
+bool wave6_vpu_ctrl_support_follower(struct device *dev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ if (!ctrl)
+ return false;
+
+ return ctrl->support_follower;
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_support_follower);
+
+int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct wave6_vpu_entity *entity)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+ bool boot;
+ int ret;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ if (!entity || !entity->dev || !entity->read_reg || !entity->write_reg)
+ return -EINVAL;
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ ret = pm_runtime_resume_and_get(ctrl->dev);
+ if (ret) {
+ dev_err(dev, "pm runtime resume fail, ret = %d\n", ret);
+ mutex_unlock(&ctrl->ctrl_lock);
+ return ret;
+ }
+
+ entity->booted = false;
+
+ if (ctrl->current_entity)
+ boot = false;
+ else
+ boot = list_empty(&ctrl->entities) ? true : false;
+
+ list_add_tail(&entity->list, &ctrl->entities);
+ if (boot)
+ ret = wave6_vpu_ctrl_try_boot(ctrl, entity);
+
+ if (ctrl->state == WAVE6_VPU_STATE_ON)
+ wave6_vpu_ctrl_on_boot(entity);
+
+ if (ret)
+ pm_runtime_put_sync(ctrl->dev);
+
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_resume_and_get);
+
+void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity *entity)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ if (!ctrl)
+ return;
+
+ if (entity == ctrl->current_entity)
+ wave6_vpu_ctrl_wait_done(dev);
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ if (!wave6_vpu_ctrl_find_entity(ctrl, entity))
+ goto exit;
+
+ list_del_init(&entity->list);
+ if (list_empty(&ctrl->entities)) {
+ if (!entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC))
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ else
+ wave6_vpu_ctrl_sleep(ctrl, entity);
+ }
+
+ if (!pm_runtime_suspended(ctrl->dev))
+ pm_runtime_put_sync(ctrl->dev);
+exit:
+ mutex_unlock(&ctrl->ctrl_lock);
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_put_sync);
+
+int wave6_vpu_ctrl_wait_done(struct device *dev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+ int ret;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ if (ctrl->state == WAVE6_VPU_STATE_OFF)
+ return -EINVAL;
+
+ if (ctrl->state == WAVE6_VPU_STATE_ON)
+ return 0;
+
+ ret = wave6_wait_event_freezable_timeout(ctrl->load_fw_wq,
+ wave6_vpu_ctrl_get_state(dev) ==
+ WAVE6_VPU_STATE_ON,
+ msecs_to_jiffies(W6_BOOT_WAIT_TIMEOUT));
+ if (ret == -ERESTARTSYS || !ret) {
+ dev_err(ctrl->dev, "fail to wait vcpu boot done,ret %d\n", ret);
+ mutex_lock(&ctrl->ctrl_lock);
+ wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
+ mutex_unlock(&ctrl->ctrl_lock);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctrl->ctrl_lock);
+ wave6_vpu_ctrl_boot_done(ctrl, 0);
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_wait_done);
+
+int wave6_vpu_ctrl_get_state(struct device *dev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ if (!ctrl)
+ return -EINVAL;
+
+ return ctrl->state;
+}
+EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_get_state);
+
+static void wave6_vpu_ctrl_init_reserved_boot_region(struct vpu_ctrl *ctrl)
+{
+ if (ctrl->boot_mem.size < WAVE6_CODE_BUF_SIZE) {
+ dev_warn(ctrl->dev, "boot memory size (%zu) is too small\n", ctrl->boot_mem.size);
+ ctrl->boot_mem.phys_addr = 0;
+ ctrl->boot_mem.size = 0;
+ memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
+ return;
+ }
+
+ ctrl->boot_mem.vaddr = devm_memremap(ctrl->dev,
+ ctrl->boot_mem.phys_addr,
+ ctrl->boot_mem.size,
+ MEMREMAP_WC);
+ if (!ctrl->boot_mem.vaddr) {
+ memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
+ return;
+ }
+
+ ctrl->boot_mem.dma_addr = dma_map_resource(ctrl->dev,
+ ctrl->boot_mem.phys_addr,
+ ctrl->boot_mem.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ if (!ctrl->boot_mem.dma_addr) {
+ memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
+ return;
+ }
+
+ dev_info(ctrl->dev, "boot phys_addr: %pad, dma_addr: %pad, size: 0x%zx\n",
+ &ctrl->boot_mem.phys_addr,
+ &ctrl->boot_mem.dma_addr,
+ ctrl->boot_mem.size);
+}
+
+static int wave6_vpu_ctrl_thermal_update(struct device *dev, int state)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+ unsigned long new_clock_rate;
+ int ret;
+
+ if (wave6_cooling_disable || !ctrl->dev_perf || state > ctrl->thermal_max || !ctrl->cooling)
+ return 0;
+
+ new_clock_rate = DIV_ROUND_UP(ctrl->freq_table[state], HZ_PER_KHZ);
+ dev_dbg(dev, "receive cooling set state: %d, new clock rate %ld\n",
+ state, new_clock_rate);
+
+ ret = dev_pm_genpd_set_performance_state(ctrl->dev_perf, new_clock_rate);
+ dev_dbg(dev, "clk set to %lu\n", clk_get_rate(ctrl->clks[ctrl->clk_id].clk));
+ if (ret && !((ret == -ENODEV) || (ret == -EOPNOTSUPP))) {
+ dev_err(dev, "failed to set perf to %lu (ret = %d)\n", new_clock_rate, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wave6_cooling_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct vpu_ctrl *ctrl = cdev->devdata;
+
+ *state = ctrl->thermal_max;
+
+ return 0;
+}
+
+static int wave6_cooling_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct vpu_ctrl *ctrl = cdev->devdata;
+
+ *state = ctrl->thermal_event;
+
+ return 0;
+}
+
+static int wave6_cooling_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct vpu_ctrl *ctrl = cdev->devdata;
+ struct wave6_vpu_entity *entity;
+
+ ctrl->thermal_event = state;
+
+ list_for_each_entry(entity, &ctrl->entities, list) {
+ if (entity->pause)
+ entity->pause(entity->dev, 0);
+ }
+
+ wave6_vpu_ctrl_thermal_update(ctrl->dev, state);
+
+ list_for_each_entry(entity, &ctrl->entities, list) {
+ if (entity->pause)
+ entity->pause(entity->dev, 1);
+ }
+
+ return 0;
+}
+
+static struct thermal_cooling_device_ops wave6_cooling_ops = {
+ .get_max_state = wave6_cooling_get_max_state,
+ .get_cur_state = wave6_cooling_get_cur_state,
+ .set_cur_state = wave6_cooling_set_cur_state,
+};
+
+static void wave6_cooling_remove(struct vpu_ctrl *ctrl)
+{
+ int i;
+
+ if (!ctrl->pd_list)
+ return;
+
+ thermal_cooling_device_unregister(ctrl->cooling);
+
+ kfree(ctrl->freq_table);
+ ctrl->freq_table = NULL;
+
+ for (i = 0; i < ctrl->pd_list->num_pds; i++) {
+ struct device *pd_dev = ctrl->pd_list->pd_devs[i];
+
+ if (!pm_runtime_suspended(pd_dev))
+ pm_runtime_force_suspend(pd_dev);
+ }
+
+ dev_pm_domain_detach_list(ctrl->pd_list);
+ ctrl->pd_list = NULL;
+ ctrl->dev_perf = NULL;
+}
+
+static void wave6_cooling_init(struct vpu_ctrl *ctrl)
+{
+ struct dev_pm_domain_attach_data pd_data = {
+ .pd_names = (const char *[]) {"vpumix", "vpuperf"},
+ .num_pd_names = 2,
+ };
+ int ret;
+ int i;
+ int num_opps;
+ unsigned long freq;
+
+ ctrl->clk_id = -1;
+ for (i = 0; i < ctrl->num_clks; i++) {
+ if (!strcmp("vpu", ctrl->clks[i].id)) {
+ ctrl->clk_id = i;
+ break;
+ }
+ }
+ if (ctrl->clk_id == -1) {
+ dev_err(ctrl->dev, "cooling device unable to get clock\n");
+ return;
+ }
+
+ ret = dev_pm_domain_attach_list(ctrl->dev, &pd_data, &ctrl->pd_list);
+ ctrl->dev_perf = NULL;
+ if (ret < 0)
+ dev_err(ctrl->dev, "didn't attach perf power domains, ret=%d", ret);
+ else if (ret == 2)
+ ctrl->dev_perf = ctrl->pd_list->pd_devs[DOMAIN_VPU_PERF];
+ dev_dbg(ctrl->dev, "get perf domain ret=%d, perf=%p\n", ret, ctrl->dev_perf);
+ if (!ctrl->dev_perf)
+ return;
+
+ num_opps = dev_pm_opp_get_opp_count(ctrl->dev_perf);
+ if (num_opps <= 0) {
+ dev_err(ctrl->dev, "fail to get pm opp count, ret = %d\n", num_opps);
+ goto error;
+ }
+
+ ctrl->freq_table = kcalloc(num_opps, sizeof(*ctrl->freq_table), GFP_KERNEL);
+ if (!ctrl->freq_table)
+ goto error;
+
+ for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) {
+ struct dev_pm_opp *opp;
+
+ opp = dev_pm_opp_find_freq_floor(ctrl->dev_perf, &freq);
+ if (IS_ERR(opp))
+ break;
+
+ dev_pm_opp_put(opp);
+
+ dev_dbg(ctrl->dev, "[%d] = %ld\n", i, freq);
+ if (freq < 100 * HZ_PER_MHZ)
+ break;
+
+ ctrl->freq_table[i] = freq;
+ ctrl->thermal_max = i;
+ }
+
+ if (!ctrl->thermal_max)
+ goto error;
+
+ ctrl->thermal_event = 0;
+ ctrl->cooling = thermal_of_cooling_device_register(ctrl->dev->of_node,
+ (char *)dev_name(ctrl->dev),
+ ctrl,
+ &wave6_cooling_ops);
+ if (IS_ERR(ctrl->cooling)) {
+ dev_err(ctrl->dev, "register cooling device failed\n");
+ goto error;
+ }
+
+ return;
+error:
+ wave6_cooling_remove(ctrl);
+}
+
+static int wave6_vpu_ctrl_probe(struct platform_device *pdev)
+{
+ struct vpu_ctrl *ctrl;
+ struct device_node *np;
+ const struct vpu_ctrl_resource *res;
+ int ret;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "dma_set_mask_and_coherent failed: %d\n", ret);
+ return ret;
+ }
+
+ res = of_device_get_match_data(&pdev->dev);
+ if (!res)
+ return -ENODEV;
+
+ ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ mutex_init(&ctrl->ctrl_lock);
+ init_waitqueue_head(&ctrl->load_fw_wq);
+ INIT_LIST_HEAD(&ctrl->entities);
+ INIT_LIST_HEAD(&ctrl->buffers);
+ dev_set_drvdata(&pdev->dev, ctrl);
+ ctrl->dev = &pdev->dev;
+ ctrl->res = res;
+ ctrl->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ctrl->reg_base))
+ return PTR_ERR(ctrl->reg_base);
+ ret = devm_clk_bulk_get_all(&pdev->dev, &ctrl->clks);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "unable to get clocks: %d\n", ret);
+ ret = 0;
+ }
+
+ ctrl->num_clks = ret;
+
+ np = of_parse_phandle(pdev->dev.of_node, "boot", 0);
+ if (np) {
+ struct resource mem;
+
+ ret = of_address_to_resource(np, 0, &mem);
+ of_node_put(np);
+ if (!ret) {
+ ctrl->boot_mem.phys_addr = mem.start;
+ ctrl->boot_mem.size = resource_size(&mem);
+ wave6_vpu_ctrl_init_reserved_boot_region(ctrl);
+ } else {
+ dev_warn(&pdev->dev, "boot resource is not available.\n");
+ }
+ }
+
+ ctrl->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+ if (ctrl->sram_pool) {
+ ctrl->sram_buf.size = ctrl->res->sram_size;
+ ctrl->sram_buf.vaddr = gen_pool_dma_alloc(ctrl->sram_pool,
+ ctrl->sram_buf.size,
+ &ctrl->sram_buf.phys_addr);
+ if (!ctrl->sram_buf.vaddr)
+ ctrl->sram_buf.size = 0;
+ else
+ ctrl->sram_buf.dma_addr = dma_map_resource(&pdev->dev,
+ ctrl->sram_buf.phys_addr,
+ ctrl->sram_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+
+ dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
+ &ctrl->sram_buf.phys_addr, &ctrl->sram_buf.dma_addr, ctrl->sram_buf.size);
+ }
+
+ if (of_find_property(pdev->dev.of_node, "support-follower", NULL))
+ ctrl->support_follower = true;
+
+ wave6_cooling_init(ctrl);
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static void wave6_vpu_ctrl_remove(struct platform_device *pdev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ wave6_vpu_ctrl_clear_buffers(ctrl);
+ wave6_cooling_remove(ctrl);
+ if (ctrl->sram_pool && ctrl->sram_buf.vaddr) {
+ dma_unmap_resource(&pdev->dev,
+ ctrl->sram_buf.dma_addr,
+ ctrl->sram_buf.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ gen_pool_free(ctrl->sram_pool,
+ (unsigned long)ctrl->sram_buf.vaddr,
+ ctrl->sram_buf.size);
+ }
+ if (ctrl->boot_mem.dma_addr)
+ dma_unmap_resource(&pdev->dev,
+ ctrl->boot_mem.dma_addr,
+ ctrl->boot_mem.size,
+ DMA_BIDIRECTIONAL,
+ 0);
+ mutex_destroy(&ctrl->ctrl_lock);
+}
+
+#ifdef CONFIG_PM
+static int wave6_vpu_ctrl_runtime_suspend(struct device *dev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(ctrl->num_clks, ctrl->clks);
+ return 0;
+}
+
+static int wave6_vpu_ctrl_runtime_resume(struct device *dev)
+{
+ struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return clk_bulk_prepare_enable(ctrl->num_clks, ctrl->clks);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int wave6_vpu_ctrl_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int wave6_vpu_ctrl_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+static const struct dev_pm_ops wave6_vpu_ctrl_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave6_vpu_ctrl_runtime_suspend, wave6_vpu_ctrl_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_ctrl_suspend, wave6_vpu_ctrl_resume)
+};
+
+static const struct of_device_id wave6_ctrl_ids[] = {
+ { .compatible = "nxp,imx95-wave633c-ctrl", .data = &wave633c_ctrl_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wave6_ctrl_ids);
+
+static struct platform_driver wave6_vpu_ctrl_driver = {
+ .driver = {
+ .name = VPU_CTRL_PLATFORM_DEVICE_NAME,
+ .of_match_table = of_match_ptr(wave6_ctrl_ids),
+ .pm = &wave6_vpu_ctrl_pm_ops,
+ },
+ .probe = wave6_vpu_ctrl_probe,
+ .remove = wave6_vpu_ctrl_remove,
+};
+
+module_platform_driver(wave6_vpu_ctrl_driver);
+MODULE_DESCRIPTION("chips&media VPU WAVE6 CTRL");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h
new file mode 100644
index 000000000000..21cfd1d2e7d4
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 control driver
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPU_CTRL_H__
+#define __WAVE6_VPU_CTRL_H__
+
+#include <linux/device.h>
+
+enum wave6_vpu_state {
+ WAVE6_VPU_STATE_OFF,
+ WAVE6_VPU_STATE_PREPARE,
+ WAVE6_VPU_STATE_ON,
+ WAVE6_VPU_STATE_SLEEP
+};
+
+struct wave6_vpu_entity {
+ struct list_head list;
+ struct device *dev;
+ u32 (*read_reg)(struct device *dev, u32 addr);
+ void (*write_reg)(struct device *dev, u32 addr, u32 data);
+ void (*on_boot)(struct device *dev);
+ void (*pause)(struct device *dev, int resume);
+ bool booted;
+};
+
+int wave6_alloc_dma(struct device *dev, struct vpu_buf *vb);
+void wave6_free_dma(struct vpu_buf *vb);
+int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct wave6_vpu_entity *entity);
+void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity *entity);
+int wave6_vpu_ctrl_get_state(struct device *dev);
+int wave6_vpu_ctrl_wait_done(struct device *dev);
+int wave6_vpu_ctrl_require_buffer(struct device *dev, struct wave6_vpu_entity *entity);
+bool wave6_vpu_ctrl_support_follower(struct device *dev);
+#endif /* __WAVE6_VPU_CTRL_H__ */
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
2025-02-10 9:07 ` [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Nas Chung
@ 2025-02-10 17:37 ` Krzysztof Kozlowski
2025-02-11 8:55 ` Nas Chung
2025-02-11 20:25 ` kernel test robot
2025-02-12 1:31 ` kernel test robot
2 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-10 17:37 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim
On 10/02/2025 10:07, Nas Chung wrote:
> +
> +int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct wave6_vpu_entity *entity)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> + bool boot;
> + int ret;
> +
> + if (!ctrl)
> + return -EINVAL;
> +
> + if (!entity || !entity->dev || !entity->read_reg || !entity->write_reg)
> + return -EINVAL;
> +
> + mutex_lock(&ctrl->ctrl_lock);
> +
> + ret = pm_runtime_resume_and_get(ctrl->dev);
> + if (ret) {
> + dev_err(dev, "pm runtime resume fail, ret = %d\n", ret);
> + mutex_unlock(&ctrl->ctrl_lock);
> + return ret;
> + }
> +
> + entity->booted = false;
> +
> + if (ctrl->current_entity)
> + boot = false;
> + else
> + boot = list_empty(&ctrl->entities) ? true : false;
> +
> + list_add_tail(&entity->list, &ctrl->entities);
> + if (boot)
> + ret = wave6_vpu_ctrl_try_boot(ctrl, entity);
> +
> + if (ctrl->state == WAVE6_VPU_STATE_ON)
> + wave6_vpu_ctrl_on_boot(entity);
> +
> + if (ret)
> + pm_runtime_put_sync(ctrl->dev);
> +
> + mutex_unlock(&ctrl->ctrl_lock);
> +
> + return ret;
> +}
Drop entire function.
> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_resume_and_get);
Drop.
> +
> +void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity *entity)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> +
> + if (!ctrl)
> + return;
> +
> + if (entity == ctrl->current_entity)
> + wave6_vpu_ctrl_wait_done(dev);
> +
> + mutex_lock(&ctrl->ctrl_lock);
> +
> + if (!wave6_vpu_ctrl_find_entity(ctrl, entity))
> + goto exit;
> +
> + list_del_init(&entity->list);
> + if (list_empty(&ctrl->entities)) {
> + if (!entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC))
> + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
> + else
> + wave6_vpu_ctrl_sleep(ctrl, entity);
> + }
> +
> + if (!pm_runtime_suspended(ctrl->dev))
> + pm_runtime_put_sync(ctrl->dev);
> +exit:
> + mutex_unlock(&ctrl->ctrl_lock);
> +}
> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_put_sync);
Drop entire function. Dead code.
... or you arranged your patches really incorrectly, but this I can't
really judge.
> +
> +int wave6_vpu_ctrl_wait_done(struct device *dev)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> + int ret;
> +
> + if (!ctrl)
> + return -EINVAL;
> +
> + if (ctrl->state == WAVE6_VPU_STATE_OFF)
> + return -EINVAL;
> +
> + if (ctrl->state == WAVE6_VPU_STATE_ON)
> + return 0;
> +
> + ret = wave6_wait_event_freezable_timeout(ctrl->load_fw_wq,
> + wave6_vpu_ctrl_get_state(dev) ==
> + WAVE6_VPU_STATE_ON,
> + msecs_to_jiffies(W6_BOOT_WAIT_TIMEOUT));
> + if (ret == -ERESTARTSYS || !ret) {
> + dev_err(ctrl->dev, "fail to wait vcpu boot done,ret %d\n", ret);
> + mutex_lock(&ctrl->ctrl_lock);
> + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
> + mutex_unlock(&ctrl->ctrl_lock);
> + return -EINVAL;
> + }
> +
> + mutex_lock(&ctrl->ctrl_lock);
> + wave6_vpu_ctrl_boot_done(ctrl, 0);
> + mutex_unlock(&ctrl->ctrl_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_wait_done);
There is no user of this outside. Drop.
> +
> +int wave6_vpu_ctrl_get_state(struct device *dev)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> +
> + if (!ctrl)
> + return -EINVAL;
> +
> + return ctrl->state;
> +}
> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_get_state);
There is no user of this outside. Drop.
Whatever export stays, must be used by a following patch. You *must* add
the kerneldoc for it.
> +
> +static void wave6_vpu_ctrl_init_reserved_boot_region(struct vpu_ctrl *ctrl)
> +{
> + if (ctrl->boot_mem.size < WAVE6_CODE_BUF_SIZE) {
> + dev_warn(ctrl->dev, "boot memory size (%zu) is too small\n", ctrl->boot_mem.size);
> + ctrl->boot_mem.phys_addr = 0;
> + ctrl->boot_mem.size = 0;
> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
> + return;
> + }
> +
> + ctrl->boot_mem.vaddr = devm_memremap(ctrl->dev,
> + ctrl->boot_mem.phys_addr,
> + ctrl->boot_mem.size,
> + MEMREMAP_WC);
> + if (!ctrl->boot_mem.vaddr) {
> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
> + return;
> + }
> +
> + ctrl->boot_mem.dma_addr = dma_map_resource(ctrl->dev,
> + ctrl->boot_mem.phys_addr,
> + ctrl->boot_mem.size,
> + DMA_BIDIRECTIONAL,
> + 0);
> + if (!ctrl->boot_mem.dma_addr) {
> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
> + return;
> + }
> +
> + dev_info(ctrl->dev, "boot phys_addr: %pad, dma_addr: %pad, size: 0x%zx\n",
> + &ctrl->boot_mem.phys_addr,
> + &ctrl->boot_mem.dma_addr,
> + ctrl->boot_mem.size);
No, drop. Reasoning further.
> +}
...
> +
> + ctrl->num_clks = ret;
> +
> + np = of_parse_phandle(pdev->dev.of_node, "boot", 0);
> + if (np) {
> + struct resource mem;
> +
> + ret = of_address_to_resource(np, 0, &mem);
> + of_node_put(np);
> + if (!ret) {
> + ctrl->boot_mem.phys_addr = mem.start;
> + ctrl->boot_mem.size = resource_size(&mem);
> + wave6_vpu_ctrl_init_reserved_boot_region(ctrl);
> + } else {
> + dev_warn(&pdev->dev, "boot resource is not available.\n");
> + }
> + }
> +
> + ctrl->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
> + if (ctrl->sram_pool) {
> + ctrl->sram_buf.size = ctrl->res->sram_size;
> + ctrl->sram_buf.vaddr = gen_pool_dma_alloc(ctrl->sram_pool,
> + ctrl->sram_buf.size,
> + &ctrl->sram_buf.phys_addr);
> + if (!ctrl->sram_buf.vaddr)
> + ctrl->sram_buf.size = 0;
> + else
> + ctrl->sram_buf.dma_addr = dma_map_resource(&pdev->dev,
> + ctrl->sram_buf.phys_addr,
> + ctrl->sram_buf.size,
> + DMA_BIDIRECTIONAL,
> + 0);
> +
> + dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
> + &ctrl->sram_buf.phys_addr, &ctrl->sram_buf.dma_addr, ctrl->sram_buf.size);
You are not supposed to print addresses. This look like fixed hardware
mappings, so probably harmless but dma_addr not. Drop entire dev_info,
this is really discouraged practice.
> + }
> +
> + if (of_find_property(pdev->dev.of_node, "support-follower", NULL))
> + ctrl->support_follower = true;
> +
> + wave6_cooling_init(ctrl);
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static void wave6_vpu_ctrl_remove(struct platform_device *pdev)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
> +
> + pm_runtime_disable(&pdev->dev);
> +
> + wave6_vpu_ctrl_clear_buffers(ctrl);
> + wave6_cooling_remove(ctrl);
> + if (ctrl->sram_pool && ctrl->sram_buf.vaddr) {
> + dma_unmap_resource(&pdev->dev,
> + ctrl->sram_buf.dma_addr,
> + ctrl->sram_buf.size,
> + DMA_BIDIRECTIONAL,
> + 0);
> + gen_pool_free(ctrl->sram_pool,
> + (unsigned long)ctrl->sram_buf.vaddr,
> + ctrl->sram_buf.size);
> + }
> + if (ctrl->boot_mem.dma_addr)
> + dma_unmap_resource(&pdev->dev,
> + ctrl->boot_mem.dma_addr,
> + ctrl->boot_mem.size,
> + DMA_BIDIRECTIONAL,
> + 0);
> + mutex_destroy(&ctrl->ctrl_lock);
> +}
> +
> +#ifdef CONFIG_PM
> +static int wave6_vpu_ctrl_runtime_suspend(struct device *dev)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> +
> + clk_bulk_disable_unprepare(ctrl->num_clks, ctrl->clks);
> + return 0;
> +}
> +
> +static int wave6_vpu_ctrl_runtime_resume(struct device *dev)
> +{
> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
> +
> + return clk_bulk_prepare_enable(ctrl->num_clks, ctrl->clks);
> +}
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int wave6_vpu_ctrl_suspend(struct device *dev)
> +{
> + return 0;
Why do you need empty callbacks?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
2025-02-10 17:37 ` Krzysztof Kozlowski
@ 2025-02-11 8:55 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-11 8:55 UTC (permalink / raw)
To: Krzysztof Kozlowski, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Krzysztof.
>-----Original Message-----
>From: Krzysztof Kozlowski <krzk@kernel.org>
>Sent: Tuesday, February 11, 2025 2:38 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; sebastian.fricke@collabora.com; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control
>driver
>
>On 10/02/2025 10:07, Nas Chung wrote:
>> +
>> +int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct
>wave6_vpu_entity *entity)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> + bool boot;
>> + int ret;
>> +
>> + if (!ctrl)
>> + return -EINVAL;
>> +
>> + if (!entity || !entity->dev || !entity->read_reg || !entity-
>>write_reg)
>> + return -EINVAL;
>> +
>> + mutex_lock(&ctrl->ctrl_lock);
>> +
>> + ret = pm_runtime_resume_and_get(ctrl->dev);
>> + if (ret) {
>> + dev_err(dev, "pm runtime resume fail, ret = %d\n", ret);
>> + mutex_unlock(&ctrl->ctrl_lock);
>> + return ret;
>> + }
>> +
>> + entity->booted = false;
>> +
>> + if (ctrl->current_entity)
>> + boot = false;
>> + else
>> + boot = list_empty(&ctrl->entities) ? true : false;
>> +
>> + list_add_tail(&entity->list, &ctrl->entities);
>> + if (boot)
>> + ret = wave6_vpu_ctrl_try_boot(ctrl, entity);
>> +
>> + if (ctrl->state == WAVE6_VPU_STATE_ON)
>> + wave6_vpu_ctrl_on_boot(entity);
>> +
>> + if (ret)
>> + pm_runtime_put_sync(ctrl->dev);
>> +
>> + mutex_unlock(&ctrl->ctrl_lock);
>> +
>> + return ret;
>> +}
>
>Drop entire function.
>
>> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_resume_and_get);
>
>Drop.
>
>> +
>> +void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity
>*entity)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> +
>> + if (!ctrl)
>> + return;
>> +
>> + if (entity == ctrl->current_entity)
>> + wave6_vpu_ctrl_wait_done(dev);
>> +
>> + mutex_lock(&ctrl->ctrl_lock);
>> +
>> + if (!wave6_vpu_ctrl_find_entity(ctrl, entity))
>> + goto exit;
>> +
>> + list_del_init(&entity->list);
>> + if (list_empty(&ctrl->entities)) {
>> + if (!entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC))
>> + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
>> + else
>> + wave6_vpu_ctrl_sleep(ctrl, entity);
>> + }
>> +
>> + if (!pm_runtime_suspended(ctrl->dev))
>> + pm_runtime_put_sync(ctrl->dev);
>> +exit:
>> + mutex_unlock(&ctrl->ctrl_lock);
>> +}
>> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_put_sync);
>
>Drop entire function. Dead code.
>
>... or you arranged your patches really incorrectly, but this I can't
>really judge.
>
>
>
>> +
>> +int wave6_vpu_ctrl_wait_done(struct device *dev)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> + int ret;
>> +
>> + if (!ctrl)
>> + return -EINVAL;
>> +
>> + if (ctrl->state == WAVE6_VPU_STATE_OFF)
>> + return -EINVAL;
>> +
>> + if (ctrl->state == WAVE6_VPU_STATE_ON)
>> + return 0;
>> +
>> + ret = wave6_wait_event_freezable_timeout(ctrl->load_fw_wq,
>> + wave6_vpu_ctrl_get_state(dev) ==
>> + WAVE6_VPU_STATE_ON,
>> +
>msecs_to_jiffies(W6_BOOT_WAIT_TIMEOUT));
>> + if (ret == -ERESTARTSYS || !ret) {
>> + dev_err(ctrl->dev, "fail to wait vcpu boot done,ret %d\n",
>ret);
>> + mutex_lock(&ctrl->ctrl_lock);
>> + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
>> + mutex_unlock(&ctrl->ctrl_lock);
>> + return -EINVAL;
>> + }
>> +
>> + mutex_lock(&ctrl->ctrl_lock);
>> + wave6_vpu_ctrl_boot_done(ctrl, 0);
>> + mutex_unlock(&ctrl->ctrl_lock);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_wait_done);
>
>There is no user of this outside. Drop.
>
>
>> +
>> +int wave6_vpu_ctrl_get_state(struct device *dev)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> +
>> + if (!ctrl)
>> + return -EINVAL;
>> +
>> + return ctrl->state;
>> +}
>> +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_get_state);
>
>There is no user of this outside. Drop.
>
>Whatever export stays, must be used by a following patch. You *must* add
>the kerneldoc for it.
I realize that my patch order was incorrect.
I will fix it and include the necessary kerneldoc in v2.
>
>> +
>> +static void wave6_vpu_ctrl_init_reserved_boot_region(struct vpu_ctrl
>*ctrl)
>> +{
>> + if (ctrl->boot_mem.size < WAVE6_CODE_BUF_SIZE) {
>> + dev_warn(ctrl->dev, "boot memory size (%zu) is too small\n",
>ctrl->boot_mem.size);
>> + ctrl->boot_mem.phys_addr = 0;
>> + ctrl->boot_mem.size = 0;
>> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
>> + return;
>> + }
>> +
>> + ctrl->boot_mem.vaddr = devm_memremap(ctrl->dev,
>> + ctrl->boot_mem.phys_addr,
>> + ctrl->boot_mem.size,
>> + MEMREMAP_WC);
>> + if (!ctrl->boot_mem.vaddr) {
>> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
>> + return;
>> + }
>> +
>> + ctrl->boot_mem.dma_addr = dma_map_resource(ctrl->dev,
>> + ctrl->boot_mem.phys_addr,
>> + ctrl->boot_mem.size,
>> + DMA_BIDIRECTIONAL,
>> + 0);
>> + if (!ctrl->boot_mem.dma_addr) {
>> + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem));
>> + return;
>> + }
>> +
>> + dev_info(ctrl->dev, "boot phys_addr: %pad, dma_addr: %pad, size:
>0x%zx\n",
>> + &ctrl->boot_mem.phys_addr,
>> + &ctrl->boot_mem.dma_addr,
>> + ctrl->boot_mem.size);
>
>No, drop. Reasoning further.
>
>> +}
>...
>
>> +
>> + ctrl->num_clks = ret;
>> +
>> + np = of_parse_phandle(pdev->dev.of_node, "boot", 0);
>> + if (np) {
>> + struct resource mem;
>> +
>> + ret = of_address_to_resource(np, 0, &mem);
>> + of_node_put(np);
>> + if (!ret) {
>> + ctrl->boot_mem.phys_addr = mem.start;
>> + ctrl->boot_mem.size = resource_size(&mem);
>> + wave6_vpu_ctrl_init_reserved_boot_region(ctrl);
>> + } else {
>> + dev_warn(&pdev->dev, "boot resource is not
>available.\n");
>> + }
>> + }
>> +
>> + ctrl->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
>> + if (ctrl->sram_pool) {
>> + ctrl->sram_buf.size = ctrl->res->sram_size;
>> + ctrl->sram_buf.vaddr = gen_pool_dma_alloc(ctrl->sram_pool,
>> + ctrl->sram_buf.size,
>> + &ctrl->sram_buf.phys_addr);
>> + if (!ctrl->sram_buf.vaddr)
>> + ctrl->sram_buf.size = 0;
>> + else
>> + ctrl->sram_buf.dma_addr = dma_map_resource(&pdev->dev,
>> + ctrl-
>>sram_buf.phys_addr,
>> + ctrl->sram_buf.size,
>> + DMA_BIDIRECTIONAL,
>> + 0);
>> +
>> + dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
>> + &ctrl->sram_buf.phys_addr, &ctrl->sram_buf.dma_addr,
>ctrl->sram_buf.size);
>
>You are not supposed to print addresses. This look like fixed hardware
>mappings, so probably harmless but dma_addr not. Drop entire dev_info,
>this is really discouraged practice.
Thanks for the detailed explanation.
I will address this in v2.
>
>
>> + }
>> +
>> + if (of_find_property(pdev->dev.of_node, "support-follower", NULL))
>> + ctrl->support_follower = true;
>> +
>> + wave6_cooling_init(ctrl);
>> +
>> + pm_runtime_enable(&pdev->dev);
>> +
>> + return 0;
>> +}
>> +
>> +static void wave6_vpu_ctrl_remove(struct platform_device *pdev)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
>> +
>> + pm_runtime_disable(&pdev->dev);
>> +
>> + wave6_vpu_ctrl_clear_buffers(ctrl);
>> + wave6_cooling_remove(ctrl);
>> + if (ctrl->sram_pool && ctrl->sram_buf.vaddr) {
>> + dma_unmap_resource(&pdev->dev,
>> + ctrl->sram_buf.dma_addr,
>> + ctrl->sram_buf.size,
>> + DMA_BIDIRECTIONAL,
>> + 0);
>> + gen_pool_free(ctrl->sram_pool,
>> + (unsigned long)ctrl->sram_buf.vaddr,
>> + ctrl->sram_buf.size);
>> + }
>> + if (ctrl->boot_mem.dma_addr)
>> + dma_unmap_resource(&pdev->dev,
>> + ctrl->boot_mem.dma_addr,
>> + ctrl->boot_mem.size,
>> + DMA_BIDIRECTIONAL,
>> + 0);
>> + mutex_destroy(&ctrl->ctrl_lock);
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int wave6_vpu_ctrl_runtime_suspend(struct device *dev)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> +
>> + clk_bulk_disable_unprepare(ctrl->num_clks, ctrl->clks);
>> + return 0;
>> +}
>> +
>> +static int wave6_vpu_ctrl_runtime_resume(struct device *dev)
>> +{
>> + struct vpu_ctrl *ctrl = dev_get_drvdata(dev);
>> +
>> + return clk_bulk_prepare_enable(ctrl->num_clks, ctrl->clks);
>> +}
>> +#endif
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int wave6_vpu_ctrl_suspend(struct device *dev)
>> +{
>> + return 0;
>
>Why do you need empty callbacks?
I forgot to remove it.
I will address this in v2.
Thanks.
Nas.
>
>Best regards,
>Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
2025-02-10 9:07 ` [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Nas Chung
2025-02-10 17:37 ` Krzysztof Kozlowski
@ 2025-02-11 20:25 ` kernel test robot
2025-02-12 1:31 ` kernel test robot
2 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2025-02-11 20:25 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: oe-kbuild-all, linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Hi Nas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linuxtv-media-pending/master]
[also build test WARNING on arm64/for-next/core robh/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nas-Chung/media-platform-chips-media-wave5-Rename-Kconfig-parameter/20250210-171144
base: https://git.linuxtv.org/media-ci/media-pending.git master
patch link: https://lore.kernel.org/r/20250210090725.4580-8-nas.chung%40chipsnmedia.com
patch subject: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20250212/202502120449.ZTdCf6WQ-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502120449.ZTdCf6WQ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502120449.ZTdCf6WQ-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from include/linux/device.h:15,
from include/linux/platform_device.h:13,
from drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:10:
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c: In function 'wave6_vpu_ctrl_load_firmware':
>> drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:383:36: warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
383 | dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:383:17: note: in expansion of macro 'dev_err'
383 | dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
| ^~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:383:54: note: format string is defined here
383 | dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
| ~~^
| |
| long int
| %d
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c: In function 'wave6_vpu_ctrl_probe':
>> drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:928:38: warning: format '%lx' expects argument of type 'long unsigned int', but argument 5 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
928 | dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
include/linux/dev_printk.h:160:58: note: in expansion of macro 'dev_fmt'
160 | dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:928:17: note: in expansion of macro 'dev_info'
928 | dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
| ^~~~~~~~
drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:928:69: note: format string is defined here
928 | dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
| ~~^
| |
| long unsigned int
| %x
vim +383 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
357
358 static void wave6_vpu_ctrl_load_firmware(const struct firmware *fw, void *context)
359 {
360 struct vpu_ctrl *ctrl = context;
361 struct wave6_vpu_entity *entity = ctrl->current_entity;
362 u32 product_code;
363 int ret;
364
365 ret = pm_runtime_resume_and_get(ctrl->dev);
366 if (ret) {
367 dev_err(ctrl->dev, "pm runtime resume fail, ret = %d\n", ret);
368 mutex_lock(&ctrl->ctrl_lock);
369 wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
370 ctrl->current_entity = NULL;
371 mutex_unlock(&ctrl->ctrl_lock);
372 release_firmware(fw);
373 return;
374 }
375
376 if (!fw || !fw->data) {
377 dev_err(ctrl->dev, "No firmware.\n");
378 ret = -EINVAL;
379 goto exit;
380 }
381
382 if (fw->size + WAVE6_EXTRA_CODE_BUF_SIZE > wave6_vpu_ctrl_get_code_buf_size(ctrl)) {
> 383 dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
384 fw->size, ctrl->boot_mem.size);
385 ret = -EINVAL;
386 goto exit;
387 }
388
389 product_code = entity->read_reg(entity->dev, W6_VPU_RET_PRODUCT_VERSION);
390 if (!PRODUCT_CODE_W_SERIES(product_code)) {
391 dev_err(ctrl->dev, "unknown product : %08x\n", product_code);
392 ret = -EINVAL;
393 goto exit;
394 }
395
396 memcpy(ctrl->boot_mem.vaddr, fw->data, fw->size);
397
398 exit:
399 mutex_lock(&ctrl->ctrl_lock);
400 if (!ret && wave6_vpu_ctrl_find_entity(ctrl, ctrl->current_entity)) {
401 wave6_vpu_ctrl_remap_code_buffer(ctrl);
402 ret = wave6_vpu_ctrl_init_vpu(ctrl);
403 } else {
404 ret = -EINVAL;
405 }
406 mutex_unlock(&ctrl->ctrl_lock);
407
408 pm_runtime_put_sync(ctrl->dev);
409 release_firmware(fw);
410
411 mutex_lock(&ctrl->ctrl_lock);
412 ctrl->current_entity = NULL;
413 if (ret)
414 wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
415 else
416 wave6_vpu_ctrl_boot_done(ctrl, 0);
417 mutex_unlock(&ctrl->ctrl_lock);
418
419 wake_up_interruptible_all(&ctrl->load_fw_wq);
420 }
421
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
2025-02-10 9:07 ` [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Nas Chung
2025-02-10 17:37 ` Krzysztof Kozlowski
2025-02-11 20:25 ` kernel test robot
@ 2025-02-12 1:31 ` kernel test robot
2 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2025-02-12 1:31 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: llvm, oe-kbuild-all, linux-media, devicetree, linux-kernel,
linux-imx, linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Hi Nas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linuxtv-media-pending/master]
[also build test WARNING on arm64/for-next/core robh/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nas-Chung/media-platform-chips-media-wave5-Rename-Kconfig-parameter/20250210-171144
base: https://git.linuxtv.org/media-ci/media-pending.git master
patch link: https://lore.kernel.org/r/20250210090725.4580-8-nas.chung%40chipsnmedia.com
patch subject: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20250212/202502120928.wbtfGrUk-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project 6807164500e9920638e2ab0cdb4bf8321d24f8eb)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502120928.wbtfGrUk-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502120928.wbtfGrUk-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:384:4: warning: format specifies type 'long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat]
383 | dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
| ~~~
| %zu
384 | fw->size, ctrl->boot_mem.size);
| ^~~~~~~~
include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
>> drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c:929:58: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat]
928 | dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n",
| ~~~
| %zx
929 | &ctrl->sram_buf.phys_addr, &ctrl->sram_buf.dma_addr, ctrl->sram_buf.size);
| ^~~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:160:67: note: expanded from macro 'dev_info'
160 | dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ~~~ ^~~~~~~~~~~
2 warnings generated.
vim +384 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
357
358 static void wave6_vpu_ctrl_load_firmware(const struct firmware *fw, void *context)
359 {
360 struct vpu_ctrl *ctrl = context;
361 struct wave6_vpu_entity *entity = ctrl->current_entity;
362 u32 product_code;
363 int ret;
364
365 ret = pm_runtime_resume_and_get(ctrl->dev);
366 if (ret) {
367 dev_err(ctrl->dev, "pm runtime resume fail, ret = %d\n", ret);
368 mutex_lock(&ctrl->ctrl_lock);
369 wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
370 ctrl->current_entity = NULL;
371 mutex_unlock(&ctrl->ctrl_lock);
372 release_firmware(fw);
373 return;
374 }
375
376 if (!fw || !fw->data) {
377 dev_err(ctrl->dev, "No firmware.\n");
378 ret = -EINVAL;
379 goto exit;
380 }
381
382 if (fw->size + WAVE6_EXTRA_CODE_BUF_SIZE > wave6_vpu_ctrl_get_code_buf_size(ctrl)) {
383 dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n",
> 384 fw->size, ctrl->boot_mem.size);
385 ret = -EINVAL;
386 goto exit;
387 }
388
389 product_code = entity->read_reg(entity->dev, W6_VPU_RET_PRODUCT_VERSION);
390 if (!PRODUCT_CODE_W_SERIES(product_code)) {
391 dev_err(ctrl->dev, "unknown product : %08x\n", product_code);
392 ret = -EINVAL;
393 goto exit;
394 }
395
396 memcpy(ctrl->boot_mem.vaddr, fw->data, fw->size);
397
398 exit:
399 mutex_lock(&ctrl->ctrl_lock);
400 if (!ret && wave6_vpu_ctrl_find_entity(ctrl, ctrl->current_entity)) {
401 wave6_vpu_ctrl_remap_code_buffer(ctrl);
402 ret = wave6_vpu_ctrl_init_vpu(ctrl);
403 } else {
404 ret = -EINVAL;
405 }
406 mutex_unlock(&ctrl->ctrl_lock);
407
408 pm_runtime_put_sync(ctrl->dev);
409 release_firmware(fw);
410
411 mutex_lock(&ctrl->ctrl_lock);
412 ctrl->current_entity = NULL;
413 if (ret)
414 wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF);
415 else
416 wave6_vpu_ctrl_boot_done(ctrl, 0);
417 mutex_unlock(&ctrl->ctrl_lock);
418
419 wake_up_interruptible_all(&ctrl->load_fw_wq);
420 }
421
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (6 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Nas Chung
@ 2025-02-10 9:07 ` Nas Chung
2025-02-11 16:43 ` kernel test robot
2025-02-10 13:05 ` [PATCH 0/8] Add support for Wave6 video codec driver Sebastian Fricke
2025-02-11 6:07 ` [EXT] " Ming Qian
9 siblings, 1 reply; 34+ messages in thread
From: Nas Chung @ 2025-02-10 9:07 UTC (permalink / raw)
To: mchehab, hverkuil, sebastian.fricke, robh, krzk+dt, conor+dt
Cc: linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Add debugfs entries and trace events to provide detailed
debugging information.
These enhancements help diagnose issues and improve debugging
capabilities for the Wave6 driver.
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
---
.../platform/chips-media/wave6/wave6-trace.h | 336 ++++++++++++++++++
.../chips-media/wave6/wave6-vpu-dbg.c | 230 ++++++++++++
.../chips-media/wave6/wave6-vpu-dbg.h | 22 ++
3 files changed, 588 insertions(+)
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-trace.h
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c
create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h
diff --git a/drivers/media/platform/chips-media/wave6/wave6-trace.h b/drivers/media/platform/chips-media/wave6/wave6-trace.h
new file mode 100644
index 000000000000..8ddba6926c60
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-trace.h
@@ -0,0 +1,336 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - wave6 driver tracer
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM wave6
+
+#if !defined(__WAVE6_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
+#define __WAVE6_TRACE_H__
+
+#include <linux/tracepoint.h>
+#include <media/videobuf2-v4l2.h>
+
+DECLARE_EVENT_CLASS(register_access,
+ TP_PROTO(struct device *dev, u32 addr, u32 value),
+ TP_ARGS(dev, addr, value),
+ TP_STRUCT__entry(
+ __string(name, dev_name(dev))
+ __field(u32, addr)
+ __field(u32, value)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->addr = addr;
+ __entry->value = value;
+ ),
+ TP_printk("%s:0x%03x 0x%08x", __get_str(name), __entry->addr, __entry->value)
+);
+
+DEFINE_EVENT(register_access, writel,
+ TP_PROTO(struct device *dev, u32 addr, u32 value),
+ TP_ARGS(dev, addr, value));
+DEFINE_EVENT(register_access, readl,
+ TP_PROTO(struct device *dev, u32 addr, u32 value),
+ TP_ARGS(dev, addr, value));
+
+TRACE_EVENT(send_command,
+ TP_PROTO(struct vpu_device *vpu_dev, u32 id, u32 std, u32 cmd),
+ TP_ARGS(vpu_dev, id, std, cmd),
+ TP_STRUCT__entry(
+ __string(name, dev_name(vpu_dev->dev))
+ __field(u32, id)
+ __field(u32, std)
+ __field(u32, cmd)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(vpu_dev->dev));
+ __entry->id = id;
+ __entry->std = std;
+ __entry->cmd = cmd;
+ ),
+ TP_printk("%s: inst id %d, std 0x%x, cmd 0x%x",
+ __get_str(name), __entry->id, __entry->std, __entry->cmd)
+);
+
+TRACE_EVENT(irq,
+ TP_PROTO(struct vpu_device *vpu_dev, u32 irq),
+ TP_ARGS(vpu_dev, irq),
+ TP_STRUCT__entry(
+ __string(name, dev_name(vpu_dev->dev))
+ __field(u32, irq)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(vpu_dev->dev));
+ __entry->irq = irq;
+ ),
+ TP_printk("%s: irq 0x%x", __get_str(name), __entry->irq)
+);
+
+TRACE_EVENT(set_state,
+ TP_PROTO(struct vpu_instance *inst, u32 state),
+ TP_ARGS(inst, state),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __string(cur_state, wave6_vpu_instance_state_name(inst->state))
+ __string(nxt_state, wave6_vpu_instance_state_name(state))
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __assign_str(cur_state, wave6_vpu_instance_state_name(inst->state));
+ __assign_str(nxt_state, wave6_vpu_instance_state_name(state));
+ ),
+ TP_printk("%s: inst[%d] set state %s -> %s",
+ __get_str(name), __entry->id, __get_str(cur_state), __get_str(nxt_state))
+);
+
+DECLARE_EVENT_CLASS(inst_internal,
+ TP_PROTO(struct vpu_instance *inst, u32 type),
+ TP_ARGS(inst, type),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __string(type, V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture")
+ __field(u32, pixelformat)
+ __field(u32, width)
+ __field(u32, height)
+ __field(u32, buf_cnt_src)
+ __field(u32, buf_cnt_dst)
+ __field(u32, processed_cnt)
+ __field(u32, error_cnt)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __assign_str(type, V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture");
+ __entry->pixelformat = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.pixelformat :
+ inst->dst_fmt.pixelformat;
+ __entry->width = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.width :
+ inst->dst_fmt.width;
+ __entry->height = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.height :
+ inst->dst_fmt.height;
+ __entry->buf_cnt_src = inst->queued_src_buf_num;
+ __entry->buf_cnt_dst = inst->queued_dst_buf_num;
+ __entry->processed_cnt = inst->processed_buf_num;
+ __entry->error_cnt = inst->error_buf_num;
+ ),
+ TP_printk("%s: inst[%d] %s %c%c%c%c %dx%d, input %d, %d, process %d, error %d",
+ __get_str(name), __entry->id, __get_str(type),
+ __entry->pixelformat,
+ __entry->pixelformat >> 8,
+ __entry->pixelformat >> 16,
+ __entry->pixelformat >> 24,
+ __entry->width, __entry->height,
+ __entry->buf_cnt_src, __entry->buf_cnt_dst,
+ __entry->processed_cnt, __entry->error_cnt)
+);
+
+DEFINE_EVENT(inst_internal, start_streaming,
+ TP_PROTO(struct vpu_instance *inst, u32 type),
+ TP_ARGS(inst, type));
+
+DEFINE_EVENT(inst_internal, stop_streaming,
+ TP_PROTO(struct vpu_instance *inst, u32 type),
+ TP_ARGS(inst, type));
+
+TRACE_EVENT(dec_pic,
+ TP_PROTO(struct vpu_instance *inst, u32 srcidx, u32 size),
+ TP_ARGS(inst, srcidx, size),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __field(u32, srcidx)
+ __field(u32, start)
+ __field(u32, size)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __entry->srcidx = srcidx;
+ __entry->start = inst->codec_info->dec_info.stream_rd_ptr;
+ __entry->size = size;
+ ),
+ TP_printk("%s: inst[%d] src[%2d] %8x, %d",
+ __get_str(name), __entry->id, __entry->srcidx, __entry->start, __entry->size)
+);
+
+TRACE_EVENT(source_change,
+ TP_PROTO(struct vpu_instance *inst, struct dec_initial_info *info),
+ TP_ARGS(inst, info),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __field(u32, width)
+ __field(u32, height)
+ __field(u32, profile)
+ __field(u32, level)
+ __field(u32, tier)
+ __field(u32, min_fb_cnt)
+ __field(u32, disp_delay)
+ __field(u32, quantization)
+ __field(u32, colorspace)
+ __field(u32, xfer_func)
+ __field(u32, ycbcr_enc)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __entry->width = info->pic_width,
+ __entry->height = info->pic_height,
+ __entry->profile = info->profile,
+ __entry->level = info->level;
+ __entry->tier = info->tier;
+ __entry->min_fb_cnt = info->min_frame_buffer_count;
+ __entry->disp_delay = info->frame_buf_delay;
+ __entry->quantization = inst->quantization;
+ __entry->colorspace = inst->colorspace;
+ __entry->xfer_func = inst->xfer_func;
+ __entry->ycbcr_enc = inst->ycbcr_enc;
+ ),
+ TP_printk("%s: inst[%d] %dx%d profile %d, %d, %d min_fb %d, delay %d, color %d,%d,%d,%d",
+ __get_str(name), __entry->id,
+ __entry->width, __entry->height,
+ __entry->profile, __entry->level, __entry->tier,
+ __entry->min_fb_cnt, __entry->disp_delay,
+ __entry->quantization,
+ __entry->colorspace, __entry->xfer_func, __entry->ycbcr_enc)
+);
+
+TRACE_EVENT(dec_done,
+ TP_PROTO(struct vpu_instance *inst, struct dec_output_info *info),
+ TP_ARGS(inst, info),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __field(u32, dec_flag)
+ __field(u32, dec_poc)
+ __field(u32, disp_flag)
+ __field(u32, disp_cnt)
+ __field(u32, rel_cnt)
+ __field(u32, src_ch)
+ __field(u32, eos)
+ __field(u32, error)
+ __field(u32, warn)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __entry->dec_flag = info->frame_decoded;
+ __entry->dec_poc = info->decoded_poc;
+ __entry->disp_flag = info->frame_display;
+ __entry->disp_cnt = info->disp_frame_num;
+ __entry->rel_cnt = info->release_disp_frame_num;
+ __entry->src_ch = info->notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE;
+ __entry->eos = info->stream_end;
+ __entry->error = info->error_reason;
+ __entry->warn = info->warn_info;
+ ),
+ TP_printk("%s: inst[%d] dec %d %d; disp %d(%d); rel %d, src_ch %d, eos %d, error 0x%x 0x%x",
+ __get_str(name), __entry->id,
+ __entry->dec_flag, __entry->dec_poc,
+ __entry->disp_flag, __entry->disp_cnt,
+ __entry->rel_cnt,
+ __entry->src_ch, __entry->eos,
+ __entry->error, __entry->warn)
+);
+
+TRACE_EVENT(enc_pic,
+ TP_PROTO(struct vpu_instance *inst, struct enc_param *param),
+ TP_ARGS(inst, param),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __field(u32, srcidx)
+ __field(u32, buf_y)
+ __field(u32, buf_cb)
+ __field(u32, buf_cr)
+ __field(u32, stride)
+ __field(u32, buf_strm)
+ __field(u32, size_strm)
+ __field(u32, force_type_enable)
+ __field(u32, force_type)
+ __field(u32, end_flag)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __entry->srcidx = param->src_idx;
+ __entry->buf_y = param->source_frame->buf_y;
+ __entry->buf_cb = param->source_frame->buf_cb;
+ __entry->buf_cr = param->source_frame->buf_cr;
+ __entry->stride = param->source_frame->stride;
+ __entry->buf_strm = param->pic_stream_buffer_addr;
+ __entry->size_strm = param->pic_stream_buffer_size;
+ __entry->force_type_enable = param->force_pic_type_enable;
+ __entry->force_type = param->force_pic_type;
+ __entry->end_flag = param->src_end;
+ ),
+ TP_printk("%s: inst[%d] src[%2d] %8x %8x %8x (%d); dst %8x(%d); force type %d(%d), end %d",
+ __get_str(name), __entry->id, __entry->srcidx,
+ __entry->buf_y, __entry->buf_cb, __entry->buf_cr, __entry->stride,
+ __entry->buf_strm, __entry->size_strm,
+ __entry->force_type_enable, __entry->force_type,
+ __entry->end_flag)
+);
+
+TRACE_EVENT(enc_done,
+ TP_PROTO(struct vpu_instance *inst, struct enc_output_info *info),
+ TP_ARGS(inst, info),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __field(u32, srcidx)
+ __field(u32, frmidx)
+ __field(u32, size)
+ __field(u32, type)
+ __field(u32, avg_qp)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __entry->srcidx = info->enc_src_idx;
+ __entry->frmidx = info->recon_frame_index;
+ __entry->size = info->bitstream_size;
+ __entry->type = info->pic_type;
+ __entry->avg_qp = info->avg_ctu_qp;
+ ),
+ TP_printk("%s: inst[%d] src %d, frame %d, size %d, type %d, qp %d, eos %d",
+ __get_str(name), __entry->id,
+ __entry->srcidx, __entry->frmidx,
+ __entry->size, __entry->type, __entry->avg_qp,
+ __entry->frmidx == RECON_IDX_FLAG_ENC_END)
+);
+
+TRACE_EVENT(s_ctrl,
+ TP_PROTO(struct vpu_instance *inst, struct v4l2_ctrl *ctrl),
+ TP_ARGS(inst, ctrl),
+ TP_STRUCT__entry(
+ __string(name, dev_name(inst->dev->dev))
+ __field(u32, id)
+ __string(ctrl_name, ctrl->name)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(inst->dev->dev));
+ __entry->id = inst->id;
+ __assign_str(ctrl_name, ctrl->name);
+ __entry->val = ctrl->val;
+ ),
+ TP_printk("%s: inst[%d] %s = %d",
+ __get_str(name), __entry->id, __get_str(ctrl_name), __entry->val)
+);
+
+#endif /* __WAVE6_TRACE_H__ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE wave6-trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c
new file mode 100644
index 000000000000..40fe75c08eeb
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave6 series multi-standard codec IP - debug interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include "wave6-vpu.h"
+#include "wave6-vpu-dbg.h"
+
+static int wave6_vpu_dbg_instance(struct seq_file *s, void *data)
+{
+ struct vpu_instance *inst = s->private;
+ struct vpu_performance_info *perf = &inst->performance;
+ struct vb2_queue *vq;
+ char str[128];
+ int num;
+ s64 tmp;
+ s64 fps;
+
+ if (!inst->v4l2_fh.m2m_ctx)
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "[%s]\n",
+ inst->type == VPU_INST_TYPE_DEC ? "Decoder" : "Encoder");
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "%s : product 0x%x, fw_ver %d.%d.%d(r%d), hw_ver 0x%x\n",
+ dev_name(inst->dev->dev), inst->dev->product_code,
+ (inst->dev->fw_version >> 24) & 0xFF,
+ (inst->dev->fw_version >> 16) & 0xFF,
+ (inst->dev->fw_version >> 0) & 0xFFFF,
+ inst->dev->fw_revision, inst->dev->hw_version);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "state = %s, pause request %d\n",
+ wave6_vpu_instance_state_name(inst->state),
+ inst->dev->pause_request);
+ if (seq_write(s, str, num))
+ return 0;
+
+ vq = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx);
+ num = scnprintf(str, sizeof(str),
+ "output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;\n",
+ vb2_is_streaming(vq),
+ vb2_get_num_buffers(vq),
+ inst->src_fmt.pixelformat,
+ inst->src_fmt.pixelformat >> 8,
+ inst->src_fmt.pixelformat >> 16,
+ inst->src_fmt.pixelformat >> 24,
+ inst->src_fmt.width,
+ inst->src_fmt.height,
+ vq->last_buffer_dequeued);
+ if (seq_write(s, str, num))
+ return 0;
+
+ vq = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx);
+ num = scnprintf(str, sizeof(str),
+ "capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;\n",
+ vb2_is_streaming(vq),
+ vb2_get_num_buffers(vq),
+ inst->dst_fmt.pixelformat,
+ inst->dst_fmt.pixelformat >> 8,
+ inst->dst_fmt.pixelformat >> 16,
+ inst->dst_fmt.pixelformat >> 24,
+ inst->dst_fmt.width,
+ inst->dst_fmt.height,
+ vq->last_buffer_dequeued);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str),
+ "capture queued %d, consumed %d, used %d\n",
+ v4l2_m2m_num_dst_bufs_ready(inst->v4l2_fh.m2m_ctx),
+ wave6_vpu_get_consumed_fb_num(inst),
+ wave6_vpu_get_used_fb_num(inst));
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "crop: (%d, %d) %d x %d\n",
+ inst->crop.left,
+ inst->crop.top,
+ inst->crop.width,
+ inst->crop.height);
+ if (seq_write(s, str, num))
+ return 0;
+
+ if (inst->scaler_info.enable) {
+ num = scnprintf(str, sizeof(str), "scale: %d x %d\n",
+ inst->scaler_info.width, inst->scaler_info.height);
+ if (seq_write(s, str, num))
+ return 0;
+ }
+
+ num = scnprintf(str, sizeof(str),
+ "queued src %d, dst %d, process %d, sequence %d, error %d, drain %d:%d\n",
+ inst->queued_src_buf_num,
+ inst->queued_dst_buf_num,
+ inst->processed_buf_num,
+ inst->sequence,
+ inst->error_buf_num,
+ inst->v4l2_fh.m2m_ctx->out_q_ctx.buffered,
+ inst->eos);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "fps");
+ if (seq_write(s, str, num))
+ return 0;
+ tmp = MSEC_PER_SEC * inst->processed_buf_num;
+ if (perf->ts_last > perf->ts_first + NSEC_PER_MSEC) {
+ fps = DIV_ROUND_CLOSEST(tmp, (perf->ts_last - perf->ts_first) / NSEC_PER_MSEC);
+ num = scnprintf(str, sizeof(str), " actual: %lld;", fps);
+ if (seq_write(s, str, num))
+ return 0;
+ }
+ if (perf->total_sw_time) {
+ fps = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time / NSEC_PER_MSEC);
+ num = scnprintf(str, sizeof(str), " sw: %lld;", fps);
+ if (seq_write(s, str, num))
+ return 0;
+ }
+ if (perf->total_hw_time) {
+ fps = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time / NSEC_PER_MSEC);
+ num = scnprintf(str, sizeof(str), " hw: %lld", fps);
+ if (seq_write(s, str, num))
+ return 0;
+ }
+ num = scnprintf(str, sizeof(str), "\n");
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str),
+ "latency(ms) first: %llu.%06llu, max %llu.%06llu\n",
+ perf->latency_first / NSEC_PER_MSEC,
+ perf->latency_first % NSEC_PER_MSEC,
+ perf->latency_max / NSEC_PER_MSEC,
+ perf->latency_max % NSEC_PER_MSEC);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str),
+ "process frame time(ms) min: %llu.%06llu, max %llu.%06llu\n",
+ perf->min_process_time / NSEC_PER_MSEC,
+ perf->min_process_time % NSEC_PER_MSEC,
+ perf->max_process_time / NSEC_PER_MSEC,
+ perf->max_process_time % NSEC_PER_MSEC);
+ if (seq_write(s, str, num))
+ return 0;
+
+ if (inst->type == VPU_INST_TYPE_DEC) {
+ num = scnprintf(str, sizeof(str), "%s order\n",
+ inst->disp_mode == DISP_MODE_DISP_ORDER ? "display" : "decode");
+ if (seq_write(s, str, num))
+ return 0;
+ } else {
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ struct enc_codec_param *param = &p_enc_info->open_param.codec_param;
+
+ num = scnprintf(str, sizeof(str), "profile %d, level %d, tier %d\n",
+ param->profile, param->level, param->tier);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "frame_rate %d, idr_period %d, intra_period %d\n",
+ param->frame_rate, param->idr_period, param->intra_period);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str), "rc %d, mode %d, bitrate %d\n",
+ param->en_rate_control,
+ param->rc_mode,
+ param->bitrate);
+ if (seq_write(s, str, num))
+ return 0;
+
+ num = scnprintf(str, sizeof(str),
+ "qp %d, i_qp [%d, %d], p_qp [%d, %d], b_qp [%d, %d]\n",
+ param->qp,
+ param->min_qp_i, param->max_qp_i,
+ param->min_qp_p, param->max_qp_p,
+ param->min_qp_b, param->max_qp_b);
+ if (seq_write(s, str, num))
+ return 0;
+ }
+
+ return 0;
+}
+
+static int wave6_vpu_dbg_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, wave6_vpu_dbg_instance, inode->i_private);
+}
+
+static const struct file_operations wave6_vpu_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = wave6_vpu_dbg_open,
+ .release = single_release,
+ .read = seq_read,
+};
+
+int wave6_vpu_create_dbgfs_file(struct vpu_instance *inst)
+{
+ char name[64];
+
+ if (!inst || !inst->dev || IS_ERR_OR_NULL(inst->dev->debugfs))
+ return -EINVAL;
+
+ scnprintf(name, sizeof(name), "instance.%d", inst->id);
+ inst->debugfs = debugfs_create_file((const char *)name,
+ VERIFY_OCTAL_PERMISSIONS(0444),
+ inst->dev->debugfs,
+ inst,
+ &wave6_vpu_dbg_fops);
+
+ return 0;
+}
+
+void wave6_vpu_remove_dbgfs_file(struct vpu_instance *inst)
+{
+ if (!inst || !inst->debugfs)
+ return;
+
+ debugfs_remove(inst->debugfs);
+ inst->debugfs = NULL;
+}
diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h
new file mode 100644
index 000000000000..fd7da1670925
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave6 series multi-standard codec IP - debug interface
+ *
+ * Copyright (C) 2025 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE6_VPU_DBG_H__
+#define __WAVE6_VPU_DBG_H__
+
+unsigned int wave6_vpu_debug(void);
+
+#define dprintk(dev, fmt, arg...) \
+ do { \
+ if (wave6_vpu_debug()) \
+ dev_info(dev, "%s: " fmt, __func__, ## arg); \
+ } while (0)
+
+int wave6_vpu_create_dbgfs_file(struct vpu_instance *inst);
+void wave6_vpu_remove_dbgfs_file(struct vpu_instance *inst);
+
+#endif /* __WAVE6_VPU_DBG_H__ */
--
2.31.1
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities
2025-02-10 9:07 ` [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities Nas Chung
@ 2025-02-11 16:43 ` kernel test robot
0 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2025-02-11 16:43 UTC (permalink / raw)
To: Nas Chung, mchehab, hverkuil, sebastian.fricke, robh, krzk+dt,
conor+dt
Cc: oe-kbuild-all, linux-media, devicetree, linux-kernel, linux-imx,
linux-arm-kernel, jackson.lee, lafley.kim, Nas Chung
Hi Nas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linuxtv-media-pending/master]
[also build test WARNING on arm64/for-next/core robh/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nas-Chung/media-platform-chips-media-wave5-Rename-Kconfig-parameter/20250210-171144
base: https://git.linuxtv.org/media-ci/media-pending.git master
patch link: https://lore.kernel.org/r/20250210090725.4580-9-nas.chung%40chipsnmedia.com
patch subject: [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20250212/202502120017.COEwtixF-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502120017.COEwtixF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502120017.COEwtixF-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c: In function 'wave6_vpu_dec_handle_dst_buffer':
>> drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c:261:13: warning: variable 'buf_size' set but not used [-Wunused-but-set-variable]
261 | u32 buf_size;
| ^~~~~~~~
--
drivers/media/platform/chips-media/wave6/wave6-hw.c: In function 'wave6_vpu_dec_flush':
>> drivers/media/platform/chips-media/wave6/wave6-hw.c:1022:37: warning: variable 'fb' set but not used [-Wunused-but-set-variable]
1022 | struct frame_buffer fb;
| ^~
vim +/buf_size +261 drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
de204321b54004 Nas Chung 2025-02-10 254
de204321b54004 Nas Chung 2025-02-10 255 static void wave6_vpu_dec_handle_dst_buffer(struct vpu_instance *inst)
de204321b54004 Nas Chung 2025-02-10 256 {
de204321b54004 Nas Chung 2025-02-10 257 struct vb2_v4l2_buffer *dst_buf;
de204321b54004 Nas Chung 2025-02-10 258 struct v4l2_m2m_buffer *v4l2_m2m_buf;
de204321b54004 Nas Chung 2025-02-10 259 struct vpu_buffer *vpu_buf;
de204321b54004 Nas Chung 2025-02-10 260 dma_addr_t buf_addr_y, buf_addr_cb, buf_addr_cr;
de204321b54004 Nas Chung 2025-02-10 @261 u32 buf_size;
de204321b54004 Nas Chung 2025-02-10 262 u32 fb_stride = inst->dst_fmt.plane_fmt[0].bytesperline;
de204321b54004 Nas Chung 2025-02-10 263 u32 luma_size = fb_stride * inst->dst_fmt.height;
de204321b54004 Nas Chung 2025-02-10 264 u32 chroma_size = (fb_stride / 2) * (inst->dst_fmt.height / 2);
de204321b54004 Nas Chung 2025-02-10 265 struct frame_buffer disp_buffer = {0};
de204321b54004 Nas Chung 2025-02-10 266 struct dec_initial_info initial_info = {0};
de204321b54004 Nas Chung 2025-02-10 267 int consumed_num = wave6_vpu_get_consumed_fb_num(inst);
de204321b54004 Nas Chung 2025-02-10 268 int ret;
de204321b54004 Nas Chung 2025-02-10 269
de204321b54004 Nas Chung 2025-02-10 270 wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info);
de204321b54004 Nas Chung 2025-02-10 271
de204321b54004 Nas Chung 2025-02-10 272 v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) {
de204321b54004 Nas Chung 2025-02-10 273 dst_buf = &v4l2_m2m_buf->vb;
de204321b54004 Nas Chung 2025-02-10 274 vpu_buf = wave6_to_vpu_buf(dst_buf);
de204321b54004 Nas Chung 2025-02-10 275
de204321b54004 Nas Chung 2025-02-10 276 if (vpu_buf->consumed)
de204321b54004 Nas Chung 2025-02-10 277 continue;
de204321b54004 Nas Chung 2025-02-10 278
de204321b54004 Nas Chung 2025-02-10 279 if (consumed_num >= WAVE6_MAX_FBS)
de204321b54004 Nas Chung 2025-02-10 280 break;
de204321b54004 Nas Chung 2025-02-10 281
de204321b54004 Nas Chung 2025-02-10 282 if (inst->dst_fmt.num_planes == 1) {
de204321b54004 Nas Chung 2025-02-10 283 buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
de204321b54004 Nas Chung 2025-02-10 284 buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
de204321b54004 Nas Chung 2025-02-10 285 buf_addr_cb = buf_addr_y + luma_size;
de204321b54004 Nas Chung 2025-02-10 286 buf_addr_cr = buf_addr_cb + chroma_size;
de204321b54004 Nas Chung 2025-02-10 287 } else if (inst->dst_fmt.num_planes == 2) {
de204321b54004 Nas Chung 2025-02-10 288 buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) +
de204321b54004 Nas Chung 2025-02-10 289 vb2_plane_size(&dst_buf->vb2_buf, 1);
de204321b54004 Nas Chung 2025-02-10 290 buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
de204321b54004 Nas Chung 2025-02-10 291 buf_addr_cb = wave6_get_dma_addr(dst_buf, 1);
de204321b54004 Nas Chung 2025-02-10 292 buf_addr_cr = buf_addr_cb + chroma_size;
de204321b54004 Nas Chung 2025-02-10 293 } else if (inst->dst_fmt.num_planes == 3) {
de204321b54004 Nas Chung 2025-02-10 294 buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) +
de204321b54004 Nas Chung 2025-02-10 295 vb2_plane_size(&dst_buf->vb2_buf, 1) +
de204321b54004 Nas Chung 2025-02-10 296 vb2_plane_size(&dst_buf->vb2_buf, 2);
de204321b54004 Nas Chung 2025-02-10 297 buf_addr_y = wave6_get_dma_addr(dst_buf, 0);
de204321b54004 Nas Chung 2025-02-10 298 buf_addr_cb = wave6_get_dma_addr(dst_buf, 1);
de204321b54004 Nas Chung 2025-02-10 299 buf_addr_cr = wave6_get_dma_addr(dst_buf, 2);
de204321b54004 Nas Chung 2025-02-10 300 }
de204321b54004 Nas Chung 2025-02-10 301 disp_buffer.buf_y = buf_addr_y;
de204321b54004 Nas Chung 2025-02-10 302 disp_buffer.buf_cb = buf_addr_cb;
de204321b54004 Nas Chung 2025-02-10 303 disp_buffer.buf_cr = buf_addr_cr;
de204321b54004 Nas Chung 2025-02-10 304 disp_buffer.width = inst->src_fmt.width;
de204321b54004 Nas Chung 2025-02-10 305 disp_buffer.height = inst->src_fmt.height;
de204321b54004 Nas Chung 2025-02-10 306 disp_buffer.stride = fb_stride;
de204321b54004 Nas Chung 2025-02-10 307 disp_buffer.map_type = LINEAR_FRAME_MAP;
de204321b54004 Nas Chung 2025-02-10 308 disp_buffer.luma_bitdepth = initial_info.luma_bitdepth;
de204321b54004 Nas Chung 2025-02-10 309 disp_buffer.chroma_bitdepth = initial_info.chroma_bitdepth;
de204321b54004 Nas Chung 2025-02-10 310 disp_buffer.chroma_format_idc = initial_info.chroma_format_idc;
de204321b54004 Nas Chung 2025-02-10 311
de204321b54004 Nas Chung 2025-02-10 312 ret = wave6_vpu_dec_register_display_buffer_ex(inst, disp_buffer);
de204321b54004 Nas Chung 2025-02-10 313 if (ret) {
de204321b54004 Nas Chung 2025-02-10 314 dev_err(inst->dev->dev, "fail register display buffer %d", ret);
de204321b54004 Nas Chung 2025-02-10 315 break;
de204321b54004 Nas Chung 2025-02-10 316 }
de204321b54004 Nas Chung 2025-02-10 317
de204321b54004 Nas Chung 2025-02-10 318 vpu_buf->consumed = true;
de204321b54004 Nas Chung 2025-02-10 319 consumed_num++;
de204321b54004 Nas Chung 2025-02-10 320 }
de204321b54004 Nas Chung 2025-02-10 321 }
de204321b54004 Nas Chung 2025-02-10 322
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] Add support for Wave6 video codec driver
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (7 preceding siblings ...)
2025-02-10 9:07 ` [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities Nas Chung
@ 2025-02-10 13:05 ` Sebastian Fricke
2025-02-11 4:47 ` Nas Chung
2025-02-11 6:07 ` [EXT] " Ming Qian
9 siblings, 1 reply; 34+ messages in thread
From: Sebastian Fricke @ 2025-02-10 13:05 UTC (permalink / raw)
To: Nas Chung
Cc: mchehab, hverkuil, robh, krzk+dt, conor+dt, linux-media,
devicetree, linux-kernel, linux-imx, linux-arm-kernel,
jackson.lee, lafley.kim
Hey Nas,
On 10.02.2025 18:07, Nas Chung wrote:
>This patch series introduces support for the Chips&Media Wave6 video
>codec IP, a completely different hardware architecture compared to Wave5.
>
>The wave6 driver is a M2M stateful encoder/decoder driver.
>It supports various video formats, including H.264 and H.265,
>for both encoding and decoding.
Sounds like the hardware supports more formats.
What are the other video formats?
Regards,
Sebastian
>
>On NXP i.MX SoCs, the Wave6 IP functionality is split between two devices:
>VPU Control Device, Manages shared resources such as firmware access and
>power domains.
>VPU Device, Provides encoding and decoding capabilities.
>The VPU device cannot operate independently without the VPU control device.
>
>This driver has been tested with GStreamer on:
>- NXP i.MX95 board
>- pre-silicon FPGA environment
>
>Test results for decoder fluster:
>- JVT-AVC_V1, Ran 77/135 tests successfully in 35.929 secs
>- JVT-FR-EXT, Ran 25/69 tests successfully in 17.717 secs
>- JCT-VC-HEVC_V1, Ran 132/147 tests successfully in 81.568 secs
>- All failures are due to unsupported hardware features:
>-- 10bit, Resolutions higher than 4K, FMO, MBAFF
>-- Extended profile, Field encoding and High422 sreams.
>
>Test results for v4l2-compliance:
>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t
>v4l2-compliance SHA: 77f5df419204 2025-02-07 08:59:59
>
>Compliance test for wave6-dec device /dev/video0:
>
>Driver Info:
> Driver name : wave6-dec
> Card type : wave6-dec
> Bus info : platform:wave6-dec
> Driver version : 6.9.2
> Capabilities : 0x84204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x04204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Detected Stateful Decoder
>
>Required ioctls:
> test VIDIOC_QUERYCAP: OK
> test invalid ioctls: OK
>
>Allow for multiple opens:
> test second /dev/video0 open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
>Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK (Not Supported)
>
>Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 0 Audio Inputs: 0 Tuners: 0
>
>Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
>Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
>Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> fail: ../utils/v4l2-compliance/v4l2-test-controls.cpp(1180): !have_source_change || !have_eos
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 7 Private Controls: 1
>
>Format ioctls:
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK (Not Supported)
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK
> test Composing: OK
> test Scaling: OK (Not Supported)
>
>Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK
>
>Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test CREATE_BUFS maximum buffers: OK
> test VIDIOC_REMOVE_BUFS: OK
> test VIDIOC_EXPBUF: OK
> test Requests: OK (Not Supported)
> test blocking wait: OK
>
>Total for wave6-dec device /dev/video0: 48, Succeeded: 47, Failed: 1, Warnings: 0
>
>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t
>v4l2-compliance SHA: 77f5df419204 2025-02-07 08:59:59
>
>Compliance test for wave6-enc device /dev/video1:
>
>Driver Info:
> Driver name : wave6-enc
> Card type : wave6-enc
> Bus info : platform:wave6-enc
> Driver version : 6.9.2
> Capabilities : 0x84204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x04204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Detected Stateful Encoder
>
>Required ioctls:
> test VIDIOC_QUERYCAP: OK
> test invalid ioctls: OK
>
>Allow for multiple opens:
> test second /dev/video1 open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
>Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK (Not Supported)
>
>Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 0 Audio Inputs: 0 Tuners: 0
>
>Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
>Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
>Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> fail: ../utils/v4l2-compliance/v4l2-test-controls.cpp(1169): node->codec_mask & STATEFUL_ENCODER
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 53 Private Controls: 0
>
>Format ioctls:
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK
> test Composing: OK (Not Supported)
> test Scaling: OK (Not Supported)
>
>Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>
>Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test CREATE_BUFS maximum buffers: OK
> test VIDIOC_REMOVE_BUFS: OK
> test VIDIOC_EXPBUF: OK
> test Requests: OK (Not Supported)
> test blocking wait: OK
>
>Total for wave6-enc device /dev/video1: 48, Succeeded: 47, Failed: 1, Warnings: 0
>
>Nas Chung (8):
> media: platform: chips-media: wave5: Rename Kconfig parameter
> media: v4l2-common: Add YUV24 format info
> dt-bindings: media: nxp: Add Wave6 video codec device
> media: chips-media: wave6: Add Wave6 codec driver
> media: chips-media: wave6: Add v4l2 m2m driver
> media: chips-media: wave6: Add Wave6 vpu interface
> media: chips-media: wave6: Add Wave6 control driver
> media: chips-media: wave6: Improve debugging capabilities
>
> .../bindings/media/nxp,wave633c.yaml | 202 ++
> MAINTAINERS | 8 +
> arch/arm64/configs/defconfig | 2 +-
> drivers/media/platform/chips-media/Kconfig | 1 +
> drivers/media/platform/chips-media/Makefile | 1 +
> .../media/platform/chips-media/wave5/Kconfig | 6 +-
> .../media/platform/chips-media/wave5/Makefile | 2 +-
> .../media/platform/chips-media/wave6/Kconfig | 26 +
> .../media/platform/chips-media/wave6/Makefile | 17 +
> .../platform/chips-media/wave6/wave6-hw.c | 3113 +++++++++++++++++
> .../platform/chips-media/wave6/wave6-hw.h | 69 +
> .../chips-media/wave6/wave6-regdefine.h | 675 ++++
> .../platform/chips-media/wave6/wave6-trace.h | 336 ++
> .../platform/chips-media/wave6/wave6-vdi.c | 52 +
> .../platform/chips-media/wave6/wave6-vdi.h | 59 +
> .../chips-media/wave6/wave6-vpu-ctrl.c | 1020 ++++++
> .../chips-media/wave6/wave6-vpu-ctrl.h | 38 +
> .../chips-media/wave6/wave6-vpu-dbg.c | 230 ++
> .../chips-media/wave6/wave6-vpu-dbg.h | 22 +
> .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++
> .../chips-media/wave6/wave6-vpu-enc.c | 2698 ++++++++++++++
> .../chips-media/wave6/wave6-vpu-v4l2.c | 381 ++
> .../platform/chips-media/wave6/wave6-vpu.c | 487 +++
> .../platform/chips-media/wave6/wave6-vpu.h | 106 +
> .../platform/chips-media/wave6/wave6-vpuapi.c | 1001 ++++++
> .../platform/chips-media/wave6/wave6-vpuapi.h | 993 ++++++
> .../chips-media/wave6/wave6-vpuconfig.h | 80 +
> .../chips-media/wave6/wave6-vpuerror.h | 262 ++
> drivers/media/v4l2-core/v4l2-common.c | 1 +
> 29 files changed, 13766 insertions(+), 5 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/media/nxp,wave633c.yaml
> create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig
> create mode 100644 drivers/media/platform/chips-media/wave6/Makefile
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-regdefine.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-trace.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuerror.h
>
>--
>2.31.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [PATCH 0/8] Add support for Wave6 video codec driver
2025-02-10 13:05 ` [PATCH 0/8] Add support for Wave6 video codec driver Sebastian Fricke
@ 2025-02-11 4:47 ` Nas Chung
0 siblings, 0 replies; 34+ messages in thread
From: Nas Chung @ 2025-02-11 4:47 UTC (permalink / raw)
To: Sebastian Fricke
Cc: mchehab@kernel.org, hverkuil@xs4all.nl, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-imx@nxp.com,
linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim
Hi, Sebastian.
>-----Original Message-----
>From: Sebastian Fricke <sebastian.fricke@collabora.com>
>Sent: Monday, February 10, 2025 10:05 PM
>To: Nas Chung <nas.chung@chipsnmedia.com>
>Cc: mchehab@kernel.org; hverkuil@xs4all.nl; robh@kernel.org;
>krzk+dt@kernel.org; conor+dt@kernel.org; linux-media@vger.kernel.org;
>devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-imx@nxp.com;
>linux-arm-kernel@lists.infradead.org; jackson.lee
><jackson.lee@chipsnmedia.com>; lafley.kim <lafley.kim@chipsnmedia.com>
>Subject: Re: [PATCH 0/8] Add support for Wave6 video codec driver
>
>Hey Nas,
>
>On 10.02.2025 18:07, Nas Chung wrote:
>>This patch series introduces support for the Chips&Media Wave6 video
>>codec IP, a completely different hardware architecture compared to Wave5.
>>
>>The wave6 driver is a M2M stateful encoder/decoder driver.
>>It supports various video formats, including H.264 and H.265,
>>for both encoding and decoding.
>
>Sounds like the hardware supports more formats.
>What are the other video formats?
You are correct.
The Wave6 IP supports VP9/AV1 decoding and AV1 encoding.
However, the IP can be configured to support only specific formats.
The Wave6 driver currently being upstreamed has been validated with
the Wave633 configuration, which supports only H.264 and H.265.
Thanks.
Nas.
>
>Regards,
>Sebastian
>
>>
>>On NXP i.MX SoCs, the Wave6 IP functionality is split between two devices:
>>VPU Control Device, Manages shared resources such as firmware access and
>>power domains.
>>VPU Device, Provides encoding and decoding capabilities.
>>The VPU device cannot operate independently without the VPU control device.
>>
>>This driver has been tested with GStreamer on:
>>- NXP i.MX95 board
>>- pre-silicon FPGA environment
>>
>>Test results for decoder fluster:
>>- JVT-AVC_V1, Ran 77/135 tests successfully in 35.929 secs
>>- JVT-FR-EXT, Ran 25/69 tests successfully in 17.717 secs
>>- JCT-VC-HEVC_V1, Ran 132/147 tests successfully in 81.568 secs
>>- All failures are due to unsupported hardware features:
>>-- 10bit, Resolutions higher than 4K, FMO, MBAFF
>>-- Extended profile, Field encoding and High422 sreams.
>>
>>Test results for v4l2-compliance:
>>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t
>>v4l2-compliance SHA: 77f5df419204 2025-02-07 08:59:59
>>
>>Compliance test for wave6-dec device /dev/video0:
>>
>>Driver Info:
>> Driver name : wave6-dec
>> Card type : wave6-dec
>> Bus info : platform:wave6-dec
>> Driver version : 6.9.2
>> Capabilities : 0x84204000
>> Video Memory-to-Memory Multiplanar
>> Streaming
>> Extended Pix Format
>> Device Capabilities
>> Device Caps : 0x04204000
>> Video Memory-to-Memory Multiplanar
>> Streaming
>> Extended Pix Format
>> Detected Stateful Decoder
>>
>>Required ioctls:
>> test VIDIOC_QUERYCAP: OK
>> test invalid ioctls: OK
>>
>>Allow for multiple opens:
>> test second /dev/video0 open: OK
>> test VIDIOC_QUERYCAP: OK
>> test VIDIOC_G/S_PRIORITY: OK
>> test for unlimited opens: OK
>>
>>Debug ioctls:
>> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
>> test VIDIOC_LOG_STATUS: OK (Not Supported)
>>
>>Input ioctls:
>> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
>> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
>> test VIDIOC_ENUMAUDIO: OK (Not Supported)
>> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
>> test VIDIOC_G/S_AUDIO: OK (Not Supported)
>> Inputs: 0 Audio Inputs: 0 Tuners: 0
>>
>>Output ioctls:
>> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
>> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
>> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
>> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
>> Outputs: 0 Audio Outputs: 0 Modulators: 0
>>
>>Input/Output configuration ioctls:
>> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
>> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
>> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
>> test VIDIOC_G/S_EDID: OK (Not Supported)
>>
>>Control ioctls:
>> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
>> test VIDIOC_QUERYCTRL: OK
>> test VIDIOC_G/S_CTRL: OK
>> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
>> fail: ../utils/v4l2-compliance/v4l2-test-
>controls.cpp(1180): !have_source_change || !have_eos
>> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
>> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>> Standard Controls: 7 Private Controls: 1
>>
>>Format ioctls:
>> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
>> test VIDIOC_G/S_PARM: OK (Not Supported)
>> test VIDIOC_G_FBUF: OK (Not Supported)
>> test VIDIOC_G_FMT: OK
>> test VIDIOC_TRY_FMT: OK
>> test VIDIOC_S_FMT: OK
>> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
>> test Cropping: OK
>> test Composing: OK
>> test Scaling: OK (Not Supported)
>>
>>Codec ioctls:
>> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
>> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
>> test VIDIOC_(TRY_)DECODER_CMD: OK
>>
>>Buffer ioctls:
>> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
>> test CREATE_BUFS maximum buffers: OK
>> test VIDIOC_REMOVE_BUFS: OK
>> test VIDIOC_EXPBUF: OK
>> test Requests: OK (Not Supported)
>> test blocking wait: OK
>>
>>Total for wave6-dec device /dev/video0: 48, Succeeded: 47, Failed: 1,
>Warnings: 0
>>
>>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t
>>v4l2-compliance SHA: 77f5df419204 2025-02-07 08:59:59
>>
>>Compliance test for wave6-enc device /dev/video1:
>>
>>Driver Info:
>> Driver name : wave6-enc
>> Card type : wave6-enc
>> Bus info : platform:wave6-enc
>> Driver version : 6.9.2
>> Capabilities : 0x84204000
>> Video Memory-to-Memory Multiplanar
>> Streaming
>> Extended Pix Format
>> Device Capabilities
>> Device Caps : 0x04204000
>> Video Memory-to-Memory Multiplanar
>> Streaming
>> Extended Pix Format
>> Detected Stateful Encoder
>>
>>Required ioctls:
>> test VIDIOC_QUERYCAP: OK
>> test invalid ioctls: OK
>>
>>Allow for multiple opens:
>> test second /dev/video1 open: OK
>> test VIDIOC_QUERYCAP: OK
>> test VIDIOC_G/S_PRIORITY: OK
>> test for unlimited opens: OK
>>
>>Debug ioctls:
>> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
>> test VIDIOC_LOG_STATUS: OK (Not Supported)
>>
>>Input ioctls:
>> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
>> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
>> test VIDIOC_ENUMAUDIO: OK (Not Supported)
>> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
>> test VIDIOC_G/S_AUDIO: OK (Not Supported)
>> Inputs: 0 Audio Inputs: 0 Tuners: 0
>>
>>Output ioctls:
>> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
>> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
>> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
>> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
>> Outputs: 0 Audio Outputs: 0 Modulators: 0
>>
>>Input/Output configuration ioctls:
>> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
>> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
>> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
>> test VIDIOC_G/S_EDID: OK (Not Supported)
>>
>>Control ioctls:
>> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
>> test VIDIOC_QUERYCTRL: OK
>> test VIDIOC_G/S_CTRL: OK
>> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
>> fail: ../utils/v4l2-compliance/v4l2-test-controls.cpp(1169):
>node->codec_mask & STATEFUL_ENCODER
>> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
>> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>> Standard Controls: 53 Private Controls: 0
>>
>>Format ioctls:
>> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
>> test VIDIOC_G/S_PARM: OK
>> test VIDIOC_G_FBUF: OK (Not Supported)
>> test VIDIOC_G_FMT: OK
>> test VIDIOC_TRY_FMT: OK
>> test VIDIOC_S_FMT: OK
>> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
>> test Cropping: OK
>> test Composing: OK (Not Supported)
>> test Scaling: OK (Not Supported)
>>
>>Codec ioctls:
>> test VIDIOC_(TRY_)ENCODER_CMD: OK
>> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
>> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>>
>>Buffer ioctls:
>> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
>> test CREATE_BUFS maximum buffers: OK
>> test VIDIOC_REMOVE_BUFS: OK
>> test VIDIOC_EXPBUF: OK
>> test Requests: OK (Not Supported)
>> test blocking wait: OK
>>
>>Total for wave6-enc device /dev/video1: 48, Succeeded: 47, Failed: 1,
>Warnings: 0
>>
>>Nas Chung (8):
>> media: platform: chips-media: wave5: Rename Kconfig parameter
>> media: v4l2-common: Add YUV24 format info
>> dt-bindings: media: nxp: Add Wave6 video codec device
>> media: chips-media: wave6: Add Wave6 codec driver
>> media: chips-media: wave6: Add v4l2 m2m driver
>> media: chips-media: wave6: Add Wave6 vpu interface
>> media: chips-media: wave6: Add Wave6 control driver
>> media: chips-media: wave6: Improve debugging capabilities
>>
>> .../bindings/media/nxp,wave633c.yaml | 202 ++
>> MAINTAINERS | 8 +
>> arch/arm64/configs/defconfig | 2 +-
>> drivers/media/platform/chips-media/Kconfig | 1 +
>> drivers/media/platform/chips-media/Makefile | 1 +
>> .../media/platform/chips-media/wave5/Kconfig | 6 +-
>> .../media/platform/chips-media/wave5/Makefile | 2 +-
>> .../media/platform/chips-media/wave6/Kconfig | 26 +
>> .../media/platform/chips-media/wave6/Makefile | 17 +
>> .../platform/chips-media/wave6/wave6-hw.c | 3113 +++++++++++++++++
>> .../platform/chips-media/wave6/wave6-hw.h | 69 +
>> .../chips-media/wave6/wave6-regdefine.h | 675 ++++
>> .../platform/chips-media/wave6/wave6-trace.h | 336 ++
>> .../platform/chips-media/wave6/wave6-vdi.c | 52 +
>> .../platform/chips-media/wave6/wave6-vdi.h | 59 +
>> .../chips-media/wave6/wave6-vpu-ctrl.c | 1020 ++++++
>> .../chips-media/wave6/wave6-vpu-ctrl.h | 38 +
>> .../chips-media/wave6/wave6-vpu-dbg.c | 230 ++
>> .../chips-media/wave6/wave6-vpu-dbg.h | 22 +
>> .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++
>> .../chips-media/wave6/wave6-vpu-enc.c | 2698 ++++++++++++++
>> .../chips-media/wave6/wave6-vpu-v4l2.c | 381 ++
>> .../platform/chips-media/wave6/wave6-vpu.c | 487 +++
>> .../platform/chips-media/wave6/wave6-vpu.h | 106 +
>> .../platform/chips-media/wave6/wave6-vpuapi.c | 1001 ++++++
>> .../platform/chips-media/wave6/wave6-vpuapi.h | 993 ++++++
>> .../chips-media/wave6/wave6-vpuconfig.h | 80 +
>> .../chips-media/wave6/wave6-vpuerror.h | 262 ++
>> drivers/media/v4l2-core/v4l2-common.c | 1 +
>> 29 files changed, 13766 insertions(+), 5 deletions(-)
>> create mode 100644
>Documentation/devicetree/bindings/media/nxp,wave633c.yaml
>> create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig
>> create mode 100644 drivers/media/platform/chips-media/wave6/Makefile
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>regdefine.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-trace.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>ctrl.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>ctrl.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dbg.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dbg.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dec.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>enc.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>v4l2.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuapi.c
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuapi.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuconfig.h
>> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuerror.h
>>
>>--
>>2.31.1
>>
^ permalink raw reply [flat|nested] 34+ messages in thread
* RE: [EXT] [PATCH 0/8] Add support for Wave6 video codec driver
2025-02-10 9:07 [PATCH 0/8] Add support for Wave6 video codec driver Nas Chung
` (8 preceding siblings ...)
2025-02-10 13:05 ` [PATCH 0/8] Add support for Wave6 video codec driver Sebastian Fricke
@ 2025-02-11 6:07 ` Ming Qian
9 siblings, 0 replies; 34+ messages in thread
From: Ming Qian @ 2025-02-11 6:07 UTC (permalink / raw)
To: Nas Chung, mchehab@kernel.org, hverkuil@xs4all.nl,
sebastian.fricke@collabora.com, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org
Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, dl-linux-imx,
linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com,
lafley.kim@chipsnmedia.com
Tested on i.MX95, the sanity test pass of encoder and decoder.
Only a v4l2-compliance issue about the deprecated behavior EOS event, other than that.
Tested-by: Ming Qian <ming.qian@oss.nxp.com>
>-----Original Message-----
>From: Nas Chung <nas.chung@chipsnmedia.com>
>Sent: Monday, February 10, 2025 5:07 PM
>To: mchehab@kernel.org; hverkuil@xs4all.nl; sebastian.fricke@collabora.com;
>robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>; linux-arm-
>kernel@lists.infradead.org; jackson.lee@chipsnmedia.com;
>lafley.kim@chipsnmedia.com; Nas Chung <nas.chung@chipsnmedia.com>
>Subject: [EXT] [PATCH 0/8] Add support for Wave6 video codec driver
>
>Caution: This is an external email. Please take care when clicking links or
>opening attachments. When in doubt, report the message using the 'Report
>this email' button
>
>
>This patch series introduces support for the Chips&Media Wave6 video codec
>IP, a completely different hardware architecture compared to Wave5.
>
>The wave6 driver is a M2M stateful encoder/decoder driver.
>It supports various video formats, including H.264 and H.265, for both
>encoding and decoding.
>
>On NXP i.MX SoCs, the Wave6 IP functionality is split between two devices:
>VPU Control Device, Manages shared resources such as firmware access and
>power domains.
>VPU Device, Provides encoding and decoding capabilities.
>The VPU device cannot operate independently without the VPU control device.
>
>This driver has been tested with GStreamer on:
>- NXP i.MX95 board
>- pre-silicon FPGA environment
>
>Test results for decoder fluster:
>- JVT-AVC_V1, Ran 77/135 tests successfully in 35.929 secs
>- JVT-FR-EXT, Ran 25/69 tests successfully in 17.717 secs
>- JCT-VC-HEVC_V1, Ran 132/147 tests successfully in 81.568 secs
>- All failures are due to unsupported hardware features:
>-- 10bit, Resolutions higher than 4K, FMO, MBAFF
>-- Extended profile, Field encoding and High422 sreams.
>
>Test results for v4l2-compliance:
>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t v4l2-compliance SHA:
>77f5df419204 2025-02-07 08:59:59
>
>Compliance test for wave6-dec device /dev/video0:
>
>Driver Info:
> Driver name : wave6-dec
> Card type : wave6-dec
> Bus info : platform:wave6-dec
> Driver version : 6.9.2
> Capabilities : 0x84204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x04204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Detected Stateful Decoder
>
>Required ioctls:
> test VIDIOC_QUERYCAP: OK
> test invalid ioctls: OK
>
>Allow for multiple opens:
> test second /dev/video0 open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
>Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK (Not Supported)
>
>Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 0 Audio Inputs: 0 Tuners: 0
>
>Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
>Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
>Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> fail: ../utils/v4l2-compliance/v4l2-test-
>controls.cpp(1180): !have_source_change || !have_eos
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 7 Private Controls: 1
>
>Format ioctls:
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK (Not Supported)
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK
> test Composing: OK
> test Scaling: OK (Not Supported)
>
>Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK
>
>Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test CREATE_BUFS maximum buffers: OK
> test VIDIOC_REMOVE_BUFS: OK
> test VIDIOC_EXPBUF: OK
> test Requests: OK (Not Supported)
> test blocking wait: OK
>
>Total for wave6-dec device /dev/video0: 48, Succeeded: 47, Failed: 1, Warnings:
>0
>
>v4l2-compliance 1.29.0-5326, 64 bits, 64-bit time_t v4l2-compliance SHA:
>77f5df419204 2025-02-07 08:59:59
>
>Compliance test for wave6-enc device /dev/video1:
>
>Driver Info:
> Driver name : wave6-enc
> Card type : wave6-enc
> Bus info : platform:wave6-enc
> Driver version : 6.9.2
> Capabilities : 0x84204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x04204000
> Video Memory-to-Memory Multiplanar
> Streaming
> Extended Pix Format
> Detected Stateful Encoder
>
>Required ioctls:
> test VIDIOC_QUERYCAP: OK
> test invalid ioctls: OK
>
>Allow for multiple opens:
> test second /dev/video1 open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
>Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK (Not Supported)
>
>Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 0 Audio Inputs: 0 Tuners: 0
>
>Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
>Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
>Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> fail: ../utils/v4l2-compliance/v4l2-test-controls.cpp(1169): node-
>>codec_mask & STATEFUL_ENCODER
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 53 Private Controls: 0
>
>Format ioctls:
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK
> test Composing: OK (Not Supported)
> test Scaling: OK (Not Supported)
>
>Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>
>Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test CREATE_BUFS maximum buffers: OK
> test VIDIOC_REMOVE_BUFS: OK
> test VIDIOC_EXPBUF: OK
> test Requests: OK (Not Supported)
> test blocking wait: OK
>
>Total for wave6-enc device /dev/video1: 48, Succeeded: 47, Failed: 1, Warnings:
>0
>
>Nas Chung (8):
> media: platform: chips-media: wave5: Rename Kconfig parameter
> media: v4l2-common: Add YUV24 format info
> dt-bindings: media: nxp: Add Wave6 video codec device
> media: chips-media: wave6: Add Wave6 codec driver
> media: chips-media: wave6: Add v4l2 m2m driver
> media: chips-media: wave6: Add Wave6 vpu interface
> media: chips-media: wave6: Add Wave6 control driver
> media: chips-media: wave6: Improve debugging capabilities
>
> .../bindings/media/nxp,wave633c.yaml | 202 ++
> MAINTAINERS | 8 +
> arch/arm64/configs/defconfig | 2 +-
> drivers/media/platform/chips-media/Kconfig | 1 +
> drivers/media/platform/chips-media/Makefile | 1 +
> .../media/platform/chips-media/wave5/Kconfig | 6 +-
> .../media/platform/chips-media/wave5/Makefile | 2 +-
> .../media/platform/chips-media/wave6/Kconfig | 26 +
> .../media/platform/chips-media/wave6/Makefile | 17 +
> .../platform/chips-media/wave6/wave6-hw.c | 3113 +++++++++++++++++
> .../platform/chips-media/wave6/wave6-hw.h | 69 +
> .../chips-media/wave6/wave6-regdefine.h | 675 ++++
> .../platform/chips-media/wave6/wave6-trace.h | 336 ++
> .../platform/chips-media/wave6/wave6-vdi.c | 52 +
> .../platform/chips-media/wave6/wave6-vdi.h | 59 +
> .../chips-media/wave6/wave6-vpu-ctrl.c | 1020 ++++++
> .../chips-media/wave6/wave6-vpu-ctrl.h | 38 +
> .../chips-media/wave6/wave6-vpu-dbg.c | 230 ++
> .../chips-media/wave6/wave6-vpu-dbg.h | 22 +
> .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++
> .../chips-media/wave6/wave6-vpu-enc.c | 2698 ++++++++++++++
> .../chips-media/wave6/wave6-vpu-v4l2.c | 381 ++
> .../platform/chips-media/wave6/wave6-vpu.c | 487 +++
> .../platform/chips-media/wave6/wave6-vpu.h | 106 +
> .../platform/chips-media/wave6/wave6-vpuapi.c | 1001
>++++++ .../platform/chips-media/wave6/wave6-vpuapi.h | 993 ++++++
> .../chips-media/wave6/wave6-vpuconfig.h | 80 +
> .../chips-media/wave6/wave6-vpuerror.h | 262 ++
> drivers/media/v4l2-core/v4l2-common.c | 1 +
> 29 files changed, 13766 insertions(+), 5 deletions(-) create mode 100644
>Documentation/devicetree/bindings/media/nxp,wave633c.yaml
> create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig
> create mode 100644 drivers/media/platform/chips-media/wave6/Makefile
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>regdefine.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>trace.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>ctrl.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>ctrl.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dbg.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dbg.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>dec.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>enc.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-
>v4l2.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuapi.c
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuapi.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuconfig.h
> create mode 100644 drivers/media/platform/chips-media/wave6/wave6-
>vpuerror.h
>
>--
>2.31.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread